VOOZH about

URL: https://dzone.com/articles/golang-kubernetes-deployment-scalable-guide

⇱ Deploying a Scalable Golang Application on Kubernetes


Related

  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Deployment
  4. Deploying a Scalable Golang Application on Kubernetes: A Practical Guide

Deploying a Scalable Golang Application on Kubernetes: A Practical Guide

Learn how to deploy and scale a Golang app on Kubernetes using best practices like stateless design, concurrency, health checks, and autoscaling.

By Aug. 11, 25 · Tutorial
Likes
Comment
Save
3.1K Views

Join the DZone community and get the full member experience.

Join For Free

Golang is the finest programming language for constructing applications that can scale well and at high density due to the concurrency and performance inherent in the language itself. Kubernetes is the best standard for container orchestration, which gives a platform for deploying, managing, and scaling applications. Together, they constitute a formidable pair for creating unobtrusive and bulletproof microservices.

This blog will lead readers through the process of deploying a scalable Golang application on Kubernetes, highlighting essential considerations alongside the more practical 'doing it' steps.

Why Golang and Kubernetes?

Before we go into the how-tos, let's just touch briefly on the whys:

  • With Golang for performance and concurrency: Go's extremely efficient lightweight goroutines and channels enable this concurrency. The fast compilation time and statically linked binaries make deployments easy. 
  • Kubernetes for scalability and resilience: A containerized application can be deployed, scaled, and managed with Kubernetes. It also enables self-healing, load balancing, and rolling updates, ensuring that the application remains up and fully functional even under heavy load.

Key Considerations for Scalability in Golang Applications

The following are certain principles you may wish to consider while designing your application and making the best use of Kubernetes for your Go applications:

  1. Statelessness: The Go application should be designed as stateless, meaning that no session data or persistent state should be stored within the application instances in memory. Instead, all states should be handled by leveraging external services such as databases (Postgres, MongoDB), caching services (Redis, Memcached), or message queues (Kafka, RabbitMQ). This will allow Kubernetes to scale your pods freely without any risk of data loss or data consistency.
  2. Concurrency: Go channels and goroutines should be employed for concurrent processing. This allows one Go instance to spawn multiple requests and thus can truly take advantage of the CPU resources. 
  3. Graceful shutdowns: The Go application must have graceful shutdown logic. On receiving a terminate command from Kubernetes, the application should finish processing ongoing requests and free its resources before exiting. This way, no need for cleanup has to be made to protect against data corruption or dropped connections. Listening to a `SIGTERM` signal is only one common way to implement this.
  4. Configuration: The application will store its configuration externally through environment variables or config files. The application thus becomes highly portable and configurable within Kubernetes without needing to build a new Docker image.
  5. Health checks: Your app should provide HTTP endpoints for liveness and readiness checks. Kubernetes uses these to ascertain whether your application is up and running, ready to handle traffic, and healthy.

Step-by-Step Deployment on Kubernetes

Let's walk through the process with a hypothetical simple Go API.

1. Containerize Your Golang Application

First, you need a `Dockerfile` to package your Go application into a Docker image.

Go
package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello from Golang App! Pod: %s\n", os.Getenv("HOSTNAME"))
	})

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	server := &http.Server{Addr: ":" + port}

	// Start HTTP server in a goroutine
	go func() {
		log.Printf("Server starting on port %s...", port)
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("Could not listen on %s: %v\n", port, err)
		}
	}()

	// Graceful shutdown
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
	<-sigChan // Block until a signal is received

	log.Println("Shutting down server gracefully...")
	shutdownCtx, cancel := time.WithTimeout(server.Context(), 5*time.Second)
	defer cancel()

	if err := server.Shutdown(shutdownCtx); err != nil {
		log.Fatalf("Server shutdown failed: %v", err)
	}
	log.Println("Server gracefully stopped.")
}


Dockerfile
# Use a minimal base image for the build stage
FROM golang:1.22 AS builder

WORKDIR /app

