aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Dockerfile6
-rw-r--r--README.md28
-rw-r--r--main.go58
4 files changed, 67 insertions, 27 deletions
diff --git a/.gitignore b/.gitignore
index c539b9c..e9341d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
tags
showreadiness
+
+.vscode/ \ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index d887713..024d6b8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
-FROM busybox:latest
+FROM scratch
LABEL maintainer="Tyler Davis <tydavis@gmail.com>"
EXPOSE 80
-COPY showreadiness /
-CMD /showreadiness
+COPY showreadiness .
+CMD ["./showreadiness"]
diff --git a/README.md b/README.md
index 9c8ae04..d816262 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,35 @@
# showReadiness
-A simple golang application to explore [liveness and readiness checks](http://kubernetes.io/docs/user-guide/pod-states/) in Kubernetes.
+A simple golang application to explore [liveness and readiness checks][1] in
+Kubernetes.
## To build
+
In the cloned directory, run the following:
-```
+
+Linux/OSX:
+
+```bash
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -installsuffix netgo -ldflags '-w -s' .
```
-## To build with only Docker
-Ensure [docker](https://www.docker.com/get-docker) is installed. In the cloned directory, run the folowing:
+Windows:
+```powershell
+$env:CGO_ENABLED=0; $env:GOOS="linux"; $env:GOARCH="amd64"; go build -a -tags netgo -installsuffix netgo -ldflags "-s"
```
-docker run --rm -v $PWD:/go/src/github.com/tydavis/showreadiness -w /go/src/github.com/tydavis/showreadiness golang:alpine /bin/sh -c "CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -installsuffix netgo -ldflags '-w -s' . "
+
+Or type your
+
+## To build with only Docker
+
+If [docker][2] is installed, run the folowing in the checked-out directory:
+
+```bash
+docker run --rm -v $PWD:/go/src/github.com/tydavis/showreadiness \
+-w /go/src/github.com/tydavis/showreadiness golang:alpine /bin/sh \
+-c "CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -installsuffix netgo -ldflags '-w -s' . "
```
+[1]:http://kubernetes.io/docs/user-guide/pod-states/
+[2]:https://www.docker.com/get-docker \ No newline at end of file
diff --git a/main.go b/main.go
index 44e7257..bff3682 100644
--- a/main.go
+++ b/main.go
@@ -5,46 +5,73 @@ import (
"log"
"net/http"
"os"
+ "sync"
"time"
)
+// Globals are generally discouraged, but this is a very simple program, and we
+// are designing with concurrent access in mind.
+
+// Creating a custom struct with a lock, so we can lock access to the object
+type status struct {
+ value int
+ sync.Mutex
+}
+
// ReadyValue indiciates the program is ready to receive traffic
-var ReadyValue = http.StatusOK
+var ReadyValue = status{value: http.StatusOK}
// LiveValue indiciates the program is alive and should not be terminated
-var LiveValue = http.StatusOK
+var LiveValue = status{value: http.StatusOK}
var hostname string
func makeNotReady(w http.ResponseWriter, r *http.Request) {
- ReadyValue = http.StatusBadRequest
+ // Lock access to the variable, then set our global ReadyValue to a failing
+ // value before sending the response
+ ReadyValue.Lock()
+ ReadyValue.value = http.StatusBadRequest
+ ReadyValue.Unlock()
w.Header().Set("responding-pod", hostname)
fmt.Fprintf(w, "%s", "Set Readiness Value to a failure state")
}
+// Hitting this endpoint (by any means) will
func makePodReady(w http.ResponseWriter, r *http.Request) {
- ReadyValue = http.StatusOK
+ ReadyValue.Lock()
+ ReadyValue.value = http.StatusOK
+ ReadyValue.Unlock()
w.Header().Set("responding-pod", hostname)
fmt.Fprintf(w, "%s", "Set Readiness Value to successful (OK) state")
}
+// This function guarantees Kubernetes will kill the pod
func killMe(w http.ResponseWriter, r *http.Request) {
- LiveValue = http.StatusBadRequest
+ LiveValue.Lock()
+ LiveValue.value = http.StatusBadRequest
+ LiveValue.Unlock()
w.Header().Set("responding-pod", hostname)
fmt.Fprintf(w, "%s", "Set Liveness Value to a failure state")
}
+// Provides Ready state to Kubernetes for receiving/stopping traffic
func readinessCheck(w http.ResponseWriter, r *http.Request) {
w.Header().Set("responding-pod", hostname)
- http.Error(w, "Responding with ReadyValue", ReadyValue)
+ ReadyValue.Lock()
+ http.Error(w, "Responding with ReadyValue", ReadyValue.value)
+ ReadyValue.Unlock()
}
+// Endpoint checked internally by Kubernetes
func livenessCheck(w http.ResponseWriter, r *http.Request) {
w.Header().Set("responding-pod", hostname)
- http.Error(w, "Responding with LiveValue", LiveValue)
+ LiveValue.Lock()
+ http.Error(w, "Responding with LiveValue", LiveValue.value)
+ LiveValue.Unlock()
}
+// The default endpoint
func rootHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("responding-pod", hostname)
fmt.Fprintf(w, "%s", "I'm serving traffic!")
@@ -54,21 +81,14 @@ func main() {
// Force log output to stdout for Docker
log.SetOutput(os.Stdout)
- // Configurable delay for startup
- var delay = (1 * time.Second)
- if os.Getenv("APPDELAY") != "" {
- var err error
- delay, err = time.ParseDuration(os.Getenv("APPDELAY"))
- if err != nil {
- log.Fatalf("Failed to parse time duration: %v", err)
- }
- }
- time.Sleep(delay)
-
// Finish startup
hostname, _ = os.Hostname()
log.Println("Service started on port 80")
+ // Set up a custom mutex to add custom handlers. [Note] this level of breakout
+ // is not required, as we could reasonably compact this into a single call,
+ // but would lose some readability. This also makes it easy for us to use a
+ // custom muxer (e.g. gorillamux), custom server, etc
mux := http.NewServeMux()
mux.HandleFunc("/", rootHandler)
mux.HandleFunc("/ping", livenessCheck)
@@ -84,8 +104,8 @@ func main() {
WriteTimeout: 3 * time.Second,
}
+ // Actually run our server
if err := server.ListenAndServe(); err != nil {
log.Fatalln(err)
}
-
}