본 글은 gasida님의 k8s-deploy 스터디 자료를 기반으로 작성되었습니다.
Kubespray로 Kubernetes 설치하기
1. Kubespray란?
Kubespray는 Kubernetes 클러스터를 자동으로 프로비저닝하고 설치하는 오픈소스 프로젝트입니다.
Ansible 플레이북을 기반으로 만들어져 있어서 복잡한 Kubernetes 설치 과정을 YAML 설정 파일 몇 개로 단순화할 수 있습니다.
Kubespray는 etcd 클러스터 구성, kubeadm 초기화, CNI 플러그인 설정, TLS 인증서 관리 등 사용자가 수동으로 쿠버네티스를 설치할 때 수행해야 하는 번거로운 작업들을 자동으로 처리해줍니다.
kubeadm, kops, RKE 등 다른 설치 방법과 비교했을 때 Kubespray의 장점은 다음과 같습니다.
첫째. 다양한 클라우드 및 베어메탈 환경을 지원합니다.
AWS, GCP, Azure, OpenStack, vSphere 등을 공식적으로 지원하고, VM이나 베어메탈에서도 동일하게 사용할 수 있습니다.
둘째. CNI 플러그인 선택이 자유롭습니다.
Calico, Flannel, Cilium, Kube-OVN 등을 설정 파일에서 간단히 바꾸면 됩니다.
셋째. Ansible 기반이므로 인프라 코드화(IaC)가 되어 반복 가능하고 버전 관리가 용이합니다.
2. Kubespray로 쿠버네티스 설치해보기
- 실습 수행 환경 : VMware Ubuntu 22.04 단일 노드
- kubespray Version : 2.29.1 / Kubernetes Version : 1.33.3
| Kubespray | Kubernetes Version (최신버전-2까지 지원) |
| 2.29.x (master-branch) | 1.31 ~ 1.33 |
| 2.28.x | 1.30 ~ 1.32 |
| 2.27.x | 1.29 ~ 1.31 |
1) sh init_config.sh
kubernetes를 설치하기 전에 모든 노드에서 실행해야 하는 초기 환경 설정 스크립트입니다.
#!/usr/bin/env bash
echo ">>>> Initial Config Start <<<<"
echo "[TASK 1] Change Timezone"
timedatectl set-local-rtc 0
timedatectl set-timezone Asia/Seoul
echo "[TASK 2] Disable firewalld and selinux"
systemctl disable --now ufw
echo "[TASK 3] Disable and turn off SWAP & Delete swap partitions"
swapoff -a
sed -i '/swapfile/d' /etc/fstab
rm -f /swapfile
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 ">>>> Initial Config End <<<<"
TASK 1 — Timezone 설정
지금은 단일 노드이지만 클러스터 구성 시에는 모든 노드의 시간을 맞춰줘야 합니다.
etcd는 내부 통신 과정에서 시간 오차에 민감하게 동작하고, TLS 인증서의 유효성 검사에도 정확한 시간이 필요합니다.
TASK 2 — 방화벽 비활성화
UFW(Uncomplicated Firewall)를 끕니다. Kubernetes는 내부적으로 다양한 포트를 사용하며, 방화벽이 활성화되어 있으면 Pod 간 통신이나 Control Plane과 Worker간 통신이 막힐 수 있습니다.
단일 노드 테스트 환경에서는 우선 비활성화하고, 프로덕션 환경에서는 필요한 포트만 열어줍니다.
TASK 3 — SWAP 비활성화
Kubernetes의 kubelet은 기본적으로 SWAP이 활성화된 상태를 지원하지 않습니다. SWAP이 사용되면 컨테이너의 메모리 사용량이 불균형적으로 변할 수 있어서 리소스 관리가 불안정해집니다. SWAP을 끄고 부팅 시 다시 활성화되지 않도록 영구적으로 제거합니다.
TASK 4 — 커널 모듈 및 sysctl 설정
overlay는 컨테이너 파일시스템에 사용되는 커널 모듈입니다.
br_netfilter는 Docker/Containerd가 사용하는 bridging 네트워크에서 iptables 규칙을 적용할 수 있도록 하는 모듈입니다.
bridge-nf-call-iptables = 1은 bridge 네트워크를 지나는 IPv4 패킷도 iptables 규칙에 의해 필터링됩니다.
ip_forward = 1은 서버가 Pod 네트워크의 패킷을 라우팅할 수 있게 합니다.
2) 사전 설정
Kubespray를 실행할 Control Plane 서버에서 직접 수행하는 단계입니다.
Kubespray는 Ansible을 사용하여 대상 서버에 SSH로 접속 후 작업을 수행하므로, SSH 키 기반 인증이 필요합니다.
# uname -a
Linux k8s-ctrl 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
Kubespray에서 지원되는 조합인지 서버의 OS, 커널 버전, 아키텍처를 확인합니다.
# which python3 && python3 -V
/usr/bin/python3
Python 3.10.12
Ansible은 Python을 의존성으로 가지고 있으므로 미리 설치해줍니다. (Python 3.10 ~ 3.12)
# apt-get install -y python3-pip git
# which pip3 && pip3 -V
/usr/bin/pip3
pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)
// /etc/hosts 확인
# ip -br -c -4 addr
lo UNKNOWN 127.0.0.1/8
ens33 UP 192.168.105.151/24
# ping -c 1 k8s-ctrl
PING k8s-ctrl (192.168.105.151) 56(84) bytes of data.
64 bytes from k8s-ctrl (192.168.105.151): icmp_seq=1 ttl=64 time=0.104 ms
--- k8s-ctrl ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.104/0.104/0.104/0.000 ms
Kubespray의 inventory에서 호스트명을 사용할 수 있도록 /etc/hosts에 각 노드의 IP와 호스트명을 등록 후 확인합니다.
# echo "root:<PASSWORD>" | chpasswd
root 비밀번호를 설정합니다. SSH 키 배포 전에 초기 접속에 사용됩니다.
# cat << EOF >> /etc/ssh/sshd_config
PermitRootLogin yes
PasswordAuthentication yes
EOF
systemctl restart sshd
SSH 설정을 바꾸어 root 계정의 비밀번호 기반 로그인을 허용합니다.
# ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa
# ssh-copy-id -o StrictHostKeyChecking=no root@192.168.105.151
단일 노드 클러스터이지만 Ansible이 localhost도 SSH로 접속하기 때문에 자기 자신에게도 키를 복사해야 합니다.
# ssh root@192.168.105.151 hostname
k8s-ctrl
# ssh -o StrictHostKeyChecking=no root@k8s-ctrl hostname
Warning: Permanently added 'k8s-ctrl' (ED25519) to the list of known hosts.
k8s-ctrl
SSH 키 인증이 비밀번호 없이 정상적으로 작동하는지 확인합니다.
3) Kubespray 설치
# git clone -b v2.29.1 https://github.com/kubernetes-sigs/kubespray.git /root/kubespray
# cd /root/kubespray
Kubespray GitHub 저장소를 받아옵니다. (v2.29.1)
# ls -l *.yml
-rw-r--r-- 1 root root 88 Jan 31 19:56 cluster.yml
-rw-r--r-- 1 root root 30 Jan 31 19:56 _config.yml
-rw-r--r-- 1 root root 747 Jan 31 19:56 galaxy.yml
-rw-r--r-- 1 root root 105 Jan 31 19:56 recover-control-plane.yml
-rw-r--r-- 1 root root 85 Jan 31 19:56 remove-node.yml
-rw-r--r-- 1 root root 85 Jan 31 19:56 remove_node.yml
-rw-r--r-- 1 root root 85 Jan 31 19:56 reset.yml
-rw-r--r-- 1 root root 85 Jan 31 19:56 scale.yml
-rw-r--r-- 1 root root 93 Jan 31 19:56 upgrade-cluster.yml
-rw-r--r-- 1 root root 93 Jan 31 19:56 upgrade_cluster.yml
주요 플레이북 파일들을 확인합니다.
- cluster.yml — 클러스터를 새로 생성하는 메인 플레이북
- scale.yml — 노드를 추가하거나 제거하는 플레이북
- upgrade-cluster.yml — 클러스터 버전 업그레이드
- reset.yml — 클러스터를 초기화(삭제)하는 플레이북
- recover-control-plane.yml — Control Plane 복구용 플레이북
- galaxy.yml — Ansible Galaxy 컬렉션 정의 파일
4) pip3, ansible 설치
# cat requirements.txt
ansible==10.7.0
cryptography==46.0.2
jmespath==1.0.1
netaddr==1.3.0
Kubespray에서 필요한 Python 패키지의 버전을 고정한 파일입니다.
cryptography는 TLS 인증서 처리 시, jmespath는 Jinja2 템플릿에서 JSON 쿼리 시, netaddr는 IP 주소 계산 시 사용됩니다.
# pip3 install -r /root/kubespray/requirements.txt
Successfully installed cffi-2.0.0 cryptography-46.0.2 jmespath-1.0.1 netaddr-1.3.0 pycparser-3.0 typing-extensions-4.15.0
requirements.txt에 정의된 패키지들을 설치합니다.
# which ansible
/usr/bin/ansible
# ansible --version
ansible [core 2.17.14]
Ansible이 정상적으로 설치되었는지 확인합니다.
# cat ansible.cfg
[ssh_connection]
pipelining=True
ssh_args = -o ControlMaster=auto -o ControlPersist=30m -o ConnectionAttempts=100 -o UserKnownHostsFile=/dev/null
#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
host_key_checking=False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp
fact_caching_timeout = 86400
timeout = 300
stdout_callback = default
display_skipped_hosts = no
library = ./library
callbacks_enabled = profile_tasks
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
Kubespray에서 제공하는 Ansible 설정 파일입니다.
- pipelining=True — SSH 연결을 재사용하여 속도를 높이는 옵션
- ControlMaster=auto / ControlPersist=30m — SSH 연결을 30분 동안 유지하여 매 Task마다 새로 연결할 필요 없음
- ConnectionAttempts=100 — 연결 실패 시 최대 100번까지 재시도
- host_key_checking=False — SSH 호스트 키 확인을 비활성화하여 자동화 중 수동 확인 프롬프트가 나오지 않도록 설정
- fact_caching — Ansible이 수집한 서버 정보를 파일로 캐시하여 반복 실행 시 속도를 높임
- callbacks_enabled = profile_tasks — 각 Task 실행 시간 출력
5) kubernetes 설치 전 kubespray inventory 구성 및 주요 설정 변경
Kubespray 실행 동작은 inventory 폴더 안의 설정 파일들에 의해 결정됩니다.
# cp -rfp /root/kubespray/inventory/sample /root/kubespray/inventory/mycluster
Kubespray가 제공하는 샘플 inventory를 복사하여 새로운 클러스터 이름으로 생성합니다. (원본 복사해서 사용)
# 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
3 directories, 27 files
- inventory.ini — 클러스터에 참여할 서버 목록과 역할을 정의
- group_vars/all/ — 모든 노드에 공통으로 적용되는 설정
- group_vars/k8s_cluster/ — Kubernetes 클러스터 자체 설정
# cat /root/kubespray/inventory/mycluster/inventory.ini
k8s-ctrl ansible_host=192.168.105.151 ip=192.168.105.151 access_ip=192.168.105.151
[kube_control_plane]
k8s-ctrl
[etcd:children]
kube_control_plane
[kube_node]
k8s-ctrl
inventory.ini을 정의합니다.
// 수정 전
# grep -iE 'kube_network_plugin:|kube_proxy_mode|enable_nodelocaldns:|^auto_renew_certificates' inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
kube_network_plugin: calico
kube_proxy_mode: ipvs
enable_nodelocaldns: true
auto_renew_certificates: false
inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml 파일에서 수정 전 기본값을 먼저 확인합니다.
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
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
kube_network_plugin: flannel
kube_proxy_mode: iptables
enable_nodelocaldns: false
auto_renew_certificates: true
auto_renew_certificates_systemd_calendar: "Mon *-*-1,2,3,4,5,6,7 03:00:00"
systemd timer를 사용하여 매달 1~7일 중 월요일에 해당하는 날 새벽 3시에 인증서 자동 갱신 작업이 수행되도록 설정합니다.
# ip -br -c -4 addr
lo UNKNOWN 127.0.0.1/8
ens33 UP 192.168.105.151/24
# echo "flannel_interface: ens33" >> inventory/mycluster/group_vars/k8s_cluster/k8s-net-flannel.yml
# grep "^[^#]" inventory/mycluster/group_vars/k8s_cluster/k8s-net-flannel.yml
flannel_interface: ens33
Flannel이 사용할 네트워크 인터페이스를 지정합니다.
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
sed -i 's|ingress_nginx_enabled: false|ingress_nginx_enabled: true|g' inventory/mycluster/group_vars/k8s_cluster/addons.yml
sed -i 's|ingress_publish_status_address:.*|ingress_publish_status_address: 192.168.105.151|' inventory/mycluster/group_vars/k8s_cluster/addons.yml
sed -i 's|argocd_enabled: false|argocd_enabled: true|g' inventory/mycluster/group_vars/k8s_cluster/addons.yml
Kubespray는 클러스터와 함께 추가 애플리케이션(addon)을 자동으로 설치할 수 있습니다.
- helm — Kubernetes 패키지 매니저. Helm Chart를 사용하여 애플리케이션을 배포하고 관리
- metrics-server — 클러스터의 CPU, 메모리 사용량을 수집하는 컴포넌트
- node-feature-discovery — 각 노드의 하드웨어 특성(CPU 기능, GPU 유무 등)을 자동으로 레이블링
- ingress-nginx — 외부 트래픽을 클러스터 내 서비스로 라우팅하는 Ingress Controller
- ingress_publish_status_address — Ingress 리소스의 status에 표시될 외부 접근 IP 지정
- argocd — GitOps 기반 CD(Continuous Delivery) 도구. Git 저장소의 변경사항을 자동으로 감지하여 클러스터에 배포
// 수정 후
# grep "^[^#]" inventory/mycluster/group_vars/k8s_cluster/addons.yml
---
helm_enabled: true
registry_enabled: false
metrics_server_enabled: true
local_path_provisioner_enabled: false
local_volume_provisioner_enabled: false
gateway_api_enabled: false
ingress_nginx_enabled: true
ingress_publish_status_address: 192.168.105.151
ingress_alb_enabled: false
cert_manager_enabled: false
metallb_enabled: false
metallb_speaker_enabled: "{{ metallb_enabled }}"
metallb_namespace: "metallb-system"
argocd_enabled: true
kube_vip_enabled: false
node_feature_discovery_enabled: true
수정된 addons.yml의 내용을 확인합니다.
// 기본 환경 정보 출력 저장
# 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
Kubernetes 설치 전의 서버 상태를 파일로 저장합니다. 설치 전과 후를 비교하여 Kubespray가 무엇을 변경했는지 확인합니다.
- ip addr — 네트워크 인터페이스 및 IP 주소
- ss -tnlp — 현재 열려있는 TCP 포트와 프로세스
- df -hT — 디스크 사용량과 파일시스템 타입
- findmnt — 마운트된 파일시스템 목록
- sysctl -a — 커널 매개변수 전체
6) Kubernetes 설치
// 배포 전, Task 목록 확인
# ansible-playbook -i inventory/mycluster/inventory.ini -v cluster.yml -e kube_version="1.33.3" --list-tasks
실제 설치를 실행하기 전에 --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
Kubernetes 클러스터 설치를 실행합니다.
ANSIBLE_FORCE_COLOR=true - 로그에 색상 코드를 강제 출력하여 성공/실패를 색깔로 구분할 수 있게 합니다.
tee kubespray_install.log - 출력과 동시에 파일에 저장되어 설치 중 오류가 발생하면 해당 로그 파일을 참고하면 됩니다.

