Skip to content

Deployment⚓︎

This tutorial builds on Hello Kubernetes to create kubernetes pods using a deployment.

Create Cluster⚓︎

Create a kind cluster named tutorial with kubernetes version 1.34.0. If you haven't done this before, see Install Kind in the previous tutorial.

kind create cluster --name tutorial --image kindest/node:v1.34.0

Create a Deployment⚓︎

Next, we'll create a deployment which creates and manages multiple pods. Each pod is similar to the one we created manually in Create a Pod.

Create Deployment Definition⚓︎

Create a new file hello-node-deployment.yaml and paste the following.

hello-node-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-node #(1)!
  labels: #(2)!
    app: hello-node
spec:
  replicas: 3 #(3)!
  selector: #(4)!
    matchLabels:
      app: hello-node
  template: #(5)!
    metadata:
      labels: #(6)!
        app: hello-node
    spec:
      containers:
        - name: app
          image: hello-node:1.0.1
          imagePullPolicy: Never
          ports:
            - containerPort: 3000

  1. name can be anything that contains only letters, numbers, and dashes. Kubernetes will name pods starting with the deployment name.
  2. The deployment's metadata.labels will make it easier for us to inspect both the deployment and its pod with a single command. Otherwise, they aren't related to the deployment's spec.selector,matchLabels or the pod's spec.template.metadata.labels below.
  3. Settings replicas: 3 will create 3 pods.
  4. The spec.selector tells kubernetes how to find pods managed by the deployment. It should match labels defined in spec.template.metadata.labels.
  5. spec.template defines how to create the deployment's pods. Notice how the deployment's spec.template.spec matches the pod spec in Create Pod Definition.
  6. The pod template's metadata.labels should include the labels from spec.selector.matchLabels above.

Apply Deployment Definition⚓︎

Apply the deployment definition to create the deployment in the cluster.

kubectl apply -f hello-node-deployment.yaml
Output
deployment.apps/hello-node created

Get Resources⚓︎

Show all kubernetes resources with the label app: node.

kubectl get all -l app=hello-node
Output
NAME                              READY   STATUS    RESTARTS   AGE
pod/hello-node-749cb98bdb-hmqvd   1/1     Running   0          32s
pod/hello-node-749cb98bdb-v7jkj   1/1     Running   0          32s
pod/hello-node-749cb98bdb-z6s99   1/1     Running   0          32s

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/hello-node   3/3     3            3           32s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/hello-node-749cb98bdb   3         3         3       32s

If the pods have a STATUS of ErrImageNeverPull, see Load Image from Hello Kubernetes.

Notice 3 pods have STATUS=Running, and the deployment shows READY 3/3. In addition to these resource types, we also see a replicaset. You can read more about how a Replica Set works in the kubernetes documentation. For now, it's enough to know that kubernetes uses replica sets to manage a deployment's pods.

Show Logs⚓︎

Just like we did with a single pod, we can inspect the logs for all of the pods created by the hello-node deployment.

kubectl logs -l app=hello-node --prefix
Output
[pod/hello-node-749cb98bdb-hmqvd/app] Server running at http://0.0.0.0:3000/
[pod/hello-node-749cb98bdb-v7jkj/app] Server running at http://0.0.0.0:3000/
[pod/hello-node-749cb98bdb-z6s99/app] Server running at http://0.0.0.0:3000/

Port Forwarding⚓︎

kubectl supports forwarding a port to one of a deployment's pods. To avoid collisions with earlier tutorials, We'll forward a different host port (3003) to container port 3000.

kubectl port-forward deployment/hello-node 3003:3000
Output
Forwarding from 127.0.0.1:3003 -> 3000
Forwarding from [::1]:3003 -> 3000

kubectl port-forward will keep running to handle connections. Open http://127.0.0.1:3003/ in the browser, and we can again see our Hello World greeting!

Hello World

kubectl port-forward will also generate some additional output.

Output
Handling connection for 3003

Now that we're done testing, press Ctrl+C in your terminal to stop the kubectl port-forward.

Logging Pod Name⚓︎

