Kubespray と Terraform でクラスターを構築する
インストール前に、このサーバーは受け入れられるか
한국어 원문으로 표시합니다.
목표
앞선 관리자가 쓰던 서버에 쿠버네티스를 올리기 전에 스왑·커널 모듈·sysctl·포트를 점검하고 고칩니다. 그리고 이 가운데 무엇을 kubespray 가 스스로 해 주고 무엇을 사람이 먼저 치워야 하는지 역할 코드를 읽어 가릅니다.
왜 중요한가
새로 받은 VM 에서는 kubespray 가 알아서 다 해 주는 것처럼 보입니다. 실제로 스왑을 끄고, br_netfilter 를 올리고, ip_forward 를 켜는 일은 preinstall·node 역할이 합니다. 그런데 현장의 서버는 새것이 아닙니다. 모니터링 에이전트가 10250 을 잡고 있으면 kubespray 는 그대로 설치를 끝까지 밀고 가고, kubelet 이 포트를 못 잡아 노드가 올라오지 않습니다. 보안 점검이 남긴 sysctl 파일이 이름순으로 뒤에 있으면 설치 당일에는 멀쩡하다가 첫 재부팅에서 파드 통신이 끊깁니다. 둘 다 긴 설치를 다 돌린 뒤에야 드러나는 종류라, 설치 전에 한 번 보는 값이 가장 쌉니다.
단계
- 아무것도 고치기 전에
/root/ks/preflight/before.json에swap_total_kb(/proc/meminfo 의 SwapTotal, 숫자),ip_forward(지금 커널 값, 숫자),br_netfilter(모듈이 올라와 있는가, 불리언),busy_ports(컨트롤 플레인 포트 2379, 2380, 6443, 10250, 10257, 10259 가운데 지금 무언가 LISTEN 중인 포트, 오름차순 숫자 배열)를 적으세요. - 켜져 있는 스왑을 모두 끄고,
/etc/fstab에서 스왑 줄을 지우거나 주석으로 막아 재부팅해도 다시 켜지지 않게 하세요. 스왑 파일 자체는 지워도 되고 남겨도 됩니다. overlay와br_netfilter를 지금 올리고,/etc/modules-load.d/k8s.conf에 두 이름을 한 줄씩 적어 부팅 때도 올라오게 하세요./etc/sysctl.d/k8s.conf에net.ipv4.ip_forward = 1,net.bridge.bridge-nf-call-iptables = 1,net.bridge.bridge-nf-call-ip6tables = 1을 적고 적용하세요. 지금 커널 값이 셋 다 1 이어야 하고, 재부팅 때 sysctl.d 를 이름순으로 다시 읽어도 셋 다 1 이어야 합니다.- 컨트롤 플레인 포트 가운데 무언가 잡고 있는 포트를 찾아, 그것을 띄운 systemd 유닛을 멈추고 부팅 때 다시 뜨지 않게(disable) 하세요.
/root/ks/preflight/ports.json에port(잡혀 있던 포트, 숫자),unit(그 프로세스를 띄운 유닛 이름, .service 포함),pid(멈추기 전 그 프로세스의 PID, 숫자)를 적습니다. 끝나면 2379, 2380, 6443, 10250, 10257, 10259 어느 것도 LISTEN 이 아니어야 합니다. /opt/ks/kubespray에서ansible -i /root/ks/inventory/lab/inventory.ini node1 -m setup으로 이 노드의 사실(facts)을 모아/root/ks/preflight/facts.json에memtotal_mb,processor_vcpus,distribution,distribution_version,kernel,default_ipv4(기본 경로의 IPv4 주소)를 적으세요. 그리고 kubespray 의roles/kubernetes/preinstall/defaults/main.yml에서 컨트롤 플레인 최소 메모리를 찾아minimal_master_memory_mb로 함께 적습니다.- kubespray v2.32.0 의
roles/kubernetes/preinstall·roles/kubernetes/node를 읽고/root/ks/preflight/who-fixes.json에 네 문제마다 kubespray 가 스스로 고치면"kubespray", 사람이 먼저 치워야 하면"operator"를 적으세요. 키는swap,br_netfilter,ip_forward,port_10250입니다. 그리고sysctl_file(kubespray 가 sysctl 값을 적는 파일 경로, 기본값)을 함께 적습니다.
참고
- VM 에 kubespray v2.32.0 과 인벤토리
/root/ks/inventory/lab/inventory.ini(노드 한 대, local 연결)가 준비돼 있습니다. 이 실습은 설치를 하지 않습니다. - 흔한 실수:
swapoff -a만 하고 fstab 을 그대로 두는 것. 다음 부팅에서 다시 켜집니다. - 흔한 실수: 프로세스만 kill 하는 것.
Restart=always유닛이 곧바로 다시 띄웁니다. - 흔한 실수: 내 sysctl 파일만 보고 끝내는 것.
sysctl --system이 읽는 순서를 확인하세요. - 문서: Kubernetes — Ports and Protocols · Kubernetes — Container Runtimes(전제 조건) · Kubespray — Port requirements
고치기 전에 지금을 적는다
아무것도 고치기 전에 /root/ks/preflight/before.json 에 swap_total_kb(/proc/meminfo 의 SwapTotal, 숫자), ip_forward(지금 커널 값, 숫자), br_netfilter(모듈이 올라와 있는가, 불리언), busy_ports(컨트롤 플레인 포트 2379, 2380, 6443, 10250, 10257, 10259 가운데 지금 무언가 LISTEN 중인 포트, 오름차순 숫자 배열)를 적으세요.
LISTEN 중인 소켓은 ss -ltnp 로 봅니다. 모듈이 올라와 있는지는 lsmod 나 /sys/module/<이름> 으로 확인합니다. 채점기는 VM 이 준비될 때 따로 잰 값과 대조하므로, 고친 다음에 적으면 맞지 않습니다.
스왑을 끄고 다시 켜지지 않게 한다
켜져 있는 스왑을 모두 끄고, /etc/fstab 에서 스왑 줄을 지우거나 주석으로 막아 재부팅해도 다시 켜지지 않게 하세요. 스왑 파일 자체는 지워도 되고 남겨도 됩니다.
swapoff 는 지금만 끕니다. 부팅 때 스왑을 켜는 것은 fstab 의 type 이 swap 인 줄입니다. 어느 파일이 스왑인지는 swapon --show 나 /proc/swaps 에 있습니다.
커널 모듈을 지금도, 부팅 때도
overlay 와 br_netfilter 를 지금 올리고, /etc/modules-load.d/k8s.conf 에 두 이름을 한 줄씩 적어 부팅 때도 올라오게 하세요.
containerd 의 기본 스냅샷터가 overlay 를 쓰고, 브리지를 지나는 파드 트래픽이 iptables 를 거치게 하는 것이 br_netfilter 입니다. modprobe 는 지금만, modules-load.d 는 다음 부팅부터입니다.
sysctl 은 마지막에 읽힌 파일이 이긴다
/etc/sysctl.d/k8s.conf 에 net.ipv4.ip_forward = 1, net.bridge.bridge-nf-call-iptables = 1, net.bridge.bridge-nf-call-ip6tables = 1 을 적고 적용하세요. 지금 커널 값이 셋 다 1 이어야 하고, 재부팅 때 sysctl.d 를 이름순으로 다시 읽어도 셋 다 1 이어야 합니다.
sysctl --system 을 돌린 뒤 ip_forward 를 다시 읽어 보세요. sysctl.d 의 파일은 이름순으로 읽히고 같은 키는 나중 것이 이깁니다. sysctl --system 의 출력이 어느 파일을 어떤 순서로 읽었는지 보여 줍니다. 앞선 관리자의 파일을 지울지, 이름을 바꿀지, 내 파일을 뒤로 보낼지는 판단입니다.
kubelet 자리를 차지한 것
컨트롤 플레인 포트 가운데 무언가 잡고 있는 포트를 찾아, 그것을 띄운 systemd 유닛을 멈추고 부팅 때 다시 뜨지 않게(disable) 하세요. /root/ks/preflight/ports.json 에 port(잡혀 있던 포트, 숫자), unit(그 프로세스를 띄운 유닛 이름, .service 포함), pid(멈추기 전 그 프로세스의 PID, 숫자)를 적습니다. 끝나면 2379, 2380, 6443, 10250, 10257, 10259 어느 것도 LISTEN 이 아니어야 합니다.
ss -ltnp 가 PID 를 보여 주고, PID 를 띄운 유닛은 systemctl status <PID> 나 /proc/<PID>/cgroup 에서 보입니다. 프로세스만 죽이면 Restart=always 인 유닛이 곧바로 다시 띄웁니다. kubespray 는 이 포트를 비워 주지 않습니다. 첫 kubeadm init 은 preflight 의 Port-10250 오류로 막히는데, kubespray 의 재시도는 그 오류를 무시 목록에 넣고 다시 돌리므로 원인은 로그 위쪽 첫 시도에만 남습니다(control-plane/tasks/kubeadm-setup.yml).
kubespray 가 보는 이 호스트
/opt/ks/kubespray 에서 ansible -i /root/ks/inventory/lab/inventory.ini node1 -m setup 으로 이 노드의 사실(facts)을 모아 /root/ks/preflight/facts.json 에 memtotal_mb, processor_vcpus, distribution, distribution_version, kernel, default_ipv4(기본 경로의 IPv4 주소)를 적으세요. 그리고 kubespray 의 roles/kubernetes/preinstall/defaults/main.yml 에서 컨트롤 플레인 최소 메모리를 찾아 minimal_master_memory_mb 로 함께 적습니다.
kubespray 의 사전 검사(0040-verify-settings.yml)는 이 사실들로 판정합니다. 메모리가 최소값보다 작으면 설치가 시작 몇 분 만에 멈춥니다. setup 모듈의 출력은 ansible_facts 아래에 있고, 기본 경로 주소는 default_ipv4.address 입니다. kubespray 는 ip 변수를 따로 주지 않으면 이 주소에 API 서버와 etcd 를 붙입니다.
무엇을 도구에 맡기고 무엇을 사람이 보나
kubespray v2.32.0 의 roles/kubernetes/preinstall·roles/kubernetes/node 를 읽고 /root/ks/preflight/who-fixes.json 에 네 문제마다 kubespray 가 스스로 고치면 "kubespray", 사람이 먼저 치워야 하면 "operator" 를 적으세요. 키는 swap, br_netfilter, ip_forward, port_10250 입니다. 그리고 sysctl_file(kubespray 가 sysctl 값을 적는 파일 경로, 기본값)을 함께 적습니다.
preinstall 의 0010-swapoff.yml 은 fstab 의 스왑 줄을 지우고 swap.target 을 가리고 swapoff 를 부릅니다. 모듈과 sysctl 은 node·preinstall 역할에서 찾을 수 있고, sysctl 파일 경로는 kubespray_defaults 의 sysctl_file_path 입니다. 포트를 비우는 작업은 어디에도 없습니다. 4단계에서 겪은 것처럼, kubespray 가 적는 파일보다 이름순으로 뒤에 오는 파일이 있으면 재부팅 때 값이 되돌아간다는 점도 함께 생각해 보세요.