Files
kodekloud-engineer/kubernetes/level 2/task-2.md

5.4 KiB

Assignment

Nautilus developers need access to the last 24 hours of logs so that they can trace issues and bugs. Therefore, we need to ship the access and error logs for the web server to a log-aggregation service. Following the separation of concerns principle, we implement the Sidecar pattern by deploying a second container that ships the error and access logs from nginx. Nginx does one thing, and it does it well - serving web pages. The second container also specializes in its task - shipping logs. Since containers are running on the same Pod, we can use a shared emptyDir volume to read and write logs.

Create a pod named webserver.

Create an emptyDir volume named shared-logs.

Create a regular container in the webserver pod from the nginx:latest image named nginx-container, and an init container from the ubuntu:latest image named sidecar-container.

Add the following command to the sidecar-container "sh","-c","while true; do cat /var/log/nginx/access.log /var/log/nginx/error.log; sleep 30; done"

Mount the shared-logs volume in both containers at /var/log/nginx. Ensure all containers are in a running state.

Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.

Solution

Kubernetes Sidecar Logging Pod — webserver

An nginx container plus a log-shipping sidecar-container, sharing an emptyDir volume at /var/log/nginx. The sidecar is defined as a native sidecar (an init container with restartPolicy: Always) so it keeps running without blocking the pod. Applied inline via a heredoc — no manifest file on disk.

Apply (heredoc → kubectl)

kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: webserver
spec:
  volumes:
    - name: shared-logs
      emptyDir: {}
  initContainers:
    - name: sidecar-container
      image: ubuntu:latest
      restartPolicy: Always
      command:
        - sh
        - -c
        - "while true; do cat /var/log/nginx/access.log /var/log/nginx/error.log; sleep 30; done"
      volumeMounts:
        - name: shared-logs
          mountPath: /var/log/nginx
  containers:
    - name: nginx-container
      image: nginx:latest
      volumeMounts:
        - name: shared-logs
          mountPath: /var/log/nginx
EOF

How it works

The catch: "init container" that must keep running

The task calls sidecar-container an init container, gives it an infinite while true loop, and requires all containers to be running. Those are contradictory for a classic init container: a normal init container must run to completion before the main container starts. An init container with while true never completes, so the pod would hang in Init:0/1 forever and nginx would never start.

The resolution: a native sidecar

Kubernetes 1.28+ supports native sidecar containers — an entry under initContainers that carries restartPolicy: Always. That one field changes the semantics:

  • it's still declared under initContainers (satisfying "init container"),
  • but with restartPolicy: Always, Kubernetes starts it and moves on without waiting for it to complete, and keeps it running for the pod's lifetime alongside the main container.

So nginx starts normally, the sidecar runs continuously tailing the logs, and the pod reaches a fully Running state — meeting both "init container" and "all containers running." This is exactly the sidecar pattern the task describes, implemented the modern, native way.

The shared volume

  • shared-logs (emptyDir) is declared once and mounted at /var/log/nginx in both containers. nginx writes access.log and error.log there (its default log directory); the sidecar reads from the same path because it's the same underlying storage. This is the "read and write logs via a shared emptyDir" mechanism the task calls for — separation of concerns: nginx serves, the sidecar ships logs, they meet only at the shared volume.

The sidecar command

sh -c "while true; do cat .../access.log .../error.log; sleep 30; done" continuously dumps the two log files every 30 seconds (standing in for shipping them to an aggregator). The infinite loop is what requires the native-sidecar treatment above — without restartPolicy: Always under initContainers, this loop would block the pod.

Note: nginx creates access.log/error.log on first request; until then the sidecar's cat may print "No such file or directory" to its own stdout, which is harmless — it keeps looping.

Verify

# Pod fully up: nginx running AND the native sidecar running
kubectl get pod webserver

# Confirm the sidecar is an init container with restartPolicy: Always
kubectl get pod webserver \
  -o jsonpath='{.spec.initContainers[0].name}{" restartPolicy="}{.spec.initContainers[0].restartPolicy}{"\n"}'

# Both mounts point at /var/log/nginx
kubectl get pod webserver \
  -o jsonpath='{range .spec.containers[*]}{.name}{" "}{.volumeMounts[0].mountPath}{"\n"}{end}'

Expected — webserver Running with the nginx container ready; the jsonpath printing sidecar-container restartPolicy=Always; and the mount path /var/log/nginx on the containers.

If the pod sits in Init:0/1, the sidecar is being treated as a classic init container — the restartPolicy: Always line is missing or the cluster predates native sidecars (needs Kubernetes 1.28+). Confirm the field made it into the spec with the second command above.