Kubernetesディストリビューション — 自分で立てる
stable チャネルに従っていたらマイナーを二段飛ばしていた
한국어 원문으로 표시합니다.
이 실습은 진짜 k3s 에서 돕니다
VM 안에 k3s v1.34.11+k3s1 한 대가 떠 있습니다. 이 클러스터를 1.35 로 한 칸 올리고, 올리기 전의 준비와 올린 뒤의 대조를 실제로 해 봅니다. 처음 뜨는 데 2분 안팎이 걸립니다. 작업 디렉터리는 /root/upgrade 입니다.
목표
k3s 를 마이너 판 한 칸 업그레이드하면서 출발 판 기록, 사용 중단 API 점검, 백업, drain 판단을 차례로 하고, 업그레이드 뒤 같은 노드와 같은 워크로드가 살아 있는지 UID 로 증명합니다. 마지막으로 다음 한 칸을 system-upgrade-controller Plan 으로 적습니다.
왜 중요한가
설치 스크립트를 다시 돌리면 업그레이드가 끝나기 때문에, 판을 고르는 일이 가볍게 여겨집니다. 그런데 채널(stable)은 지금 클러스터가 몇 판인지 모르고 최신 권장판으로 갑니다. 1.34 에서 stable 로 올리면 stable 이 1.36 인 날에는 마이너 두 칸을 건너뛰고, 쿠버네티스 skew 정책은 인스턴스가 하나뿐인 클러스터에서도 이것을 허용하지 않습니다. 건너뛰기를 막아 주는 도구는 없으니 사람이 판을 고정하고 한 칸씩 올려야 합니다.
그리고 "올라갔다" 는 증거가 되지 않습니다. 올리기 전에 판과 UID 를 적어 두지 않으면, 올린 뒤에 같은 클러스터가 같은 워크로드를 들고 올라왔는지 확인할 방법이 없습니다.
단계
- API 서버 판·kubelet 판·노드 이름·노드 UID 를
/root/upgrade/before.json에 저장하세요. upg네임스페이스에 Deploymentweb(nginx 1.27-alpine, 레플리카 2)과 PDBweb(minAvailable 1)을 만들고/root/upgrade/workload.json에 UID 를 적으세요.apiserver_requested_deprecated_apis지표를/root/upgrade/deprecated.txt에 옮기고removed_by_target=을 적으세요.- SQLite DB 와 토큰을
/root/upgrade/backup/에 백업하고/root/upgrade/backup.json을 쓰세요. - drain 을 시도해 출력을
/root/upgrade/drain.txt에 남기고, uncordon 한 뒤decision=줄을 붙이세요. v1.35.8+k3s1로 업그레이드하고/root/upgrade/upgrade.json을 쓰세요.- 업그레이드 뒤 상태와 skew 허용 범위를
/root/upgrade/after.json에 적으세요. - Plan CRD 를 넣고 다음 한 칸을 고정한 Plan
k3s-server-next를/root/upgrade/plan.yaml로 적용하세요. /root/upgrade/report.md에 다섯 줄과 설명을 쓰세요.
참고
- 이 VM 의 k3s 설정은
/etc/rancher/k3s/config.yaml에 있습니다(disable: traefik). 설치 때 환경변수로 준 값은 다시 돌릴 때 또 주지 않으면 사라지지만, 설정 파일은 남습니다. - 이미지는
public.ecr.aws/docker/library/...를 씁니다. Docker Hub 는 받기 제한에 걸릴 수 있습니다. - 흔한 실수 1: 업그레이드를 먼저 하고 before.json 을 나중에 쓰는 것. 채점기는 기록이 업그레이드보다 먼저 쓰였는지 봅니다.
- 흔한 실수 2: drain 이 실패한 뒤 uncordon 을 잊는 것. 대체 파드가 Pending 에 머물러 뒤 단계의 Ready 확인이 모두 떨어집니다.
- system-upgrade-controller 의 컨트롤러와
rancher/k3s-upgrade이미지는 Docker Hub 에 있어 이 환경에서는 실행하지 않습니다. Plan 은 저장만 되고 실제 업그레이드는 일어나지 않습니다.
출발 판을 먼저 적는다
API 서버 판·kubelet 판·노드 이름·노드 UID 를 /root/upgrade/before.json 에 server_version, kubelet_version, node_name, node_uid 키로 저장하세요.
업그레이드 뒤에는 이전 판을 어디서도 다시 볼 수 없습니다. kubectl version -o json 의 serverVersion 과 노드 오브젝트의 status.nodeInfo, metadata.uid 를 보세요. UID 는 뒤 단계에서 '같은 노드가 올라갔는가' 를 대조하는 값입니다.
PDB 가 걸린 워크로드를 올린다
upg 네임스페이스에 Deployment web(이미지 public.ecr.aws/docker/library/nginx:1.27-alpine, 레플리카 2)과 app=web 을 고르는 PodDisruptionBudget web(minAvailable 1)을 만들고, Deployment UID 를 /root/upgrade/workload.json 에 deployment_uid, pdb_min_available 키로 저장하세요.
PDB 는 '자발적 중단(eviction) 때 최소 몇 개는 남겨 달라' 는 약속입니다. kubectl create deployment 와 kubectl create pdb 로 만들 수 있고, 두 파드가 Ready 가 된 뒤 UID 를 적으세요. Docker Hub 이미지는 쓰지 않습니다.
누가 아직 옛 API 를 부르나
API 서버 지표에서 apiserver_requested_deprecated_apis 줄을 그대로 /root/upgrade/deprecated.txt 에 옮기고, 그중 목표 판 1.35 까지 제거되는(removed_release 가 1.35 이하인) 것의 개수를 removed_by_target=<수> 줄로 적으세요.
kubectl get --raw /metrics 로 API 서버 지표를 볼 수 있습니다. 라벨 중 removed_release 가 비어 있으면 사용 중단만 되었고 제거 일정은 없다는 뜻입니다. 이 클러스터는 아무것도 안 해도 한 줄이 나옵니다.
DB 와 토큰을 함께 백업한다
SQLite 저장소를 /root/upgrade/backup/state.db 로, 서버 토큰을 /root/upgrade/backup/token 으로 백업하고, 백업한 판과 토큰 해시를 /root/upgrade/backup.json 에 k3s_version, token_sha256 키로 적으세요.
k3s 의 SQLite 는 /var/lib/rancher/k3s/server/db/ 에 있습니다. 쓰는 중인 DB 는 파일 복사보다 sqlite3 의 온라인 백업 명령이 안전합니다. 토큰이 왜 필요한지는 이론 글의 백업 절을 다시 보세요.
drain 이 끝나지 않는다
노드를 kubectl drain --ignore-daemonsets --delete-emptydir-data --timeout=40s 로 비워 보고 출력 전체를 /root/upgrade/drain.txt 에 저장한 뒤 노드를 uncordon 하세요. 마지막 줄에 결정을 decision=upgrade-without-drain 또는 decision=add-node-first 로 적습니다.
drain 은 cordon 후 eviction API 로 파드를 내보내고, eviction 은 PDB 를 지킵니다. 노드가 한 대면 쫓겨난 파드의 대체 파드가 어디로 가야 할지 생각해 보세요. drain 이 실패로 끝나도 출력은 파일에 남겨야 합니다.
마이너 한 칸만 올린다
설치 스크립트를 목표 판 태그에서 받아 INSTALL_K3S_VERSION=v1.35.8+k3s1 로 업그레이드하고, /root/upgrade/upgrade.json 에 from, to, node_uid 키로 결과를 적으세요.
채널 대신 판을 고정합니다. 설치 스크립트는 raw.githubusercontent.com 의 k3s-io/k3s 저장소에서 그 판 태그의 install.sh 를 받습니다. 이 VM 의 설정은 /etc/rancher/k3s/config.yaml 에 있어서 다시 줄 필요가 없습니다. 끝나면 API 가 응답할 때까지 기다린 뒤 값을 적으세요.
같은 것이 올라갔는지 대조한다
업그레이드 뒤 상태를 /root/upgrade/after.json 에 server_version, deployment_uid, web_ready, web_restarts(web 파드 재시작 합), traefik_deployed, kubelet_allowed, kubectl_allowed 키로 적으세요. 마지막 둘은 지금 API 서버 판에 대해 skew 정책이 허용하는 마이너 판 목록("1.xx" 문자열)입니다.
워크로드는 UID 로, 설정은 traefik 이 되살아났는지로 대조합니다. skew 정책에서 kubelet 은 API 서버보다 몇 판 낮게까지, kubectl 은 위아래 몇 판까지 되는지 이론 글의 표를 보세요.
다음 한 칸을 Plan 으로 쓴다
system-upgrade-controller v0.20.1 의 crd.yaml 을 적용하고, system-upgrade 네임스페이스에 Plan k3s-server-next 를 /root/upgrade/plan.yaml 로 작성해 적용하세요. 지금 판의 바로 다음 마이너 k3s 판을 version 으로 고정하고, 서버 노드만 고르며, 한 대씩 cordon 해서 올리도록 합니다.
CRD 는 GitHub 릴리스의 고정 판 주소에서 받습니다. 컨트롤러는 띄우지 않으므로 Plan 은 실행되지 않고 저장만 됩니다. CRD 는 version 도 channel 도 없는 Plan 을 그대로 받아 주니, 적용이 성공했다고 맞는 Plan 인 것은 아닙니다. k3s 공식 문서의 서버 Plan 예시에서 channel 을 무엇으로 바꿔야 할지 생각하세요.
stable 을 따랐다면 몇 칸이었나
/root/upgrade/report.md 에 initial=, current=, next_plan=, stable_channel=(지금 k3s stable 채널이 가리키는 판), stable_minor_jump=(출발 판에서 그 판까지 마이너 칸 수) 다섯 줄과, 왜 채널 대신 판을 고정했는지 설명을 150자 이상 쓰세요.
채널이 가리키는 판은 https://update.k3s.io/v1-release/channels 가 JSON 으로 알려 줍니다. 칸 수는 마이너 숫자의 차이입니다. 설명에는 skew 정책과, 무엇이 그 건너뛰기를 막아 주지 않았는지를 넣으세요.