설치 완료 후 각 Task별 실행 시간이 출력됩니다. (총 설치 시간 6분 23초)
7) Kubernetes 설치 확인
# kubectl get node -v=6
I0131 20:41:32.490277 66683 loader.go:402] Config loaded from file: /root/.kube/config
I0131 20:41:32.490670 66683 envvar.go:172] "Feature gate default state" feature="InOrderInformers" enabled=true
I0131 20:41:32.490686 66683 envvar.go:172] "Feature gate default state" feature="WatchListClient" enabled=false
I0131 20:41:32.490713 66683 envvar.go:172] "Feature gate default state" feature="ClientsAllowCBOR" enabled=false
I0131 20:41:32.490732 66683 envvar.go:172] "Feature gate default state" feature="ClientsPreferCBOR" enabled=false
I0131 20:41:32.490748 66683 envvar.go:172] "Feature gate default state" feature="InformerResourceVersion" enabled=false
I0131 20:41:32.503781 66683 round_trippers.go:632] "Response" verb="GET" url="https://127.0.0.1:6443/api/v1/nodes?limit=500" status="200 OK" milliseconds=9
NAME STATUS ROLES AGE VERSION
k8s-ctrl Ready control-plane 2m33s v1.33.3
kubectl이 어떤 kubeconfig 파일을 사용하고, API Server에 어떤 요청을 보내고, 어떤 응답을 받았는지 볼 수 있습니다.
# kubectl get node -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-ctrl Ready control-plane 4m36s v1.33.3 192.168.105.151 <none> Ubuntu 22.04.5 LTS 5.15.0-164-generic containerd://2.1.5
// DiskPressure 문제로 argocd,ingress-nginx,node-feature-discovery 삭제..
# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-5d784884df-wl5p2 1/1 Running 0 15m
kube-system dns-autoscaler-676999957f-n9wls 1/1 Running 0 15m
kube-system kube-apiserver-k8s-ctrl 1/1 Running 1 16m
kube-system kube-controller-manager-k8s-ctrl 1/1 Running 2 16m
kube-system kube-flannel-pwqd5 1/1 Running 0 15m
kube-system kube-proxy-bs8rw 1/1 Running 0 15m
kube-system kube-scheduler-k8s-ctrl 1/1 Running 1 16m
kube-system metrics-server-7cd7f9897-79h5w 1/1 Running 0 14m
addon으로 ArgoCD, Ingress-nginx, Node Feature Discovery를 설치하였지만 디스크 용량 부족(DiskPressure) 문제로 삭제하였습니다.
8) Kubernetes 삭제
# ANSIBLE_FORCE_COLOR=true ansible-playbook -i inventory/mycluster/inventory.ini reset.yml -b | tee kubespray_reset.log

