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-podto 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.localresolves (i.e., if the service myservice is available). - If the service is not available, it prints
waiting for service to be upand 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
Runningstate. - 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
Waitingstate 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 upThe 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 3sname: 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 runningand 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=sanjeebwas 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>