---
id: kubernetes-init-sidecar
title: "Init container và sidecar"
shortTitle: "Init & sidecar"
track: kubernetes
trackTitle: "Kubernetes"
order: 7
level: important
status: published
estimatedMinutes: 35
prerequisites:
  - kubernetes-config-secrets
next: kubernetes-helm
reviewedAgainst: 2026-10-15
sources:
  - title: "KodeKloud Engineer — 100 Days of DevOps"
    url: https://engineer.kodekloud.com/practice
  - title: "Init Containers"
    url: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
  - title: "Sidecar Containers"
    url: https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/
---

# Init container và sidecar

Một Pod không chỉ một process. Init chạy xong rồi mới tới app. Sidecar chạy cùng app: ship log, đồng bộ file, không nhét vào image chính.

## Để làm gì

Bạn viết `initContainers` chạy tuần tự tới khi thành công, phân biệt với container phụ sống suốt đời Pod, và đọc log đúng `-c` khi STATUS là `Init:0/1`.

## Gồm những gì

- `initContainers`: chạy hết, lần lượt, fail thì kubelet thử lại (trừ `restartPolicy: Never` trên Pod).
- Sidecar kiểu cũ: thêm phần tử trong `containers`, chung `emptyDir`.
- Sidecar native (ổn định từ Kubernetes 1.33): `initContainers` + `restartPolicy: Always`.
- `kubectl logs POD -c tên`.

Không viết service mesh. Job + sidecar chỉ nhắc: sidecar native không chặn Job hoàn thành.

## Dùng khi nào

App phải đợi Service DNS lên — init `nslookup`. App viết file, process khác đọc — sidecar + volume chung.

Đừng nhét `sleep 60` vào image app chỉ để chờ DB. Tách init, image app giữ mỏng.

## Kiến thức cốt lõi

Init nằm cạnh `containers`, không thay `containers`. Giống container thường (image, command, volume, resources) nhưng:

- Phải chạy **xong** (exit 0).
- Nhiều init: kubelet chạy **lần lượt**. Cái sau chờ cái trước thành công.
- Không dùng `readinessProbe` trên init thường — docs cấm, vì "ready" của init là đã xong.
- Cổng init không gom vào Service.

STATUS `Init:0/2` = init thứ nhất chưa xong, app chưa start. Pod `Pending` lúc đó là bình thường. `logs POD -c init-myservice`.

Fail: kubelet restart init đó. `restartPolicy: Never` trên Pod thì Pod fail luôn. Code init phải chạy lại được: file trên `emptyDir` có thể đã tồn tại.

Sidecar **cũ** (mọi bản): hai (hay hơn) phần tử trong `containers`. Cùng Pod = cùng network, `localhost` gọi nhau. Chung file thì `emptyDir` như bài volume. Không có thứ tự start chắc như init — cả hai start gần như cùng lúc. Lab 100 Days hay dùng kiểu này.

Sidecar **native**: kê trong `initContainers`, thêm `restartPolicy: Always`. Kubelet coi là sidecar, giữ chạy suốt đời Pod. Start theo thứ tự list `initContainers`; cái native đã `started` thì tới phần tử sau. Tắt Pod: app dừng trước, sidecar sau, ngược thứ tự spec. Feature ổn định từ 1.33; 1.29 bật mặc định. Cluster cũ hơn: dùng hai `containers`.

`kubectl logs` / `exec` luôn `-c` khi không phải Pod một container. Thiếu `-c` thì kubectl bắt chọn.

## Lệnh và code mẫu

Init đợi — ý docs (không copy lab): vòng `nslookup` tên Service rồi exit 0. App chỉ start sau đó.

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: with-init
spec:
  containers:
    - name: app
      image: busybox:1.36
      command: ["sh", "-c", "echo app-running && sleep 3600"]
  initContainers:
    - name: wait-svc
      image: busybox:1.36
      command: ["sh", "-c", "until nslookup kubernetes.default.svc.cluster.local; do sleep 2; done"]
