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 label name: 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.
[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.
  • 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
  • Main Container State:
    • The main container (myapp-container) is in the Waiting state with the reason PodInitializing.
    • This means the main container cannot start until the init container completes successfully.

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 ClusterIP 10.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 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>
All systems normal

© 2025 2023 Sanjeeb KC. All rights reserved.