Kubernetes : Deploying multi-replica Go App (Kube101 part 1)
Learn Kubernetes by deploying multi-replica Golang HTTP Service in K0s and see how useful Kubernetes can manage your micro services to scale.
Objectives:
Create a simple Golang HTTP service that serves a “/check-host” endpoint, printing “Hello, from ${host_name}”. Deploy it on Kubernetes with multiple replicas and set up a load balancer. You’ll see a different host name each time you request the server.
Set Up
- Golang SDK environment, I assume you already have basic understanding of Go.
- Docker, ensure you can build the go service to Docker image and deploy it to Dockerhub or local registry
- K0s or other Kubernetes distro (K3s, Minikube, MicroK8s, etc) installed on the local machine along with Kubectl command
(in this Post, I’ll use K0s along with the Kubectl built-in command) - (Optional) Kubernetes GUI management tool like Lens
How To
Configure Load Balancer
As we will create 5 replicas for the Go service. In Kubernetes, running a service with five replicas means you have five instances of the same service running concurrently.
To ensure incoming requests are evenly distributed across these replicas, a Load Balancer is used. This Load Balancer exposes the service to a dedicated IP address within your local network subnet and intelligently distributes requests to each replica based on its algorithm. This setup ensures efficient load distribution and improves service reliability.
We’ll use MetalLB for the Load Balancer, this is the step:
⚙️ Install MetalLB by Manifest
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml
✅ Ensure the installation by checking MetalLB Controller and Speaker pod
sudo k0s kubectl get pods -n metallb-system
📋 Check the the assignable IP Range for MetalLB
First, check our local network configuration to know what IP can be used as the IP Range for MetalLB
ifconfig
Because I use my local home network, I know that some IP addresses are already occupied for other devices, therefore, I will use 20 IPs from range 192.168.18.120–192.168.18.140 for MetalLB config-map.
📍Configure IP Range for MetalLB
Create a file named metallb-configmap.yaml and paste this code:
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.18.120-192.168.18.140
Apply config to Kubernetes
sudo k0s kubectl apply -f metallb-configmap.yaml
Create Go service
Create a simple HTTP service that will print Hostname when we navigate to (/check-host) path, make main.go file and put this:
package main
import (
"fmt"
"net/http"
"os"
)
func handler(w http.ResponseWriter, r *http.Request) {
hostname, err := os.Hostname()
if err != nil {
fmt.Fprintf(w, "Error: %v", err)
return
}
fmt.Fprintf(w, "Hostname: %s", hostname)
}
func main() {
http.HandleFunc("/check-host", handler)
port := os.Getenv("SERVICE_PORT")
if port == "" {
port = "8001" // default port if SERVICE_PORT is not set
}
fmt.Printf("Starting server on port %s... version %s\n", port, "0.0.1")
if err := http.ListenAndServe(":"+port, nil); err != nil {
fmt.Printf("Error: %v\n", err)
}
}
🐋 Build it as Docker Image
Create Dockerfile
from golang:1.22.4-alpine
WORKDIR /app
copy . .
RUN go build -o main .
EXPOSE 8001
CMD ["./main"]
Build it, make sure your Docker already login to Dockerhub account, rename it with your own image
docker build -t {YOUR_DOCKERHUB_USERNAME}/go-simple-http-service:0.0.1 .
Push to Docker repository
docker push {YOUR_DOCKERHUB_USERNAME}/go-simple-http-service:0.0.1
Create New Namespace
We’ll create new namespace to organize this deployment, namely go-http-example
sudo k0s kubectl create namespace go-http-example
Create Deployment Config
We’ll create two configuration files:
- Go Service Deployment Config: Manages the deployment of Go service pods, including replica configuration
- Kubernetes Service Config: Acts as the load balancer, exposing the internal Go service pods to the assigned IP from MetalLB
go-http-service-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-simple-http
namespace: go-http-example
spec:
selector:
matchLabels:
app: go-simple-http
replicas: 5
template:
metadata:
labels:
app: go-simple-http
spec:
containers:
- name: go-simple-http
image: gilangprambudi/go-simple-http-service:0.0.1
ports:
- containerPort: 8001
go-http-service-lb-deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: golang-http-service-lb
namespace: go-http-example
spec:
type: LoadBalancer
selector:
app: go-simple-http
ports:
- protocol: TCP
port: 80
targetPort: 8001
Apply Config to Kubernetes
type this command
sudo k0s kubectl apply -f go-http-service-lb-deployment.yaml
sudo k0s kubectl apply -f go-http-service-deployment.yaml
Ensure if LB Service has been assigned with External IP from MetalLB
sudo k0s kubectl get service -n go-http-example
Now, check if all the pods are running successfully
sudo k0s kubectl get pods -n go-http-example
Test it
We can check if the Pod is really running and load balancer is working as expected by simply navigate to browser and go to the given <External-IP>/check-host
Try reloading for several times, ensure to hard reload it in browser (in chrome press CTRL + R) to prevent from browser caching, then you’ll see the hostname is changing according to the available pods