kubespray 와 Terraform 으로 클러스터 세우기
폐쇄망에 들고 갈 것의 목록 — 파일·이미지·파이썬
목표
kubespray 가 설치 중에 받는 파일과 이미지의 목록을 만들고, 인벤토리의 오프라인 변수로 그 목록이 사내 미러(registry.lab.internal:5000, http://files.lab.internal)를 가리키게 바꿉니다. 미러를 채울 사람에게 넘길 대응표와, 제어 노드의 Ansible 까지 담은 반입 꾸러미를 만듭니다. 실제 폐쇄망과 미러는 만들지 않습니다.
왜 중요한가
폐쇄망 설치의 실패는 대부분 "빠뜨린 것" 입니다. 반입 심사를 거쳐 들고 들어간 뒤에야 파일 하나가 없다는 것을 알면 다시 나갔다 와야 하고, 그 왕복이 며칠입니다. 그래서 설치 도구가 무엇을 받는지 도구 스스로 말하게 하고(generate_list.sh), 그 목록이 정말 이번에 설치할 판의 것인지, 모든 주소가 사내를 가리키는지를 밖에 있을 때 확인해야 합니다. 이 모듈에서 만나는 목록 판 함정은 실제로 이 코스를 만들며 겪은 것입니다 — 인벤토리에 판을 적어 두었는데 목록은 다른 판으로 나왔습니다.
단계
/opt/ks/kubespray/contrib/offline에서./generate_list.sh를 인자 없이 돌리고, 만들어진temp/files.list·temp/images.list를/root/ks/offline/default/에 복사하세요./root/ks/offline/default/count.json에files,images(두 목록의 줄 수)와registries(images.list 의 첫 경로 조각별 개수, 예 {"quay.io": 3})를 적으세요.- 인벤토리의 kube_version 은 1.35.8 입니다.
./generate_list.sh -i /root/ks/inventory/lab/inventory.ini로 한 번, 여기에-e kube_version=1.35.8을 더해 한 번 돌리고 각각 images.list 의 kube-apiserver 태그를 확인하세요./root/ks/offline/trap.json에with_inventory(첫 실행의 kube-apiserver 태그),with_extra_var(두 번째 실행의 태그),ignored_group(인벤토리의 kube_version 이 적힌 group_vars 그룹 가운데 목록 플레이북에 적용되지 않은 그룹 이름)을 적으세요. /root/ks/inventory/lab/group_vars/all/offline.yml를 고쳐registry_host: "registry.lab.internal:5000",files_repo: "http://files.lab.internal"를 두고, kubespray 문서의 폐쇄망 절대로kube_image_repo·gcr_image_repo·docker_image_repo·quay_image_repo·github_image_repo를{{ registry_host }}로,github_url·dl_k8s_io_url·storage_googleapis_url·get_helm_url을{{ files_repo }}/<원래 도메인>으로 두세요. 파일은 group_vars/all 에 있어야 합니다../generate_list.sh -i /root/ks/inventory/lab/inventory.ini -e kube_version=1.35.8로 목록을 다시 만들고 두 파일을/root/ks/offline/mirror/에 복사하세요. files.list 의 모든 줄이http://files.lab.internal/로, images.list 의 모든 줄이registry.lab.internal:5000/로 시작하고, 줄 수가 1단계와 같아야 합니다.- 미러를 채우는 사람에게 넘길 대응표를 만드세요. 오프라인 변수를 적용하지 않은 1.35.8 원본 목록과 4단계의 미러 목록을 줄 단위로 짝지어,
/root/ks/offline/image-map.tsv에원본<TAB>미러를 한 줄에 하나씩(images.list 의 모든 이미지) 적으세요. /root/ks/inventory/lab/group_vars/all/offline.yml에containerd_registries_mirrors를 더해, prefixregistry.lab.internal:5000가 hosthttp://registry.lab.internal:5000를 pull·resolve 로 쓰고 TLS 검증을 건너뛰게(skip_verify: true) 하세요.ansible-inventory --host node1이 이 목록을 그대로 풀어야 합니다.- kubespray 의
requirements.txt로 파이썬 패키지를/root/ks/offline/pypi/에 내려받고(pip download), 인터넷을 쓰지 않는 설치가 그 디렉터리만으로 풀리는지pip install --dry-run --no-index --find-links /root/ks/offline/pypi -r requirements.txt로 확인하세요./root/ks/offline/pypi.json에wheels(내려받은 파일 수),resolved(dry-run 이 성공했는가, 불리언)를 적습니다.
참고
- kubespray v2.32.0 이
/opt/ks/kubespray에, 인벤토리가/root/ks/inventory/lab/inventory.ini(kube_version 1.35.8)에 준비돼 있습니다. 이 VM 은 인터넷(80/443)에 나갈 수 있어 7단계의 내려받기가 됩니다. - generate_list.sh 는
/opt/ks/kubespray/contrib/offline/temp/에 결과를 덮어씁니다. 단계마다 필요한 파일을 복사해 두세요. - 흔한 실수: 목록을 만들 때
-i만 주고 판이 맞는지 보지 않는 것. - 흔한 실수: 오프라인 변수를 group_vars/k8s_cluster 에 두는 것. etcd 전용 노드와 목록 플레이북이 그 값을 받지 못합니다.
- 문서: Kubespray — Offline environment · Kubespray — contrib/offline
무엇을 받는지 목록부터
/opt/ks/kubespray/contrib/offline 에서 ./generate_list.sh 를 인자 없이 돌리고, 만들어진 temp/files.list·temp/images.list 를 /root/ks/offline/default/ 에 복사하세요. /root/ks/offline/default/count.json 에 files, images(두 목록의 줄 수)와 registries(images.list 의 첫 경로 조각별 개수, 예 {"quay.io": 3})를 적으세요.
generate_list.sh 는 roles/kubespray_defaults/defaults/main/download.yml 에서 download_url 과 이미지 repo·tag 를 뽑아 틀을 만들고, 작은 플레이북으로 변수를 채웁니다. 켜지 않은 CNI·애드온의 것까지 모두 들어 있어 실제 설치보다 넉넉합니다. 이미지 목록의 첫 조각이 곧 미러해야 할 원본 레지스트리입니다.
목록이 조용히 다른 판으로 나온다
인벤토리의 kube_version 은 1.35.8 입니다. ./generate_list.sh -i /root/ks/inventory/lab/inventory.ini 로 한 번, 여기에 -e kube_version=1.35.8 을 더해 한 번 돌리고 각각 images.list 의 kube-apiserver 태그를 확인하세요. /root/ks/offline/trap.json 에 with_inventory(첫 실행의 kube-apiserver 태그), with_extra_var(두 번째 실행의 태그), ignored_group(인벤토리의 kube_version 이 적힌 group_vars 그룹 가운데 목록 플레이북에 적용되지 않은 그룹 이름)을 적으세요.
generate_list.yml 은 hosts: localhost 로 돕니다. localhost 는 인벤토리의 어느 그룹에도 없어서 all 의 group_vars 만 받습니다. 목록이 틀린 판으로 나오면 반입한 파일로는 설치가 시작되자마자 '파일이 없다' 로 멈춥니다 — 그것도 폐쇄망 현장에서요.
인벤토리가 사내 미러를 가리키게
/root/ks/inventory/lab/group_vars/all/offline.yml 를 고쳐 registry_host: "registry.lab.internal:5000", files_repo: "http://files.lab.internal" 를 두고, kubespray 문서의 폐쇄망 절대로 kube_image_repo·gcr_image_repo·docker_image_repo·quay_image_repo·github_image_repo 를 {{ registry_host }} 로, github_url·dl_k8s_io_url·storage_googleapis_url·get_helm_url 을 {{ files_repo }}/<원래 도메인> 으로 두세요. 파일은 group_vars/all 에 있어야 합니다.
문서의 팁대로 files_repo 아래에 원래 도메인을 첫 디렉터리로 두면(files_repo/github.com/...) 미러를 채울 때 URL 을 기계적으로 옮길 수 있습니다. 변수를 all 에 두는 이유는 두 가지입니다 — etcd 만 있는 노드도 받아야 하고, 목록 플레이북(localhost)도 이 값을 읽어야 합니다.
목록이 전부 사내 주소가 되었나
./generate_list.sh -i /root/ks/inventory/lab/inventory.ini -e kube_version=1.35.8 로 목록을 다시 만들고 두 파일을 /root/ks/offline/mirror/ 에 복사하세요. files.list 의 모든 줄이 http://files.lab.internal/ 로, images.list 의 모든 줄이 registry.lab.internal:5000/ 로 시작하고, 줄 수가 1단계와 같아야 합니다.
한 줄이라도 원래 도메인이 남아 있으면 그 파일이나 이미지는 폐쇄망에서 받을 수 없습니다. 남은 줄이 있다면 어느 변수가 빠졌는지 그 줄의 도메인이 알려 줍니다.
원본과 미러의 짝
미러를 채우는 사람에게 넘길 대응표를 만드세요. 오프라인 변수를 적용하지 않은 1.35.8 원본 목록과 4단계의 미러 목록을 줄 단위로 짝지어, /root/ks/offline/image-map.tsv 에 원본<TAB>미러 를 한 줄에 하나씩(images.list 의 모든 이미지) 적으세요.
오프라인 변수는 group_vars/all 에 있으니, 원본 목록은 인벤토리 없이 -e kube_version=... 만 주고 만듭니다. 두 목록은 같은 틀에서 나와 순서가 같습니다. 레지스트리 주소만 바뀌고 경로는 그대로라는 점이 미러 설계의 핵심입니다 — 미러 쪽 경로를 바꾸면 이 대응이 깨집니다.
노드가 사내 레지스트리를 믿게
/root/ks/inventory/lab/group_vars/all/offline.yml 에 containerd_registries_mirrors 를 더해, prefix registry.lab.internal:5000 가 host http://registry.lab.internal:5000 를 pull·resolve 로 쓰고 TLS 검증을 건너뛰게(skip_verify: true) 하세요. ansible-inventory --host node1 이 이 목록을 그대로 풀어야 합니다.
kubespray 문서는 containerd 2 와 1.7 의 설정 방법이 다르다고 적습니다. 2 에서는 containerd_registries_mirrors 가 /etc/containerd/certs.d//hosts.toml 로 바뀝니다. 실습용이라 TLS 를 끄지만, 운영에서는 사내 CA 로 서명한 인증서를 쓰고 skip_verify 를 켜지 않는 것이 원칙입니다.
Ansible 도 반입해야 한다
kubespray 의 requirements.txt 로 파이썬 패키지를 /root/ks/offline/pypi/ 에 내려받고(pip download), 인터넷을 쓰지 않는 설치가 그 디렉터리만으로 풀리는지 pip install --dry-run --no-index --find-links /root/ks/offline/pypi -r requirements.txt 로 확인하세요. /root/ks/offline/pypi.json 에 wheels(내려받은 파일 수), resolved(dry-run 이 성공했는가, 불리언)를 적습니다.
폐쇄망에서는 제어 노드의 Ansible 도 가져가야 합니다. kubespray 문서가 파이썬 패키지를 '선택' 으로 적은 것은 OS 가 같은 판을 주는 경우를 뜻하는데, 이 판은 ansible==12.3.0 처럼 정확한 판을 요구해서 대개 직접 가져가야 합니다. 내려받을 때와 설치할 때의 파이썬 판과 CPU 아키텍처가 같아야 합니다 — 휠 파일 이름에 그것이 적혀 있습니다.