246. Deployment With kubeadm - Introduction

kubeadm 설치 흐름

  1. VM 프로비저닝 (Vagrant / Cloud)
  2. 컨테이너 런타임 설치 (containerd)
  3. kubeadm / kubelet / kubectl 설치
  4. 마스터 노드 초기화kubeadm init
  5. CNI 플러그인 설치 (Weave / Calico)
  6. 워커 노드 Joinkubeadm 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 kubenode01

249. 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 --system

Step 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 --version

Step 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 지원성능 평범중규모, 암호화 필요
CalicoNetwork Policy 정식 지원, BGP 라우팅 고성능설정 복잡프로덕션 표준
CiliumeBPF 기반 고성능, 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-system

Step 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 nodes

join 토큰 재발급 (만료된 경우)

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-certs

kubeadm 전체 설치 요약

단계대상작업
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 kubeadmBefore you begininstalling kubeadm
2. containerd 설치Container Runtimescontainer runtimes
3. kubeadm 패키지Installing kubeadmInstalling kubeadm, kubelet and kubectlinstalling kubeadm
4. kubeadm initCreating a cluster with kubeadmInitializing your control-plane nodecreating a cluster with kubeadm
5. CNI 설치Creating a cluster with kubeadmInstalling a Pod network add-on(위와 동일)
6. kubeadm joinCreating a cluster with kubeadmJoining your nodes(위와 동일)
7. 토큰 재발급Creating a cluster with kubeadmManage tokenskubeadm token

CNI별 --pod-network-cidr

CNI--pod-network-cidr
Weave기본값 (지정 안 해도 됨)
Flannel10.244.0.0/16
Calico192.168.0.0/16

시험에서 자주 빠뜨리는 디테일

페이지 따라하기만 해선 놓치는 것

  • swap: swapoff -a 외에 /etc/fstab에서 swap 라인 주석 처리(영구 비활성화) 문제로 자주 출제
  • 코드 블록 위 OS 탭이 Ubuntu/Debian(apt) 인지 확인
  • containerd SystemdCgroup=true 누락 → kubelet crashloop
  • kubeadm init 후 kubeconfig 복사 3줄 (mkdir -p $HOME/.kube …) 잊지 말기
  • 다중 NIC 환경에서는 --apiserver-advertise-address 명시
  • 워커에서 kubeadm join 전, 1~3단계 완료됐는지 확인