# Copy go mod and sum files to download dependencies
COPY go.mod go.sum ./
RUN go mod download

# Copy the source code
COPY . .

# Build the Go application
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

# Use a scratch image for the final, very small image
FROM alpine:latest

WORKDIR /root/

# Install ca-certificates for HTTPS calls if needed (optional but recommended)
RUN apk --no-cache add ca-certificates

# Copy the compiled binary from the builder stage
COPY --from=builder /app/main .

# Expose the port your application listens on
EXPOSE 8080

# Run the executable
CMD ["./main"]


Build and push the Docker images to the registry:

docker build -t your-docker-repo/golang-app:1.0.0 .

docker push your-docker-repo/golang-app:1.0.0

2. Define Kubernetes Manifests

Now, let's create the Kubernetes resource definitions.

A. deployment.yaml

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
 name: golang-app-deployment
 labels:
 app: golang-app
spec:
 replicas: 3 # Start with 3 replicas for high availability
 selector:
 matchLabels:
 app: golang-app
 template:
 metadata:
 labels:
 app: golang-app
 spec:
 containers:
 - name: golang-app
 image: your-docker-repo/golang-app:1.0.0 # Replace with your image
 ports:
 - containerPort: 8080
 env:
 - name: PORT
 value: "8080"
 resources: # Define resource requests and limits for better scheduling and stability
 requests:
 memory: "64Mi"
 cpu: "100m" # 100 millicores (0.1 CPU core)
 limits:
 memory: "128Mi"
 cpu: "200m" # 200 millicores (0.2 CPU core)
 livenessProbe: # Checks if the app is still running
 httpGet:
 path: / # Or a dedicated /health endpoint
 port: 8080
 initialDelaySeconds: 5
 periodSeconds: 10
 readinessProbe: # Checks if the app is ready to serve traffic
 httpGet:
 path: / # Or a dedicated /ready endpoint
 port: 8080
 initialDelaySeconds: 10
 periodSeconds: 15
          timeoutSeconds: 5


B. service.yaml

YAML
apiVersion: v1
kind: Service
metadata:
 name: golang-app-service
 labels:
 app: golang-app
spec:
 selector:
 app: golang-app
 ports:
 - protocol: TCP
 port: 80 # The port the service exposes
 targetPort: 8080 # The port your application listens on inside the container
  type: ClusterIP # Exposes the Service on a cluster-internal IP. Default for many apps.


C. Horizontal Pod Autoscaler (hpa.yaml)

YAML
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
 name: golang-app-hpa
spec:
 scaleTargetRef:
 apiVersion: apps/v1
 kind: Deployment
 name: golang-app-deployment
 minReplicas: 3 # Minimum number of pods
 maxReplicas: 10 # Maximum number of pods
 metrics:
 - type: Resource
 resource:
 name: cpu
 target:
 type: Utilization
 averageUtilization: 70 # Target CPU utilization (percentage)
 # You can also scale based on memory or custom metrics
 # - type: Resource
 # resource:
 # name: memory
 # target:
 # type: Utilization
  #       averageUtilization: 80


3. Deploy to Kubernetes

Markdown
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f hpa.yaml


Some of the Best tools to monitor your Kubernetes resources are:

Conclusion

Scale up a Golang application in Kubernetes to reap its user-friendliness in building modern, resilient, and performance-oriented systems. Ensure that you adopt best practices for Go application design, such as making the application stateless, concurrent, and ensuring graceful shutdowns. You will allow Kubernetes features such as deployments, services, and horizontal pod autoscaling to balance the workload on your application accordingly. Come on, adopt this combination to perfect your microservices architecture!

Golang Kubernetes application Docker (software) Go (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • Serverless vs Containers: Choosing the Right Architecture for Your Application
  • Container Checkpointing in Kubernetes With a Custom API
  • 7 Ways of Containerizing Your Node.js Application
  • Auto-Scaling a Spring Boot Native App With Nomad

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

Let's be friends: