Kind stands for kubernetes in docker and is a tool for running a local kubernetes cluster where docker containers act as nodes. This is a great way to get started learning and using kubernetes before relying on a cloud provider. It nicely integrates with tooling, is thoroughly documented, supports mutlti-node clusters and is CNCF certified conformant kubernetes installer. We will be using Kind to deploy an application and then connecting it with a service that was deployed via docker compose. Let’s get started!

Once again we will be using the Python application that we used from our earlier article. If you want to see how to connect multiple docker services together, you can go and check it out! Let’s start by getting Kind setup.

Kind Setup

First make sure that you have the Kind cli installed, which can be found here. It should look like this after installation:

$ kind
kind creates and manages local Kubernetes clusters using Docker container 'nodes'

Usage:
  kind [command]

Available Commands:
  build       Build one of [node-image]
  completion  Output shell completion code for the specified shell (bash, zsh or fish)
  create      Creates one of [cluster]
  delete      Deletes one of [cluster]
  export      Exports one of [kubeconfig, logs]
  get         Gets one of [clusters, nodes, kubeconfig]
  help        Help about any command
  load        Loads images into nodes
  version     Prints the kind CLI version

Flags:
  -h, --help              help for kind
      --loglevel string   DEPRECATED: see -v instead
  -q, --quiet             silence all stderr output
  -v, --verbosity int32   info log verbosity, higher value produces more output
      --version           version for kind

Use "kind [command] --help" for more information about a command.

Create a kind cluster:

kind create cluster

Create a local docker image for the application and from within the repo run:

docker build -t poetryanimaldb:1.0 .

Load the image into the cluster with:

kind load docker-image poetryanimaldb:1.0

Set up Postgres via Docker

To set up the postgres container, we are going to use docker compose. You may notice in the repo that there are two files for docker compose. compose.yaml is for connecting to a running docker container and the other one, compose.kind.yaml we will be using to connect to kind.

When we look at the file, the most important part is the top-level element networks. Since the kind network was created earlier when we created the Kind cluster, the external: true tells docker that the network’s lifecycle is mantained outside of this application and therefore it will not attempt to create it.

The services.postgresql.networks is used to connect the container to the network.

services:
  postgresql:
    container_name: postgresql-1
    image: postgres:15
    environment:
      - POSTGRES_DB
      - POSTGRES_USER
      - POSTGRES_PASSWORD
    ports:
      - ${POSTGRES_PORT}:5432
    restart: always
    volumes:
      - db_data:/var/lib/postgresql/data

    # this is used to connect to the container to the network
    networks:
      - kind

volumes:
  db_data:

networks:
  kind:
    external: true

To start the docker container:

docker compose -f compose.kind.yaml up -d

Deploy Application to Kind

To interact with the cluster, first make sure that kubectl is installed - Installation

To use the context with kubectl:

kubectl cluster-info --context kind-kind

You should see the follwing when running kubectl config current-context:

$ kubectl config current-context
kind-kind

From within the kubernetes/ folder there is a deployment manifest that will create 1 pod via a ReplicaSet. The image that we built earlier will be the image that is run in the container from within the pod.

Inside the same folder, there is also a service manifest which deploys a service of type ClusterIP. Which makes it only available from within the cluster.

To deploy the application to Kind, apply the files to the cluster:

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

Use kubectl get services and kubectl get pods to check that they are running appropriately

$ kubectl get services
NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes       ClusterIP   10.96.0.1      <none>        443/TCP    1d
python-service   ClusterIP   10.96.76.239   <none>        5000/TCP   2m23s

$ kubectl get pods
NAME                                 READY   STATUS    RESTARTS   AGE
python-deployment-86b66c64df-zn6fb   1/1     Running   0          2m27s

To interact with it, we can port-forward the service

kubectl port-forward services/python-service 5000:5000

The application should now be available at localhost:5000 🤠