(추가)
Kubernetes 설치 후 시스템 상태 변화 확인
# 기본 환경 정보 출력 저장
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
설치 후 서버 상태를 파일로 저장합니다.
# 파일 출력 비교
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
설치 전 저장해놨던 파일과 설치 후 파일을 비교하여 시스템 상태 변화를 확인합니다.
- ip_addr — docker0, veth, flannel.1 등의 가상 네트워크 인터페이스가 새로 생성되었는지 확인
- ss — 6443(API Server), 2379/2380(etcd), 10250(kubelet), 10259(scheduler), 10257(controller-manager) 등 포트 확인
- df — 컨테이너 이미지와 overlay 파일시스템으로 인해 디스크 사용량이 얼마나 증가했는지 확인
- findmnt — overlay 파일시스템과 tmpfs가 새로 마운트되었는지 확인 (각 컨테이너마다 overlay 마운트 생성)
- sysctl — bridge-nf-call-iptables, ip_forward 등의 커널 매개변수가 올바르게 적용되었는지 확인
1. ip_addr-1.txt vs ip_addr-2.txt (네트워크 인터페이스)
설치 전에는 lo(루프백)와 ens33(물리 인터페이스) 두 개였지만 설치 후 다음 세 개의 가상 인터페이스가 추가되었습니다.

