Files
project-infra/docs/standards/infra/k3s-specific.md
T

225 lines
11 KiB
Markdown

# K3s-specific 기준
## 목적
이 문서는 일반 Kubernetes 표준과 **분리**해서, K3s 운영에서만 발생하는 특수성을 고정한다.
목표:
- K3s packaged component (`coredns`, `traefik`, `local-storage`, `metrics-server`, `servicelb`)를 일반 manifest처럼 관리하는 실수를 막는다
- `/var/lib/rancher/k3s/server/manifests`를 source-of-truth로 쓰는 실수를 막는다
- 멀티 server HA 환경에서 `critical configuration value mismatch` join 실패를 예방한다
- embedded registry mirror(Spegel)의 네트워크·버전 게이트를 정확히 이해한다
- 1000+ 서비스 prod 스케일에서 K3s의 어떤 기능을 켜고 어떤 기능을 외부로 뺄지 기준을 박는다
## 공식 의미 (근거 URL 포함)
- K3s packaged component: `coredns`, `traefik`, `local-storage`, `metrics-server` (매니페스트 파일 기반) + `servicelb`(매니페스트 없이 `--disable`만 가능).
- AddOn auto-deploy: `/var/lib/rancher/k3s/server/manifests` 하위 파일은 server 시작 시 + 파일 변경 시 자동 apply. packaged component는 K3s가 재기록하므로 직접 수정 금지.
- multi-server 유저 AddOn은 서버 간 자동 동기화되지 **않는다**.
- K3s 설정: `/etc/rancher/k3s/config.yaml` + `/etc/rancher/k3s/config.yaml.d/*.yaml` drop-in.
- critical 값 (cluster-cidr / service-cidr / cluster-dns / cluster-domain / disable 세트 / CNI / embedded-registry 활성화)이 서버 간 불일치면 `critical configuration value mismatch` join 실패.
- packaged Helm component(`traefik` 등) 커스터마이징은 `HelmChartConfig` (apiVersion `helm.cattle.io/v1`).
- K3s 기본 local storage는 Rancher Local Path Provisioner (`local-path` StorageClass, node-local, not replicated).
- **embedded registry mirror (Spegel)**: 기본 비활성. 활성화 시 노드 간 TCP 5001 (p2p gossip) + TCP 6443 (registry + supervisor)이 reachable해야 한다. 출처: `https://docs.k3s.io/installation/registry-mirror` — "all nodes must be able to reach each other via their internal IP addresses, on TCP ports 5001 and 6443".
- K3s 이미지 import: `/var/lib/rancher/k3s/agent/images/*.tar{,.zst,.gz}`.
- K3s는 기본적으로 network policy enforcer (kube-router 기반)를 포함한다. 외부 CNI(Cilium 등) 사용 시 `--disable-network-policy` + `--flannel-backend=none` 조합 필요.
## 기본 규칙
### 1. K3s 전용 규칙은 별도 문서로 유지
일반 Kubernetes 표준 문서에 K3s 특수성을 흩뿌리지 않는다. 분리 범주:
- packaged component
- AddOn auto-deploy
- config.yaml / config.yaml.d
- local-path provisioner
- embedded registry mirror
- critical server flags
- Helm component customization
### 2. packaged component는 “편의 기능”, 직접 수정 절대 금지
관리 대상:
- `coredns`
- `traefik`
- `local-storage`
- `metrics-server`
- `servicelb` (manifest 없음, flag로만 제어)
금지:
- `/var/lib/rancher/k3s/server/manifests/traefik.yaml` 직접 edit
- packaged manifest를 Git SoT로 관리
- 재시작 후 overwrite되는 파일에 운영 커스터마이징 저장
### 3. packaged component 유지/비활성은 cluster bootstrap 때 박는다
1000-서비스 prod 스케일에서 현재 기준:
| component | prod 기본 | 이유 |
|----------------|-----------|-------------------------------------------------------------|
| `traefik` | disable | ingress-nginx / Envoy Gateway로 교체. Traefik은 dev만. |
| `servicelb` | disable | MetalLB L2/BGP 또는 외부 LB. klipper는 노드 80/443 점유. |
| `local-storage`| disable | Longhorn / Ceph RBD / CSI. node-local은 DR 불가. |
| `metrics-server`| keep | HPA + `kubectl top` 전제. 대체 pipeline 준비되면 교체 가능. |
| `coredns` | keep | 교체는 특수 케이스. node-local dns cache는 별도로 추가. |
| network policy | 상황별 | Cilium 도입 시 disable. 기본 kube-router 유지도 가능. |
### 4. server critical config는 Git에서 단일 파일로 관리
`/etc/rancher/k3s/config.yaml`이 Git의 inventory repo (Ansible / Fleet / CI)에서 push된다.
서버별 ad-hoc 수정 금지. critical 값 mismatch는 **join 실패**로 직결된다.
일치해야 하는 값:
- `cluster-cidr`, `service-cidr`, `cluster-dns`, `cluster-domain`
- `disable` 세트
- `flannel-backend` / `disable-network-policy`
- `embedded-registry` 활성화 여부
- `datastore-endpoint` (etcd / external DB)
### 5. CLI argument보다 config file 우선
재현성 / diff / multi-node 동기화를 위해 server/agent 플래그는 모두 `config.yaml`로.
`/etc/rancher/k3s/config.yaml.d/*.yaml` drop-in은 역할별 파일 분리(예: `10-networking.yaml`, `20-audit.yaml`)에 사용.
### 6. `/var/lib/rancher/k3s/server/manifests`는 apply sink, SoT 아님
- 운영 SoT = Git (+ Kustomize / ArgoCD / Flux)
- 이 디렉터리는 bootstrap addon에만 한정 (예: `k3s-addons-disabled.yaml` placeholder)
- 서버별로 다른 파일을 두고 "알아서 맞겠지"는 금지
- `.skip` 파일은 **임시** 비활성화 용. 장기 disable은 `--disable` 플래그로.
### 7. multi-server user AddOn은 Git push, 로컬 scp 금지
K3s는 user AddOn을 서버 간 동기화하지 않는다. 멀티 server 환경에서 AddOn을 쓰려면:
- GitOps 컨트롤러(ArgoCD/Flux)가 apply
- 또는 Ansible/Fleet이 단일 server 노드에만 drop
- 또는 완전히 포기하고 `kubectl apply`로만 관리 (권장)
### 8. packaged Helm component 커스터마이징은 `HelmChartConfig`
traefik 유지가 불가피할 때:
```yaml
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
<override values>
```
- `metadata.name` / `namespace`는 대응 `HelmChart`와 반드시 일치
- 민감 값은 `valuesSecrets`로 Secret 참조 (valuesContent에 하드코딩 금지)
- HelmChartConfig 자체는 Git 관리
### 9. local-path provisioner는 dev/test 한정
Rancher Local Path Provisioner = node-local hostPath. 특성:
- ReadWriteOnce only
- 노드 장애 시 데이터 접근 불가
- 백업/DR 불가 (StorageClass 레벨 스냅샷 없음)
- binding mode = WaitForFirstConsumer (Pod가 뜰 때 PV 생성)
기준:
- dev/test StatefulSet의 PVC 기본값으로만 허용
- prod의 DB / Vault / MinIO / Kafka / etcd backup target에 절대 사용 금지
- prod storage는 **Longhorn (K3s 권장) / Ceph RBD / 외부 CSI** 중 택1
### 10. metrics-server는 유지 기본값
HPA v2 metrics, `kubectl top`, VPA, kube-state-metrics 연동 모두가 전제. disable 시 Prometheus Adapter 등 대체 pipeline을 먼저 준비한 뒤에만 꺼야 한다.
### 11. traefik / servicelb는 포트 점유 + 노드 노출 전략을 같이 본다
- `servicelb` (klipper) = 모든 노드가 80/443 HostPort로 열림. prod에서는 거의 항상 disable + MetalLB 또는 외부 LB.
- `traefik` 유지 시 IngressClass / Middleware / EntryPoint 세 레이어가 전부 K3s 관리. prod에서는 disable + `ingress-nginx` DaemonSet 또는 Envoy Gateway Deployment.
### 12. network policy controller 충돌
- 기본: K3s 내장 kube-router 기반 enforcer
- Cilium / Calico 도입 시: `--flannel-backend=none` + `--disable-network-policy` + `--disable=servicelb`
- 도입 계획은 클러스터 bootstrap 결정 사항 (리빌드 없이 swap 불가에 가까움)
### 13. embedded registry mirror (Spegel): 명시적 opt-in + 네트워크 요구사항
- 기본 **비활성**
- 활성화 방법: `/etc/rancher/k3s/config.yaml``embedded-registry: true` + `registries.yaml`에 mirror 설정
- **네트워크 요구사항** (공식): 모든 노드가 서로 **TCP 5001 (p2p gossip) + TCP 6443 (local registry + supervisor)**에 도달 가능해야 한다. firewall / security group에서 해당 포트 오픈 필수.
- 활성화 대상:
- airgap / 반-airgap 환경
- 이미지 pull bottleneck이 심한 대규모 배포
- external registry 의존을 낮춰야 하는 환경
- 클러스터 범위 기능이므로 **모든 server/agent에 동일 적용**
### 14. 이미지 import / airgap 전략
- 평상시: registry pull (internal mirror 선호)
- airgap: `/var/lib/rancher/k3s/agent/images/*.tar{,.zst,.gz}` 사용, import 절차를 runbook에 명시
- 이미지 import는 agent startup 때만 로드됨 → 런타임 교체는 re-push 필요
### 15. K3s version gating을 항상 확인
다음 기능은 버전에 따라 동작/옵션이 바뀌므로, 업그레이드 전 CHANGELOG 확인 필수:
- embedded registry mirror (Spegel)
- image pre-import
- `HelmChartConfig` schema
- `disable-helm-controller` 동작
- etcd snapshot / S3 backup 옵션
### 16. K3s-specific 예외는 component 문서보다 먼저 확정
이 문서에서 박고 내려가야 하는 결정:
- traefik 유지/비활성
- servicelb 유지/비활성
- local-storage 유지 범위 (env별)
- metrics-server 유지
- network policy controller 선택
- embedded registry mirror 사용 여부
그 다음에 keycloak / vault / minio / ingress / storage 문서로 내려간다.
### 17. `kubectl apply --server-side` 기본 사용
K3s도 SSA 지원. ArgoCD / Flux / CI 모두 `--server-side --field-manager=<id>` 기본. last-applied-configuration annotation 2MB 한계 회피 + multi-controller ownership 명시.
### 18. etcd snapshot은 K3s 고유 메커니즘 사용
- embedded etcd면 `k3s etcd-snapshot` CLI 또는 `--etcd-snapshot-*` config
- S3 업로드 설정은 `/etc/rancher/k3s/config.yaml`에 선언
- 외부 datastore(PostgreSQL/MySQL) 사용 시 backup은 해당 DB 레이어에서 따로
## 현재 스택 기본 권장안 (prod)
- `traefik`: disable, ingress-nginx + cert-manager로 교체
- `servicelb`: disable, MetalLB (L2 또는 BGP)로 교체
- `local-storage`: disable (prod), dev/staging 만 유지. Longhorn으로 교체
- `metrics-server`: keep (HPA 전제)
- `network policy`: 현 단계 kube-router 유지, Cilium 도입은 별 RFC
- `embedded registry mirror`: off (현재 airgap 아님), 옵션으로 남김
- `etcd snapshot`: S3 업로드 활성, 6시간 주기, 72시간 retention
- `HelmChartConfig`: traefik 유지 경로를 쓰지 않으므로 현재 미사용
- apply 방식: `kubectl apply --server-side --field-manager=argocd`
## 프로젝트 기준 요약
- K3s 전용 규칙은 별도 문서
- packaged component 직접 수정 금지 (HelmChartConfig / disable만)
- `manifests/`는 SoT 아님
- critical config는 Git 단일 파일, 서버 간 동일
- local-path는 dev/test만
- embedded registry mirror는 TCP 5001 + 6443 reachability가 전제
- prod에서 traefik/servicelb/local-storage 전부 disable이 기본
- Server-Side Apply가 GitOps 기본