Recently, I decided to revisit Kubernetes and Go APIs by working on a practical project—building and deploying a containerized event logger. While I’ve had experience with backend systems, refreshing my knowledge in a hands-on way felt like the best approach. This project not only reinforced core Kubernetes concepts but also helped me streamline my workflow for containerized API development.
Project Overview: Kubernetes Event Logger
The goal of this project was to build a small Go-based API that logs Kubernetes events and serves them over an HTTP endpoint. The API was containerized using Docker and deployed to a Kubernetes cluster running on kind
(Kubernetes in Docker).
Building the Go API
The API itself is straightforward—it listens on port 8080
and provides a /events
endpoint that returns a list of simulated Kubernetes events. Here’s a breakdown of the key steps involved in writing the API:
Set up a basic Go module with
go mod init
.Implement a simple HTTP server with
net/http
.Define a struct to store Kubernetes events, simulating real cluster logs.
Containerize the application using a multi-stage Docker build.
Here’s the core of the API:
package main
import (
"encoding/json"
"log"
"net/http"
"time"
)
type Event struct {
Type string `json:"type"`
Message string `json:"message"`
Timestamp time.Time `json:"timestamp"`
}
var events = []Event{
{"INFO", "Pod kube-api restarted", time.Now()},
{"WARNING", "Node memory pressure detected", time.Now()},
{"ERROR", "Failed to pull image: registry.example.com/nginx", time.Now()},
}
func eventHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(events)
}
func main() {
http.HandleFunc("/events", eventHandler)
log.Println("Server is running on port 8080...")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Containerizing the API
To ensure portability, I containerized the application using a multi-stage Docker build, which allowed me to keep the final image lightweight. Here’s the Dockerfile used for the build:
FROM golang:1.21 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod tidy
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o kube-event-logger main.go
FROM debian:stable-slim
WORKDIR /root/
COPY --from=builder /app/kube-event-logger .
RUN chmod +x /root/kube-event-logger
HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:8080/events || exit 1
CMD ["/root/kube-event-logger"]
Once built, I tagged the image and ensured it could run locally:
docker build -t kube-event-logger .
docker run -p 8080:8080 kube-event-logger
Setting Up a Local Kubernetes Cluster
To deploy the application in Kubernetes, I used kind
to spin up a local cluster:
kind create cluster --name kube-event-cluster
After verifying the cluster was up and running with kubectl get nodes
, I loaded the Docker image into the cluster:
kind load docker-image kube-event-logger --name kube-event-cluster
Deploying to Kubernetes
I created a Kubernetes deployment and service to run the API within the cluster. The deployment YAML includes labels, resource management considerations, and is designed for easy scaling and monitoring.
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-event-logger
labels:
app: kube-event-logger
spec:
replicas: 2
selector:
matchLabels:
app: kube-event-logger
template:
metadata:
labels:
app: kube-event-logger
annotations:
description: "Deployment for the Go-based Kubernetes event logger"
spec:
containers:
- name: kube-event-logger
image: kube-event-logger
ports:
- containerPort: 8080
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
readinessProbe:
httpGet:
path: /events
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /events
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
apiVersion: v1
kind: Service
metadata:
name: kube-event-logger-service
spec:
type: NodePort
selector:
app: kube-event-logger
ports:
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 32347
After applying these configurations with kubectl apply -f
, I confirmed the deployment and service were running:
kubectl get pods
kubectl get service kube-event-logger-service
Verifying the Deployment
Once deployed, I was able to access the API within the cluster by curling the service URL:
curl http://localhost:32347/events
This successfully returned the list of simulated Kubernetes events.
Enhancements & Additional Resources
To make this project even better, consider the following improvements and additional resources:
Include an Architecture Diagram to visualize the interaction between the Go API, Docker container, and Kubernetes cluster.
Add a Getting Started section with prerequisites, a checklist, and a quick-start guide for readers.
Enhance error handling and logging in the Go API, including use of the
context
package for graceful shutdowns.Implement Readiness and Liveness Probes in the Kubernetes deployment for better pod lifecycle management.
Link to a GitHub repository with the complete codebase and further reading on Kubernetes, Go, and Docker best practices.
Consider integrating a live demo or interactive code sandbox to allow readers to experiment with the project.
Final Thoughts
This project served as a great way to reinforce Kubernetes fundamentals and Go API development. The ability to containerize and deploy services efficiently is a crucial skill, and Kubernetes makes scaling and managing distributed applications significantly easier. Moving forward, I plan to integrate real Kubernetes event listening and possibly extend this with a persistent database backend.
If you’re looking for a practical Kubernetes and Go refresher, this type of hands-on project is a solid way to sharpen your skills.