flannel.1
- IP: 10.233.64.1/16
- Flannel이 생성한 VXLAN 가상 인터페이스입니다. Pod 간 통신을 위한 오버레이 네트워크의 게이트웨이 역할을 합니다.
cni0
- IP: 10.233.64.1/24
- Flannel이 생성한 가상 브릿지입니다. 해당 노드에 실행 중인 Pod들이 이 브릿지를 통해 호스트 네트워크에 연결됩니다.
vethad31bb00, veth49e972c, veth09803dbf
- 각각 컨테이너마다 생성된 가상 이더넷 페어입니다. 컨테이너 내부의 eth0과 호스트의 cni0 브릿지를 연결하는 역할입니다. Pod가 하나 생길 때마다 veth 페어가 하나씩 추가됩니다.
- 세 개가 생성되었는데 이는 현재 실행 중인 Pod 수와 대응됩니다.
2. ss-1.txt vs ss-2.txt (포트 및 프로세스)
설치 전에는 sshd와 systemd-resolve만 리스닝 상태였습니다.
설치 후 추가된 포트와 프로세스는 다음과 같습니다.

| Port | Process | Description |
| 37897 | containerd | 컨테이너 런타임 내부 통신 |
| 2380 | etcd | etcd 클러스터 노드 간 통신 (peer 통신) |
| 2379 | etcd | etcd 클라이언트 요청 수신 (API Server 여기에 연결) |
| 10250 | kubelet | API Server에서 노드 상태 확인 및 Pod 관리 명령을 보내는 포트 |
| 10248 | kubelet | kubelet 헬스체크용 포트 |
| 10249 | kube-proxy | kube-proxy 메트릭 포트 |
| 10259 | kube-scheduler | 스케줄러 메트릭 및 리더 선출용 포트 |
| 10257 | kube-controller | 컨트롤러 매니저 메트릭 및 리더 선출용 포트 |
| 10256 | kube-proxy | kube-proxy 헬스체크용 포트 |
| 6443 | kube-apiserver | kubectl 및 클러스터 내부 모든 컴포넌트가 통신하는 메인 포트 |
3. df-1.txt vs df-2.txt (디스크 사용량)
두 파일의 차이는 다음과 같습니다.

