Building clusters with Kubespray and Terraform
One inventory file shapes the whole cluster
한국어 원문으로 표시합니다.
목표
kubespray v2.32.0 의 샘플 인벤토리로 노드 한 대짜리 클러스터의 인벤토리를 설계하고, 판을 group_vars 에 고정하고, 변수가 어느 층에서 이기는지와 그룹 이름을 틀렸을 때 무엇이 깨지는지를 직접 확인합니다. 클러스터는 아직 세우지 않습니다.
왜 중요한가
kubespray 로 클러스터를 세울 때 사람이 직접 쓰는 것은 사실상 인벤토리와 group_vars 뿐입니다. 플레이북은 그대로 두고 이 두 가지만 바꿔 클러스터의 모양(누가 컨트롤 플레인이고 누가 etcd 인가)과 내용(어느 판, 어느 CNI, 어느 런타임)을 정합니다. 그래서 설치가 틀어지는 원인도 대개 여기 있습니다 — 그룹 이름 하나를 틀리면 설치 1분 만에 엉뚱한 오류로 멈추고, 판을 적지 않으면 같은 인벤토리가 kubespray 를 올릴 때마다 다른 쿠버네티스를 설치합니다. 긴 설치를 돌리기 전에 인벤토리 도구로 풀린 값을 확인하는 습관이 이 모듈의 목표입니다.
단계
/opt/ks/kubespray/inventory/sample을/root/ks/inventory/lab로 통째로 복사하세요.group_vars/all/all.yml과group_vars/k8s_cluster/k8s-cluster.yml이 그 아래에 있어야 합니다./root/ks/inventory/lab/inventory.ini에 노드node1을kube_control_plane·kube_node그룹에 넣고,etcd는kube_control_plane을 자식 그룹으로 받게([etcd:children]) 적으세요.k8s_cluster도kube_control_plane·kube_node를 자식으로 받게([k8s_cluster:children]) 적습니다. 연결 방식은 인벤토리 줄이 아니라/root/ks/inventory/lab/host_vars/node1.yml에ansible_connection: local로 둡니다. inventory.ini 에는ansible_connection이 없어야 합니다./opt/ks/kubespray에서ansible-inventory --list를 두 번 돌려 파싱된 호스트 수를 세고/root/ks/parse.json에dir_hosts(-i /root/ks/inventory/lab로 디렉터리를 줬을 때),file_hosts(-i /root/ks/inventory/lab/inventory.ini),ignored_ext(kubespray 의 ansible.cfg 가 인벤토리 디렉터리에서 건너뛰는 확장자 중 inventory.ini 를 가리는 것, 점 포함 문자열)를 적으세요./root/ks/inventory/lab/group_vars/k8s_cluster/k8s-cluster.yml에kube_version: 1.35.8을 더하세요(샘플에는 없습니다). 그다음ansible-inventory --host node1으로 실제로 풀린 값을 읽어/root/ks/vars.json에kube_version,container_manager,kube_network_plugin,kube_proxy_mode,kube_service_addresses,kube_pods_subnet여섯 개를 문자열로 적으세요./root/ks/inventory/lab/group_vars/all/all.yml끝에kube_version: 1.34.11을 잠시 더한 뒤,ansible -i /root/ks/inventory/lab/inventory.ini node1 -m debug -a var=kube_version으로 실제 값을 보고, 같은 명령에-e kube_version=1.36.4를 붙여 한 번 더 보세요./root/ks/precedence.json에all_yml(all.yml 에 넣은 값),effective(-e 없이 이긴 값),extra_vars(-e 를 줬을 때 값),winner_file(-e 없이 이긴 값이 적힌 파일의 인벤토리 기준 상대 경로)을 적은 뒤 all.yml 에 넣은 줄은 지웁니다./root/ks/broken/inventory.ini는 누군가[masters]로 적은 인벤토리입니다. 고치지 말고/opt/ks/kubespray에서ansible-playbook -i /root/ks/broken/inventory.ini playbooks/boilerplate.yml을 돌려 보세요./root/ks/broken.json에failed_task(실패한 작업의 이름, 역할 접두사 없이),node1_groups(이 인벤토리에서 node1 이 속한 그룹 이름 정렬 배열, all 과 ungrouped 제외),missing_group(비어 있어야 할 리 없는데 비어 있는 kubespray 그룹 이름)을 적으세요./opt/ks/kubespray에서ansible-playbook -i /root/ks/inventory/lab/inventory.ini playbooks/boilerplate.yml을 돌려 출력 전체를/root/ks/logs/boilerplate.log에 저장하세요. PLAY RECAP 에failed=0이어야 합니다./root/ks/report.json에kubespray_tag(git -C /opt/ks/kubespray describe --tags),ansible_core(ansible --version첫 줄의 판 번호, 예 2.19.0),kube_version_default(이 판의 기본 kube_version),kube_version_min(이 판이 받아 주는 가장 낮은 판)을 적으세요.
참고
- VM 에 kubespray v2.32.0 이
/opt/ks/kubespray에, Ansible 이/opt/ks/venv가상환경에 있습니다.ansible·ansible-playbook·ansible-inventory는 PATH 에 연결해 두었습니다. - 플레이북과 인벤토리 도구는
/opt/ks/kubespray에서 돌리세요. 그 디렉터리의ansible.cfg가 roles·library 경로를 알려 줍니다. - 흔한 실수:
-i /root/ks/inventory/lab처럼 디렉터리를 넘기는 것. 이 저장소 설정에서는 inventory.ini 가 무시됩니다. - 흔한 실수:
cp -r대상이 이미 있을 때 한 단계 더 깊이 복사되는 것. - 문서: Kubespray — Inventory · Kubespray — Ansible 변수 층 · Ansible — 변수 우선순위
샘플 인벤토리를 내 자리로 복사한다
/opt/ks/kubespray/inventory/sample 을 /root/ks/inventory/lab 로 통째로 복사하세요. group_vars/all/all.yml 과 group_vars/k8s_cluster/k8s-cluster.yml 이 그 아래에 있어야 합니다.
kubespray 는 인벤토리 디렉터리 옆의 group_vars 를 읽습니다. 샘플을 고치지 않고 복사하는 이유는 다음 판으로 올릴 때 샘플이 바뀌기 때문입니다. 대상 디렉터리가 이미 있으면 cp -r 은 그 안에 sample 이라는 하위 디렉터리를 하나 더 만듭니다.
노드 한 대를 세 그룹에 넣는다
/root/ks/inventory/lab/inventory.ini 에 노드 node1 을 kube_control_plane·kube_node 그룹에 넣고, etcd 는 kube_control_plane 을 자식 그룹으로 받게([etcd:children]) 적으세요. k8s_cluster 도 kube_control_plane·kube_node 를 자식으로 받게([k8s_cluster:children]) 적습니다. 연결 방식은 인벤토리 줄이 아니라 /root/ks/inventory/lab/host_vars/node1.yml 에 ansible_connection: local 로 둡니다. inventory.ini 에는 ansible_connection 이 없어야 합니다.
이 VM 이 제어 노드이자 대상 노드라 ssh 대신 local 연결을 씁니다. 그 사실을 host_vars 에 두면, 노드가 늘 때 인벤토리에는 이름만 더하고 연결 방식은 노드별 파일에서 바꾸면 됩니다. 그룹 이름은 kubespray 가 정한 철자 그대로여야 합니다. 샘플 inventory.ini 에는 k8s_cluster 가 없습니다 — kubespray 가 플레이북 안에서 만들기 때문인데, 그러면 플레이북 밖의 도구(ansible-inventory, ansible 애드혹)는 group_vars/k8s_cluster 를 읽지 못합니다.
디렉터리를 주면 호스트가 0개다
/opt/ks/kubespray 에서 ansible-inventory --list 를 두 번 돌려 파싱된 호스트 수를 세고 /root/ks/parse.json 에 dir_hosts(-i /root/ks/inventory/lab 로 디렉터리를 줬을 때), file_hosts(-i /root/ks/inventory/lab/inventory.ini), ignored_ext(kubespray 의 ansible.cfg 가 인벤토리 디렉터리에서 건너뛰는 확장자 중 inventory.ini 를 가리는 것, 점 포함 문자열)를 적으세요.
호스트 수는 --list 결과의 _meta.hostvars 키 개수로 셀 수 있습니다. ansible-inventory 가 어느 설정 파일을 읽는지는 ansible-config dump --only-changed 로 볼 수 있고, 그 파일은 현재 디렉터리에서 찾습니다.
판을 group_vars 에 고정한다
/root/ks/inventory/lab/group_vars/k8s_cluster/k8s-cluster.yml 에 kube_version: 1.35.8 을 더하세요(샘플에는 없습니다). 그다음 ansible-inventory --host node1 으로 실제로 풀린 값을 읽어 /root/ks/vars.json 에 kube_version, container_manager, kube_network_plugin, kube_proxy_mode, kube_service_addresses, kube_pods_subnet 여섯 개를 문자열로 적으세요.
kube_version 을 적지 않으면 kubespray 판마다 기본값이 바뀌어, 같은 인벤토리로 다른 날 다른 쿠버네티스가 설치됩니다. 파일에 적은 것과 Ansible 이 실제로 푼 값이 같은지는 인벤토리 도구로 확인합니다. YAML 에서 1.35 처럼 점 하나짜리 숫자는 실수로 읽히지만 세 마디 판 번호는 문자열입니다.
같은 변수가 세 곳에 있으면
/root/ks/inventory/lab/group_vars/all/all.yml 끝에 kube_version: 1.34.11 을 잠시 더한 뒤, ansible -i /root/ks/inventory/lab/inventory.ini node1 -m debug -a var=kube_version 으로 실제 값을 보고, 같은 명령에 -e kube_version=1.36.4 를 붙여 한 번 더 보세요. /root/ks/precedence.json 에 all_yml(all.yml 에 넣은 값), effective(-e 없이 이긴 값), extra_vars(-e 를 줬을 때 값), winner_file(-e 없이 이긴 값이 적힌 파일의 인벤토리 기준 상대 경로)을 적은 뒤 all.yml 에 넣은 줄은 지웁니다.
Ansible 은 더 구체적인 그룹의 group_vars 가 all 을 이깁니다. k8s_cluster 는 all 의 자식입니다. -e 로 준 extra vars 는 무엇보다 이깁니다 — 그래서 kubespray 문서가 -e 를 '내부 변수를 덮을 때' 로 좁혀 쓰라고 합니다. 명령은 kubespray 디렉터리에서 돌리세요.
그룹 이름을 틀리면 무엇이 깨지나
/root/ks/broken/inventory.ini 는 누군가 [masters] 로 적은 인벤토리입니다. 고치지 말고 /opt/ks/kubespray 에서 ansible-playbook -i /root/ks/broken/inventory.ini playbooks/boilerplate.yml 을 돌려 보세요. /root/ks/broken.json 에 failed_task(실패한 작업의 이름, 역할 접두사 없이), node1_groups(이 인벤토리에서 node1 이 속한 그룹 이름 정렬 배열, all 과 ungrouped 제외), missing_group(비어 있어야 할 리 없는데 비어 있는 kubespray 그룹 이름)을 적으세요.
오류 문구가 그룹 이름이 틀렸다고 말해 주지 않습니다. 실패한 조건식이 어느 그룹을 찾다 실패했는지 읽으세요. 옛 이름 kube-master 는 kubespray 가 알아서 옮겨 주지만 masters 는 아닙니다. 노드가 속한 그룹(자식 그룹을 거친 것 포함)은 ansible ... -m debug -a var=group_names 로 볼 수 있습니다.
내 인벤토리는 검사를 통과한다
/opt/ks/kubespray 에서 ansible-playbook -i /root/ks/inventory/lab/inventory.ini playbooks/boilerplate.yml 을 돌려 출력 전체를 /root/ks/logs/boilerplate.log 에 저장하세요. PLAY RECAP 에 failed=0 이어야 합니다.
boilerplate.yml 은 cluster.yml·upgrade-cluster.yml·reset.yml 이 모두 맨 앞에서 부르는 검사 묶음입니다. 여기서 막히는 것은 설치를 시작하기도 전에 막히는 것이라, 설치 전에 따로 돌려 두면 긴 플레이북을 돌리다 1분 만에 멈추는 일을 피할 수 있습니다.
이 판의 kubespray 가 받아 주는 범위
/root/ks/report.json 에 kubespray_tag(git -C /opt/ks/kubespray describe --tags), ansible_core(ansible --version 첫 줄의 판 번호, 예 2.19.0), kube_version_default(이 판의 기본 kube_version), kube_version_min(이 판이 받아 주는 가장 낮은 판)을 적으세요.
kubespray 는 기본 판과 최소 판을 따로 적어 두지 않고 roles/kubespray_defaults/vars/main/checksums.yml 의 kubelet 체크섬 목록에서 첫 키와 마지막 키로 계산합니다(roles/kubespray_defaults/defaults/main/main.yml). 체크섬이 없는 판은 설치할 수 없다는 뜻입니다.