Deployment

Learn how to create a Kubernetes deployment and deploying the Hello World container image.

This section continues from the previous section - make sure you do the tutorial in sequence.

Pod

A Kubernetes Pod is a group of tightly coupled containers, tied together that must start, stop, and scale together. In many case a Pod is associated to only one container. Multiple containers in a single pod can be useful when you have, for example, a container that runs the application, and another container that periodically polls logs/metrics from the application container.

Every Pod has a unique, ephemeral, and routable IP address. I.e., a container inside of a Pod can directly reach another the IP address of another Pod (and the containers in that Pod).

All containers within a single pod are scheduled to a single physical resource (the same Node), and all containers within a Pod will share the same networking interface, IP address, volumes, etc.

You can start a single Pod in Kubernetes by creating a Pod resource. However, a Pod created this way would be known as an Unmanaged Pod. If an Unmanaged Pod dies/exits, it will not be restarted by Kubernetes. A better way to start a Pod, is by using a higher-level construct such as a Deployment.

Deployment

Deployment provides declarative way to manage a set of Pods. You only need to describe the desired state in a Deployment resource, and behind the scenes, a Kubernetes Deployment controller will change the actual state to the desired state for you. It does this using a resource called a ReplicaSet under the covers.

Deployment YAML

You can create a Deployment and deploy into Kubernetes using kubectl command line like in the Hello World tutorial. That's great to get a feel of Kubernetes. However, it's best that you create a YAML file first, and then deploy the YAML file.

# Under the helloworld-springboot-tomcat directory , create a k8s directory
mkdir k8s/
‚Äč
PROJECT_ID=$(gcloud config get-value project)
kubectl create deployment helloworld \
--image=gcr.io/${PROJECT_ID}/helloworld \
--dry-run \
-o yaml > k8s/deployment.yaml

You can open the k8s/deployment.yaml file to see the content. Following is a version of the YAML file where it's slimmed down to the bare minimum.

k8s/deployment.yaml
# API Version and Kind are important to indicate the type of resource
apiVersion: apps/v1
kind: Deployment
metadata:
# Every Kubernetes resource has a name that's unique within a namespace
name: helloworld
# Every Kubernetes can have labels, label key/value pairs can be queried later.
labels:
app: helloworld
spec:
# The number of the pods that start
replicas: 1
# The labels that matches the pods within this deployment
selector:
matchLabels:
app: helloworld
# Every instance of the pod will be created using the template below
template:
metadata:
# Every new pod created by the deployment will have these labels
# The name of a newly created pod will be generated
labels:
app: helloworld
spec:
containers:
# Every container can have a name, and the container image to run
- name: helloworld
image: gcr.io/.../helloworld

You can read more about Deployment in the Kubernetes Deployment Guide.

Deploy

Use kubectl command line to deploy the YAML file:

kubectl apply -f k8s/deployment.yaml

To verify the application is deployed, see all the pods that are running:

kubectl get pods

You should see that there is one pod running!

NAME READY STATUS RESTARTS AGE
helloworld-... 1/1 Running 0 ...

Basic Interactions

Describe Details

For every Kubernetes resource, you can describe the details of a resource, and see its current state, and any events, errors that may have occurred.

Describe a Deployment:

kubectl describe deployment helloworld

Describe a Pod:

POD_NAME=$(kubectl get pods -lapp=helloworld -o jsonpath='{.items[0].metadata.name}')
kubectl delete pod ${POD_NAME}

Find Pods with Labels

kubectl get pods shows you every pod running in the current namespace. You can limit the output to just the application you are interested in by select only pods matching certain label key/value pairs.

kubectl get pods -lapp=helloworld

Scaling

Scale the number of instances from 1 to 2.

kubectl scale deployment helloworld --replicas=2

Verify that there are now 2 pods running:

kubectl get pods

Delete a Pod

Out of the 2 pods, pick one to delete, and then observe that Kubernetes automatically starts another pod instance so that there are always 2 pods running.

POD_NAME=$(kubectl get pods -lapp=helloworld -o jsonpath='{.items[0].metadata.name}')
kubectl delete pod ${POD_NAME}

Verify that there still 2 pods running, but one of them has a lower age indicating it's recently started.

kubectl get pods

Delete All Pods

You can use labels to delete all pods matching certain label key/value pairs.

kubectl delete pod -lapp=helloworld

Stream Logs

You can see the logs from the pod, and follow the log as new logs are produced:

POD_NAME=$(kubectl get pods -lapp=helloworld -o jsonpath='{.items[0].metadata.name}')
kubectl logs -f ${POD_NAME}

Executing Commands

You can execute commands directly in the container instance. However, the container image will need to contains the command that you'd like to run. The Hello World application built with Jib uses a Distroless base image by default - and the Distroless base image does not come with any shell commands for security purposes.

Let's deploy an Nginx container that contains the executables and see how you can shell into the container instance.

kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/controllers/nginx-deployment.yaml

See that Nginx container is running:

kubectl get pods -lapp=nginx

Use a specific Nginx pod, and shell into the container instance:

POD_NAME=$(kubectl get pods -lapp=nginx -o jsonpath='{.items[0].metadata.name}')
kubectl exec -ti ${POD_NAME} /bin/bash

The -ti flag means to receive output from TTY, and also that the session is interactive (i.e., you'll be typing commands).

Once you are in the container instance's shell, you can explore the container instance:

# Within the container instance shell:
ls
ls /sbin
ls /bin
exit

In this Nginx container image, you can see that there are actually many command line utilities that's not needed for production deployment of an Nginx server. Exposing more commands like this may increase attack surface area if the container instance is compromised. For this reason, Distroless base images do not include any commands. On the other hand, lack of commands may increase the difficulty to debug the application instance.

Delete the Nginx deployment before you continue!

kubectl delete deployment nginx-deployment