루트 파일시스템(/) 사용량 증가
| 구분 | Used | Avail | Use |
| 설치 전 | 5.0G | 4.4G | 54% |
| 설치 후 | 7.1G | 2.2G | 77% |
컨테이너 이미지 레이어가 /var/lib/containerd에 저장되면서 약 2.1G가 추가로 사용되었습니다.
(사용율 77% - DiskPressure 문제 원인)
overlay 파일시스템 대량 추가
설치 후 /run/containerd/io.containerd.runtime.v2.task/k8s.io/... 경로에 overlay 타입의 마운트가 여러개 생성되었습니다.
각 컨테이너마다 하나씩 생성되고 이미지 레이어를 기반으로 컨테이너별 읽기-쓰기 레이어가 추가됩니다. 모두 루트 파일시스템의 9.8G 용량을 공유합니다.
tmpfs 및 shm 추가
각 Pod마다 /run/containerd/.../sandboxes/... 경로에 tmpfs와 shm이 생성됩니다.
shm은 컨테이너 간 공유 메모리 영역이고, 기본 크기는 64M입니다.
kubelet Pod별로는 용량이 조금 다르게 할당되는 경우도 있습니다.
4. sysctl-1.txt vs sysctl-2.txt (커널 매개변수)
sysctl 파일 차이입니다.

