Intro to Kind Kubernetes (Local Kubernetes Development) - Part 2
To make the process of building more complex Kind infra, Kind provides configuration files which can be passed to the kind create CLI.
This example will be walking through creating a dev ready Kind cluster for web app development which will allow hosting a Frontend/Backend/DB with Ingress resources.
Setting up cluster
The below command will setup a 3 node cluster.
echo ''' kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane kubeadmConfigPatches: - | kind: InitConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 80 hostPort: 80 protocol: TCP - containerPort: 443 hostPort: 443 protocol: TCP - role: worker - role: worker ''' | kind create cluster --config=-
Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.19.1) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 ✓ Joining worker nodes 🚜
You can check the cluster node status by running
kubectl get nodes
NAME STATUS ROLES AGE VERSION kind-control-plane Ready master 5m8s v1.19.1 kind-worker Ready <none> 4m38s v1.19.1 kind-worker2 Ready <none> 4m38s v1.19.1
Configure an Nginx ingress controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/kind/deploy.yaml
tic/provider/kind/deploy.yaml namespace/ingress-nginx created serviceaccount/ingress-nginx created configmap/ingress-nginx-controller created clusterrole.rbac.authorization.k8s.io/ingress-nginx created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created role.rbac.authorization.k8s.io/ingress-nginx created rolebinding.rbac.authorization.k8s.io/ingress-nginx created service/ingress-nginx-controller-admission created service/ingress-nginx-controller created deployment.apps/ingress-nginx-controller created validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created serviceaccount/ingress-nginx-admission created clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created role.rbac.authorization.k8s.io/ingress-nginx-admission created rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created job.batch/ingress-nginx-admission-create created job.batch/ingress-nginx-admission-patch created
Run this command to wait until ingress controller is ready (espeshally important in CI test environments)
kubectl wait --namespace ingress-nginx \ --for=condition=ready pod \ --selector=app.kubernetes.io/component=controller \ --timeout=90s
pod/ingress-nginx-controller-55bc59c885-8kcp4 condition met
Deploy example app to test ingress deploy. This deploys two pods & services, with an ingress that directs traffic between the two services.
kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/usage.yaml
pod/foo-app created service/foo-service created pod/bar-app created service/bar-service created
You can view these services by accessing:
In order to demonstrate the end to end workflow, this guide will walk through a very simple app deployment. This app will just return the number of requests recieved. The container will be built locally & deployed in Kind. Network ingress will come through the ingress setup previously.
The first step is to create a docker image with the required dependencies. For simplicity in the demo, I’ve included the docker file inline in the docker build command below.
echo ''' FROM python RUN pip install flask requests''' | docker build -t k8s_demo:local -f - .
To push the docker image to Kind, run
kind load docker-image k8s_demo:local. This makes the docker image available in the Kind k8s cluster.
Then, run the following command to deploy a container with the config to Kind:
echo ''' apiVersion: v1 kind: ConfigMap metadata: name: demo-api data: run.py: | from flask import Flask app = Flask(__name__) num_requests = 0 @app.route("/api") def count(): global num_requests num_requests += 1 return(str(num_requests)) if __name__ == "__main__": app.run(host="0.0.0.0") --- kind: Pod apiVersion: v1 metadata: name: demo labels: app: demo spec: containers: - name: demo image: k8s_demo:local command: ["python"] args: [ "/app/run.py" ] imagePullPolicy: IfNotPresent volumeMounts: - name: config mountPath: /app volumes: - name: config configMap: name: demo-api --- kind: Service apiVersion: v1 metadata: name: demo spec: selector: app: demo ports: - port: 5000 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo spec: rules: - http: paths: - path: /api pathType: Exact backend: service: name: demo port: number: 5000 ''' | kubectl apply -f -
configmap/demo-api created pod/demo created service/demo created ingress.networking.k8s.io/demo created
You can view the resources created by running
kubectl describe <either ingress,pod,or configmap>.
Once the pod starts, you can view the app by opening: http://localhost/api which returns the request count.
Finally, to cleanup & delete the cluster, run
kind delete cluster