Lesson 2.1: Pods (Basic Pod operations, multi-container pods)
Imperative
[root@master ~]# kubectl run nginx-pod --image=nginx:latest
pod/nginx-pod created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-pod 1/1 Running 0 16s
Declarative
[root@master ~]# cat pod.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
env: demo
type: frontend
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80
[root@master ~]# kubectl create -f pod.yml
Generating a Manifest File
The below command is a very useful way to generate a Kubernetes Pod manifest file using kubectl.
[root@master ~]# kubectl run nginx --image=nginx --dry-run=client -o yaml > pod-new.yml
# Modify the file according to the requirement
[root@master ~]# cat pod-new.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
-
kubectl run nginx:
- This is the command to create a Pod named nginx.
-
--image=nginx:
- Specifies the Docker image to use for the Pod. In this case, it's the official nginx image.
-
--dry-run=client:
- The --dry-run=client flag tells kubectl to simulate the creation of the Pod without actually creating it in the cluster.
- This is useful for generating a manifest file or testing a command without making any changes to the cluster.
-
-o yaml:
- The -o yaml flag outputs the generated Pod configuration in YAML format.
- Instead of applying the configuration directly, it prints the YAML manifest to the terminal.
-
> pod-new.yml:
- This redirects the output of the command (the YAML manifest) to a file named pod-new.yml.
[root@master ~]# kubectl describe pod nginx-pod
[root@master ~]# kubectl get pods nginx-pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-pod 1/1 Running 0 2m10s env=demo,type=frontend
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-pod 1/1 Running 0 2m37s 10.244.0.7 cka-cluster1-control-plane <none> <none>
Multi-Container Pods
A multi-container Pod in Kubernetes is a single Pod that contains multiple containers running together in a shared environment. These containers share the same network namespace, storage, and lifecycle, but they can perform different tasks or roles within the Pod.
Key Characteristics of Multi-Container Pods
-
Shared Resources:
- Network: Containers in the same Pod share the same IP address and port space. They can communicate with each other using localhost.
- Storage: Containers can share volumes (e.g., emptyDir, ConfigMap, Secret) to exchange data.
- Lifecycle: All containers in the Pod start and stop together. If one container fails, the entire Pod is affected.
-
Sidecar Pattern: Multi-container Pods are often used to implement the sidecar pattern, where a secondary container (the "sidecar") assists the primary container by providing additional functionality (e.g., logging, monitoring, or proxying).
-
Init Containers: Multi-container Pods can also include init containers, which run before the main containers to perform setup tasks (e.g., waiting for dependencies, initializing data).
-
Use Cases:
- Logging and monitoring (e.g., a logging sidecar container).
- Proxying network traffic (e.g., an Istio sidecar proxy).
- Data processing (e.g., a container that processes data generated by another container).
- Dependency management (e.g., an init container that waits for a database to be ready).
This example demonstrates how to use init containers to manage dependencies and ensure that your application starts only when all required resources are available.
[root@master ~]# cat multi-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
name: myapp-pod
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh','-c','echo the app is running && sleep 30']
env:
- name: FIRSTNAME
value: "sanjeeb"
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh','-c']
args: ['until nslookup myservice.default.svc.cluster.local ; do echo waiting for service to be up ; sleep 2 ; done ']
Pod Definition
apiVersion: v1
: Specifies the Kubernetes API version.kind
: Pod: Defines the resource type as a Pod.metadata
:name: myapp
: The Pod is named myapp.labels
: Adds a labelname: myapp-pod
to the Pod for identification.
Container Definition
- containers: Defines the main container(s) in the Pod.
name: myapp-container
: The container is named myapp-container.image: busybox:1.28
: Uses the busybox:1.28 image, a lightweight Linux utility container.command
: Specifies the command to run in the container:['sh','-c','echo the app is running && sleep 30']
This command prints the app is running and then sleeps for 30 seconds.
env:
Defines environment variables for the container:FIRSTNAME: "sanjeeb"
: Sets the environment variable FIRSTNAME to sanjeeb.
Init Container
- initContainers: Defines one or more init containers that run before the main container(s).
name: init-myservice
: The init container is named init-myservice.image: busybox:1.28
: Uses the same busybox:1.28 image.- command and args: Specifies the command and arguments to run in the init container:
- This script repeatedly checks if the DNS name
myservice.default.svc.cluster.local
resolves (i.e., if the service myservice is available). - If the service is not available, it prints
waiting for service to be up
and sleeps for 2 seconds before retrying. - Once the service is available, the init container exits successfully, allowing the main container to start.
- This script repeatedly checks if the DNS name
[root@master ~]# kubectl apply -f multi-pod.yml
pod/myapp created
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp 0/1 Init:0/1 0 7s
[root@master ~]# kubectl describe pod myapp
...
Status: Pending
Init Containers:
init-myservice:
Command:
sh
-c
Args:
until nslookup myservice.default.svc.cluster.local ; do echo waiting for service to be up ; sleep 2 ; done
State: Running
Containers:
myapp-container:
Command:
sh
-c
echo the app is running && sleep 30
State: Waiting
Reason: PodInitializing
...
- Pod Status:
- The output shows that the Pod myapp is in the Init:0/1 state, which means the init container (init-myservice) is running, but the main container (myapp-container) has not started yet.
- Init:0/1: This indicates that 0 out of 1 init containers have completed successfully.
- The Pod is in the Pending state because the init container is still running.
- The output shows that the Pod myapp is in the Init:0/1 state, which means the init container (init-myservice) is running, but the main container (myapp-container) has not started yet.
- Init Container State:
- The init container (init-myservice) is in the
Running
state. - It is executing the command:
until nslookup myservice.default.svc.cluster.local ; do echo waiting for service to be up ; sleep 2 ; done
- The init container (init-myservice) is in the
- Main Container State:
- The main container (myapp-container) is in the
Waiting
state with the reasonPodInitializing
. - This means the main container cannot start until the init container completes successfully.
- The main container (myapp-container) is in the
Error Logs
[root@master ~]# kubectl logs pod/myapp
Defaulted container "myapp-container" out of: myapp-container, init-myservice (init)
Error from server (BadRequest): container "myapp-container" in pod "myapp" is waiting to start: PodInitializing
[root@master ~]# kubectl logs pod/myapp -c init-myservice
nslookup: can't resolve 'myservice.default.svc.cluster.local'
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
waiting for service to be up
The logs confirm that the init container (init-myservice) is stuck because it cannot resolve the DNS name myservice.default.svc.cluster.local
. This means the service myservice does not exist in the default namespace.
- The init container was repeatedly trying to resolve the DNS name but failed because the service didn’t exist.
- The DNS server (10.96.0.10, which is CoreDNS) was reachable, but the service myservice was missing.
- The Pod was stuck in the Init:0/1 state because the init container hadn’t completed successfully.
- The main container (myapp-container) was in the Waiting state with the reason PodInitializing.
Creating the service
To fix the issue, create the myservice
service using the following YAML:
[root@master ~]# cat multi-pod-service.yml
apiVersion: v1
kind: Service
metadata:
name: myservice
namespace: default
spec:
selector:
app: myservice
ports:
- protocol: TCP
port: 80
targetPort: 80
[root@master ~]# kubectl apply -f multi-pod-service.yml
service/myservice created
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24h
myservice ClusterIP 10.96.83.233 <none> 80/TCP 3s
name: myservice
: The service is named myservice.namespace: default
: The service is created in the default namespace.selector: app: myservice
: The service will route traffic to Pods with the label app: myservice.port: 80
: The service exposes port 80.targetPort: 80
: The service forwards traffic to port 80 on the Pods. The service myservice was successfully created with the ClusterIP10.96.83.233
.
Success Logs
Once the service was created, the init container was able to resolve the DNS name myservice.default.svc.cluster.local
and exited successfully.
[root@master ~]# kubectl logs pod/myapp
Defaulted container "myapp-container" out of: myapp-container, init-myservice (init)
the app is running
# The DNS lookup succeeded, and the init container completed its task.
[root@master ~]# kubectl logs pod/myapp -c init-myservice
...
Name: myservice.default.svc.cluster.local
Address 1: 10.96.83.233 myservice.default.svc.cluster.local
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp 1/1 Running 4 (57s ago) 72m
[root@master ~]# kubectl exec -it myapp -- printenv
...
HOSTNAME=myapp
FIRSTNAME=sanjeeb
- The DNS lookup succeeded, and the init container completed its task.
- After the init container completed, the main container (myapp-container) started and executed its command:
- The main container printed
the app is running
and then slept for 30 seconds (as defined in the Pod YAML).
- The main container printed
- The Pod transitioned to the Running state
- The environment variable
FIRSTNAME=sanjeeb
was successfully passed to the container (as defined in the Pod YAML).
Note: You cannot add or remove the init containers once it is created
Example
[root@master nginx-multi-container]# cat pod.yml
apiVersion: v1
kind: Pod
metadata:
name: multi-container-pod
labels:
app: myservice
spec:
initContainers:
- name: init-myservice
image: busybox:latest
command: ['sh','-c','until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done']
containers:
- name: nginx-container
image: nginx:latest
command: ["sh", "-c", "mkdir -p /var/log/nginx && nginx -g 'daemon off;'"]
ports:
- containerPort: 80
- name: logging-sidecar
image: busybox:latest
command: ["sh", "-c", "while [ ! -f /var/log/nginx/access.log ]; do sleep 1; done; tail -f /var/log/nginx/access.log"]
[root@master nginx-multi-container]# kubectl apply -f pod.yml
pod/multi-container-pod created
[root@master nginx-multi-container]# kubectl get pods
NAME READY STATUS RESTARTS AGE
multi-container-pod 0/2 Init:0/1 0 6s
[root@master nginx-multi-container]# kubectl logs pod/multi-container-pod
Defaulted container "nginx-container" out of: nginx-container, logging-sidecar, init-myservice (init)
Error from server (BadRequest): container "nginx-container" in pod "multi-container-pod" is waiting to start: PodInitializing
[root@master nginx-multi-container]# kubectl logs pod/multi-container-pod -c nginx-container
Error from server (BadRequest): container "nginx-container" in pod "multi-container-pod" is waiting to start: PodInitializing
[root@master nginx-multi-container]# kubectl logs pod/multi-container-pod -c logging-sidecar
Error from server (BadRequest): container "logging-sidecar" in pod "multi-container-pod" is waiting to start: PodInitializing
[root@master nginx-multi-container]# kubectl logs pod/multi-container-pod -c init-myservice
** server can't find myservice.default.svc.cluster.local: NXDOMAIN
[root@master nginx-multi-container]# cat myservice.yml
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
type: NodePort
selector:
app: myservice
ports:
- port: 80
targetPort: 80
nodePort: 30001
[root@master nginx-multi-container]# kubectl apply -f myservice.yml
service/myservice created
[root@master nginx-multi-container]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 25h
myservice ClusterIP 10.96.195.178 <none> 80/TCP 3s
[root@master nginx-multi-container]# kubectl logs pod/multi-container-pod -c logging-sidecar
Name: myservice.default.svc.cluster.local
[root@master nginx-multi-container]# kubectl logs pod/multi-container-pod -c logging-sidecar
# No logs
[root@master nginx-multi-container]# kubectl get pods
NAME READY STATUS RESTARTS AGE
multi-container-pod 2/2 Running 0 117s
[root@master nginx-multi-container]# kubectl exec -it multi-container-pod -- sh
Defaulted container "nginx-container" out of: nginx-container, logging-sidecar, init-myservice (init)
# cd /var/log/nginx
# ls
access.log error.log
[root@master nginx-multi-container]# curl localhost:30001
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>