Consider the following: You’re migrating some microservices to Kubernetes with certain API dependencies, which are not yet reachable. There can be plenty of reasons for that: Some dependent services run in a highly secured data center on-prem and are not yet migrated, some APIs may not be fully developed yet.
In this post we explore the use of Mockoon in Kubernetes: We’ll expose Mockoon via internal DNS and make it reachable for a simple test web application.
Exploring the Mockoon GUI
I highly recommend checking out the desktop app over here: https://mockoon.com/download/. If you’re following on macOS, just use brew for convenience:
brew install --cask mockoon
The Mockoon UI enables you a postman-y overview of all your mock routes. It’s quite intuitive, feel free to play around with it. If you find yourself struggling with the navigation, check out their great Mockoon GUI cheat sheet.
In our demo app we’ll be using the plain demo API with faker.js in the background generating some random userdate on the route /users
. Right-click the “Demo API” in the left sidebar and grab the json file containing the config. That’s what we’ll need in the next step.
Mockoon + Docker = ♥️
We’ll be using the actively maintained Docker image Mockoon CLI. To try out the image locally, grab your exported json file and give it a spin:
docker run -d --mount type=bind,source=/home/username/your-data-file.json,target=/data,readonly -p 3000:3000 mockoon/cli:latest -d data -i 0 -p 3000
Now curl your mock API:
$ curl localhost:3000/users
# Response
{
"Templating example": "For more information about templating, click the blue 'i' above this editor",
"users": [
{
"userId": "90741",
"firstname": "Shany",
"lastname": "Dach",
"friends": [
]
},
...
}
Great! Your Mockoon server is exposed correctly. Now then, let’s build something in Go requesting our mock API.
Setting up the Go microservice
For my exemplary microservice I’m using a small Golang server handling three routes, /
, /healthz
and /mockoon
. /mockoon will HTTP GET the mock API from mockoon’s /users
path and print it as plain text. If you want to follow along, grab the code from this GitHub Gist.
To reproduce a common DevOps practice our server will pull the mockoon route /users
from the environmental variable MOCKURL
. Once we deploy our k8s manifests, we’ll set the variable to http://mockoon.mockoon.svc.cluster.local/users
. Let’s check out the relevant function in go:
func mockoon() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/mockoon" {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
resp, err := http.Get(os.Getenv("MOCKURL"))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "Querying Mockoon API from ENV VAR:", os.Getenv("MOCKURL"))
fmt.Fprintln(w, string(body))
})
}
Dockerizing our Go Microservice
I highly encourage you to check out Google’s distroless container images.
Restricting what’s in your runtime container to precisely what’s necessary for your app is a best practice employed by Google and other tech giants that have used containers in production for many years. It improves the signal to noise of scanners (e.g. CVE) and reduces the burden of establishing provenance to just what you need.
The Dockerfile of our Go server will look like that:
FROM golang:1.17-bullseye as build
WORKDIR /go/src/app
ADD . /go/src/app
RUN go get -d -v ./...
RUN go build -o /go/bin/app
FROM gcr.io/distroless/base-debian11
COPY --from=build /go/bin/app /
EXPOSE 8090
CMD ["/app"]
Dont forget to build, tag and push your image to the repository of your liking. Also make sure your Kubernetes Cluster has the ability to pull your image from your desired registry.
Exposing Mockoon in Kubernetes
The basic infrastructure will look like this:
The Go server pod (go-mockoon) will be requesting the Mockoon pod (mockoon) by its internal DNS. The Mockoon pod mounts /data/data.json
from the ConfigMap (mockoon-data). Check out the manifests:
---
apiVersion: v1
kind: Namespace
metadata:
name: mockoon
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-mockoon
namespace: mockoon
spec:
replicas: 1
selector:
matchLabels:
app: go-mockoon
template:
metadata:
labels:
app: go-mockoon
spec:
containers:
- name: go-mockoon
image: yourrepo/go-mockoon
env:
- name: MOCKURL
value: http://mockoon.mockoon.svc.cluster.local/users
ports:
- containerPort: 8090
livenessProbe:
httpGet:
path: /healthz
port: 8090
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: go-mockoon
namespace: mockoon
spec:
ports:
- protocol: TCP
port: 80
targetPort: 8090
selector:
app: go-mockoon
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: go-mockoon
namespace: mockoon
spec:
rules:
- host: go-mockoon.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: go-mockoon
port:
number: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mockoon
namespace: mockoon
spec:
replicas: 1
selector:
matchLabels:
app: mockoon
template:
metadata:
labels:
app: mockoon
spec:
containers:
- name: mockoon
image: mockoon/cli:latest
args: ["-d", "/data/data.json"]
ports:
- containerPort: 3000
volumeMounts:
- name: data
mountPath: "/data"
volumes:
- name: data
configMap:
name: mockoon-data
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: mockoon
namespace: mockoon
spec:
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: NodePort
selector:
app: mockoon
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mockoon-data
namespace: mockoon
data:
data.json: |
{
...
}
Now check your pods:
$ kubectl get pods -n mockoon
NAME READY STATUS RESTARTS AGE
go-mockoon-98cd57695-b6mwn 1/1 Running 0 2d14h
mockoon-69bb77755d-c96dd 1/1 Running 0 2d14h
Now test your Go server by requesting the host you set in your ingress resource, i.e. go-mockoon.example.com. Tail the logs of your go-mockoon pod:
$ kubectl logs -f go-mockoon-98cd57695-b6mwn -n mockoon
...
http: 2022/02/13 23:12:43 1644793963376041701 GET /healthz 10.0.22.15:45010 kube-probe/1.21+
http: 2022/02/13 23:12:46 1644793966405444999 GET /mockoon 10.0.5.247:6206 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:96.0) Gecko/20100101 Firefox/96.0
Requesting go-mockoon.example.com/mockoon
will redirect to the internal Mockoon pod /users
route, located at http://mockoon.mockoon.svc.cluster.local/users
. You should see the faker.js generated user data originating from the Mockoon pod 🦝 🎉.
I want the true Dev Experience!
Me too. In part 2 we’ll explore Helm charts and an introduction to Skaffold. Stay tuned!