Now that we have more than one pod running, it would be nice to know which is handling the request.

Update Code To Log Pod Name⚓︎

We'll need to modify the source code of our node service to print the pod name.

index.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const { createServer } = require('node:http');

const hostname = '0.0.0.0';
const port = 3000;
const podName = process.env.POD_NAME || 'unknown'; //(1)!

const server = createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end(`Hello World from pod ${podName}\n`); //(2)!
});

server.listen(port, hostname, () => {
  console.log(`Server running on pod ${podName} at http://${hostname}:${port}/`); //(3)!
});

  1. Set the javascript constant podName to the value stored in the POD_NAME environment variable. If POD_NAME is not set, use 'unknown', which will happen until we reconfigure the deployment.
  2. Include podName in the response shown in the browser.
  3. Include podName in the log message printed on pod startup.

Rebuild the docker image:

docker build --tag hello-node:1.0.2 . && kind load docker-image --name tutorial hello-node:1.0.2

Update Deployment Image⚓︎

Modify the deployment to use the new version:

hello-node-deployment-1.0.2.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-node
  labels:
    app: hello-node
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-node
  template:
    metadata:
      labels:
        app: hello-node
    spec:
      containers:
        - name: app
          image: hello-node:1.0.2 #(1)!
          imagePullPolicy: Never
          ports:
            - containerPort: 3000

  1. version updated to 1.0.2 to match the new docker image

Re-apply the deployment definition.

kubectl apply -f hello-node-deployment-1.0.2.yaml
Output
deployment.apps/hello-node configured

Check the startup logs.

kubectl logs -l app=hello-node --prefix
Output
[pod/hello-node-b84c9b567-pjcfj/app] Server running on pod unknown at http://0.0.0.0:3000/
[pod/hello-node-b84c9b567-v6pgj/app] Server running on pod unknown at http://0.0.0.0:3000/
[pod/hello-node-b84c9b567-d86sd/app] Server running on pod unknown at http://0.0.0.0:3000/

Forward a port to the deployment again.

kubectl port-forward deployment/hello-node 3003:3000

Open http://127.0.0.1:3003/ in the browser, and we can see the Hello World from pod unknown greeting!

Hello World

Press Ctrl+C in your terminal to stop the kubectl port-forward.

Update Deployment Environment⚓︎

Modify the deployment to set the POD_NAME environment variable.

hello-node-deployment-1.0.2-pod-name.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-node
  labels:
    app: hello-node
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-node
  template:
    metadata:
      labels:
        app: hello-node
    spec:
      containers:
        - name: app
          image: hello-node:1.0.2
          imagePullPolicy: Never
          ports:
            - containerPort: 3000
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name #(1)!

  1. Set the POD_NAME environment variable to the pod's metadata.name See Information available via fieldRef in the kubernetes documentation.

Re-apply the deployment definition.

kubectl apply -f hello-node-deployment-1.0.2-pod-name.yaml
Output
deployment.apps/hello-node configured

Check the startup logs.

kubectl logs -l app=hello-node --prefix
Output
[pod/hello-node-7f746ffc8d-4v4dq/app] Server running on pod hello-node-7f746ffc8d-4v4dq at http://0.0.0.0:3000/
[pod/hello-node-7f746ffc8d-8xfts/app] Server running on pod hello-node-7f746ffc8d-8xfts at http://0.0.0.0:3000/
[pod/hello-node-7f746ffc8d-zjqbc/app] Server running on pod hello-node-7f746ffc8d-zjqbc at http://0.0.0.0:3000/

Forward a port to the deployment again.

kubectl port-forward deployment/hello-node 3003:3000

Open http://127.0.0.1:3003/ in the browser, and we can see the Hello World from pod ... greeting!

Hello World

Note that if you press refresh a few times, the message won't change because the same pod handles every request. Because kubectl port-forward selects the deployment's first pod, there's no way to choose another with this method. In the next tutorial, we'll learn how to create a Service which sends traffic to the pods.

Press Ctrl+C in your terminal to stop the kubectl port-forward.