Files

139 lines
5.4 KiB
Markdown

# Assignment
There are some applications that need to be deployed on Kubernetes cluster and these apps have some pre-requisites where some configurations need to be changed before deploying the app container. Some of these changes cannot be made inside the images so the DevOps team has come up with a solution to use init containers to perform these tasks during deployment. Below is a sample scenario that the team is going to test first.
Create a Deployment named as ic-deploy-devops.
Configure spec as replicas should be 1, labels app should be ic-devops, template's metadata lables app should be the same ic-devops.
The initContainers should be named as ic-msg-devops, use image fedora with latest tag and use command '/bin/bash', '-c' and 'echo Init Done - Welcome to xFusionCorp Industries > /ic/media'. The volume mount should be named as ic-volume-devops and mount path should be /ic.
Main container should be named as ic-main-devops, use image fedora with latest tag and use command '/bin/bash', '-c' and 'while true; do cat /ic/media; sleep 5; done'. The volume mount should be named as ic-volume-devops and mount path should be /ic.
Volume to be named as ic-volume-devops and it should be an emptyDir type.
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
# Solution
# Deployment with Init Container — `ic-deploy-devops`
An init container writes a message to a shared `emptyDir` volume; the main container then reads it
in a loop. This is the canonical init-container pattern. Applied inline via a heredoc — no manifest
file on disk.
## Apply (heredoc → kubectl)
```bash
kubectl apply -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: ic-deploy-devops
labels:
app: ic-devops
spec:
replicas: 1
selector:
matchLabels:
app: ic-devops
template:
metadata:
labels:
app: ic-devops
spec:
initContainers:
- name: ic-msg-devops
image: fedora:latest
command:
- /bin/bash
- -c
- "echo Init Done - Welcome to xFusionCorp Industries > /ic/media"
volumeMounts:
- name: ic-volume-devops
mountPath: /ic
containers:
- name: ic-main-devops
image: fedora:latest
command:
- /bin/bash
- -c
- "while true; do cat /ic/media; sleep 5; done"
volumeMounts:
- name: ic-volume-devops
mountPath: /ic
volumes:
- name: ic-volume-devops
emptyDir: {}
EOF
kubectl rollout status deployment/ic-deploy-devops
```
## How it works
### The heredoc apply pattern
- **`kubectl apply -f -`** reads from **stdin**; nothing written to disk.
- **`<<'EOF'` (delimiter quoted)** keeps the manifest literal — the right default for k8s YAML.
### Init container vs. main container — the ordering guarantee
This is a **classic** init container (under `initContainers`, no `restartPolicy` override), which
behaves very differently from the main container:
- **`ic-msg-devops` (init)** runs **first, to completion**, before any main container starts. It
`echo`s the message into `/ic/media` and exits `0`. Because it's a one-shot task that finishes,
a classic init container is exactly right here — it does setup work, then gets out of the way.
- **`ic-main-devops` (main)** starts **only after** the init container succeeds. It then loops,
`cat`-ing `/ic/media` every 5 seconds. The `while true` keeps it running so the pod stays up.
The sequencing is guaranteed by Kubernetes: init containers complete before app containers begin.
That's what makes the pattern work — the file is written before the main container ever tries to
read it.
### The shared `emptyDir` volume
- **`ic-volume-devops` (`emptyDir: {}`)** is declared once and mounted at **`/ic` in both
containers**. `emptyDir` is created empty when the pod starts and shared by all its containers, so
the init container's write to `/ic/media` is visible to the main container at the same path. This
is the hand-off mechanism: init writes, main reads, through shared storage.
Both `volumeMounts` reference the same volume name (`ic-volume-devops`) at the same path — that's
what ties them to one storage location.
### Why the commands need `/bin/bash -c`
Each command is a shell one-liner (a redirect for the init, a loop for the main), so both run via
`/bin/bash -c`. The main container's `while true` loop is what keeps it in `Running` state — without
a long-running process, the `fedora` container would exit immediately and the pod would crash-loop.
## Verify
```bash
# Deployment ready
kubectl get deployment ic-deploy-devops
kubectl get pods -l app=ic-devops
# Init container completed (check pod init status)
kubectl get pod -l app=ic-devops \
-o jsonpath='{.items[0].status.initContainerStatuses[0].state}{"\n"}'
# Main container is printing the message from the shared volume
kubectl logs -l app=ic-devops -c ic-main-devops --tail=3
```
Expected — deployment `READY 1/1`, the init container state showing `terminated`/`reason:
Completed`, and the main container's logs repeatedly printing
`Init Done - Welcome to xFusionCorp Industries`.
> If the pod is stuck in `Init:0/1`, the init container hasn't completed — check
> `kubectl logs -l app=ic-devops -c ic-msg-devops`. Unlike a native sidecar, a classic init
> container here is *meant* to finish, and it does (the echo exits immediately).