This project contains a simple GO rest API service. This service is useful to test the Kubernetes and Docker.
We also packaged it as a Docker Image. We used mutli stage build to create the small docker image. and The size of the image is very small. It's just 12.4 MB. You can build/push/pull it from docker hub using below command.
$ docker build -t davarski/go-rest-api-demo .
$ docker login
$ docker push davarski/go-rest-api-demo
$ docker pull davarski/go-rest-api-demo
We are using the Gorilla Mux and Following routes are implemented
/info
- Returns the info about the request./health-check
- Returns JSON response asTrue
if the service is running fine. We can also add custom delay by setting theHEALTHDELAY
Environment variable./env
- Returns present container environment variables in JSON format./quote
- Returns a Random Quote from thequotes.json
file.
Clone the repo and run the main.go
using the go run
### Install Go
$ wget https://go.dev/dl/go1.18.4.linux-amd64.tar.gz
$ sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.18.4.linux-amd64.tar.gz
$ grep GO ~/.bashrc
export GOROOT=/usr/local/go
export PATH=${GOROOT}/bin:${PATH}
export GOPATH=$HOME/go
export PATH=${GOPATH}/bin:${PATH}
$ go version
go version go1.18.4 linux/amd64
$ go run main.go
2022/08/01 12:05:54 Simple API Server(1.0.0) running on 0.0.0.0:32000
By default server listens on 10000
Port on all Interfaces (0.0.0.0)
of node. Goto the 127.0.0.1:10000/info
from your browser or by using the curl
.
Please look at the Running on Docker section
Please look at the Running on Kubernetes section
{"Endpoint":"/info","Host":"127.0.0.1:10000","Method":"GET","RemoteIP":"127.0.0.1:60942","Version":"1.0.0"}
$ curl 127.0.0.1:10000/info
{"Endpoint":"/info","Host":"127.0.0.1:10000","Method":"GET","RemoteIP":"127.0.0.1:60942","Version":"1.0.0"}
This /health-check
route, Returns healthy:true
if server is running fine. So we can see the status of the server by monitoring this route. This can be used with the Kubernetes Readiness and Liveness probes.
We can also add custom delay by setting the HEALTHDELAY
environment variable.
$ curl 127.0.0.1:10000/health-check
{"healthy":true}
This /env
route dumps the all environment variables
$ curl 127.0.0.1:10000/env
{"Version":"1.0.0","env":"CLUTTER_IM_MODULE=xim, LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.
...
This /quote
route will generate random quote. We use the quotes.json
file, which contains the list of quotes with author names. You can pass your own json
quotes file to override the quotes.
$ curl 127.0.0.1:10000/quote
{"Quote":"If my mind can conceive it, if my heart can believe it, then I can achieve it. - Muhammad Ali","Version":"1.0.0"}
$ curl 127.0.0.1:10000/quote
{"Quote":"Any fool can write code that a computer can understand. Good programmers write code that humans can understand. - Martin Fowler","Version":"1.0.0"}
$ curl 127.0.0.1:10000/quote
{"Quote":"The only true wisdom is in knowing you know nothing. - Socrates","Version":"1.0.0"}
We can change the Port number where API server is running by setting the PORT
environment variable.
By default server runs on 10000
Port.
$ go run main.go
2022/08/01 12:14:18 Simple API Server(1.0.0) running on 0.0.0.0:10000
Set the PORT
Environment variable and run the go run
. If you are in Linux set using the export
command.
$ export PORT="32000"
$ go run main.go
2022/08/01 12:18:19 Simple API Server(1.0.0) running on 0.0.0.0:32000
We can see the PORT
is changed.
We can delay the /health-check
endpoint response by setting the HEALTHDELAY
Environment variable.
$ export HEALTHDELAY="5"
Re-run the app
$ go run main.go
2022/08/01 12:21:59 Simple API Server(1.0.0) running on 0.0.0.0:10000
2022/08/01 12:22:06 Entering /health-check endpoint, Invoked from 127.0.0.1:36984
2022/08/01 12:22:11 Added 5 seconds delay, Serving Requst Now
$ curl 127.0.0.1:10000/health-check
{"healthy":true}
Note that the response is served after 5 seconds at
00:43:53
You can change the source Quotes fine by setting the QUOTESFILE
environment variable. Please look at the following example.
$ cp quotes.json test.json
$ export QUOTESFILE="./test.json"
$ go run main.go
2022/08/01 12:36:38 Simple API Server(1.0.0) running on 0.0.0.0:10000
2022/08/01 12:36:50 Entered /quote endpoint, Invoked from 127.0.0.1:45226 , using ./test.json as QuotesSource
2022/08/01 12:36:50 The only true wisdom is in knowing you know nothing. - Socrates
$ curl 127.0.0.1:10000/quote
{"Quote":"The only true wisdom is in knowing you know nothing. - Socrates","Version":"1.0.0"}
$ unset QUOTESFILE
$ go run main.go
2022/08/01 12:39:15 Simple API Server(1.0.0) running on 0.0.0.0:10000
2022/08/01 12:39:20 Entered /quote endpoint, Invoked from 127.0.0.1:46610 , using ./quotes.json as QuotesSource
2022/08/01 12:39:20 If my mind can conceive it, if my heart can believe it, then I can achieve it. - Muhammad Ali
$ curl 127.0.0.1:10000/quote
{"Quote":"If my mind can conceive it, if my heart can believe it, then I can achieve it. - Muhammad Ali","Version":"1.0.0"}
Here I have added a
test.json
file on the same folder, So I have used relative Path. Please make sure to specify the correct path for file (or use the Absolute path)
You can create the docker container using the docker run
like below.
$ docker run -d -p 10000:10000 davarski/go-rest-api-demo
26b56788f3cf4521e64d19fbe1a6cd480e4a52012a0130b05e928f86b86654da
By default server listens on 10000
Port on all Interfaces (0.0.0.0)
of node. We have exposed the port 10000
to the host system. So that I can test with curl
or any other app.
We can change the Port number where API server is running by setting the PORT
environment variable. By default server runs on 10000
Port.
Here is an example to change the default port number using the docker environment variable. Use the -e
option and pass the desired port number to PORT
environment variable.
$ docker run -d -e PORT='32000' -p 32000:32000 davarski/go-rest-api-demo
b9dbfdda77dfd365ae6ff71a8117c8d29669e81620af281efdcec227976f142a
You can check the logs to see where the server is listening.
$ docker logs 51b5ce01e53f
2022/08/01 09:44:53 Simple API Server(1.0.0) running on 0.0.0.0:32000
Here it is listening on 0.0.0.0:32000
Make a call to any of the API endpoint or route.
$ curl 127.0.0.1:32000/quote
{"Quote":"The only way to learn a new programming language is by writing programs in it. - Dennis Ritchie","Version":"1.0.0"}
We can delay the /health-check
endpoint response by setting the HEALTHDELAY
Environment variable. The configurable health-check API is useful to test the Readiness and Liveness Probes of K8s
Here I am setting the 5 Seconds
delay by passing the 5
to HEALTHDELAY
env.
$ docker run -d -e HEALTHDELAY='5' -p 10000:10000 davarski/go-rest-api-demo
bcbcd1e06093c82e5a8a62ee01df8fa4f0f6048f8e0c535d726e9b8385c07b78
Now try to access the /health-check
API. and you will get the delayed response ( You are response delayed by 5 seconds).
$ curl 127.0.0.1:10000/health-check
{"healthy":true}
We can also verify the delay by looking into the docker container logs.
$ docker logs bcbcd1e06093
2022/08/01 09:47:43 Simple API Server(1.0.0) running on 0.0.0.0:10000
2022/08/01 09:48:18 Entering /health-check endpoint, Invoked from 10.30.0.1:48810
2022/08/01 09:48:23 Added 5 seconds delay, Serving Requst Now
We can see the request was received at 18:40:08
and we delayed it by 5 seconds and served the request at 18:40:13
.
## KIND install
$ curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.14.0/kind-linux-amd64 && chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind
## Create cluster (CNI=Calico, Enable ingress)
$ cd kubernetes
$ kind create cluster --name devops --config cluster-config.yaml
$ kind get kubeconfig --name="devops" > admin.conf
$ export KUBECONFIG=./admin.conf
$ kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
$ kubectl -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true
## Ingress Nginx (optional)
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
## LoadBalancer (MetalLB)
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
### Edit metallb-configmap-davar.yaml
$ docker network inspect -f '{{.IPAM.Config}}' kind
[{172.20.0.0/16 172.17.0.1 map[]} {fc00:f853:ccd:e793::/64 map[]}]
$ cat metallb-configmap-carbon.yaml
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 172.20.0.200-172.20.0.250
$ kubectl apply -f metallb-configmap.yaml
create a qotd manifest definition file and specify the container image as davarski/go-rest-api-demo
. Here is an example.
$ cat kubernetes/loadbalancer-usage.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: rest
labels:
app: rest
spec:
replicas: 2
selector:
matchLabels:
app: rest
template:
metadata:
labels:
app: rest
spec:
containers:
- name: rest
image: davarski/go-rest-api-demo
ports:
- name: http
containerPort: 10000
---
kind: Service
apiVersion: v1
metadata:
name: rest
spec:
type: LoadBalancer
selector:
app: rest
ports:
# Default port used by the image
- port: 10000
Let's create the Go microservice using the kubectl create
command, You can also use the kubectl apply
command,
$ kubectl apply -f loadbalancer-qotd.yaml
deployment.apps/rest created
service/rest created
let's check if the pod is created using the kubectl get pods
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/rest-786fc49b6-gqvvq 1/1 Running 0 15s
pod/rest-786fc49b6-t7qtq 1/1 Running 0 15s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9m8s
service/rest LoadBalancer 10.96.15.71 172.20.0.200 10000:31061/TCP 15s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/rest 2/2 2 2 15s
NAME DESIRED CURRENT READY AGE
replicaset.apps/rest-786fc49b6 2 2 2 15s
0 6s
$ curl http://172.20.0.200:10000/info
{"Endpoint":"/info","Host":"172.20.0.200:10000","Method":"GET","RemoteIP":"192.168.188.128:36300","Version":"1.0.0"}
$ curl http://172.20.0.200:10000/health-check
{"healthy":true}
$ curl http://172.20.0.200:10000/env
{"Version":"1.0.0","env":"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, HOSTNAME=rest-786fc49b6-ks57w, KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1, REST_SERVICE_PORT=10000, REST_PORT=tcp://10.96.9.7:10000, REST_PORT_10000_TCP=tcp://10.96.9.7:10000, REST_PORT_10000_TCP_PROTO=tcp, REST_PORT_10000_TCP_ADDR=10.96.9.7, KUBERNETES_SERVICE_HOST=10.96.0.1, KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443, REST_SERVICE_HOST=10.96.9.7, KUBERNETES_SERVICE_PORT=443, KUBERNETES_SERVICE_PORT_HTTPS=443, KUBERNETES_PORT=tcp://10.96.0.1:443, KUBERNETES_PORT_443_TCP_PORT=443, REST_PORT_10000_TCP_PORT=10000, KUBERNETES_PORT_443_TCP_PROTO=tcp, HOME=/root, VERSION=1.0.0"}
$ curl http://172.20.0.200:10000/quote
{"Quote":"There is no great genius without some touch of madness. - Aristotle","Version":"1.0.0"}
$ curl http://172.20.0.200:10000/quote
{"Quote":"The only true wisdom is in knowing you know nothing. - Socrates","Version":"1.0.0"}
$ curl http://172.20.0.200:10000/quote
{"Quote":"Programming isn't about what you know; it's about what you can figure out. - Chris Pine","Version":"1.0.0"}
Now the pod is created. You can also check the pod logs using the kubectl log
command like below.
$ kubectl get po
NAME READY STATUS RESTARTS AGE
rest-786fc49b6-gqvvq 1/1 Running 0 119s
rest-786fc49b6-t7qtq 1/1 Running 0 119s
$ kubectl logs rest-786fc49b6-gqvvq
2022/08/01 10:59:46 Simple API Server(1.0.0) running on 0.0.0.0:10000
2022/08/01 11:00:53 Entering /info endpoint, Invoked from 192.168.188.128:51946
2022/08/01 11:01:12 Entering /health-check endpoint, Invoked from 192.168.188.128:3009
2022/08/01 11:01:23 Entered /quote endpoint, Invoked from 192.168.188.128:1345 , using ./quotes.json as QuotesSource
2022/08/01 11:01:23 Yeah We alll shine on, Like the Moon, and the Stars, And the SUN. - John Lennon
Get more details about the pod using the kubectl describe pod
command.
$ kubectl describe po rest-786fc49b6-ks57w
...
$ kind delete cluster --name=devops