diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..eb646df --- /dev/null +++ b/.dockerignore @@ -0,0 +1,34 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Coverage output +coverage.out +profile.cov + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +# vim files +*.swp + +# Pycharm/IDEA +.idea/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fe90d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Coverage +coverage.out + +# Bild artifacts +k8s-signal-logger + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +.idea/ + +# Ignore vim files +*.swp + +release.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..197587b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +# To build: +# $ docker run --rm -v $(pwd):/go/src/github.com/micahhausler/k8s-signal-logger -w /go/src/github.com/micahhausler/k8s-signal-logger golang:1.7 go build -v -a -tags netgo -installsuffix netgo -ldflags '-w' +# $ docker build -t micahhausler/k8s-signal-logger . +# +# To run: +# $ docker run micahhausler/k8s-signal-logger + +FROM alpine + +MAINTAINER Micah Hausler, + +RUN apk -U add ca-certificates + +COPY k8s-signal-logger /bin/k8s-signal-logger +RUN chmod 755 /bin/k8s-signal-logger + +EXPOSE 8080 + +ENTRYPOINT ["/bin/k8s-signal-logger"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1c5d379 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Micah Hausler + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c9f30c2 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# k8s-signal-logger + +k8s-signal-logger is a simple program for observing how Kubernetes responds to +[liveness and readiness probes](http://kubernetes.io/docs/api-reference/v1/definitions/#_v1_container) + +There are 3 endpoints to the container: + +- `/healthz` - Used for the health check +- `/ready` - Used for the readiness check +- `/` - A homepage handler - always responds with `200` + +## Try it out + +The following commands run: + +- Create the deployment and service +- Get the service's nodePort and a node's IP +- Run Apache bench against it +- Update the deployment. Once the deployment is completed, you can see the results from apache bench + +``` +kubectl create -f deployment.yaml -f service.yaml +export PORT=$(kubectl get -f service.yaml -o json | jq -r .spec.ports[0].nodePort) +export NODE=$(kubectl get no -o json | jq -r .items[0].status.addresses[0].address) +ab -n 1000000 -c 20 http://$NODE:$PORT/ + +# In a separate terminal +# - change a label on deployment.yaml +kubectl replace -f deployment.yaml +``` + +## License +MIT License. See [License](/LICENSE) for full text diff --git a/deployment.yaml b/deployment.yaml new file mode 100644 index 0000000..24a8931 --- /dev/null +++ b/deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + description: k8s-signal-logger + labels: + app: k8s-signal-logger + name: k8s-signal-logger + namespace: default +spec: + replicas: 2 + selector: + matchLabels: + app: k8s-signal-logger + strategy: + rollingUpdate: + maxSurge: "50%" + maxUnavailable: 0 + type: RollingUpdate + template: + metadata: + annotations: + description: k8s-signal-logger + labels: + app: k8s-signal-logger + server: web + name: k8s-signal-logger + spec: + containers: + - name: k8s-signal-logger + image: micahhausler/k8s-signal-logger + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 8080 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 4 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + failureThreshold: 1 + httpGet: + path: /ready + port: 8080 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + ports: + - containerPort: 8080 + protocol: TCP + dnsPolicy: Default + restartPolicy: Always + terminationGracePeriodSeconds: 30 diff --git a/main.go b/main.go new file mode 100644 index 0000000..a784064 --- /dev/null +++ b/main.go @@ -0,0 +1,67 @@ +package main + +import ( + "log" + "net/http" + "os" + "os/signal" + "syscall" +) + +var ok bool + +var ( + Term os.Signal = syscall.SIGTERM +) + +// log the Signal to STDOUT +func logSignal(c chan os.Signal) { + for s := range c { + log.Println("Got signal:", s) + ok = false + } + +} + +func main() { + ok = true + c := make(chan os.Signal) + signal.Notify(c, Term) + + go logSignal(c) + log.Println("starting server at :8080") + http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + if ok { + log.Printf("/healthz - OK - %d", http.StatusOK) + w.WriteHeader(http.StatusOK) + w.Write([]byte("OK")) + return + } else { + log.Printf("/healthz - FAIL - %d", http.StatusServiceUnavailable) + w.WriteHeader(http.StatusServiceUnavailable) + w.Write([]byte("FAIL")) + return + } + + }) + http.HandleFunc("/ready", func(w http.ResponseWriter, r *http.Request) { + if ok { + log.Printf("/ready - OK - %d", http.StatusOK) + w.WriteHeader(http.StatusOK) + w.Write([]byte("OK")) + return + } else { + log.Printf("/ready - FAIL - %d", http.StatusServiceUnavailable) + w.WriteHeader(http.StatusServiceUnavailable) + w.Write([]byte("FAIL")) + return + } + + }) + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + log.Printf("/- OK - %d", http.StatusOK) + w.WriteHeader(http.StatusOK) + w.Write([]byte("Welcome!\n")) + }) + http.ListenAndServe(":8080", nil) +} diff --git a/service.yaml b/service.yaml new file mode 100644 index 0000000..1972491 --- /dev/null +++ b/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: k8s-signal-logger + name: k8s-signal-logger + namespace: default +spec: + ports: + - name: http + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: k8s-signal-logger + type: NodePort