이번엔 kubespray에서 k8s를 설치하는 cluster.yaml 동작 중심으로 설치 과정을 재정리
플레이북 호출 구조
/root/kubespray/cluster.yml
└── playbooks/cluster.yml (import)
├── boilerplate.yml
├── internal_facts.yml
├── install_etcd.yml
└── 각종 Role 실행
cat /root/kubespray/cluster.yml
---
- name: Install Kubernetes
ansible.builtin.import_playbook: playbooks/cluster.yml
전체 설치 흐름 요약
cluster.yml은 5개의 논리적 단계(A~E)로 구성되며, 각 단계는 명확한 목적을 가진다.
| 단계 | 목적 | 핵심 Role | PLAY |
|---|
| A | 초기화 및 정보 수집 | validate_inventory, bootstrap_os, network_facts | 1~5 |
| B | 인프라 및 엔진 준비 | kubernetes/preinstall, container-engine, download | 5 |
| C | 데이터 저장소 및 노드 구성 | etcd, kubernetes/node | 6~9 |
| D | 컨트롤 플레인 및 네트워크 | kubernetes/control-plane, kubernetes/kubeadm, network_plugin | 10~11 |
| E | 부가 서비스 설치 | kubernetes-apps, metrics_server, helm | 12~15 |
cluster.yml 전체 구조와 PLAY 매핑
| 단계 | cluster.yml 섹션 | 실행되는 PLAY | 대상 호스트 |
|---|
| A | import_playbook: boilerplate.yml | PLAY 1~3: Ansible 버전 확인, Inventory 검증, Bastion SSH | localhost, all |
| A | import_playbook: internal_facts.yml | PLAY 4~5: Bootstrap hosts, Gather facts | all |
| B | Prepare for etcd install | (PLAY 5 계속) preinstall, container-engine, download | k8s_cluster:etcd |
| C | import_playbook: install_etcd.yml | PLAY 6~8: etcd 준비, worker 추가, etcd 설치 | etcd, k8s_cluster |
| C | Install Kubernetes nodes | PLAY 9: K8s 노드 설치 | k8s_cluster |
| D | Install the control plane | PLAY 10: Control Plane 설치 | kube_control_plane |
| D | Invoke kubeadm and install a CNI | PLAY 11: kubeadm init/join, CNI 설치 | k8s_cluster |
| E | Install Calico Route Reflector | PLAY 12: Calico RR (선택) | calico_rr |
| E | Patch Kubernetes for Windows | PLAY 13: Windows 패치 (선택) | kube_control_plane[0] |
| E | Install Kubernetes apps | PLAY 14: 애드온 설치 | kube_control_plane |
| E | Apply resolv.conf changes | PLAY 15: DNS 설정 정리 | k8s_cluster |
PLAY 전체 목록 (14개)
| 순번 | PLAY 이름 | 단계 | 설명 |
|---|
| 1 | Check Ansible version | A | Kubespray 지원 Ansible 버전 확인 (2.17.3 <= version < 2.18.0) |
| 2 | Inventory setup and validation | A | inventory 정합성 검증: kube_control_plane, etcd 그룹 존재 여부, etcd 홀수 노드, CIDR 유효성 |
| 3 | Install bastion ssh config | A | Bastion(점프 호스트) SSH 설정. 미사용 시 skip |
| 4 | Bootstrap hosts for Ansible | A | 모든 노드를 Ansible 실행 가능 상태로 준비: Python, sudo, 기본 패키지 |
| 5 | Gather facts | A | Ansible fact 수집. 이후 조건 분기에 사용 |
| 6 | Prepare for etcd install | C | etcd user 생성, 디렉터리, 방화벽/포트, 인증서 경로 준비 |
| 7 | Add worker nodes to the etcd play if needed | C | kube_node + etcd 겸용 노드를 etcd PLAY에 추가 |
| 8 | Install etcd | C | etcd binary 설치, TLS 인증서 생성, systemd 등록, 클러스터 구성 |
| 9 | Install Kubernetes nodes | C | 모든 노드에 kubelet 등 공통 컴포넌트 설치 |
| 10 | Install the control plane | D | control-plane 노드 구성: kubeadm init, API server, scheduler |
| 11 | Invoke kubeadm and install a CNI | D | kubeadm join, CNI 플러그인 설치 |
| 12 | Install Calico Route Reflector | E | Calico BGP RR 설정. Calico BGP 미사용 시 skip |
| 13 | Patch Kubernetes for Windows | E | Windows 노드 지원 패치. Linux-only 시 skip |
| 14 | Install Kubernetes apps | E | CoreDNS, metrics-server, Helm 등 애드온 설치 |
| 15 | Apply resolv.conf changes now that cluster DNS is up | E | 클러스터 DNS 안정화 후 노드 DNS 설정 정리 |
cluster.yaml 관점 설치 흐름도

각 PLAY별로 각 노드(Master/Worker)와 영역(OS/Network/K8s)에서 변화 과정 추적