fs.dentry-state / fs.inode-nr / fs.inode-state — 파일시스템 오브젝트 수 증가
| 매개변수 | 설치 전 | 설치 후 |
| fs.dentry-state (첫 번째 값) | 147251 | 172730 |
| fs.file-nr (첫 번째 값) | 1440 | 2368 |
| fs.inode-nr (첫 번째 값) | 97828 | 115786 |
| fs.inode-state (첫 번째 값) | 97828 | 115786 |
컨테이너 이미지 레이어와 overlay 파일시스템이 대량으로 추가되면서 커널이 관리하는 dentry(디렉토리 엔트리), inode, 열린 파일 수가 모두 증가했습니다. fs.file-nr은 현재 열린 파일 디스크립터 수이고, fs.inode-nr은 사용 중인 inode 수입니다.
fs.quota.syncs — 쿼타 동기화 횟수
| 매개변수 | 설치 전 | 설치 후 |
| fs.quota.syncs | 26 | 85 |
파일시스템 쿼타 동기화가 반복 실행되었습니다. overlay 파일시스템의 마운트/유지 작업과 관련됩니다.
kernel.ns_last_pid — 마지막 생성된 PID
| 매개변수 | 설치 전 | 설치 후 |
| kernel.ns_last_pid | 52013 | 67410 |
마지막으로 할당된 PID 값을 의미합니다. Kubernetes 컨테이너 실행을 위한 프로세스들이 생성되면서 값이 증가하였습니다.
net.ipv4.conf.veth* / net.ipv4.conf.cni0 / net.ipv4.conf.flannel.1 — 가상 인터페이스별 네트워크 설정 추가
net.ipv4.conf 섹션에 veth09803dbf, vethad31bb00, veth49e972c, cni0, flannel.1 등의 가상 인터페이스별 설정이 대량으로 추가되었습니다. 각 인터페이스마다 동일한 구조의 설정값이 생성됩니다.
'Kubernetes' 카테고리의 다른 글
| [Kubernetes] 폐쇄망(Air-Gap) 환경에서 k8s 실습 환경 구성 (0) | 2026.02.14 |
|---|---|
| [Kubespray] Kubernetes HA 구성 실습 (0) | 2026.02.07 |
| [kubeadm] Kubernetes 버전 업그레이드 (1.32 -> 1.35) (0) | 2026.01.22 |
| Kubernetes 설치 과정에서 등장하는 용어 정리 (0) | 2026.01.19 |
| [Ansible] 개념 정리 및 실습 (0) | 2026.01.17 |