Brushing Up on Kubernetes and Go APIs: A Practical Deployment Guide

Published on 2/3/2025

By Nathan Sanchez

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.