avatar

Bhuwan Upadhyay

Talks all about software engineering

Published on

Kubernetes setup using kind

Authors

Introduction

This article explains method of installing the kubernetes cluster locally using kind tool. Also, it describes how to create kubernetes local cluster, install metallb load balancer, enable local docker registry and install nginx ingress controller.

Prerequisites

Build Tools

Recommend using the latest version of those tools.

Environment variables

# kindest version
export kindest_version='v1.23.0'
# local docker registry name
export reg_name='kind-registry'
# local docker registry container exposed port
export reg_port='5001'

Kubernetes cluster

Following commands will create local kubernetes cluster.

cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
# cluster with the local registry enabled in containerd
containerdConfigPatches:
- |-
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:$reg_port"]
    endpoint = ["http://$reg_name:5000"]
nodes:
- role: control-plane
    kubeadmConfigPatches:
  # cluster with the ingress enabled
  - |
    kind: InitConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "ingress-ready=true"
  extraPortMappings:
  - containerPort: 80
    hostPort: 80
    protocol: TCP
  - containerPort: 443
    hostPort: 443
    protocol: TCP
- role: worker
  EOF

Verify pods are running by using following command

kubectl get pods --all-namespaces -o wide

Docker registry

Following commands will enable local docker registry in local kubernetes cluster.

# create registry container unless it already exists
docker run -d --restart=always -p "127.0.0.1:${reg_port}:5000" --name "${reg_name}" registry:2
# connect the registry to the cluster network if not already connected
docker network connect "kind" "${reg_name}"
# Document the local registry
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: local-registry-hosting
  namespace: kube-public
data:
  localRegistryHosting.v1: |
    host: "localhost:$reg_port"
    help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
EOF

MetalLB load balancer

Following commands will install metallb load balancer in local kubernetes cluster.

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml
kubectl wait deployment -n metallb-system controller --for condition=Available=True --timeout=90s
IP=$(docker network inspect -f '{{.IPAM.Config}}' kind | awk '{print $1}' | awk '{ split(substr($1,3), i,"."); print i[1]"."i[2]}')
echo "Kind Network IP Prefix: $IP"
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - $IP.255.200-$IP.255.250
EOF
kubectl rollout restart deployment -n metallb-system controller

Nginx Ingress Controller

Following commands will install ngnix ingress controller in local kubernetes cluster.

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace

Example Usage

Using local registry

Following commands will use local docker registry to push docker images.

# pull an image
docker pull hashicorp/http-echo:0.2.3
# tag the image to use the local registry
docker tag hashicorp/http-echo:0.2.3 localhost:5001/http-echo:0.2.3
# push it to the registry
docker push localhost:5001/http-echo:0.2.3

Using metallb loadbalancer

All the requests incoming to this loadbalancer ip address will be routed in ngnix service.

# get external ip for loadbalancer service
export LB_IP=$(kubectl get svc/ingress-nginx-controller -n ingress-nginx -o=jsonpath='{.status.loadBalancer.ingress[0].ip}') && echo $LB_IP

Using ngnix ingress controller

Following commands will deploy simple application with ingress host url.

# configure root domain for foo service
export ROOT_DOMAIN='localdev.me'
# apply manifests for foo service
cat <<EOF | kubectl apply -f -
---
kind: Namespace
apiVersion: v1
metadata:
  name: foo-system
---
kind: Pod
apiVersion: v1
metadata:
  name: foo-app
  namespace: foo-system
  labels:
    app: foo
spec:
  containers:
  - name: foo-app
        args:
    - "-text=foo"
---
kind: Service
apiVersion: v1
metadata:
  name: foo-service
  namespace: foo-system
spec:
  selector:
    app: foo
  ports:
  - port: 5678
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: foo-ingress
  namespace: foo-system
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: foo.$ROOT_DOMAIN
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: foo-service
            port:
              number: 5678
---
EOF

Verify ingress host url for foo service:

  • Using directly host url
# append host url in /etc/hosts file
printf "%s\t%s\n" "$LB_IP" "foo.$ROOT_DOMAIN" | sudo tee -a /etc/hosts > /dev/null
# verify /etc/hosts
cat /etc/hosts
# get foo service
curl -D- http://foo.$ROOT_DOMAIN
  • Using external ip address and host header
curl -D- http://$LB_IP -H "Host: foo.$ROOT_DOMAIN"

Cleanup resources

Following commands will delete local kubernetes cluster and other resources.

# delete cluster
kind delete cluster
# delete local registry
docker rm -f -v kind-registry
# manually remove line if added in /etc/hosts using above `printf` command while testing `Using directly host url`
sudo vi /etc/hosts

References