각 단계별 Master/Worker 노드의 3개 영역 업데이트 내용:
| 단계 | OS 영역 | Network 영역 | K8s 영역 |
|---|
| A | Python, 기본 패키지, Facts 수집 | IP 정보 수집 | (없음) |
| B | swap 비활성화, sysctl, containerd | ip_forward, br_netfilter | 바이너리 다운로드 |
| C | etcd 사용자, 인증서 디렉터리 | etcd 포트 2379/2380 | etcd 클러스터, kubelet, TLS |
| D | /etc/kubernetes, 인증서 갱신 cron | API Server :6443, CNI, Pod CIDR | apiserver, controller, scheduler, kube-proxy |
| E | resolv.conf → CoreDNS, Helm | CoreDNS 서비스, 클러스터 DNS | CoreDNS Pod, metrics-server, ClusterRole |
A. 초기화 및 정보 수집 (Boilerplate & Facts)
모든 노드에 공통적으로 필요한 설정을 적용하고, 각 서버의 사양 정보를 수집하여 이후 설치 단계에서 변수로 활용한다.
※ 보일러플레이트(Boilerplate)?
- 컴퓨터 프로그래밍에서 최소한의 변경으로 여러 곳에서 재사용되며, 반복적으로 비슷한 형태를 띄는 표준화된 코드 블록
호출 구조
- name: Common tasks for every playbooks
import_playbook: boilerplate.yml
- name: Gather facts
import_playbook: internal_facts.yml
PLAY 1: Check Ansible version
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 1 | - | Check 2.17.3 <= Ansible version < 2.18.0 | Ansible 버전 범위 검증 |
| 2 | - | Check that python netaddr is installed | Python netaddr 모듈 설치 확인 |
| 3 | - | Check that jinja is not too old (install via pip) | Jinja2 버전 확인 |
PLAY 2: Inventory setup and validation
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 4 | dynamic_groups | Match needed groups by their old names or definition | 그룹 매칭 및 정의 |
| 5 | validate_inventory | Stop if removed tags are used | 제거된 태그 사용 시 중지 |
| 6 | validate_inventory | Stop if kube_control_plane group is empty | control-plane 그룹 비어있으면 중지 |
| 7 | validate_inventory | Stop if etcd group is empty in external etcd mode | 외부 etcd 모드에서 etcd 그룹 비어있으면 중지 |
| 8 | validate_inventory | Stop if unsupported version of Kubernetes | 지원하지 않는 K8s 버전이면 중지 |
| 9 | validate_inventory | Stop if known booleans are set as strings | boolean 값이 문자열로 설정되면 중지 |
| 10 | validate_inventory | Stop if even number of etcd hosts | etcd 호스트가 짝수면 중지 (홀수 권장) |
| 11 | validate_inventory | Guarantee that enough network address space is available for all pods | Pod용 네트워크 주소 공간 충분한지 확인 |
| 12 | validate_inventory | Check that kube_service_addresses is a network range | Service CIDR이 네트워크 범위인지 확인 |
| 13 | validate_inventory | Check that kube_pods_subnet is a network range | Pod CIDR이 네트워크 범위인지 확인 |
| 14 | validate_inventory | Check that kube_pods_subnet does not collide with kube_service_addresses | Pod/Service CIDR 충돌 확인 |
| 15 | validate_inventory | Check that ipv4 IP range is enough for the nodes | IPv4 범위가 노드에 충분한지 확인 |
| 16 | validate_inventory | Stop if unsupported options selected | 지원하지 않는 옵션 선택 시 중지 |
| 17 | validate_inventory | Ensure minimum containerd version | containerd 최소 버전 확인 |
PLAY 3: Install bastion ssh config
Bastion(점프 호스트) 미사용 시 대부분 skip된다.
PLAY 4: Bootstrap hosts for Ansible
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 18 | bootstrap_os | Fetch /etc/os-release | OS 릴리즈 정보 가져오기 |
| 19 | bootstrap_os | Include tasks | OS별 태스크 포함 |
| 20 | bootstrap_os | Gather host facts to get ansible_distribution_version | 배포판 버전 정보 수집 |
| 21 | bootstrap_os | Add proxy to yum.conf or dnf.conf if http_proxy is defined | 프록시 설정 추가 (RedHat 계열) |
| 22 | bootstrap_os | Check presence of fastestmirror.conf | fastestmirror 설정 확인 |
| 23 | system_packages | Gather OS information | OS 정보 수집 |
| 24 | system_packages | Remove legacy docker repo file | 레거시 docker repo 파일 제거 |
| 25 | system_packages | Manage packages | 패키지 관리 |
| 26 | bootstrap_os | Create remote_tmp for it is used by another module | remote_tmp 디렉터리 생성 |
| 27 | bootstrap_os | Gather facts | fact 수집 |
| 28 | bootstrap_os | Assign inventory name to unconfigured hostnames | hostname 미설정 시 inventory 이름 할당 |
| 29 | bootstrap_os | Ensure bash_completion.d folder exists | bash_completion.d 폴더 생성 |
PLAY 5: Gather facts
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 30 | network_facts | Gather ansible_default_ipv4 | 기본 IPv4 정보 수집 |
| 31 | network_facts | Set fallback_ip | fallback IP 설정 |
| 32 | network_facts | Gather ansible_default_ipv6 | 기본 IPv6 정보 수집 |
| 33 | network_facts | Set fallback_ip6 | fallback IPv6 설정 |
| 34 | network_facts | Set main access ip | 메인 접근 IP 설정 (IPv4/IPv6 스택 옵션 기반) |
| 35 | network_facts | Set main ip | 메인 IP 설정 |
| 36 | network_facts | Set main access ips (mixed ips for dualstack) | 듀얼스택용 혼합 IP 설정 |
| 37 | network_facts | Set main ips (mixed ips for dualstack) | 듀얼스택용 메인 IP 설정 |
| 38 | - | Gather minimal facts | 최소 fact 수집 |
| 39 | - | Gather necessary facts (network) | 네트워크 fact 수집 |
| 40 | - | Gather necessary facts (hardware) | 하드웨어 fact 수집 |
| 41 | adduser | User | Create User Group | 사용자 그룹 생성 |
| 42 | adduser | User | Create User | 사용자 생성 |
B. 인프라 및 엔진 준비 (Prepare for etcd & container-engine)
방화벽, 커널 파라미터, Swap 비활성화 등 K8s 설치를 위한 OS 최적화를 수행하고, 컨테이너 런타임과 필요한 바이너리/이미지를 다운로드한다.
호출 구조
- name: Prepare for etcd install
hosts: k8s_cluster:etcd
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
- { role: kubernetes/preinstall, tags: preinstall }
- { role: "container-engine", tags: "container-engine", when: deploy_container_engine }
- { role: download, tags: download, when: "not skip_downloads" }
Role별 주요 기능
| Role | 기능 | 주요 작업 |
|---|
| kubespray_defaults | 공통 변수 로드 | Kubespray 전체에서 사용하는 경로, 버전 등 변수 로드 |
| kubernetes/preinstall | OS 최적화 | 방화벽, 커널 파라미터, Swap 비활성화, 디렉터리 생성 |
| container-engine | 컨테이너 런타임 설치 | containerd, runc, crictl, nerdctl 설치 및 설정 |
| download | 바이너리/이미지 다운로드 | kubeadm, kubectl, kubelet, CNI, 컨테이너 이미지 다운로드 |
kubernetes/preinstall Role TASK
| 순번 | TASK 이름 | 설명 |
|---|
| 43 | Check if /etc/fstab exists | /etc/fstab 존재 확인 |
| 44 | Remove swapfile from /etc/fstab | fstab에서 swap 항목 제거 |
| 45 | Mask swap.target (persist swapoff) | swap.target 마스킹으로 swap 영구 비활성화 |
| 46 | Disable swap | swap 비활성화 |
| 47 | Check resolvconf | resolvconf 확인 |
| 48 | Check existence of /etc/resolvconf/resolv.conf.d | resolvconf 디렉터리 존재 확인 |
| 49 | Check status of /etc/resolv.conf | resolv.conf 상태 확인 |
| 50 | Fetch resolv.conf | resolv.conf 가져오기 |
| 51 | NetworkManager | Check if host has NetworkManager | NetworkManager 존재 확인 |
| 52 | Check systemd-resolved | systemd-resolved 확인 |
| 53 | Set default dns if remove_default_searchdomains is false | 기본 DNS 설정 |
| 54 | Set dns facts | DNS fact 설정 |
| 55 | Check if kubelet is configured | kubelet 설정 여부 확인 |
| 56 | Check if early DNS configuration stage | 초기 DNS 설정 단계 확인 |
| 57 | Target resolv.conf files | resolv.conf 파일 대상 지정 |
| 58 | Check if /etc/dhclient.conf exists | dhclient.conf 존재 확인 |
| 59 | Check if /etc/dhcp/dhclient.conf exists | dhcp/dhclient.conf 존재 확인 |
| 60 | Target dhclient hook file for Red Hat family | RedHat용 dhclient hook 파일 지정 |
| 61 | Check /usr readonly | /usr 읽기전용 확인 |
| 62 | Stop if non systemd OS type | systemd 아닌 OS면 중지 |
| 63 | Stop if the os does not support | 지원하지 않는 OS면 중지 |
| 64 | Stop if memory is too small for control plane nodes | control-plane 노드 메모리 부족하면 중지 |
| 65 | Stop if memory is too small for nodes | 노드 메모리 부족하면 중지 |
| 66 | Stop if cgroups are not enabled on nodes | cgroups 미활성화면 중지 |
| 67 | Stop if ip var does not match local ips | IP 변수가 로컬 IP와 불일치하면 중지 |
| 68 | Stop if access_ip is not pingable | access_ip에 ping 불가면 중지 |
| 69 | Stop if bad hostname | 잘못된 hostname이면 중지 |
| 70 | Stop if /etc/resolv.conf has no configured nameservers | nameserver 미설정이면 중지 |
| 71 | Create kubernetes directories | kubernetes 디렉터리 생성 |
| 72 | Create other directories of root owner | root 소유 기타 디렉터리 생성 |
| 73 | Check if kubernetes kubeadm compat cert dir exists | kubeadm 호환 인증서 디렉터리 존재 확인 |
| 74 | Create kubernetes kubeadm compat cert dir | kubeadm 호환 인증서 디렉터리 생성 |
| 75 | Create cni directories | CNI 디렉터리 생성 |
| 76 | NetworkManager | Ensure NetworkManager conf.d dir | NetworkManager conf.d 디렉터리 확인 |
| 77 | NetworkManager | Prevent NetworkManager from managing K8S interfaces | NetworkManager가 K8s 인터페이스 관리 방지 |
| 78 | NetworkManager | Add nameservers to NM configuration | NetworkManager에 nameserver 추가 |
| 79 | Set default dns if remove_default_searchdomains is false | 기본 DNS 설정 |
| 80 | NetworkManager | Add DNS search to NM configuration | NetworkManager에 DNS search 추가 |
| 81 | NetworkManager | Add DNS options to NM configuration | NetworkManager에 DNS 옵션 추가 |
| 82 | Confirm selinux deployed | SELinux 배포 확인 |
| 83 | Set selinux policy | SELinux 정책 설정 |
| 84 | Clean previously used sysctl file locations | 이전 sysctl 파일 위치 정리 |
| 85 | Stat sysctl file configuration | sysctl 파일 설정 상태 확인 |
| 86 | Change sysctl file path to link source if linked | 심볼릭 링크면 소스 경로로 변경 |
| 87 | Make sure sysctl file path folder exists | sysctl 파일 경로 폴더 존재 확인 |
| 88 | Enable ip forwarding | IP 포워딩 활성화 |
| 89 | Check if we need to set fs.may_detach_mounts | fs.may_detach_mounts 설정 필요 여부 확인 |
| 90 | Ensure kubelet expected parameters are set | kubelet 예상 파라미터 설정 확인 |
| 91 | Disable fapolicyd service | fapolicyd 서비스 비활성화 |
| 92 | Check if we are running inside a Azure VM | Azure VM 내부 실행 여부 확인 |
container-engine Role TASK
| 순번 | 서브 Role | TASK 이름 | 설명 |
|---|
| 93 | validate-container-engine | check if fedora coreos | Fedora CoreOS 확인 |
| 94 | validate-container-engine | set is_ostree | is_ostree 설정 |
| 95 | validate-container-engine | Ensure kubelet systemd unit exists | kubelet systemd unit 존재 확인 |
| 96 | validate-container-engine | Populate service facts | 서비스 fact 수집 |
| 97 | validate-container-engine | Check if containerd is installed | containerd 설치 여부 확인 |
| 98 | validate-container-engine | Check if docker is installed | docker 설치 여부 확인 |
| 99 | validate-container-engine | Check if crio is installed | crio 설치 여부 확인 |
| 100 | containerd-common | check if fedora coreos | Fedora CoreOS 확인 |
| 101 | containerd-common | set is_ostree | is_ostree 설정 |
| 102 | runc | check if fedora coreos | Fedora CoreOS 확인 |
| 103 | runc | set is_ostree | is_ostree 설정 |
| 104 | runc | Uninstall runc package managed by package manager | 패키지 관리자로 설치된 runc 제거 |
| 105 | runc | Download runc binary | runc 바이너리 다운로드 |
| 106 | runc | Prep_download | Set a few facts | 다운로드 준비 fact 설정 |
| 107 | runc | Download_file | Set pathname of cached file | 캐시 파일 경로 설정 |
| 108 | runc | Download_file | Create dest directory on node | 노드에 대상 디렉터리 생성 |
| 109 | runc | Download_file | Download item | 파일 다운로드 |
| 110 | runc | Download_file | Extract file archives | 파일 아카이브 추출 |
| 111 | runc | Copy runc binary from download dir | 다운로드 디렉터리에서 runc 바이너리 복사 |
| 112 | runc | Remove orphaned binary | 고아 바이너리 제거 |
| 113 | crictl | Install crictl | crictl 설치 |
| 114 | crictl | Download crictl | crictl 다운로드 |
| 115 | crictl | Prep_download | Set a few facts | 다운로드 준비 fact 설정 |
| 116 | crictl | Download_file | Set pathname of cached file | 캐시 파일 경로 설정 |
| 117 | crictl | Download_file | Create dest directory on node | 노드에 대상 디렉터리 생성 |
| 118 | crictl | Download_file | Download item | 파일 다운로드 |
| 119 | crictl | Download_file | Extract file archives | 파일 아카이브 추출 |
| 120 | crictl | Extract_file | Unpacking archive | 아카이브 압축 해제 |
| 121 | crictl | Install crictl config | crictl 설정 설치 |
| 122 | crictl | Copy crictl binary from download dir | crictl 바이너리 복사 |
| 123 | nerdctl | Download nerdctl | nerdctl 다운로드 |
| 124 | nerdctl | Prep_download | Set a few facts | 다운로드 준비 fact 설정 |
| 125 | nerdctl | Download_file | Set pathname of cached file | 캐시 파일 경로 설정 |
| 126 | nerdctl | Download_file | Create dest directory on node | 노드에 대상 디렉터리 생성 |
| 127 | nerdctl | Download_file | Download item | 파일 다운로드 |
| 128 | nerdctl | Download_file | Extract file archives | 파일 아카이브 추출 |
| 129 | nerdctl | Extract_file | Unpacking archive | 아카이브 압축 해제 |
| 130 | nerdctl | Copy nerdctl binary from download dir | nerdctl 바이너리 복사 |
| 131 | nerdctl | Create configuration dir | nerdctl 설정 디렉터리 생성 |
| 132 | nerdctl | Install nerdctl configuration | nerdctl 설정 설치 |
| 133 | containerd | Download containerd | containerd 다운로드 |
| 134 | containerd | Prep_download | Set a few facts | 다운로드 준비 fact 설정 |
| 135 | containerd | Download_file | Set pathname of cached file | 캐시 파일 경로 설정 |
| 136 | containerd | Download_file | Create dest directory on node | 노드에 대상 디렉터리 생성 |
| 137 | containerd | Download_file | Download item | 파일 다운로드 |
| 138 | containerd | Download_file | Extract file archives | 파일 아카이브 추출 |
| 139 | containerd | Unpack containerd archive | containerd 아카이브 압축 해제 |
| 140 | containerd | Generate systemd service for containerd | containerd.service 생성 |
| 141 | containerd | Ensure containerd directories exist | containerd 디렉터리 존재 확인 |
| 142 | containerd | Generate default base_runtime_spec | 기본 base_runtime_spec 생성 |
| 143 | containerd | Store generated default base_runtime_spec | base_runtime_spec 저장 |
| 144 | containerd | Write base_runtime_specs | base_runtime_specs 작성 |
| 145 | containerd | Copy containerd config file | containerd config.toml 복사 |
| 146 | containerd | Create registry directories | 레지스트리 디렉터리 생성 |
| 147 | containerd | Write hosts.toml file | hosts.toml 파일 작성 |
| 148 | containerd | Ensure containerd is started and enabled | containerd 시작 및 활성화 |
download Role TASK (주요 항목)
| 순번 | TASK 이름 | 설명 |
|---|
| 149 | Prep_download | Set a few facts | 다운로드 준비 fact 설정 |
| 150 | Prep_download | Register docker images info | docker 이미지 정보 등록 |
| 151 | Prep_download | Create staging directory on remote node | 스테이징 디렉터리 생성 |
| 152 | Download | Get kubeadm binary and list of required images | kubeadm 및 필요 이미지 목록 가져오기 |
| 153 | Prep_kubeadm_images | Download kubeadm binary | kubeadm 바이너리 다운로드 |
| 154 | Prep_kubeadm_images | Copy kubeadm binary to system path | kubeadm 시스템 경로로 복사 |
| 155 | Prep_kubeadm_images | Create kubeadm config | kubeadm 설정 생성 |
| 156 | Prep_kubeadm_images | Generate list of required images | 필요 이미지 목록 생성 |
| 157 | Prep_kubeadm_images | Parse list of images | 이미지 목록 파싱 |
| 158 | Prep_kubeadm_images | Convert list of images to dict | 이미지 목록 dict 변환 |
| 159 | Download | Download files / images | 파일/이미지 다운로드 실행 |
| 160~ | (반복) Download_file / Download_container 시리즈 | kubectl, kubelet, CNI, helm 등 다운로드 |
다운로드 대상 바이너리:
| 바이너리 | 설명 |
|---|
| kubeadm | 클러스터 초기화 도구 |
| kubectl | CLI 클라이언트 |
| kubelet | 노드 에이전트 |
| CNI plugins | 네트워크 플러그인 |
| calicoctl | Calico CLI (Calico 사용 시) |
| etcdctl, etcdutl | etcd 관리 도구 |
| helm | 패키지 매니저 |
| crictl | CRI 디버깅 도구 |
다운로드 대상 컨테이너 이미지:
| 이미지 | 설명 |
|---|
| kube-apiserver | API 서버 |
| kube-controller-manager | 컨트롤러 매니저 |
| kube-scheduler | 스케줄러 |
| kube-proxy | kube-proxy |
| pause | 인프라 컨테이너 |
| coredns | 클러스터 DNS |
| flannel / calico | CNI 플러그인 |
| metrics-server | 메트릭 서버 |
| dns-node-cache | 노드 로컬 DNS 캐시 |
C. 데이터 저장소 및 노드 구성 (Etcd & K8s Nodes)
Kubernetes의 상태 정보를 저장하는 etcd 클러스터를 구축하고, 모든 노드에 kubelet 등 기초 컴포넌트를 설치한다.
호출 구조
- name: Install etcd
vars:
etcd_cluster_setup: true
etcd_events_cluster_setup: "{{ etcd_events_cluster_enabled }}"
import_playbook: install_etcd.yml
- name: Install Kubernetes nodes
hosts: k8s_cluster
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
- { role: kubernetes/node, tags: node }
PLAY 6: Prepare for etcd install
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 251 | - | Gathering Facts | fact 수집 |
| 252 | - | Check if nodes needs etcd client certs | 네트워크 플러그인에 따른 etcd 클라이언트 인증서 필요 여부 |
| 253 | adduser | User | Create User Group | etcd 사용자 그룹 생성 |
| 254 | adduser | User | Create User | etcd 사용자 생성 |
PLAY 7: Add worker nodes to the etcd play if needed
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 255 | adduser | User | Create User Group | 사용자 그룹 생성 |
| 256 | adduser | User | Create User | 사용자 생성 |
PLAY 8: Install etcd
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 257 | etcd | Check etcd certs | etcd 인증서 확인 |
| 258 | etcd | Check_certs | Register certs on first etcd node | 첫 번째 etcd 노드에서 기존 인증서 등록 |
| 259 | etcd | Check_certs | Set default value for sync_certs, gen_certs | sync_certs, gen_certs 기본값 false 설정 |
| 260 | etcd | Check certs | Register ca and etcd admin/member certs on etcd hosts | etcd 호스트에 CA 및 admin/member 인증서 등록 |
| 261 | etcd | Check certs | Register ca and etcd node certs on kubernetes hosts | kubernetes 호스트에 CA 및 노드 인증서 등록 |
| 262 | etcd | Check_certs | Set 'gen_certs' to true (1/2) | 인증서 없으면 gen_certs=true (1/2) |
| 263 | etcd | Check_certs | Set 'gen_certs' to true (2/2) | 인증서 없으면 gen_certs=true (2/2) |
| 264 | etcd | Checkcerts | Set 'gen*_certs' groups | 인증서 생성 필요 노드 추적용 그룹 설정 |
| 265 | etcd | Check_certs | Set 'etcd_member_requires_sync' | CA/member 인증서 없거나 체크섬 불일치 시 동기화 필요 |
| 266 | etcd | Check_certs | Set 'sync_certs' to true | sync_certs=true 설정 |
| 267 | etcd | Generate etcd certs | etcd 인증서 생성 |
| 268 | etcd | Gen_certs | create etcd cert dir | etcd 인증서 디렉터리 생성 |
| 269 | etcd | Gen_certs | create etcd script dir | etcd 스크립트 디렉터리 생성 |
| 270 | etcd | Gen_certs | write openssl config | openssl 설정 작성 |
| 271 | etcd | Gen_certs | copy certs generation script | 인증서 생성 스크립트 복사 |
| 272 | etcd | Gen_certs | run cert generation script for etcd and control plane | etcd 및 control-plane용 인증서 생성 |
| 273 | etcd | Gen_certs | run cert generation script for all clients | 모든 클라이언트용 인증서 생성 |
| 274 | etcd | Gen_certs | check certificate permissions | 인증서 권한 확인 |
| 275 | etcd | Trust etcd CA | etcd CA 신뢰 설정 |
| 276 | etcd | Gen_certs | target ca-certificate store file | CA 인증서 저장소 파일 지정 |
| 277 | etcd | Gen_certs | add CA to trusted CA dir | 신뢰 CA 디렉터리에 CA 추가 |
| 278 | etcd | Gen_certs | update ca-certificates (RedHat) | ca-certificates 업데이트 |
| 279 | etcd | Trust etcd CA on nodes if needed | 필요시 노드에서 etcd CA 신뢰 설정 |
| 280 | etcd | Gen_certs | Get etcd certificate serials | etcd 인증서 시리얼 가져오기 |
| 281 | etcd | Set etcd_client_cert_serial | etcd_client_cert_serial 설정 |
| 282 | etcdctl_etcdutl | Download etcd binary | etcd 바이너리 다운로드 |
| 283 | etcdctl_etcdutl | Extract_file | Unpacking archive | 아카이브 압축 해제 |
| 284 | etcdctl_etcdutl | Copy etcd binary | etcd 바이너리 복사 |
| 285 | etcdctl_etcdutl | Copy etcdctl and etcdutl binary | etcdctl, etcdutl 바이너리 복사 |
| 286 | etcdctl_etcdutl | Create etcdctl wrapper script | etcdctl 래퍼 스크립트 생성 |
| 287 | etcd | Install etcd | etcd 설치 |
| 288 | etcd | Get currently-deployed etcd version | 현재 etcd 버전 확인 |
| 289 | etcd | Restart etcd if necessary | 필요시 etcd 재시작 |
| 290 | etcd | Install | Copy etcd binary from download dir | etcd 바이너리 설치 |
| 291 | etcd | Configure etcd | etcd 설정 |
| 292 | etcd | Configure | Check if etcd cluster is healthy | etcd 클러스터 건강 상태 확인 |
| 293 | etcd | Configure | Refresh etcd config | etcd 설정 새로고침 |
| 294 | etcd | Refresh config | Create etcd config file | etcd 설정 파일 생성 |
| 295 | etcd | Configure | Copy etcd.service systemd file | etcd.service 파일 복사 |
| 296 | etcd | Configure | reload systemd | systemd 리로드 |
| 297 | etcd | Configure | Ensure etcd is running | etcd 실행 확인 |
| 298 | etcd | Configure | Wait for etcd cluster to be healthy | etcd 클러스터 건강 대기 |
| 299 | etcd | Configure | Check if member is in etcd cluster | 멤버 클러스터 소속 확인 |
| 300 | etcd | Refresh etcd config | etcd 설정 새로고침 |
| 301 | etcd | Refresh etcd config again for idempotency | 멱등성을 위해 재실행 |
etcd 인증서 처리 흐름
- 첫 번째 etcd 노드에서 인증서 존재 여부 확인
- 인증서 없으면
gen_certs 플래그 설정
- openssl config 작성 후 인증서 생성 스크립트 실행
- 생성 인증서: ca.crt/key, server.crt/key, peer.crt/key, admin.crt/key, member.crt/key
- CA 인증서를 신뢰 저장소에 추가
- 다른 노드에 동기화 필요 시
sync_certs 플래그 설정
PLAY 9: Install Kubernetes nodes
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 302 | kubernetes/node | Set kubelet_cgroup_driver_detected fact for containerd | containerd용 cgroup driver 감지 |
| 303 | kubernetes/node | Set kubelet_cgroup_driver | kubelet cgroup driver 설정 |
| 304 | kubernetes/node | Ensure /var/lib/cni exists | /var/lib/cni 존재 확인 |
| 305 | kubernetes/node | Install | Copy kubelet binary from download dir | kubelet 바이너리 설치 |
| 306 | kubernetes/node | Ensure nodePort range is reserved | nodePort 범위 예약 확인 |
| 307 | kubernetes/node | Verify if br_netfilter module exists | br_netfilter 모듈 존재 확인 |
| 308 | kubernetes/node | Verify br_netfilter module path exists | br_netfilter 모듈 경로 확인 |
| 309 | kubernetes/node | Enable br_netfilter module | br_netfilter 모듈 활성화 |
| 310 | kubernetes/node | Persist br_netfilter module | br_netfilter 부팅 시 자동 로드 |
| 311 | kubernetes/node | Check if bridge-nf-call-iptables key exists | bridge-nf-call-iptables 키 확인 |
| 312 | kubernetes/node | Enable bridge-nf-call tables | bridge-nf-call 테이블 활성화 |
| 313 | kubernetes/node | Set kubelet api version to v1beta1 | kubelet API 버전 설정 |
| 314 | kubernetes/node | Write kubelet environment config file (kubeadm) | kubelet 환경 설정 파일 작성 |
| 315 | kubernetes/node | Write kubelet config file | kubelet 설정 파일 작성 |
| 316 | kubernetes/node | Write kubelet systemd init file | kubelet.service 파일 작성 |
| 317 | kubernetes/node | Enable kubelet | kubelet 서비스 활성화 |
D. 컨트롤 플레인 및 네트워크 (Control Plane & CNI)
마스터 노드에 API 서버, 스케줄러 등을 설정하고, kubeadm으로 클러스터를 구성하며, CNI를 설치하여 파드 간 통신을 가능하게 한다.
호출 구조
- name: Install the control plane
hosts: kube_control_plane
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
- { role: kubernetes/control-plane, tags: control-plane }
- { role: kubernetes/client, tags: client }
- { role: kubernetes-apps/cluster_roles, tags: cluster-roles }
- name: Invoke kubeadm and install a CNI
hosts: k8s_cluster
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
- { role: kubernetes/kubeadm, tags: kubeadm }
- { role: kubernetes/node-label, tags: node-label }
- { role: kubernetes/node-taint, tags: node-taint }
- { role: kubernetes-apps/common_crds }
- { role: network_plugin, tags: network }
PLAY 10: Install the control plane
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 318 | kubernetes/control-plane | Pre-upgrade | Delete control plane manifests if etcd secrets changed | etcd 시크릿 변경 시 매니페스트 삭제 |
| 319 | kubernetes/control-plane | Create kube-scheduler config | kube-scheduler 설정 생성 |
| 320 | kubernetes/control-plane | Install | Copy kubectl binary from download dir | kubectl 설치 |
| 321 | kubernetes/control-plane | Install kubectl bash completion | kubectl 자동완성 설치 |
| 322 | kubernetes/control-plane | Set kubectl bash completion file permissions | 파일 권한 설정 |
| 323 | kubernetes/control-plane | Check which kube-control nodes are already members | 기존 클러스터 멤버 확인 |
| 324 | kubernetes/control-plane | Set fact first_kube_control_plane | 첫 번째 control-plane 노드 설정 |
| 325 | kubernetes/control-plane | Kubeadm | Check if kubeadm has already run | kubeadm 실행 여부 확인 |
| 326 | kubernetes/control-plane | Kubeadm | aggregate all SANs | 인증서 SAN 목록 집계 |
| 327 | kubernetes/control-plane | Kubeadm | Create kubeadm config | kubeadm 설정 파일 생성 |
| 328 | kubernetes/control-plane | Kubeadm | Initialize first control plane node (1st try) | kubeadm init 실행 |
| 329 | kubernetes/control-plane | Create kubeadm token for joining nodes with 24h expiration | join 토큰 생성 (24시간 만료) |
| 330 | kubernetes/control-plane | Set kubeadm_token | kubeadm_token 설정 |
| 331 | kubernetes/control-plane | Kubeadm | Join other control plane nodes | 다른 control-plane 노드 join |
| 332 | kubernetes/control-plane | Set kubeadm_discovery_address | kubeadm_discovery_address 설정 |
| 333 | kubernetes/control-plane | Upload certificates so they are fresh and not expired | 인증서 업로드 |
| 334 | kubernetes/control-plane | Parse certificate key if not set | 인증서 키 파싱 |
| 335 | kubernetes/control-plane | Wait for k8s apiserver | API 서버 대기 |
| 336 | kubernetes/control-plane | Check already run | 실행 완료 확인 |
| 337 | kubernetes/control-plane | Kubeadm | Remove taint for control plane node with node role | taint 제거 (필요시) |
| 338 | kubernetes/control-plane | Include kubeadm secondary server apiserver fixes | 보조 서버 apiserver 수정 |
| 339 | kubernetes/control-plane | Update server field in component kubeconfigs | 컴포넌트 kubeconfig server 필드 업데이트 |
| 340 | kubernetes/control-plane | Include kubelet client cert rotation fixes | kubelet 인증서 rotation 수정 |
| 341 | kubernetes/control-plane | Fixup kubelet client cert rotation 1/2 | rotation 수정 1/2 |
| 342 | kubernetes/control-plane | Fixup kubelet client cert rotation 2/2 | rotation 수정 2/2 |
| 343 | kubernetes/control-plane | Install script to renew K8S control plane certificates | 인증서 갱신 스크립트 설치 |
| 344 | kubernetes/control-plane | Renew K8S control plane certificates monthly 1/2 | 월간 인증서 갱신 1/2 |
| 345 | kubernetes/control-plane | Renew K8S control plane certificates monthly 2/2 | 월간 인증서 갱신 2/2 |
| 346 | kubernetes/client | Set external kube-apiserver endpoint | 외부 API 서버 엔드포인트 설정 |
| 347 | kubernetes/client | Create kube config dir | ~/.kube 디렉터리 생성 |
| 348 | kubernetes/client | Copy admin kubeconfig to user home | admin.conf를 ~/.kube/config로 복사 |
| 349 | kubernetes/client | Wait for k8s apiserver | API 서버 대기 |
| 350 | kubernetes-apps/cluster_roles | Kubernetes Apps | Wait for kube-apiserver | API 서버 대기 |
| 351 | kubernetes-apps/cluster_roles | Add ClusterRoleBinding to admit nodes | 노드 승인용 ClusterRoleBinding 추가 |
| 352 | kubernetes-apps/cluster_roles | Apply workaround to allow all nodes with cert O=system:nodes | 노드 등록 워크어라운드 |
| 353 | kubernetes-apps/cluster_roles | Remove old webhook ClusterRole | 이전 webhook ClusterRole 제거 |
| 354 | kubernetes-apps/cluster_roles | Remove old webhook ClusterRoleBinding | 이전 webhook ClusterRoleBinding 제거 |
| 355 | kubernetes-apps/cluster_roles | PriorityClass | Copy k8s-cluster-critical-pc.yml | PriorityClass 파일 복사 |
| 356 | kubernetes-apps/cluster_roles | PriorityClass | Create k8s-cluster-critical | PriorityClass 생성 |
PLAY 11: Invoke kubeadm and install a CNI
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 357 | kubernetes/kubeadm | Set kubeadm_discovery_address | discovery 주소 설정 |
| 358 | kubernetes/kubeadm | Check if kubelet.conf exists | kubelet.conf 존재 확인 |
| 359 | kubernetes/kubeadm | Check if kubeadm CA cert is accessible | kubeadm CA 인증서 접근 확인 |
| 360 | kubernetes/kubeadm | Fetch CA certificate from control plane node | CA 인증서 가져오기 |
| 361 | kubernetes/kubeadm | Check if discovery kubeconfig exists | discovery kubeconfig 존재 확인 |
| 362 | kubernetes/kubeadm | Get current resourceVersion of kube-proxy configmap | kube-proxy configmap resourceVersion |
| 363 | kubernetes/kubeadm | Update server field in kube-proxy kubeconfig | kube-proxy kubeconfig server 필드 업데이트 |
| 364 | kubernetes/kubeadm | Get new resourceVersion of kube-proxy configmap | 새 resourceVersion 확인 |
| 365 | kubernetes/kubeadm | Set ca.crt file permission | ca.crt 파일 권한 설정 |
| 366 | kubernetes/kubeadm | Restart all kube-proxy pods | kube-proxy pod 재시작 |
| 367 | kubernetes/node-label | Kubernetes Apps | Wait for kube-apiserver | API 서버 대기 |
| 368 | kubernetes/node-label | Set role node label to empty list | role 노드 레이블 초기화 |
| 369 | kubernetes/node-label | Set inventory node label to empty list | inventory 노드 레이블 초기화 |
| 370 | kubernetes/node-taint | Set role and inventory node taint to empty list | taint 초기화 |
| 371 | network_plugin/cni | CNI | make sure /opt/cni/bin exists | /opt/cni/bin 존재 확인 |
| 372 | network_plugin/cni | CNI | Copy cni plugins | CNI 플러그인 복사 |
| 373 | network_plugin/flannel | Flannel | Create Flannel manifests | Flannel 매니페스트 생성 |
| 374 | network_plugin/flannel | Flannel | Start Resources | Flannel DaemonSet 배포 |
| 375 | network_plugin/flannel | Flannel | Wait for flannel subnet.env file presence | subnet.env 파일 대기 |
E. 부가 서비스 설치 (Apps & DNS)
Ingress Controller, Storage Provisioner 등 클러스터 운영에 필요한 앱들을 배포하고, 최종적으로 노드의 DNS가 클러스터 내부 DNS를 바라보도록 수정한다.
호출 구조
- name: Install Calico Route Reflector
hosts: calico_rr
roles:
- { role: network_plugin/calico/rr, tags: ['network', 'calico_rr'] }
- name: Patch Kubernetes for Windows
hosts: kube_control_plane[0]
roles:
- { role: win_nodes/kubernetes_patch, tags: ["control-plane", "win_nodes"] }
- name: Install Kubernetes apps
hosts: kube_control_plane
roles:
- { role: kubespray_defaults }
- { role: kubernetes-apps/external_cloud_controller, tags: external-cloud-controller }
- { role: kubernetes-apps/policy_controller, tags: policy-controller }
- { role: kubernetes-apps/ingress_controller, tags: ingress-controller }
- { role: kubernetes-apps/external_provisioner, tags: external-provisioner }
- { role: kubernetes-apps, tags: apps }
- name: Apply resolv.conf changes now that cluster DNS is up
hosts: k8s_cluster
roles:
- { role: kubespray_defaults }
- { role: kubernetes/preinstall, when: "dns_mode != 'none' and resolvconf_mode == 'host_resolvconf'", tags: resolvconf, dns_late: true }
PLAY 12: Install Calico Route Reflector
Calico BGP 미사용 환경이면 skip된다.
PLAY 13: Patch Kubernetes for Windows
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 376 | win_nodes/kubernetes_patch | Ensure that user manifests directory exists | 사용자 매니페스트 디렉터리 확인 |
| 377 | win_nodes/kubernetes_patch | Check current nodeselector for kube-proxy daemonset | kube-proxy nodeselector 확인 |
| 378 | win_nodes/kubernetes_patch | Apply nodeselector patch for kube-proxy daemonset | nodeselector 패치 적용 |
Linux-only 환경이면 skip된다.
PLAY 14: Install Kubernetes apps
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 379 | kubernetes-apps/ansible | Kubernetes Apps | Wait for kube-apiserver | API 서버 대기 |
| 380 | kubernetes-apps/ansible | Kubernetes Apps | CoreDNS | CoreDNS 배포 |
| 381 | kubernetes-apps/helm | Helm | Gather os specific variables | OS별 변수 수집 |
| 382 | kubernetes-apps/helm | Helm | Install PyYaml | PyYaml 설치 |
| 383 | kubernetes-apps/helm | Helm | Download helm | helm 다운로드 |
| 384 | kubernetes-apps/helm | Prep_download | Set a few facts | 다운로드 준비 |
| 385 | kubernetes-apps/helm | Download_file | Download item | helm 다운로드 |
| 386 | kubernetes-apps/helm | Extract_file | Unpacking archive | 아카이브 압축 해제 |
| 387 | kubernetes-apps/helm | Helm | Copy helm binary from download dir | helm 설치 |
| 388 | kubernetes-apps/helm | Helm | Get helm completion | helm completion 가져오기 |
| 389 | kubernetes-apps/helm | Helm | Install helm completion | helm 자동완성 설치 |
| 390 | kubernetes-apps/metrics_server | Metrics Server | Delete addon dir | 애드온 디렉터리 삭제 |
| 391 | kubernetes-apps/metrics_server | Metrics Server | Create addon dir | 애드온 디렉터리 생성 |
| 392 | kubernetes-apps/metrics_server | Metrics Server | Templates list | 템플릿 목록 |
| 393 | kubernetes-apps/metrics_server | Metrics Server | Create manifests | 매니페스트 생성 |
| 394 | kubernetes-apps/metrics_server | Metrics Server | Apply manifests | metrics-server 배포 |
kubernetes-apps Role별 기능
| Role | 기능 | 설명 |
|---|
| external_cloud_controller | 클라우드 컨트롤러 | cloud-controller-manager 외부 실행 (베어메탈은 비활성) |
| policy_controller | 정책 컨트롤러 | PodSecurity Admission, OPA/Gatekeeper 연계 |
| ingress_controller | Ingress 컨트롤러 | NGINX Ingress, HAProxy Ingress, Traefik 등 |
| external_provisioner | 스토리지 프로비저너 | CSI provisioner, NFS provisioner, Ceph 등 |
| kubernetes-apps | 핵심 앱 | CoreDNS, Metrics Server, Local Path Provisioner, Helm |
PLAY 15: Apply resolv.conf changes now that cluster DNS is up
| 순번 | Role | TASK 이름 | 설명 |
|---|
| 395 | adduser | User | Create User Group | 사용자 그룹 생성 |
| 396 | adduser | User | Create User | 사용자 생성 |
| 397 | kubernetes/preinstall | Check resolvconf | resolvconf 확인 |
| 398 | kubernetes/preinstall | Check existence of /etc/resolvconf/resolv.conf.d | 디렉터리 존재 확인 |
| 399 | kubernetes/preinstall | Check status of /etc/resolv.conf | resolv.conf 상태 확인 |
| 400 | kubernetes/preinstall | Fetch resolv.conf | resolv.conf 가져오기 |
| 401 | kubernetes/preinstall | NetworkManager | Check if host has NetworkManager | NetworkManager 확인 |
| 402 | kubernetes/preinstall | Check systemd-resolved | systemd-resolved 확인 |
| 403 | kubernetes/preinstall | Set default dns | 기본 DNS 설정 |
| 404 | kubernetes/preinstall | Set dns facts | DNS fact 설정 |
| 405 | kubernetes/preinstall | Check if kubelet is configured | kubelet 설정 확인 |
| 406 | kubernetes/preinstall | Check if early DNS configuration stage | DNS 설정 단계 확인 |
| 407 | kubernetes/preinstall | Target resolv.conf files | resolv.conf 대상 지정 |
| 408 | kubernetes/preinstall | NetworkManager | Ensure NetworkManager conf.d dir | conf.d 디렉터리 확인 |
| 409 | kubernetes/preinstall | NetworkManager | Prevent NetworkManager from managing K8S interfaces | K8s 인터페이스 관리 방지 |
| 410 | kubernetes/preinstall | NetworkManager | Add nameservers to NM configuration | CoreDNS IP를 nameserver로 추가 |
| 411 | kubernetes/preinstall | NetworkManager | Add DNS search to NM configuration | 클러스터 도메인을 search에 추가 |
| 412 | kubernetes/preinstall | NetworkManager | Add DNS options to NM configuration | DNS 옵션 추가 |
Role별 TASK 수 분포
| Role | TASK 수 (대략) | 단계 | 주요 기능 |
|---|
| download | ~150 | B | 바이너리/이미지 다운로드 (가장 많음) |
| kubernetes/preinstall | ~50 | A, B, E | 시스템 사전 설정, swap, sysctl |
| container-engine/* | ~55 | B | containerd, runc, crictl, nerdctl |
| etcd | ~55 | C | etcd 인증서 생성, 클러스터 구성 |
| kubernetes/control-plane | ~30 | D | kubeadm init, control-plane 구성 |
| kubernetes/node | ~15 | C | kubelet 설치, br_netfilter |
| kubernetes/kubeadm | ~12 | D | worker join, kube-proxy 설정 |
| network_plugin/* | ~8 | D | CNI 플러그인 (Flannel/Calico) |
| kubernetes-apps/* | ~20 | E | CoreDNS, metrics-server, Helm |
| validate_inventory | ~13 | A | inventory 검증 |
| bootstrap_os | ~12 | A | OS 부트스트랩 |
| adduser | ~8 | A, C, E | 사용자/그룹 생성 |
정리
Kubespray는 559개의 TASK를 14개 PLAY로 구조화하여 실행한다.
핵심 포인트:
- download Role이 가장 많은 TASK 차지 - 바이너리와 컨테이너 이미지 다운로드가 핵심
- 검증 TASK가 많음 - 설치 실패를 사전에 방지하기 위한 철저한 검증
- 멱등성 보장 - 동일 TASK 반복 실행해도 결과 동일하도록 설계
- 조건부 실행 - bastion, Windows, Calico 등 환경에 따라 skip 처리
각 단계의 Role과 TASK를 이해하면 설치 실패 시 로그에서 문제 지점을 빠르게 파악할 수 있다.