# 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: |- ``` - `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=` 기본. 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 기본