246. Deployment With kubeadm - Introduction
kubeadm 설치 흐름
- VM 프로비저닝 (Vagrant / Cloud)
- 컨테이너 런타임 설치 (containerd)
- kubeadm / kubelet / kubectl 설치
- 마스터 노드 초기화 —
kubeadm init - CNI 플러그인 설치 (Weave / Calico)
- 워커 노드 Join —
kubeadm join
248. Provision VMs With Vagrant
Vagrantfile 예시 (마스터 1 + 워커 2)
# Vagrantfile
ENV['VAGRANT_NO_PARALLEL'] = 'yes'
Vagrant.configure("2") do |config|
# 마스터 노드
config.vm.define "kubemaster" do |node|
node.vm.box = "ubuntu/focal64"
node.vm.hostname = "kubemaster"
node.vm.network "private_network", ip: "192.168.56.2"
node.vm.provider "virtualbox" do |v|
v.name = "kubemaster"
v.cpus = 2
v.memory = 2048
end
end
# 워커 노드
NodeCount = 2
(1..NodeCount).each do |i|
config.vm.define "kubenode0#{i}" do |node|
node.vm.box = "ubuntu/focal64"
node.vm.hostname = "kubenode0#{i}"
node.vm.network "private_network", ip: "192.168.56.#{i + 2}"
node.vm.provider "virtualbox" do |v|
v.name = "kubenode0#{i}"
v.cpus = 1
v.memory = 1024
end
end
end
end# VM 시작
vagrant up
# VM 상태 확인
vagrant status
# 특정 VM SSH 접속
vagrant ssh kubemaster
vagrant ssh kubenode01249. Demo - Deployment with kubeadm
Step 1. 모든 노드 공통 설정
Step 1에서 하는 일들의 의미
- swap 비활성화: kubelet은 Pod의 메모리 사용량을 정확히 알아야 스케줄링/OOM 결정이 가능. swap이 켜져있으면 RAM 부족해도 디스크로 밀려가 성능 예측 불가 → v1.22+부터 조건부 허용이지만 여전히 비활성화 권장.
- br_netfilter 커널 모듈: iptables 규칙이 브리지를 통과하는 트래픽(Pod 간 통신)에도 적용되게 함. 없으면 kube-proxy가 Service 트래픽을 제어 못함.
- ip_forward=1: Linux가 라우터처럼 패킷 포워딩하게 허용. Pod 네트워킹에 필수.
# ── 1-1. swap 비활성화 ──────────────────────────────────────
sudo swapoff -a
# 재부팅 후에도 유지: /etc/fstab에서 swap 라인 주석 처리
sudo sed -i '/ swap / s/^/#/' /etc/fstab
# ── 1-2. 커널 모듈 로드 ─────────────────────────────────────
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# ── 1-3. sysctl 파라미터 설정 ────────────────────────────────
cat <<EOF | sudo tee /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
sudo sysctl --systemStep 2. 컨테이너 런타임 설치 (containerd)
# ── 2-1. Docker 공식 GPG 키 및 저장소 추가 ──────────────────
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# ── 2-2. containerd 설치 ─────────────────────────────────────
sudo apt-get update
sudo apt-get install -y containerd.io
# ── 2-3. containerd 기본 설정 생성 ──────────────────────────
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# ── 2-4. SystemdCgroup 활성화 (중요!) ───────────────────────
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' \
/etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd
# 확인
sudo systemctl status containerd
SystemdCgroup = true설정이 없으면 kubelet과 cgroup 드라이버 불일치로 노드가 NotReady 상태가 됨
왜 SystemdCgroup인가? cgroup(control groups)은 Linux가 프로세스별 CPU/메모리 한도를 강제하는 메커니즘. 이걸 관리하는 드라이버가 systemd(시스템 전체 관리) 또는 cgroupfs(직접 조작) 두 가지가 있음.
- 현대 리눅스는 systemd가 이미 cgroup을 관리하고 있음
- 거기에 cgroupfs가 또 끼어들면 이중 관리로 충돌 발생 → Pod가 의도한 리소스 한도를 못 받음
- kubelet과 containerd 모두 SystemdCgroup으로 통일해야 함
Step 3. kubeadm / kubelet / kubectl 설치
# ── 3-1. Kubernetes apt 저장소 추가 ─────────────────────────
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | \
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \
https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | \
sudo tee /etc/apt/sources.list.d/kubernetes.list
# ── 3-2. 설치 ──────────────────────────────────────────────
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
# 자동 업데이트 방지 (버전 고정)
sudo apt-mark hold kubelet kubeadm kubectl
# 확인
kubeadm version
kubectl version --client
kubelet --versionStep 4. 마스터 노드 초기화 (마스터에서만)
# kubeadm init
sudo kubeadm init \
--apiserver-advertise-address=192.168.56.2 \
--pod-network-cidr=10.244.0.0/16
# ── init 완료 후 kubectl 설정 ────────────────────────────────
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 클러스터 확인
kubectl get nodes # 마스터 노드 NotReady (CNI 미설치)
kubectl get pods -A # kube-system 파드 상태 확인
kubeadm init출력 마지막의kubeadm join명령어를 반드시 저장해 둘 것
Step 5. CNI 플러그인 설치 (마스터에서)
CNI 설치 전에는 노드가 NotReady 상태. Pod 간 통신을 책임질 네트워크가 아직 없기 때문. CNI 설치 → CoreDNS Pod 정상 기동 → 노드가 Ready로 전환.
CNI 선택 기준 (어떤 걸 쓸까?)
| CNI | 장점 | 단점 | 선택 상황 |
|---|---|---|---|
| Flannel | 설치 간단, 리소스 적음 | Network Policy 미지원 | 학습/개발, 보안 요구 낮음 |
| Weave | 암호화 옵션, Network Policy 지원 | 성능 평범 | 중규모, 암호화 필요 |
| Calico | Network Policy 정식 지원, BGP 라우팅 고성능 | 설정 복잡 | 프로덕션 표준 |
| Cilium | eBPF 기반 고성능, L7 정책 지원 | 커널 요구사항 있음 | 대규모, 관측성 중요 |
시험 환경은 대부분 Flannel 또는 Weave. 실무는 Calico가 사실상 표준.
# Flannel (--pod-network-cidr=10.244.0.0/16 필요)
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
# Weave Net
kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml
# Calico
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/calico.yaml
# CNI 설치 후 노드 상태 확인 (Ready로 변경되어야 함)
kubectl get nodes
kubectl get pods -n kube-systemStep 6. 워커 노드 Join (각 워커에서)
# kubeadm init 출력에서 복사한 join 명령 실행
sudo kubeadm join 192.168.56.2:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:<hash>
# 마스터에서 노드 확인
kubectl get nodesjoin 토큰 재발급 (만료된 경우)
kubeadm이 init 시 출력한 join 명령의 토큰은 기본 24시간 만료. 그 이후에 워커를 추가하려면 재발급 필요.
# 토큰 목록 확인
kubeadm token list
# 새 토큰 생성
kubeadm token create
# CA 인증서 해시 확인
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | \
openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'
# 토큰 + 해시를 합쳐 join 명령 재구성 (가장 편리)
kubeadm token create --print-join-command
# Control Plane용 certificate-key 재업로드 (HA 추가 시)
sudo kubeadm init phase upload-certs --upload-certskubeadm 전체 설치 요약
| 단계 | 대상 | 작업 |
|---|---|---|
| 1 | 모든 노드 | swap 비활성화, 커널 모듈 로드, sysctl 설정 |
| 2 | 모든 노드 | containerd 설치 (SystemdCgroup=true) |
| 3 | 모든 노드 | kubeadm + kubelet + kubectl 설치 (apt-mark hold로 버전 고정) |
| 4 | 마스터 노드만 | kubeadm init → ~/.kube/config 설정 |
| 5 | 마스터 노드만 | CNI 플러그인 설치 (Weave / Flannel / Calico) |
| 6 | 워커 노드 | kubeadm join 실행 |
| 7 | 검증 | kubectl get nodes, kubectl get pods -A |
250. Lab
CKA 시험은
kubernetes.io문서만 접근 가능. 메뉴 트리 대신 우상단 검색창에 키워드 치는 게 빠름. 코드 블록 위 OS 탭(Ubuntu/RHEL 등) 도 항상 확인.
진입 페이지 매핑
| 단계 | 페이지 제목 | 검색 키워드 |
|---|---|---|
| 1. 사전 준비 | Installing kubeadm → Before you begin | installing kubeadm |
| 2. containerd 설치 | Container Runtimes | container runtimes |
| 3. kubeadm 패키지 | Installing kubeadm → Installing kubeadm, kubelet and kubectl | installing kubeadm |
4. kubeadm init | Creating a cluster with kubeadm → Initializing your control-plane node | creating a cluster with kubeadm |
| 5. CNI 설치 | Creating a cluster with kubeadm → Installing a Pod network add-on | (위와 동일) |
6. kubeadm join | Creating a cluster with kubeadm → Joining your nodes | (위와 동일) |
| 7. 토큰 재발급 | Creating a cluster with kubeadm → Manage tokens | kubeadm token |
CNI별 --pod-network-cidr
| CNI | --pod-network-cidr |
|---|---|
| Weave | 기본값 (지정 안 해도 됨) |
| Flannel | 10.244.0.0/16 |
| Calico | 192.168.0.0/16 |
시험에서 자주 빠뜨리는 디테일
페이지 따라하기만 해선 놓치는 것
- swap:
swapoff -a외에/etc/fstab에서 swap 라인 주석 처리(영구 비활성화) 문제로 자주 출제- 코드 블록 위 OS 탭이 Ubuntu/Debian(apt) 인지 확인
- containerd
SystemdCgroup=true누락 → kubelet crashloopkubeadm init후 kubeconfig 복사 3줄 (mkdir -p $HOME/.kube…) 잊지 말기- 다중 NIC 환경에서는
--apiserver-advertise-address명시- 워커에서
kubeadm join전, 1~3단계 완료됐는지 확인