kubernetes
Pod

Pod

What is Pod?

Pod is a single instance of an application and is the smallest unit of a Kubernetes application. It basically wraps container or provides an abstraction layer over container. Normally, pod is only run one application container inside it (one-to-one relationship).

Each pod will get its IP address and when the pod is recreated, then the new IP address will be assigned to that pod. So, the pod can use its IP address to communicate with each other pods using its internal IP address.

Commands

# Deploy nginx image to pod with the pod-name "nginx"
kubectl run <pod-name> --image=<image>
 
# Example
kubectl run nginx --image=nginx
kubectl run nginx --image=nginx --port=8000 # container exposes port
kubectl run nginx --image=nginx --port=8080 --expose # Create a cluster IP associated with the pod port number
 
kubectl get pods
kubectl get pod <pod-name>
kubectl describe pod <pod-name>
kubectl delete pod <pod-name>
 
kubectl exec <pod-name> -- <command>
kubectl exec mypod -- /bin/bash
 
kubectl apply -f <filename>
kubectl create -f <filename>
 
kubectl edit pod <pod-name>
 
# extract pod definition to a file
kubectl get pod <pod-name> -o yaml > pod.yaml
 
# get more pod information like IP address, etc
kubectl get pods -o wide

Pod YAML File

Here is the sample pod YAML file, to apply this file, you need to type kubectl apply -f pod.yaml.

KindVersion
Podv1
Servicev1
ReplicaSetapps/v1
Deploymentapps/v1
pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp
  labels:
    name: myapp
spec:
  containers:
    - name: myapp
      image: nginx
      ports:
        - containerPort: 8080

Init Containers

Init container is a special type of container that run before the main container. It will be run only once and must complete successfully before the main container starts.

Use case:

  • Wait for a database to be ready
  • Prepare a configuration file
  • Load data
init-container.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
    - name: main-container
      image: api:1.0.0
  initContainers:
    - name: init-database
      image: mysql
      command: ['sh', '-c', 'mysql -h db -u root -p $MYSQL_ROOT_PASSWORD < /scripts/init.sql']
  • If you specify multiple init containers, they will be run in order.

Multi-container pods

Multi-container pods are like helper containers. The two or more containers can communicate directly via localhost as they share the same network space. Of course, they are sharing the same storage space and same lifecycle (created and destroyed together) as well.

Design Patterns

Sidecar Pattern

Sidecar pattern is a container attached to the main container to extend or enhance the main container. For example, a sidecar container can collect logs from the main container, then can forward them to a centralized logging system like Elasticsearch.

Use case:

  • Logging
  • Monitoring
  • Security
  • Data synchronization
sidecar.yml
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
    - name: app-container
      image: alpine
      command: ["/bin/sh"]
      args: ["-c", "while true; do date >> /var/log/index.html; sleep 2;done"]
      volumeMounts:
        - name: logs
          mountPath: /var/log
    - name: log-agent
      image: nginx
      ports:
        - containerPort: 80
      volumeMounts:
        - name: logs
          mountPath: /usr/share/nginx/html
  volumes:
    - name: logs
      emptyDir: {}
  • In this case, when you port-forward to the port 80, you will see the logs from the app-container.

Adapter Pattern

Adapter pattern is a container that acts as a translator between the main containers and the external systems. Basically, you can use this pattern to manipulate and transform the data into a standardize format before sending it to the external system.

For example, you have multiple applications that generated logs in different formats, then you can use the adapter pattern to transform the logs into a standardize format before sending them to the centralized logging system, so that the centralized logging system can easily parse and analyze the logs.

Use case:

  • Data transformation
  • Protocol translation
  • API adaptation (Reverse Proxy)
  • Standardize data format
adapter.yml
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
    - name: app-container
      image: alpine
      command: ["/bin/sh"]
      args: ["-c", "while true; do date >> /var/log/debug.log; sleep 2;done"]
      volumeMounts:
        - name: logs
          mountPath: /var/log
    - name: log-adapter
      args: ["/bin/sh"]
      args: ["-c", "tail -f /var/log/debug.log|sed 's/^/DEBUG: /' > /var/log/transformed.log"]
      volumeMounts:
        - name: logs
          mountPath: /var/log
  volumes:
    - name: logs
      emptyDir: /var/log

Ambassador Pattern

Ambassador Pattern is a container that acts as a proxy to the external services. It is used to hide the complexity of the external services from the main container. Therefore, this ambassador container will act as a client proxy (manage all incoming and outgoing network traffic) between the main container and the external services.

For example, your application need to connect to external database, now the application need to connect to different database based on the environment (development, staging, production) and you also need to make sure that the application connect to the correct database based on the environment, in this case, you can use the ambassador pattern to manage the connection to the database, so that the application only need to connect to the ambassador container as localhost and the ambassador container will manage the connection to the correct database based on the environment.

ambassador.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: db-config
data:
  development: "dev-db.example.com"
  staging: "staging-db.example.com"
  production: "prod-db.example.com"
---
apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
  labels:
    app: ambassador
    environment: development # Change this based on the environment
spec:
  containers:
    - name: backend
      image: backend
      env:
        - name: DB_HOST
          value: "localhost"
      ports:
        - containerPort: 8080
    - name: ambassador
      image: ambassador-image
      env:
        - name: ENVIRONMENT
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels.environment
        - name: DB_HOST
          valueFrom:
            configMapKeyRef:
              name: db-config
              key: $(ENVIRONMENT)
      ports:
        - containerPort: 80
  • ConfigMap is used to store the database connection based on the environment.
  • ambassador container reads the env variable and configures itself to connect to the correct database based on the environment.
  • backend container connects to the ambassador container as localhost.