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>