diff --git a/docs/session-lab-concepts.md b/docs/session-lab-concepts.md index 9460d89..39397b2 100644 --- a/docs/session-lab-concepts.md +++ b/docs/session-lab-concepts.md @@ -1895,6 +1895,123 @@ EOF **왜 여기 나오나** — JGroups 7800 포트만 골라서 막는 실험을 nftables가 아니라 NetworkPolicy로 하면, **운영에서 쓸 방식 그대로** 검증하게 된다. +### 무엇을 어디에 설치하는가 + +| 도구 | lab host | 게스트 | 워크스테이션 | +|---|---|---|---| +| libvirt / QEMU | 필요 | — | — | +| nginx | 필요 (L7 진입점) | — | — | +| certbot | 필요 | — | — | +| kubectl / helm / k9s | 필요 | 불필요 | — | +| **k3s** | — | **필요** | — | +| **docker** | **설치 금지** | **설치 금지** | 필요 (이미지 빌드) | +| java / maven | 불필요 | 불필요 | 불필요 | + +**kubectl을 게스트에 안 깔아도 되는 이유** — k3s 바이너리가 kubectl을 +내장한다. 게스트에서는 `sudo k3s kubectl ...`로 쓰고, 평소 조작은 lab host의 +kubectl로 한다. + +**java/maven이 아무 데도 필요 없는 이유** — Keycloak도 애플리케이션도 +컨테이너로 돈다. 이미지 안에 JRE가 들어 있고, 빌드는 Dockerfile의 Maven +스테이지가 컨테이너 안에서 수행한다. + +### Docker를 lab host에 설치하면 안 되는 이유 + +**결론부터: 이미지 저장소가 둘로 갈려서 `docker build`한 이미지를 k3s가 +보지 못하게 된다.** + +**컨테이너 런타임의 층 구조** + +``` + dockerd 사용자 편의 계층 — 빌드, 볼륨, 네트워크, CLI + │ + containerd 컨테이너 수명주기 데몬 — 이미지를 자기 저장소에 보관 + │ + runc 프로세스를 실제로 격리해 실행하는 저수준 도구 +``` + +**k3s는 자체 containerd를 번들한다.** Docker와 무관하게 이미 완결된 스택이다. + +| | k3s | Docker | +|---|---|---| +| 소켓 | `/run/k3s/containerd/containerd.sock` | `/run/containerd/containerd.sock` | +| 이미지 저장 | `/var/lib/rancher/k3s/agent/containerd/` | `/var/lib/docker/` | + +Docker를 설치하면 **containerd 인스턴스가 두 개**가 된다. 그리고 둘은 서로의 +이미지를 알지 못한다. + +``` + docker build ─▶ dockerd ─▶ /var/lib/docker/ ← k3s 는 여기를 안 본다 + 파드 생성 ─▶ k3s containerd ─▶ /var/lib/rancher/... ← 이미지 없음 +``` + +증상은 **`docker images`에는 보이는데 파드는 `ErrImageNeverPull`** 이다. +쿠버네티스 입문에서 가장 흔한 혼란이며, 원인이 눈에 보이지 않아 오래 헤맨다. + +**저장소 분리 말고도 충돌 지점이 있다** + +| 자원 | 충돌 내용 | +|---|---| +| cgroup 드라이버 | dockerd 기본은 `cgroupfs`, k3s는 `systemd`. 한 노드에서 두 관리자가 cgroup 트리를 다툰다 | +| iptables/nftables | Docker가 `DOCKER`, `DOCKER-USER` 체인과 MASQUERADE 규칙을 심는다. flannel 규칙과 순서가 엉키면 파드 트래픽이 Docker 규칙에 걸린다 | +| 브리지 대역 | `docker0`가 `172.17.0.0/16`을 점유한다. 클러스터 서비스 대역이나 사내망과 겹치면 라우팅이 깨진다 | +| 디스크 | 같은 이미지가 두 벌 저장된다 | + +**이 실험대에는 이유가 하나 더 있다.** lab host에는 libvirt가 +`virbr0` NAT와 자체 방화벽 규칙을 운영 중이다. Docker의 iptables 규칙이 +여기에 얹히면 게스트 네트워크가 예측 불가능해진다. **네트워크 장애를 +의도적으로 주입하는 실험대에서 원인 불명의 네트워크 변수를 늘리는 것은 +치명적이다** — 실험 결과인지 환경 문제인지 구분할 수 없게 된다. + +> `k3s server --docker`로 Docker를 런타임으로 지정하는 방법이 과거에 +> 있었지만, 쿠버네티스 1.24의 dockershim 제거 이후 별도 `cri-dockerd`를 +> 요구하며 권장되지 않는다. 얻는 것이 없다. + +### 그러면 이미지는 어떻게 넣는가 + +| 방법 | 적합한 경우 | +|---|---| +| 공개 레지스트리에서 pull | **Keycloak·PostgreSQL·Redis 등 공식 이미지** — 아무 준비도 필요 없다 | +| **`ctr images import`** | **자체 빌드 이미지가 소수일 때** ← 이 실험대 | +| 클러스터 내 레지스트리 | 빌드·배포 반복이 잦아질 때 | + +자체 이미지는 애플리케이션(BFF, token-mediator, echo)뿐이므로 두 번째로 충분하다. + +``` + 워크스테이션 (docker 보유) lab host (경유만) 게스트 (k3s containerd) + docker build + docker save ──── ssh ────▶ ──── ssh ────▶ sudo k3s ctr images import - +``` + +```bash +docker build -t keycloak-pattern-api:lab backend +docker save keycloak-pattern-api:lab \ + | ssh test-server "ssh kc-lab-1 'sudo k3s ctr images import -'" +docker save keycloak-pattern-api:lab \ + | ssh test-server "ssh kc-lab-2 'sudo k3s ctr images import -'" +``` + +**주의 세 가지** + +1. **노드마다 따로 반입한다.** 스케줄러가 어느 노드에 배치할지 모른다. + 한쪽에만 있으면 반대편에 배치될 때 실패한다. +2. **매니페스트에 `imagePullPolicy: Never`를 준다.** 없으면 로컬에 이미지가 + 있어도 레지스트리에서 당기려 시도하다 실패한다. +3. **`ctr`이 아니라 `k3s ctr`을 쓴다.** `k3s ctr`은 k3s의 containerd 소켓을 + 가리키는 래퍼다. 시스템에 별도 `ctr`이 있으면 다른 소켓을 보게 되어 + "성공했는데 파드는 이미지를 못 찾는" 상태가 된다. + +**ssh가 두 번 중첩되는 이유** — 게스트가 lab host의 libvirt NAT 뒤에 있어서 +워크스테이션에서 직접 접속할 수 없다. lab host의 `~/.ssh/config`에 있는 +`kc-lab-*` 별칭을 거쳐야 한다. + +**확인** + +```bash +ssh test-server "ssh kc-lab-1 'sudo k3s ctr images ls -q | grep keycloak-pattern'" +kubectl -n header-lab get pods -o wide # ErrImageNeverPull 이면 반입 실패 +``` + --- ## 6층. Arch 특이사항