## Là gì

Kubernetes giữ số replica đã khai và tạo Pod mới khi Pod lệch trạng thái đó. `kubectl` nói chuyện với `kube-apiserver`. Process chạy trong **Pod**. **Deployment** giữ replica. **Service** cấp tên ổn định. Volume, Secret, init/sidecar gắn vào spec Pod.

| Object | Việc |
| --- | --- |
| Pod | Chỗ container chạy. Một IP. Tạo lại thì IP đổi |
| Deployment | ReplicaSet + template. Scale, rollout, undo |
| Service | Selector theo label. Mặc định ClusterIP |
| PVC | Xin đĩa. Pod ghi `claimName`, không trỏ tên PV |
| Secret | Mật khẩu, token. etcd mặc định không mã hóa |

## Để làm gì

- Đưa app stateless lên cluster: Deployment + Service.
- Đổi image không tắt hết replica, rollback khi tag sai.
- Giữ data MySQL/Redis trên PVC; chia file trong một Pod bằng `emptyDir`.
- Đưa config/mật khẩu lúc chạy, không nhét vào image.

## Lưu ý quan trọng

- **`kubectl run` tạo Pod**, không tạo Deployment.
- **Service chọn label**, không chọn tên Deployment. Ba chỗ `app: …` phải cùng giá trị.
- **`requests` xếp node, `limits` là trần.** Lab hay bắt khai đúng số.
- **Running ≠ Ready.** Probe fail thì Service không có endpoint.
- **`port` là cổng Service, `targetPort` là cổng Pod.**
- **Đổi `replicas` không tạo revision.** Đổi template mới có. `undo` không trả số replica.
- **RollingUpdate mặc định 25% unavailable, 25% surge.** `revisionHistoryLimit` mặc định 10.
- **`set image deploy/TÊN CONTAINER=image`.** Tên trước `=` là container.
- **`emptyDir` chết cùng Pod.** PVC sống sau khi thay Pod.
- **`volumeMounts.name` = `volumes[].name`.** Sai tên thì fail mount.
- **Secret `get -o yaml` là base64, không phải mã hóa.**
- **Đổi Secret không restart Pod.** Cần `rollout restart` hoặc đổi template.
- **Init chạy hết, lần lượt.** Sidecar lab: thêm `containers` + `emptyDir`. Native: `initContainers` + `restartPolicy: Always` (1.29+).
- **`logs` / `exec` có `-c` khi nhiều container.**
- **Đọc `current-context` trước `apply`.**
- **Ingress không nhận traffic nếu thiếu controller.**
- **Đừng sửa ReplicaSet của Deployment.**

## Lệnh tổng quan

```bash
kubectl config current-context
kubectl run lab-nginx --image=nginx:1.27-alpine --dry-run=client -o yaml
kubectl apply --dry-run=client -f ./k8s
kubectl apply -f ./k8s
kubectl get deploy,svc,pods -l app=web
kubectl describe pod -l app=web
kubectl logs -l app=web --tail=50
kubectl exec web-xxxx -c nginx -- printenv
kubectl port-forward service/web-service 8080:80
kubectl set image deployment/web-app nginx=nginx:1.27-alpine
kubectl rollout status deployment/web-app
kubectl rollout history deployment/web-app
kubectl rollout undo deployment/web-app
kubectl create secret generic db-pass --from-literal=password=change-me
kubectl delete -f ./k8s
```

## Cú pháp cần nhớ

```yaml
# Deployment: selector = template labels
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27-alpine
          ports:
            - name: http
              containerPort: 80
          resources:
            requests: { cpu: 50m, memory: 64Mi }
            limits: { cpu: 200m, memory: 128Mi }
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-pass
                  key: password
          volumeMounts:
            - name: data
              mountPath: /var/lib/data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: lab-pvc
---
# Service: selector = label Pod
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
    - port: 80
      targetPort: http
```