```

Sidecar kiểu cũ, chung `emptyDir`:

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: with-sidecar
spec:
  containers:
    - name: app
      image: busybox:1.36
      command: ["sh", "-c", "while true; do echo tick >> /var/log/app/out.log; sleep 2; done"]
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
    - name: shipper
      image: busybox:1.36
      command: ["sh", "-c", "tail -F /var/log/app/out.log"]
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
  volumes:
    - name: logs
      emptyDir: {}
```

```bash
kubectl apply -f with-sidecar.yaml
kubectl logs with-sidecar -c shipper
kubectl logs with-init -c wait-svc
```

Sidecar native (cluster ≥ 1.29, ổn định 1.33): cùng ý, nhưng `shipper` nằm `initContainers` kèm `restartPolicy: Always`. Docs có mẫu `deployment-sidecar.yaml`. Lab không đòi bản native thì đừng viết — hai `containers` đủ.

## Thực hành

1. Apply Pod init. `get pod` lúc đầu: `Init:…`. `logs -c wait-svc`.
2. Apply Pod sidecar. `logs -c shipper` thấy dòng `tick`.
3. `exec` nhầm không `-c` — đọc thông báo kubectl.
4. Cố ý sai command init (`false`). Xem restart / `CrashLoop` trên init, app không Running.

## Kết quả mong đợi

- Init xong thì app `Running` `1/1`.
- Sidecar in log app viết vào volume chung.
- Init fail: STATUS không sang Running của app.

## Checklist

- [ ] Init chạy tuần tự, xong mới app.
- [ ] `logs` / `exec` có `-c`.
- [ ] Sidecar lab: thêm `containers` + `emptyDir`.
- [ ] Native sidecar: `initContainers` + `restartPolicy: Always` — chỉ khi cluster đủ bản.
- [ ] Init idempotent nếu ghi `emptyDir`.

## Thẻ ôn

### kubernetes-init-sidecar-init
kind: distinguish
cue: Init chạy hết, lần lượt, rồi mới app. STATUS Init:0/N. `logs -c` tên init.

Q: `get pod` in `Init:0/1`, READY `0/1`. App chưa log. Việc đúng là gì, và xóa Pod có bắt init chạy lại không?

A: `kubectl logs POD -c <tên-init>`. App chưa start nên không có log app. Init fail thì kubelet thử lại; xóa Pod tạo Pod mới, **mọi** init chạy lại từ đầu. Đừng `exec` vào app — container app chưa có.

### kubernetes-init-sidecar-share
kind: distinguish
cue: Sidecar lab: container thứ hai trong `containers`, chung emptyDir. Native: initContainers + restartPolicy Always (1.29+).

Q: App ghi `/var/log/app/out.log`, process khác `tail -F` cùng file, sống suốt đời Pod. Khai kiểu nào trên cluster 1.27, và `localhost` giữa hai process được không?

A: Hai phần tử `containers` + `emptyDir` mount cùng path. Cùng Pod thì cùng network: `localhost` + cổng. `restartPolicy: Always` trên `initContainers` là sidecar native — 1.27 không dựa vào đó. Init thường exit 0 rồi chết, không `tail` mãi.

## Lỗi thường gặp

**`logs` không `-c`.** Pod hai container, kubectl không đoán.

**Init `sleep 5` rồi tưởng DB chắc sẵn.** Docs gợi đợi DNS/Service (`nslookup` vòng). `sleep` cố định vẫn race.

**Sidecar viết trong `initContainers` mà không `restartPolicy: Always`.** Đó là init: chạy xong là hết, không ship log suốt đời.

**Cùng tên init và app.** API từ chối. Mỗi container trong Pod một tên.

## Nguồn

1. [KodeKloud Engineer — 100 Days of DevOps](https://engineer.kodekloud.com/practice) — đề cương ngày Kubernetes Sidecar Containers, Init Containers. Trang practice cần đăng nhập. Bài này viết lại lệnh, không chép lab.
2. [Init Containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) — tuần tự, chạy hết, `Init:0/N`, idempotent, không readiness trên init thường.
3. [Sidecar Containers](https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/) — `restartPolicy: Always` trên init, ổn định 1.33; hai `containers` trên cluster cũ.

## Tiếp theo

[Helm](./04-helm.md)
