GitHub 공식 레포지토리(https://github.com/kubernetes-sigs/kubespray) 에서 kubespray 를 아래와 같이 요약하고 있습니다.
Deploy a Production Ready Kubernetes Cluster
그래서 kubespray 는 "kubespray는 Ansible 기반으로 쿠버네티스(Kubernetes) 클러스터를 자동으로 설치·업그레이드·관리하기 위한 오픈소스 배포 도구" 로 요약할 수 있습니다.
내부적으로는 Ansible playbook 으로 구성되어 있고 이번 블로그에서는 playbook 을 분석해 보겠습니다.
특히 폐쇄망(Air-Gap) 환경에서 K8S 클러스터 설치에 kubespray를 이용하면 효과적입니다.

kubespray 를 이용하여 K8S 클러스터 생성 부터 운영 전반을 지원할 수 있습니다.
- 신규 클러스터 생성
- (컨트롤 플레인) 클러스터 업그레이드
- 클러스터 스케일링
- 노드 관리 - 노드 추가, 노드 제거
- 클러스터 재설정
- 설정 관리
- 백업/복구, 업그레이드 시 etcd 스냅샷 수행
kubespray 설치 사전 요건
- Ansible v2.14+, Jinja 2.11+ and python-netaddr is installed on the machine that will run Ansible commands
- Ansible 2.17.3 이상 & Python 3.10 ~ 3.12
- Spec : Control Plane (Memory 2 GB), Worker Node (Memory 1 GB)
- Linux Kernel Requirements : 5.8+ 이상 권장
- Rocky Linux [9, 10](experimental in 10: see [Rocky Linux 10 notes]
실습환경 배포
| # 실습용 디렉터리 생성 mkdir k8s-kubespary cd k8s-kubespary # 파일 다운로드 https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/k8s-kubespary/Vagrantfile https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/k8s-kubespary/init_cfg.sh # 실습 환경 배포 vagrant up vagrant status |
참고) Vagrantfile, init_cfg.sh
Vagrantfile
# Base Image https://portal.cloud.hashicorp.com/vagrant/discover/bento/rockylinux-10.0
BOX_IMAGE = "bento/rockylinux-10.0"
BOX_VERSION = "202510.26.0"
Vagrant.configure("2") do |config|
# ControlPlane Nodes
config.vm.define "k8s-ctr" do |subconfig|
subconfig.vm.box = BOX_IMAGE
subconfig.vm.box_version = BOX_VERSION
subconfig.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--groups", "/Kubespray-Lab"]
vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"]
vb.name = "k8s-ctr"
vb.cpus = 4
vb.memory = 4096
vb.linked_clone = true
end
subconfig.vm.host_name = "k8s-ctr"
subconfig.vm.network "private_network", ip: "192.168.10.10"
subconfig.vm.network "forwarded_port", guest: 22, host: "60100", auto_correct: true, id: "ssh"
subconfig.vm.synced_folder "./", "/vagrant", disabled: true
subconfig.vm.provision "shell", path: "init_cfg.sh"
end
end
init_cfg.sh
#!/usr/bin/env bash
echo ">>>> Initial Config Start <<<<"
echo "[TASK 1] Change Timezone and Enable NTP"
timedatectl set-local-rtc 0
timedatectl set-timezone Asia/Seoul
echo "[TASK 2] Disable firewalld and selinux"
systemctl disable --now firewalld >/dev/null 2>&1
setenforce 0
sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config
echo "[TASK 3] Disable and turn off SWAP & Delete swap partitions"
swapoff -a
sed -i '/swap/d' /etc/fstab
sfdisk --delete /dev/sda 2 >/dev/null 2>&1
partprobe /dev/sda >/dev/null 2>&1
echo "[TASK 4] Config kernel & module"
cat << EOF > /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
modprobe overlay >/dev/null 2>&1
modprobe br_netfilter >/dev/null 2>&1
cat << EOF >/etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system >/dev/null 2>&1
echo "[TASK 5] Setting Local DNS Using Hosts file"
sed -i '/^127\.0\.\(1\|2\)\.1/d' /etc/hosts
cat << EOF >> /etc/hosts
192.168.10.10 k8s-ctr
EOF
echo "[TASK 6] Delete default routing - enp0s9 NIC" # setenforce 0 설정 필요
nmcli connection modify enp0s9 ipv4.never-default yes
nmcli connection up enp0s9 >/dev/null 2>&1
echo "sudo su -" >> /home/vagrant/.bashrc
echo ">>>> Initial Config End <<<<"
사전 설정 수행 & kubespray git clone
"vagrant ssh" 명령을 수행한 후 아래 초기 작업(kubespray 사전조건)을 진행합니다.
| # Linux Kernel Requirements : 5.8+ 이상 권장 uname -a Linux k8s-ctr 6.12.0-55.39.1.el10_0.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Oct 15 14:24:00 UTC 2025 x86_64 GNU/Linux # Python : 3.10 ~ 3.12 : (참고) bento/rockylinux-9 경우 3.9 which python && python -V which python3 && python3 -V 3.12.9 # pip , git 설치 dnf install -y python3-pip git which pip && pip -V which pip3 && pip3 -V pip 23.3.2 from /usr/lib/python3.12/site-packages/pip (python 3.12) # /etc/hosts 확인 ip -br -c -4 addr lo UNKNOWN 127.0.0.1/8 enp0s3 UP 10.0.2.15/24 enp0s8 UP 192.168.10.10/24 cat /etc/hosts # Loopback entries; do not change. # For historical reasons, localhost precedes localhost.localdomain: 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 # See hosts(5) for proper format and other examples: # 192.168.1.10 foo.example.org foo # 192.168.1.13 bar.example.org bar 192.168.10.10 k8s-ctr # SSH 접속을 위한 설정 <-- ansible 을 이용하렴 ssh 접속이 가능해야 함 echo "root:qwe123" | chpasswd cat << EOF >> /etc/ssh/sshd_config PermitRootLogin yes PasswordAuthentication yes EOF systemctl restart sshd # Setting SSH Key ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa # ssh-copy-id ssh-copy-id -o StrictHostKeyChecking=no root@192.168.10.10 root@192.168.10.10's password: qwe123 # ssh 접속 확인 : IP, hostname ssh root@192.168.10.10 hostname ssh -o StrictHostKeyChecking=no root@k8s-ctr hostname ssh root@k8s-ctr hostname k8s-ctr # Clone Kubespray Repository git clone -b v2.29.1 https://github.com/kubernetes-sigs/kubespray.git /root/kubespray cd /root/kubespray # (옵션) IDE에서 VM SSH 접속(root/qwe123)해서 편집 창 열기 ![]() ![]() # 최상단 plybook 확인 -> 각각 import_playbook 확인 ls -l *.yml -rw-r--r--. 1 root root 88 Jan 24 20:55 cluster.yml # ansible.builtin.import_playbook: playbooks/cluster.yml -rw-r--r--. 1 root root 30 Jan 24 20:55 _config.yml -rw-r--r--. 1 root root 747 Jan 24 20:55 galaxy.yml -rw-r--r--. 1 root root 105 Jan 24 20:55 recover-control-plane.yml -rw-r--r--. 1 root root 85 Jan 24 20:55 remove-node.yml -rw-r--r--. 1 root root 85 Jan 24 20:55 remove_node.yml -rw-r--r--. 1 root root 85 Jan 24 20:55 reset.yml -rw-r--r--. 1 root root 85 Jan 24 20:55 scale.yml # ansible.builtin.import_playbook: playbooks/scale.yml -rw-r--r--. 1 root root 93 Jan 24 20:55 upgrade-cluster.yml -rw-r--r--. 1 root root 93 Jan 24 20:55 upgrade_cluster.yml ![]() # tree -L 2 ... ├── inventory │ ├── local │ └── sample ... ├── playbooks │ ├── ansible_version.yml │ ├── boilerplate.yml │ ├── cluster.yml* │ ├── facts.yml │ ├── install_etcd.yml │ ├── internal_facts.yml │ ├── recover_control_plane.yml │ ├── remove_node.yml │ ├── reset.yml │ ├── scale.yml │ └── upgrade_cluster.yml ... ├── roles │ ├── adduser │ ├── bastion-ssh-config │ ├── bootstrap-os │ ├── bootstrap_os │ ├── container-engine │ ├── download │ ├── dynamic_groups │ ├── etcd │ ├── etcdctl_etcdutl │ ├── etcd_defaults │ ├── helm-apps │ ├── kubernetes │ ├── kubernetes-apps │ ├── kubespray-defaults │ ├── kubespray_defaults │ ├── network_facts │ ├── network_plugin │ ├── recover_control_plane │ ├── remove-node │ ├── remove_node │ ├── reset │ ├── system_packages │ ├── upgrade │ ├── validate_inventory │ └── win_nodes ... # Install Python Dependencies cat requirements.txt ansible==10.7.0 # Needed for community.crypto module cryptography==46.0.3 # Needed for jinja2 json_query templating jmespath==1.0.1 # Needed for ansible.utils.ipaddr netaddr==1.3.0 pip3 install -r /root/kubespray/requirements.txt Successfully installed MarkupSafe-3.0.3 ansible-10.7.0 ansible-core-2.17.14 cffi-2.0.0 cryptography-46.0.2 jinja2-3.1.6 jmespath-1.0.1 netaddr-1.3.0 pycparser-3.0 resolvelib-1.0.1 # ansible 버전 확인 : Ansible 2.17.3 이상 which ansible ansible --version ansible [core 2.17.14] config file = /root/kubespray/ansible.cfg ... python version = 3.12.9 (main, Aug 14 2025, 00:00:00) [GCC 14.2.1 20250110 (Red Hat 14.2.1-7)] (/usr/bin/python3) jinja version = 3.1.6 libyaml = True # pip list 확인 pip list Package Version ------------------------- ----------- ansible 10.7.0 ansible-core 2.17.14 ... Jinja2 3.1.6 jmespath 1.0.1 ... netaddr 1.3.0 ... # 해당 폴더에서 ansible-playbook 실행 시 적용되는 ansible.cfg --> k8s 를 관리하는 편리한 옵션 설정이 들어가 있음 cat ansible.cfg [ssh_connection] # 통신 속도 및 안정성 최적화 pipelining=True # SSH 세션을 여러 번 열지 않고 하나의 세션에서 여러 명령을 한꺼번에 실행 ssh_args = -o ControlMaster=auto -o ControlPersist=30m -o ConnectionAttempts=100 -o UserKnownHostsFile=/dev/null ## ControlMaster=auto -o ControlPersist=30m: 한 번 연결된 SSH 커넥션을 30분 동안 유지합니다. 매번 로그인할 필요가 없어 성능이 향상됩니다. ## ConnectionAttempts=100: 네트워크 불안정으로 연결 실패 시 100번까지 재시도합니다. ## UserKnownHostsFile=/dev/null: 접속 대상의 지문(fingerprint)을 저장하지 않아 관리가 편해집니다. #control_path = ~/.ssh/ansible-%%r@%%h:%%p [defaults] # https://github.com/ansible/ansible/issues/56930 (to ignore group names with - and .) force_valid_group_names = ignore # Ansible은 원래 그룹 이름에 -나 . 사용을 제한하지만, 쿠버네티스 리소스 명칭 규칙상 이를 허용하도록 설정 host_key_checking=False # 새 서버 접속 시 "Are you sure you want to continue connecting?"이라는 확인 창이 뜨지 않게 합니다. gathering = smart # 대상 서버의 정보(Fact)를 한 번만 수집하고 /tmp에 JSON 파일로 저장합니다. (아래 설명 이어서) fact_caching = jsonfile # 재실행 시 서버 정보를 다시 수집하지 않아 시간이 단축됩니다. 86400(24시간) 동안 캐시를 유지합니다. fact_caching_connection = /tmp fact_caching_timeout = 86400 timeout = 300 stdout_callback = default display_skipped_hosts = no library = ./library callbacks_enabled = profile_tasks # 각 Task가 실행되는 데 걸리는 시간을 표시해 줍니다. 어떤 단계에서 병목이 생기는지 확인할 때 매우 유용합니다. roles_path = roles:$VIRTUAL_ENV/usr/local/share/kubespray/roles:$VIRTUAL_ENV/usr/local/share/ansible/roles:/usr/share/kubespray/roles deprecation_warnings=False inventory_ignore_extensions = ~, .orig, .bak, .ini, .cfg, .retry, .pyc, .pyo, .creds, .gpg # 백업용이나 임시 파일을 인벤토리로 인식하여 에러가 발생하는 것을 방지합니다. [inventory] ignore_patterns = artifacts, credentials # 배포 결과물(artifacts)이나 중요 정보(credentials) 폴더 내의 파일을 인벤토리 스캔 대상에서 제외합니다. |
Kubespary 를 통한 k8s 배포 (5분 정도 소요) : 목표 환경을 위한 파라미터 설정
- [Variables](https://github.com/kubernetes-sigs/kubespray/blob/master/docs/ansible/vars.md)
kubespray 를 이용하여 Rocky Linux 9 버전의 1대의 머신에 k8s 클러스터를 생성해 보겠습니다.
| # inventory 디렉터리 복사 cp -rfp /root/kubespray/inventory/sample /root/kubespray/inventory/mycluster tree inventory/mycluster/ inventory/mycluster/ ├── group_vars │ ├── all │ │ ├── all.yml │ │ ├── aws.yml │ │ ├── azure.yml │ │ ├── containerd.yml │ │ ├── coreos.yml │ │ ├── cri-o.yml │ │ ├── docker.yml │ │ ├── etcd.yml │ │ ├── gcp.yml │ │ ├── hcloud.yml │ │ ├── huaweicloud.yml │ │ ├── oci.yml │ │ ├── offline.yml │ │ ├── openstack.yml │ │ ├── upcloud.yml │ │ └── vsphere.yml │ └── k8s_cluster │ ├── addons.yml │ ├── k8s-cluster.yml │ ├── k8s-net-calico.yml │ ├── k8s-net-cilium.yml │ ├── k8s-net-custom-cni.yml │ ├── k8s-net-flannel.yml │ ├── k8s-net-kube-ovn.yml │ ├── k8s-net-kube-router.yml │ ├── k8s-net-macvlan.yml │ └── kube_control_plane.yml └── inventory.ini # inventory.ini 작성 cat << EOF > /root/kubespray/inventory/mycluster/inventory.ini k8s-ctr ansible_host=192.168.10.10 ip=192.168.10.10 [kube_control_plane] k8s-ctr [etcd:children] kube_control_plane [kube_node] k8s-ctr EOF # https://github.com/kubernetes-sigs/kubespray/blob/master/docs/ansible/vars.md ## <your-favorite-editor> inventory/mycluster/group_vars/all.yml # for every node, including etcd grep "^[^#]" inventory/mycluster/group_vars/all/all.yml --- bin_dir: /usr/local/bin loadbalancer_apiserver_port: 6443 loadbalancer_apiserver_healthcheck_port: 8081 no_proxy_exclude_workers: false kube_webhook_token_auth: false kube_webhook_token_auth_url_skip_tls_verify: false ntp_enabled: false ntp_manage_config: false ntp_servers: - "0.pool.ntp.org iburst" - "1.pool.ntp.org iburst" - "2.pool.ntp.org iburst" - "3.pool.ntp.org iburst" unsafe_show_logs: false allow_unsupported_distribution_setup: false ## <your-favorite-editor> inventory/mycluster/group_vars/k8s_cluster.yml # for every node in the cluster (not etcd when it's separate) grep "^[^#]" inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml --- kube_config_dir: /etc/kubernetes kube_script_dir: "{{ bin_dir }}/kubernetes-scripts" kube_manifest_dir: "{{ kube_config_dir }}/manifests" kube_cert_dir: "{{ kube_config_dir }}/ssl" kube_token_dir: "{{ kube_config_dir }}/tokens" kube_api_anonymous_auth: true local_release_dir: "/tmp/releases" retry_stagger: 5 kube_owner: kube kube_cert_group: kube-cert kube_log_level: 2 credentials_dir: "{{ inventory_dir }}/credentials" kube_network_plugin: calico kube_network_plugin_multus: false kube_service_addresses: 10.233.0.0/18 kube_pods_subnet: 10.233.64.0/18 kube_network_node_prefix: 24 kube_service_addresses_ipv6: fd85:ee78:d8a6:8607::1000/116 kube_pods_subnet_ipv6: fd85:ee78:d8a6:8607::1:0000/112 kube_network_node_prefix_ipv6: 120 kube_apiserver_ip: "{{ kube_service_subnets.split(',') | first | ansible.utils.ipaddr('net') | ansible.utils.ipaddr(1) | ansible.utils.ipaddr('address') }}" kube_apiserver_port: 6443 # (https) kube_proxy_mode: ipvs kube_proxy_strict_arp: false kube_proxy_nodeport_addresses: >- {%- if kube_proxy_nodeport_addresses_cidr is defined -%} [{{ kube_proxy_nodeport_addresses_cidr }}] {%- else -%} [] {%- endif -%} kube_encrypt_secret_data: false cluster_name: cluster.local ndots: 2 dns_mode: coredns enable_nodelocaldns: true enable_nodelocaldns_secondary: false nodelocaldns_ip: 169.254.25.10 nodelocaldns_health_port: 9254 nodelocaldns_second_health_port: 9256 nodelocaldns_bind_metrics_host_ip: false nodelocaldns_secondary_skew_seconds: 5 enable_coredns_k8s_external: false coredns_k8s_external_zone: k8s_external.local enable_coredns_k8s_endpoint_pod_names: false resolvconf_mode: host_resolvconf deploy_netchecker: false skydns_server: "{{ kube_service_subnets.split(',') | first | ansible.utils.ipaddr('net') | ansible.utils.ipaddr(3) | ansible.utils.ipaddr('address') }}" skydns_server_secondary: "{{ kube_service_subnets.split(',') | first | ansible.utils.ipaddr('net') | ansible.utils.ipaddr(4) | ansible.utils.ipaddr('address') }}" dns_domain: "{{ cluster_name }}" container_manager: containerd kata_containers_enabled: false kubeadm_certificate_key: "{{ lookup('password', credentials_dir + '/kubeadm_certificate_key.creds length=64 chars=hexdigits') | lower }}" k8s_image_pull_policy: IfNotPresent kubernetes_audit: false default_kubelet_config_dir: "{{ kube_config_dir }}/dynamic_kubelet_dir" volume_cross_zone_attachment: false persistent_volumes_enabled: false event_ttl_duration: "1h0m0s" auto_renew_certificates: false # auto_renew_certificates_systemd_calendar: "Mon *-*-1,2,3,4,5,6,7 03:00:00" # First Monday of each month kubeadm_patches_dir: "{{ kube_config_dir }}/patches" kubeadm_patches: [] remove_anonymous_access: false # 테스트할 기능 관련 수정 sed -i 's|kube_network_plugin: calico|kube_network_plugin: flannel|g' inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml sed -i 's|kube_proxy_mode: ipvs|kube_proxy_mode: iptables|g' inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml sed -i 's|enable_nodelocaldns: true|enable_nodelocaldns: false|g' inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml sed -i 's|auto_renew_certificates: false|auto_renew_certificates: true|g' inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml sed -i 's|# auto_renew_certificates_systemd_calendar|auto_renew_certificates_systemd_calendar|g' inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml grep -iE 'kube_network_plugin:|kube_proxy_mode|enable_nodelocaldns:|^auto_renew_certificates' inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml ## flannel 설정 수정 inventory/mycluster/group_vars/k8s_cluster/k8s-net-flannel.yml cat inventory/mycluster/group_vars/k8s_cluster/k8s-net-flannel.yml echo "flannel_interface: enp0s9" >> inventory/mycluster/group_vars/k8s_cluster/k8s-net-flannel.yml grep "^[^#]" inventory/mycluster/group_vars/k8s_cluster/k8s-net-flannel.yml ## <your-favorite-editor> inventory/mycluster/group_vars/kube_control_plane.yml # for the control plane cat inventory/mycluster/group_vars/k8s_cluster/kube_control_plane.yml # Reservation for control plane kubernetes components # kube_memory_reserved: 512Mi # kube_cpu_reserved: 200m # kube_ephemeral_storage_reserved: 2Gi # kube_pid_reserved: "1000" # Reservation for control plane host system # system_memory_reserved: 256Mi # system_cpu_reserved: 250m # system_ephemeral_storage_reserved: 2Gi # system_pid_reserved: "1000" ## <your-favorite-editor> addons.yml grep "^[^#]" inventory/mycluster/group_vars/k8s_cluster/addons.yml --- helm_enabled: false registry_enabled: false metrics_server_enabled: false local_path_provisioner_enabled: false local_volume_provisioner_enabled: false gateway_api_enabled: false ingress_nginx_enabled: false ingress_publish_status_address: "" ingress_alb_enabled: false cert_manager_enabled: false metallb_enabled: false metallb_speaker_enabled: "{{ metallb_enabled }}" metallb_namespace: "metallb-system" argocd_enabled: false kube_vip_enabled: false node_feature_discovery_enabled: false # 테스트할 기능 관련 수정 sed -i 's|helm_enabled: false|helm_enabled: true|g' inventory/mycluster/group_vars/k8s_cluster/addons.yml sed -i 's|metrics_server_enabled: false|metrics_server_enabled: true|g' inventory/mycluster/group_vars/k8s_cluster/addons.yml sed -i 's|node_feature_discovery_enabled: false|node_feature_discovery_enabled: true|g' inventory/mycluster/group_vars/k8s_cluster/addons.yml grep -iE 'helm_enabled:|metrics_server_enabled:|node_feature_discovery_enabled:' inventory/mycluster/group_vars/k8s_cluster/addons.yml # etcd.yml : 파드가 아닌 systemd unit grep "^[^#]" inventory/mycluster/group_vars/all/etcd.yml --- etcd_data_dir: /var/lib/etcd etcd_deployment_type: host # containerd.yml cat inventory/mycluster/group_vars/all/containerd.yml --- # Please see roles/container-engine/containerd/defaults/main.yml for more configuration options # containerd_storage_dir: "/var/lib/containerd" # containerd_state_dir: "/run/containerd" # containerd_oom_score: 0 # containerd_default_runtime: "runc" # containerd_snapshotter: "native" # containerd_runc_runtime: # name: runc # type: "io.containerd.runc.v2" # engine: "" ...(생략)... # 기본 환경 정보 출력 저장 ip addr | tee -a ip_addr-1.txt ss -tnlp | tee -a ss-1.txt df -hT | tee -a df-1.txt findmnt | tee -a findmnt-1.txt sysctl -a | tee -a sysctl-1.txt # 지원 버전 정보 확인 cat roles/kubespray_defaults/vars/main/checksums.yml | grep -i kube -A40 # 배포: 아래처럼 반드시 ~/kubespray 디렉토리에서 ansible-playbook 를 실행하자! # Deploy Kubespray with Ansible Playbook - run the playbook as root # The option `--become` is required, as for example writing SSL keys in /etc/, # installing packages and interacting with various systemd daemons. # ansible-playbook -i inventory/mycluster/inventory.ini -v cluster.yml -e kube_version="1.33.3" --list-tasks # 배포 전, Task 목록 확인 ANSIBLE_FORCE_COLOR=true ansible-playbook -i inventory/mycluster/inventory.ini -v cluster.yml -e kube_version="1.33.3" | tee kubespray_install.log ~~~(약 5분정도 소요)~~~ Saturday 31 January 2026 13:24:42 +0900 (0:10:01.288) 0:19:21.856 ****** =============================================================================== network_plugin/flannel : Flannel | Wait for flannel subnet.env file presence - 601.29s download : Download_container | Download image if required ------------- 20.24s download : Download_file | Download item ------------------------------- 17.08s kubernetes/control-plane : Kubeadm | Initialize first control plane node (1st try) -- 16.16s download : Download_container | Download image if required ------------- 13.97s container-engine/containerd : Download_file | Download item ------------ 12.91s download : Download_container | Download image if required ------------- 11.99s download : Download_container | Download image if required ------------- 11.85s container-engine/crictl : Download_file | Download item ---------------- 10.88s download : Download_file | Download item ------------------------------- 10.32s system_packages : Manage packages --------------------------------------- 9.99s container-engine/runc : Download_file | Download item ------------------- 9.20s container-engine/nerdctl : Download_file | Download item ---------------- 9.15s download : Download_container | Download image if required -------------- 8.59s etcdctl_etcdutl : Download_file | Download item ------------------------- 8.13s download : Download_container | Download image if required -------------- 7.96s etcd : Restart etcd ----------------------------------------------------- 7.73s download : Download_container | Download image if required -------------- 7.65s download : Download_file | Download item -------------------------------- 7.57s container-engine/crictl : Extract_file | Unpacking archive -------------- 7.51s # 설치 확인 : /root/.kube/config more kubespray_install.log kubectl get node -v=6 I0131 13:37:03.125332 32893 loader.go:402] Config loaded from file: /root/.kube/config I0131 13:37:03.126005 32893 envvar.go:172] "Feature gate default state" feature="InformerResourceVersion" enabled=false I0131 13:37:03.126029 32893 envvar.go:172] "Feature gate default state" feature="InOrderInformers" enabled=true I0131 13:37:03.126036 32893 envvar.go:172] "Feature gate default state" feature="WatchListClient" enabled=false I0131 13:37:03.126042 32893 envvar.go:172] "Feature gate default state" feature="ClientsAllowCBOR" enabled=false I0131 13:37:03.126052 32893 envvar.go:172] "Feature gate default state" feature="ClientsPreferCBOR" enabled=false I0131 13:37:03.149892 32893 round_trippers.go:632] "Response" verb="GET" url="https://127.0.0.1:6443/api/v1/nodes?limit=500" status="200 OK" milliseconds=12 NAME STATUS ROLES AGE VERSION k8s-ctr Ready control-plane 23m v1.33.3 cat /root/.kube/config kubectl config view apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://127.0.0.1:6443 name: cluster.local contexts: - context: cluster: cluster.local user: kubernetes-admin name: kubernetes-admin@cluster.local current-context: kubernetes-admin@cluster.local kind: Config preferences: {} users: - name: kubernetes-admin user: client-certificate-data: DATA+OMITTED client-key-data: DATA+OMITTED # k8s kubectl get node -owide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME k8s-ctr Ready control-plane 24m v1.33.3 192.168.10.10 <none> Rocky Linux 10.0 (Red Quartz) 6.12.0-55.39.1.el10_0.x86_64 containerd://2.1.5 kubectl get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system kube-apiserver-k8s-ctr 1/1 Running 0 24m ...(생략)... # 기본 환경 정보 출력 저장 ip addr | tee -a ip_addr-2.txt ss -tnlp | tee -a ss-2.txt df -hT | tee -a df-2.txt findmnt | tee -a findmnt-2.txt sysctl -a | tee -a sysctl-2.txt # 파일 출력 비교 : 빠져나오기 ':q' -> ':q' => 변경된 부분이 어떤 동작과 역할인지 조사해보기! , ctrl + f / b vi -d ip_addr-1.txt ip_addr-2.txt ![]() vi -d ss-1.txt ss-2.txt ![]() vi -d df-1.txt df-2.txt ![]() vi -d findmnt-1.txt findmnt-2.txt ![]() vi -d sysctl-1.txt sysctl-2.txt ![]() |
위 결과를 보듯이 kubespray 를 이용하면 클러스터 구서이 간편하며 이때 변경하고자 하는 부분의 변수만 설정하면 됩니다.
주로 사용하는 변수 목록은 아래 링크를 참고하세요
- Configurable Parameters in Kubespray
Ansible Playbook & Role 분석
루트에 있는 cluster.yml --> playbooks/cluster.yml 에 있는 TASK 구조는

- "사전 검증 → 접근/부트스트랩 → etcd → node → control-plane → CNI → 애드온" 절차를 거칩니다.

PLAY 과정을 좀더 상세히 살펴보겠습니다.
| cat kubespray_install.log | grep -E 'PLAY' PLAY [Check Ansible version] ****************************** # Kubespray가 지원하는 Ansible 버전인지 확인 PLAY [Inventory setup and validation] ********************* # inventory 설정 정합성 검증 : kube_control_plane, etcd 그룹 존재 여부, etcd 노드 수 (odd 권장), Pod CIDR / Service CIDR 유효성, Kubernetes 버전 지원 여부 PLAY [Install bastion ssh config] ************************* # Bastion(점프 호스트) 환경 지원 : bastion 미사용 시 대부분 skip PLAY [Bootstrap hosts for Ansible] ************************ # 모든 노드를 Ansible 실행 가능한 상태로 만듦 : Python 설치, sudo 권한 확보, 기본 패키지 설치, /usr/bin/python 보장 PLAY [Gather facts] *************************************** # Ansible fact 수집 : 이후 TASK들이: when: ansible_os_family == "Debian" 같은 조건 분기에서 사용됨 PLAY [Prepare for etcd install] *************************** # etcd 설치 전 사전 준비 : etcd user 생성, 디렉터리 생성, 방화벽 / 포트, cert 경로 준비 PLAY [Add worker nodes to the etcd play if needed] ******** # worker + etcd 겸용 노드 지원 : kube_node: + etcd: 둘 다 포함된 노드를 etcd PLAY에 추가 PLAY [Install etcd] *************************************** # etcd 설치 : etcd binary 설치, TLS 인증서 생성, systemd 등록, 클러스터 구성 PLAY [Install Kubernetes nodes] *************************** # 모든 노드에 공통 K8s 컴포넌트 설치, 아직 클러스터 join은 안 함 PLAY [Install the control plane] ************************** # kube_control_plane 그룹 : control-plane 노드 구성 PLAY [Invoke kubeadm and install a CNI] ******************* # kubeadm init / join 실행 , 네트워크(CNI) 설치 PLAY [Install Calico Route Reflector] ********************* # Calico BGP 미사용환경이면 skip PLAY [Patch Kubernetes for Windows] *********************** # Linux-only 환경이면 skip PLAY [Install Kubernetes apps] **************************** # 기본 애드온 설치 : CoreDNS, metrics-server 등 PLAY [Apply resolv.conf changes now that cluster DNS is up] # CoreDNS 설치 후 노드의 DNS 설정 최종 정리 : bootstrap 단계에선 임시 resolv.conf 사용, 클러스터 DNS 안정화 후 되돌림 PLAY RECAP ************************************************ # TASK 는 총 559개입니다. cat kubespray_install.log | grep -E 'TASK' | wc -l 559 cat kubespray_install.log | grep -E 'TASK' TASK [Check 2.17.3 <= Ansible version < 2.18.0] ******************************** TASK [Check that python netaddr is installed] ********************************** TASK [Check that jinja is not too old (install via pip)] *********************** TASK [dynamic_groups : Match needed groups by their old names or definition] *** TASK [validate_inventory : Stop if removed tags are used] ********************** TASK [validate_inventory : Stop if kube_control_plane group is empty] ********** TASK [validate_inventory : Stop if etcd group is empty in external etcd mode] *** TASK [validate_inventory : Stop if unsupported version of Kubernetes] ********** TASK [validate_inventory : Stop if known booleans are set as strings (Use JSON format on CLI: -e "{'key': true }")] *** TASK [validate_inventory : Stop if even number of etcd hosts] ****************** TASK [validate_inventory : Guarantee that enough network address space is available for all pods] *** TASK [validate_inventory : Check that kube_service_addresses is a network range] *** TASK [validate_inventory : Check that kube_pods_subnet is a network range] ***** TASK [validate_inventory : Check that kube_pods_subnet does not collide with kube_service_addresses] *** TASK [validate_inventory : Check that ipv4 IP range is enough for the nodes] *** TASK [validate_inventory : Stop if unsupported options selected] *************** TASK [validate_inventory : Ensure minimum containerd version] ****************** TASK [bootstrap_os : Fetch /etc/os-release] ************************************ TASK [bootstrap_os : Include tasks] ******************************************** TASK [bootstrap_os : Gather host facts to get ansible_distribution_version ansible_distribution_major_version] *** TASK [bootstrap_os : Add proxy to yum.conf or dnf.conf if http_proxy is defined] *** TASK [bootstrap_os : Check presence of fastestmirror.conf] ********************* TASK [system_packages : Gather OS information] ********************************* TASK [system_packages : Remove legacy docker repo file] ************************ TASK [system_packages : Manage packages] *************************************** TASK [bootstrap_os : Create remote_tmp for it is used by another module] ******* TASK [bootstrap_os : Gather facts] ********************************************* TASK [bootstrap_os : Assign inventory name to unconfigured hostnames (non-CoreOS, non-Flatcar, Suse and ClearLinux, non-Fedora)] *** TASK [bootstrap_os : Ensure bash_completion.d folder exists] ******************* TASK [network_facts : Gather ansible_default_ipv4] ***************************** TASK [network_facts : Set fallback_ip] ***************************************** TASK [network_facts : Gather ansible_default_ipv6] ***************************** TASK [network_facts : Set fallback_ip6] **************************************** TASK [network_facts : Set main access ip(access_ip based on ipv4_stack/ipv6_stack options).] *** TASK [network_facts : Set main ip(ip based on ipv4_stack/ipv6_stack options).] *** TASK [network_facts : Set main access ips(mixed ips for dualstack).] *********** TASK [network_facts : Set main ips(mixed ips for dualstack).] ****************** TASK [Gather minimal facts] **************************************************** TASK [Gather necessary facts (network)] **************************************** TASK [Gather necessary facts (hardware)] *************************************** TASK [adduser : User | Create User Group] ************************************** TASK [adduser : User | Create User] ******************************************** TASK [kubernetes/preinstall : Check if /etc/fstab exists] ********************** TASK [kubernetes/preinstall : Remove swapfile from /etc/fstab] ***************** TASK [kubernetes/preinstall : Mask swap.target (persist swapoff)] ************** TASK [kubernetes/preinstall : Disable swap] ************************************ TASK [kubernetes/preinstall : Check resolvconf] ******************************** TASK [kubernetes/preinstall : Check existence of /etc/resolvconf/resolv.conf.d] *** TASK [kubernetes/preinstall : Check status of /etc/resolv.conf] **************** TASK [kubernetes/preinstall : Fetch resolv.conf] ******************************* TASK [kubernetes/preinstall : NetworkManager | Check if host has NetworkManager] *** TASK [kubernetes/preinstall : Check systemd-resolved] ************************** TASK [kubernetes/preinstall : Set default dns if remove_default_searchdomains is false] *** TASK [kubernetes/preinstall : Set dns facts] *********************************** TASK [kubernetes/preinstall : Check if kubelet is configured] ****************** TASK [kubernetes/preinstall : Check if early DNS configuration stage] ********** TASK [kubernetes/preinstall : Target resolv.conf files] ************************ TASK [kubernetes/preinstall : Check if /etc/dhclient.conf exists] ************** TASK [kubernetes/preinstall : Check if /etc/dhcp/dhclient.conf exists] ********* TASK [kubernetes/preinstall : Target dhclient hook file for Red Hat family] **** TASK [kubernetes/preinstall : Check /usr readonly] ***************************** TASK [kubernetes/preinstall : Stop if non systemd OS type] ********************* TASK [kubernetes/preinstall : Stop if the os does not support] ***************** TASK [kubernetes/preinstall : Stop if memory is too small for control plane nodes] *** TASK [kubernetes/preinstall : Stop if memory is too small for nodes] *********** TASK [kubernetes/preinstall : Stop if cgroups are not enabled on nodes] ******** TASK [kubernetes/preinstall : Stop if ip var does not match local ips] ********* TASK [kubernetes/preinstall : Stop if access_ip is not pingable] *************** TASK [kubernetes/preinstall : Stop if bad hostname] **************************** TASK [kubernetes/preinstall : Stop if /etc/resolv.conf has no configured nameservers] *** TASK [kubernetes/preinstall : Create kubernetes directories] ******************* TASK [kubernetes/preinstall : Create other directories of root owner] ********** TASK [kubernetes/preinstall : Check if kubernetes kubeadm compat cert dir exists] *** TASK [kubernetes/preinstall : Create kubernetes kubeadm compat cert dir (kubernetes/kubeadm issue 1498)] *** TASK [kubernetes/preinstall : Create cni directories] ************************** TASK [kubernetes/preinstall : NetworkManager | Ensure NetworkManager conf.d dir] *** TASK [kubernetes/preinstall : NetworkManager | Prevent NetworkManager from managing K8S interfaces (kube-ipvs0/nodelocaldns)] *** TASK [kubernetes/preinstall : NetworkManager | Add nameservers to NM configuration] *** TASK [kubernetes/preinstall : Set default dns if remove_default_searchdomains is false] *** TASK [kubernetes/preinstall : NetworkManager | Add DNS search to NM configuration] *** TASK [kubernetes/preinstall : NetworkManager | Add DNS options to NM configuration] *** TASK [kubernetes/preinstall : Confirm selinux deployed] ************************ TASK [kubernetes/preinstall : Set selinux policy] ****************************** TASK [kubernetes/preinstall : Clean previously used sysctl file locations] ***** TASK [kubernetes/preinstall : Stat sysctl file configuration] ****************** TASK [kubernetes/preinstall : Change sysctl file path to link source if linked] *** TASK [kubernetes/preinstall : Make sure sysctl file path folder exists] ******** TASK [kubernetes/preinstall : Enable ip forwarding] **************************** TASK [kubernetes/preinstall : Check if we need to set fs.may_detach_mounts] **** TASK [kubernetes/preinstall : Ensure kubelet expected parameters are set] ****** TASK [kubernetes/preinstall : Disable fapolicyd service] *********************** TASK [kubernetes/preinstall : Check if we are running inside a Azure VM] ******* TASK [container-engine/validate-container-engine : Validate-container-engine | check if fedora coreos] *** TASK [container-engine/validate-container-engine : Validate-container-engine | set is_ostree] *** TASK [container-engine/validate-container-engine : Ensure kubelet systemd unit exists] *** TASK [container-engine/validate-container-engine : Populate service facts] ***** TASK [container-engine/validate-container-engine : Check if containerd is installed] *** TASK [container-engine/validate-container-engine : Check if docker is installed] *** TASK [container-engine/validate-container-engine : Check if crio is installed] *** TASK [container-engine/containerd-common : Containerd-common | check if fedora coreos] *** TASK [container-engine/containerd-common : Containerd-common | set is_ostree] *** TASK [container-engine/runc : Runc | check if fedora coreos] ******************* TASK [container-engine/runc : Runc | set is_ostree] **************************** TASK [container-engine/runc : Runc | Uninstall runc package managed by package manager] *** TASK [container-engine/runc : Runc | Download runc binary] ********************* TASK [container-engine/runc : Prep_download | Set a few facts] ***************** TASK [container-engine/runc : Download_file | Set pathname of cached file] ***** TASK [container-engine/runc : Download_file | Create dest directory on node] *** TASK [container-engine/runc : Download_file | Download item] ******************* TASK [container-engine/runc : Download_file | Extract file archives] *********** TASK [container-engine/runc : Copy runc binary from download dir] ************** TASK [container-engine/runc : Runc | Remove orphaned binary] ******************* TASK [container-engine/crictl : Install crictl] ******************************** TASK [container-engine/crictl : Crictl | Download crictl] ********************** TASK [container-engine/crictl : Prep_download | Set a few facts] *************** TASK [container-engine/crictl : Download_file | Set pathname of cached file] *** TASK [container-engine/crictl : Download_file | Create dest directory on node] *** TASK [container-engine/crictl : Download_file | Download item] ***************** TASK [container-engine/crictl : Download_file | Extract file archives] ********* TASK [container-engine/crictl : Extract_file | Unpacking archive] ************** TASK [container-engine/crictl : Install crictl config] ************************* TASK [container-engine/crictl : Copy crictl binary from download dir] ********** TASK [container-engine/nerdctl : Nerdctl | Download nerdctl] ******************* TASK [container-engine/nerdctl : Prep_download | Set a few facts] ************** TASK [container-engine/nerdctl : Download_file | Set pathname of cached file] *** TASK [container-engine/nerdctl : Download_file | Create dest directory on node] *** TASK [container-engine/nerdctl : Download_file | Download item] **************** TASK [container-engine/nerdctl : Download_file | Extract file archives] ******** TASK [container-engine/nerdctl : Extract_file | Unpacking archive] ************* TASK [container-engine/nerdctl : Nerdctl | Copy nerdctl binary from download dir] *** TASK [container-engine/nerdctl : Nerdctl | Create configuration dir] *********** TASK [container-engine/nerdctl : Nerdctl | Install nerdctl configuration] ****** TASK [container-engine/containerd : Containerd | Download containerd] ********** TASK [container-engine/containerd : Prep_download | Set a few facts] *********** TASK [container-engine/containerd : Download_file | Set pathname of cached file] *** TASK [container-engine/containerd : Download_file | Create dest directory on node] *** TASK [container-engine/containerd : Download_file | Download item] ************* TASK [container-engine/containerd : Download_file | Extract file archives] ***** TASK [container-engine/containerd : Containerd | Unpack containerd archive] **** TASK [container-engine/containerd : Containerd | Generate systemd service for containerd] *** TASK [container-engine/containerd : Containerd | Ensure containerd directories exist] *** TASK [container-engine/containerd : Containerd | Generate default base_runtime_spec] *** TASK [container-engine/containerd : Containerd | Store generated default base_runtime_spec] *** TASK [container-engine/containerd : Containerd | Write base_runtime_specs] ***** TASK [container-engine/containerd : Containerd | Copy containerd config file] *** TASK [container-engine/containerd : Containerd | Create registry directories] *** TASK [container-engine/containerd : Containerd | Write hosts.toml file] ******** TASK [container-engine/containerd : Containerd | Ensure containerd is started and enabled] *** TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Prep_download | Register docker images info] ****************** TASK [download : Prep_download | Create staging directory on remote node] ****** TASK [download : Download | Get kubeadm binary and list of required images] **** TASK [download : Prep_kubeadm_images | Download kubeadm binary] **************** TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Prep_kubeadm_images | Copy kubeadm binary from download dir to system path] *** TASK [download : Prep_kubeadm_images | Create kubeadm config] ****************** TASK [download : Prep_kubeadm_images | Generate list of required images] ******* TASK [download : Prep_kubeadm_images | Parse list of images] ******************* TASK [download : Prep_kubeadm_images | Convert list of images to dict for later use] *** TASK [download : Download | Download files / images] *************************** TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Extract_file | Unpacking archive] ***************************** TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Extract_file | Unpacking archive] ***************************** TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Extract_file | Unpacking archive] ***************************** TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Prep_download | Set a few facts] ****************************** TASK [download : Download_file | Set pathname of cached file] ****************** TASK [download : Download_file | Create dest directory on node] **************** TASK [download : Download_file | Download item] ******************************** TASK [download : Download_file | Extract file archives] ************************ TASK [download : Extract_file | Unpacking archive] ***************************** TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [download : Set default values for flag variables] ************************ TASK [download : Set_container_facts | Display the name of the image being processed] *** TASK [download : Set_container_facts | Set if containers should be pulled by digest] *** TASK [download : Set_container_facts | Define by what name to pull the image] *** TASK [download : Set_container_facts | Define file name of image] ************** TASK [download : Set_container_facts | Define path of image] ******************* TASK [download : Set image save/load command for containerd] ******************* TASK [download : Set image save/load command for containerd on localhost] ****** TASK [download : Download_container | Prepare container download] ************** TASK [download : Check_pull_required | Generate a list of information about the images on a node] *** TASK [download : Check_pull_required | Set pull_required if the desired image is not yet loaded] *** TASK [download : debug] ******************************************************** TASK [download : Download_container | Download image if required] ************** TASK [download : Download_container | Remove container image from cache] ******* TASK [Gathering Facts] ********************************************************* TASK [Check if nodes needs etcd client certs (depends on network_plugin)] ****** TASK [adduser : User | Create User Group] ************************************** TASK [adduser : User | Create User] ******************************************** TASK [adduser : User | Create User Group] ************************************** TASK [adduser : User | Create User] ******************************************** TASK [etcd : Check etcd certs] ************************************************* TASK [etcd : Check_certs | Register certs that have already been generated on first etcd node] *** TASK [etcd : Check_certs | Set default value for 'sync_certs', 'gen_certs' and 'etcd_secret_changed' to false] *** TASK [etcd : Check certs | Register ca and etcd admin/member certs on etcd hosts] *** TASK [etcd : Check certs | Register ca and etcd node certs on kubernetes hosts] *** TASK [etcd : Check_certs | Set 'gen_certs' to true if expected certificates are not on the first etcd node(1/2)] *** TASK [etcd : Check_certs | Set 'gen_certs' to true if expected certificates are not on the first etcd node(2/2)] *** TASK [etcd : Check_certs | Set 'gen_*_certs' groups to track which nodes needs to have certs generated on first etcd node] *** TASK [etcd : Check_certs | Set 'etcd_member_requires_sync' to true if ca or member/admin cert and key don't exist on etcd member or checksum doesn't match] *** TASK [etcd : Check_certs | Set 'sync_certs' to true] *************************** TASK [etcd : Generate etcd certs] ********************************************** TASK [etcd : Gen_certs | create etcd cert dir] ********************************* TASK [etcd : Gen_certs | create etcd script dir (on k8s-ctr1)] ***************** TASK [etcd : Gen_certs | write openssl config] ********************************* TASK [etcd : Gen_certs | copy certs generation script] ************************* TASK [etcd : Gen_certs | run cert generation script for etcd and kube control plane nodes] *** TASK [etcd : Gen_certs | run cert generation script for all clients] *********** TASK [etcd : Gen_certs | check certificate permissions] ************************ TASK [etcd : Trust etcd CA] **************************************************** TASK [etcd : Gen_certs | target ca-certificate store file] ********************* TASK [etcd : Gen_certs | add CA to trusted CA dir] ***************************** TASK [etcd : Gen_certs | update ca-certificates (RedHat)] ********************** TASK [etcd : Trust etcd CA on nodes if needed] ********************************* TASK [etcd : Gen_certs | target ca-certificate store file] ********************* TASK [etcd : Gen_certs | add CA to trusted CA dir] ***************************** TASK [etcd : Gen_certs | Get etcd certificate serials] ************************* TASK [etcd : Set etcd_client_cert_serial] ************************************** TASK [etcdctl_etcdutl : Download etcd binary] ********************************** TASK [etcdctl_etcdutl : Prep_download | Set a few facts] *********************** TASK [etcdctl_etcdutl : Download_file | Set pathname of cached file] *********** TASK [etcdctl_etcdutl : Download_file | Create dest directory on node] ********* TASK [etcdctl_etcdutl : Download_file | Download item] ************************* TASK [etcdctl_etcdutl : Download_file | Extract file archives] ***************** TASK [etcdctl_etcdutl : Extract_file | Unpacking archive] ********************** TASK [etcdctl_etcdutl : Copy etcd binary] ************************************** TASK [etcdctl_etcdutl : Copy etcdctl and etcdutl binary from download dir] ***** TASK [etcdctl_etcdutl : Create etcdctl wrapper script] ************************* TASK [etcd : Install etcd] ***************************************************** TASK [etcd : Get currently-deployed etcd version] ****************************** TASK [etcd : Restart etcd if necessary] **************************************** TASK [etcd : Install | Copy etcd binary from download dir] ********************* TASK [etcd : Configure etcd] *************************************************** TASK [etcd : Configure | Check if etcd cluster is healthy] ********************* TASK [etcd : Configure | Refresh etcd config] ********************************** TASK [etcd : Refresh config | Create etcd config file] ************************* TASK [etcd : Configure | Copy etcd.service systemd file] *********************** TASK [etcd : Configure | reload systemd] *************************************** TASK [etcd : Configure | Ensure etcd is running] ******************************* TASK [etcd : Configure | Wait for etcd cluster to be healthy] ****************** TASK [etcd : Configure | Check if member is in etcd cluster] ******************* TASK [etcd : Refresh etcd config] ********************************************** TASK [etcd : Refresh config | Create etcd config file] ************************* TASK [etcd : Refresh etcd config again for idempotency] ************************ TASK [etcd : Refresh config | Create etcd config file] ************************* TASK [kubernetes/node : Set kubelet_cgroup_driver_detected fact for containerd] *** TASK [kubernetes/node : Set kubelet_cgroup_driver] ***************************** TASK [kubernetes/node : Ensure /var/lib/cni exists] **************************** TASK [kubernetes/node : Install | Copy kubelet binary from download dir] ******* TASK [kubernetes/node : Ensure nodePort range is reserved] ********************* TASK [kubernetes/node : Verify if br_netfilter module exists] ****************** TASK [kubernetes/node : Verify br_netfilter module path exists] **************** TASK [kubernetes/node : Enable br_netfilter module] **************************** TASK [kubernetes/node : Persist br_netfilter module] *************************** TASK [kubernetes/node : Check if bridge-nf-call-iptables key exists] *********** TASK [kubernetes/node : Enable bridge-nf-call tables] ************************** TASK [kubernetes/node : Set kubelet api version to v1beta1] ******************** TASK [kubernetes/node : Write kubelet environment config file (kubeadm)] ******* TASK [kubernetes/node : Write kubelet config file] ***************************** TASK [kubernetes/node : Write kubelet systemd init file] *********************** TASK [kubernetes/node : Enable kubelet] **************************************** TASK [kubernetes/control-plane : Pre-upgrade | Delete control plane manifests if etcd secrets changed] *** TASK [kubernetes/control-plane : Create kube-scheduler config] ***************** TASK [kubernetes/control-plane : Install | Copy kubectl binary from download dir] *** TASK [kubernetes/control-plane : Install kubectl bash completion] ************** TASK [kubernetes/control-plane : Set kubectl bash completion file permissions] *** TASK [kubernetes/control-plane : Check which kube-control nodes are already members of the cluster] *** TASK [kubernetes/control-plane : Set fact first_kube_control_plane] ************ TASK [kubernetes/control-plane : Kubeadm | Check if kubeadm has already run] *** TASK [kubernetes/control-plane : Kubeadm | aggregate all SANs] ***************** TASK [kubernetes/control-plane : Kubeadm | Create kubeadm config] ************** TASK [kubernetes/control-plane : Kubeadm | Initialize first control plane node (1st try)] *** TASK [kubernetes/control-plane : Create kubeadm token for joining nodes with 24h expiration (default)] *** TASK [kubernetes/control-plane : Set kubeadm_token] **************************** TASK [kubernetes/control-plane : Kubeadm | Join other control plane nodes] ***** TASK [kubernetes/control-plane : Set kubeadm_discovery_address] **************** TASK [kubernetes/control-plane : Upload certificates so they are fresh and not expired] *** TASK [kubernetes/control-plane : Parse certificate key if not set] ************* TASK [kubernetes/control-plane : Wait for k8s apiserver] *********************** TASK [kubernetes/control-plane : Check already run] **************************** TASK [kubernetes/control-plane : Kubeadm | Remove taint for control plane node with node role] *** TASK [kubernetes/control-plane : Include kubeadm secondary server apiserver fixes] *** TASK [kubernetes/control-plane : Update server field in component kubeconfigs] *** TASK [kubernetes/control-plane : Include kubelet client cert rotation fixes] *** TASK [kubernetes/control-plane : Fixup kubelet client cert rotation 1/2] ******* TASK [kubernetes/control-plane : Fixup kubelet client cert rotation 2/2] ******* TASK [kubernetes/control-plane : Install script to renew K8S control plane certificates] *** TASK [kubernetes/control-plane : Renew K8S control plane certificates monthly 1/2] *** TASK [kubernetes/control-plane : Renew K8S control plane certificates monthly 2/2] *** TASK [kubernetes/client : Set external kube-apiserver endpoint] **************** TASK [kubernetes/client : Create kube config dir for current/ansible become user] *** TASK [kubernetes/client : Copy admin kubeconfig to current/ansible become user home] *** TASK [kubernetes/client : Wait for k8s apiserver] ****************************** TASK [kubernetes-apps/cluster_roles : Kubernetes Apps | Wait for kube-apiserver] *** TASK [kubernetes-apps/cluster_roles : Kubernetes Apps | Add ClusterRoleBinding to admit nodes] *** TASK [kubernetes-apps/cluster_roles : Apply workaround to allow all nodes with cert O=system:nodes to register] *** TASK [kubernetes-apps/cluster_roles : Kubernetes Apps | Remove old webhook ClusterRole] *** TASK [kubernetes-apps/cluster_roles : Kubernetes Apps | Remove old webhook ClusterRoleBinding] *** TASK [kubernetes-apps/cluster_roles : PriorityClass | Copy k8s-cluster-critical-pc.yml file] *** TASK [kubernetes-apps/cluster_roles : PriorityClass | Create k8s-cluster-critical] *** TASK [kubernetes/kubeadm : Set kubeadm_discovery_address] ********************** TASK [kubernetes/kubeadm : Check if kubelet.conf exists] *********************** TASK [kubernetes/kubeadm : Check if kubeadm CA cert is accessible] ************* TASK [kubernetes/kubeadm : Fetch CA certificate from control plane node] ******* TASK [kubernetes/kubeadm : Check if discovery kubeconfig exists] *************** TASK [kubernetes/kubeadm : Get current resourceVersion of kube-proxy configmap] *** TASK [kubernetes/kubeadm : Update server field in kube-proxy kubeconfig] ******* TASK [kubernetes/kubeadm : Get new resourceVersion of kube-proxy configmap] **** TASK [kubernetes/kubeadm : Set ca.crt file permission] ************************* TASK [kubernetes/kubeadm : Restart all kube-proxy pods to ensure that they load the new configmap] *** TASK [kubernetes/node-label : Kubernetes Apps | Wait for kube-apiserver] ******* TASK [kubernetes/node-label : Set role node label to empty list] *************** TASK [kubernetes/node-label : Set inventory node label to empty list] ********** TASK [kubernetes/node-label : debug] ******************************************* TASK [kubernetes/node-label : debug] ******************************************* TASK [kubernetes/node-taint : Set role and inventory node taint to empty list] *** TASK [kubernetes/node-taint : debug] ******************************************* TASK [kubernetes/node-taint : debug] ******************************************* TASK [network_plugin/cni : CNI | make sure /opt/cni/bin exists] **************** TASK [network_plugin/cni : CNI | Copy cni plugins] ***************************** TASK [network_plugin/cni : CNI | make sure /opt/cni/bin exists] **************** TASK [network_plugin/cni : CNI | Copy cni plugins] ***************************** TASK [network_plugin/flannel : Flannel | Create Flannel manifests] ************* TASK [network_plugin/flannel : Flannel | Start Resources] ********************** TASK [network_plugin/flannel : Flannel | Wait for flannel subnet.env file presence] *** TASK [win_nodes/kubernetes_patch : Ensure that user manifests directory exists] *** TASK [win_nodes/kubernetes_patch : Check current nodeselector for kube-proxy daemonset] *** TASK [win_nodes/kubernetes_patch : Apply nodeselector patch for kube-proxy daemonset] *** TASK [win_nodes/kubernetes_patch : debug] ************************************** TASK [win_nodes/kubernetes_patch : debug] ************************************** TASK [kubernetes-apps/ansible : Kubernetes Apps | Wait for kube-apiserver] ***** TASK [kubernetes-apps/ansible : Kubernetes Apps | CoreDNS] ********************* TASK [kubernetes-apps/helm : Helm | Gather os specific variables] ************** TASK [kubernetes-apps/helm : Helm | Install PyYaml] **************************** TASK [kubernetes-apps/helm : Helm | Download helm] ***************************** TASK [kubernetes-apps/helm : Prep_download | Set a few facts] ****************** TASK [kubernetes-apps/helm : Download_file | Set pathname of cached file] ****** TASK [kubernetes-apps/helm : Download_file | Create dest directory on node] **** TASK [kubernetes-apps/helm : Download_file | Download item] ******************** TASK [kubernetes-apps/helm : Download_file | Extract file archives] ************ TASK [kubernetes-apps/helm : Extract_file | Unpacking archive] ***************** TASK [kubernetes-apps/helm : Helm | Copy helm binary from download dir] ******** TASK [kubernetes-apps/helm : Helm | Get helm completion] *********************** TASK [kubernetes-apps/helm : Helm | Install helm completion] ******************* TASK [kubernetes-apps/metrics_server : Metrics Server | Delete addon dir] ****** TASK [kubernetes-apps/metrics_server : Metrics Server | Create addon dir] ****** TASK [kubernetes-apps/metrics_server : Metrics Server | Templates list] ******** TASK [kubernetes-apps/metrics_server : Metrics Server | Create manifests] ****** TASK [kubernetes-apps/metrics_server : Metrics Server | Apply manifests] ******* TASK [adduser : User | Create User Group] ************************************** TASK [adduser : User | Create User] ******************************************** TASK [kubernetes/preinstall : Check resolvconf] ******************************** TASK [kubernetes/preinstall : Check existence of /etc/resolvconf/resolv.conf.d] *** TASK [kubernetes/preinstall : Check status of /etc/resolv.conf] **************** TASK [kubernetes/preinstall : Fetch resolv.conf] ******************************* TASK [kubernetes/preinstall : NetworkManager | Check if host has NetworkManager] *** TASK [kubernetes/preinstall : Check systemd-resolved] ************************** TASK [kubernetes/preinstall : Set default dns if remove_default_searchdomains is false] *** TASK [kubernetes/preinstall : Set dns facts] *********************************** TASK [kubernetes/preinstall : Check if kubelet is configured] ****************** TASK [kubernetes/preinstall : Check if early DNS configuration stage] ********** TASK [kubernetes/preinstall : Target resolv.conf files] ************************ TASK [kubernetes/preinstall : Check if /etc/dhclient.conf exists] ************** TASK [kubernetes/preinstall : Check if /etc/dhcp/dhclient.conf exists] ********* TASK [kubernetes/preinstall : Target dhclient hook file for Red Hat family] **** TASK [kubernetes/preinstall : Check /usr readonly] ***************************** TASK [kubernetes/preinstall : NetworkManager | Ensure NetworkManager conf.d dir] *** TASK [kubernetes/preinstall : NetworkManager | Prevent NetworkManager from managing K8S interfaces (kube-ipvs0/nodelocaldns)] *** TASK [kubernetes/preinstall : NetworkManager | Add nameservers to NM configuration] *** TASK [kubernetes/preinstall : Set default dns if remove_default_searchdomains is false] *** TASK [kubernetes/preinstall : NetworkManager | Add DNS search to NM configuration] *** TASK [kubernetes/preinstall : NetworkManager | Add DNS options to NM configuration] *** |
playbooks/cluster.yml 설치 절차
- cluster.yml은 Kubespray의 메인 플레이북으로, 클러스터 생성의 전체 과정을 정의합니다.


playbooks/cluster.yml : 전체 과정
A. 초기화 및 정보 수집 (Boilerplate & Facts)
- 모든 노드에 공통적으로 필요한 설정을 적용하고, 각 서버의 사양 정보를 수집하여 이후 설치 단계에서 변수로 활용합니다.
B. 인프라 및 엔진 준비 (Prepare for etcd & container-engine)
- kubernetes/preinstall: 방화벽, 커널 파라미터, Swap 비활성화 등 K8s 설치를 위한 OS 최적화를 수행합니다.
- container-engine: Docker나 Containerd 같은 컨테이너 런타임을 설치합니다.
- download: 설치에 필요한 모든 바이너리와 이미지들을 미리 다운로드합니다.
C. 데이터 저장소 및 노드 구성 (Etcd & K8s Nodes)
- etcd: 쿠버네티스의 상태 정보를 저장하는 DB 클러스터를 구축합니다.
- kubernetes/node: 모든 노드에 Kubelet, Kube-proxy 등 기초 컴포넌트를 설치합니다.
D. 컨트롤 플레인 및 네트워크 (Control Plane & CNI)
- control-plane: 마스터 노드에 API 서버, 스케줄러 등을 설정합니다.
- kubeadm: kubeadm init 또는 join을 통해 클러스터를 하나로 묶습니다.
- network_plugin: Calico, Flannel 등 CNI를 설치하여 파드 간 통신을 가능하게 합니다.
E. 부가 서비스 설치 (Apps & DNS)
- Ingress Controller, Storage Provisioner 등 클러스터 운영에 필요한 앱들을 배포하고, 최종적으로 노드의 DNS(resolv.conf)가 클러스터 내부 DNS를 바라보도록 수정합니다.

파일 내용을 좀 더 상세히 분석해보겠습니다.
| cat playbooks/cluster.yml --- - name: Common tasks for every playbooks import_playbook: boilerplate.yml - name: Gather facts import_playbook: internal_facts.yml - name: Prepare for etcd install hosts: k8s_cluster:etcd # 이 작업은 쿠버네티스 클러스터에 속한 모든 노드(k8s_cluster)와 etcd 전용 노드(etcd) 전체를 대상으로 실행. gather_facts: false any_errors_fatal: "{{ any_errors_fatal | default(true) }}" # 하나라도 에러가 발생하면 전체 배포 프로세스를 즉시 중단합니다. environment: "{{ proxy_disable_env }}" # 인터넷 통신 시 프록시 설정을 제어합니다. 주로 내부 통신 시 프록시를 우회하도록 설정할 때 사용됩니다. roles: - { role: kubespray_defaults } # Kubespray 전체에서 사용하는 공통 변수(경로, 버전 등)를 로드합니다. - { role: kubernetes/preinstall, tags: preinstall } # OS 레벨의 사전 설정을 수행합니다. 예) 커널 파라미터(sysctl) 최적화 등 - { role: "container-engine", tags: "container-engine", when: deploy_container_engine } # 컨테이너 런타임(containerd, Docker 등)을 설치합니다. - { role: download, tags: download, when: "not skip_downloads" } # 설치에 필요한 모든 바이너리와 컨테이너 이미지를 다운로드합니다. - name: Install etcd vars: etcd_cluster_setup: true # etcd를 “클러스터 모드”로 초기화. 단일 노드라도 내부 로직은 클러스터 기준으로 동작. 신규 클러스터 생성 시 반드시 true etcd_events_cluster_setup: "{{ etcd_events_cluster_enabled }}" # true 일 경우 events 전용 etcd 클러스터를 별도로 구성, 대부분 환경에서는 false import_playbook: install_etcd.yml # Playbook을 import 하는 구조, 즉, 여기에는 hosts:가 없고 install_etcd.yml 안에 실제 Play들이 있음. - name: Install Kubernetes nodes # 이 노드를 "kubelet이 돌아가는 Kubernetes 노드"로 만든다. hosts: k8s_cluster # 모든 k8s 노드 : control-plane , worker gather_facts: false any_errors_fatal: "{{ any_errors_fatal | default(true) }}" environment: "{{ proxy_disable_env }}" roles: - { role: kubespray_defaults } - { role: kubernetes/node, tags: node } # 예) kubelet 설치 등 - name: Install the control plane hosts: kube_control_plane # 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 } # 설치 : apiserver, kcm, scheduler - { role: kubernetes/client, tags: client } # kubectl 설치, admin kubeconfig 생성 준비 - { role: kubernetes-apps/cluster_roles, tags: cluster-roles } # Kubernetes 기본 ClusterRole 생성, bootstrap / node / admin 권한 관련 - 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} # kubeadm init* / join* 실행 - { role: kubernetes/node-label, tags: node-label } # inventory 기반으로 node label 설정 - { role: kubernetes/node-taint, tags: node-taint } # control-plane taint 설정 - { role: kubernetes-apps/common_crds } # CNI / ingress / storage에서 사용하는 공통 CRD 먼저 설치 - { role: network_plugin, tags: network } # 실제 CNI 플러그인 설치 단계* : Calico / Cilium / Flannel / Weave 등 - name: Install Calico Route Reflector hosts: calico_rr gather_facts: false any_errors_fatal: "{{ any_errors_fatal | default(true) }}" environment: "{{ proxy_disable_env }}" roles: - { role: kubespray_defaults } - { role: network_plugin/calico/rr, tags: ['network', 'calico_rr'] } - name: Patch Kubernetes for Windows hosts: kube_control_plane[0] gather_facts: false any_errors_fatal: "{{ any_errors_fatal | default(true) }}" environment: "{{ proxy_disable_env }}" roles: - { role: kubespray_defaults } - { role: win_nodes/kubernetes_patch, tags: ["control-plane", "win_nodes"] } - name: Install Kubernetes apps hosts: kube_control_plane # control-plane 노드만 : 실제로는 클러스터 전체에 리소스를 배포하지만, 명령 실행 위치만 control-plane gather_facts: false any_errors_fatal: "{{ any_errors_fatal | default(true) }}" environment: "{{ proxy_disable_env }}" roles: - { role: kubespray_defaults } # 공통 변수 로딩, apps 관련 enable/disable 값 정리 - { role: kubernetes-apps/external_cloud_controller, tags: external-cloud-controller } # cloud-controller-manager 외부 실행 버전, 베어메탈 / lab 환경이면 보통 비활성 - { role: kubernetes-apps/policy_controller, tags: policy-controller } # Kubernetes Policy 계열 컨트롤러, 예) PodSecurity Admission, OPA / Gatekeeper 연계 - { role: kubernetes-apps/ingress_controller, tags: ingress-controller } # Ingress Controller 설치, 예) NGINX Ingress, HAProxy Ingress, Traefik - { role: kubernetes-apps/external_provisioner, tags: external-provisioner } # 외부 스토리지 프로비저너, 예) CSI provisioner, NFS external provisioner, Ceph RBD / CephFS - { role: kubernetes-apps, tags: apps } # CoreDNS (이미 설치됐지만 재확인), Metrics Server, Local Path Provisioner, Helm add-ons - name: Apply resolv.conf changes now that cluster DNS is up hosts: k8s_cluster # 모든 노드 gather_facts: false any_errors_fatal: "{{ any_errors_fatal | default(true) }}" environment: "{{ proxy_disable_env }}" roles: - { role: kubespray_defaults } - { role: kubernetes/preinstall, when: "dns_mode != 'none' and resolvconf_mode == 'host_resolvconf'", tags: resolvconf, dns_late: true } |
'Kubernetes' 카테고리의 다른 글
| [K8S Deploy 6주차] 폐쇄망에서 kubespray를 이용한 K8S 구성 (0) | 2026.02.14 |
|---|---|
| [K8S Deploy 3주차] kubeadm 을 이용한 K8S 클러스터 구성 (0) | 2026.01.22 |
| [K8S Deploy 2주차] Ansible 기초 (0) | 2026.01.12 |
| [K8S Deploy 1주차] Kubernetes 손 설치 (1) | 2026.01.10 |
| MinIO - DirectPV & Performance (1) | 2025.09.20 |







