Kubeadm & K8s 업그레이드¶
kubeadm으로 Kubernetes 클러스터를 구축하고 버전 업그레이드하는 방법을 정리한다.
들어가며¶
Week 3에서는 kubeadm을 사용하여 Kubernetes 클러스터를 구축하고, 클러스터의 버전을 업그레이드하는 방법을 학습한다.
Week 1에서 "The Hard Way"로 모든 컴포넌트를 수동 설치하며 K8s의 내부 동작을 이해했다면, 이번 주차에서는 프로덕션 환경에서 실제로 사용되는 kubeadm 도구를 통해 효율적인 클러스터 운영 방법을 익힙니다.
학습 목표¶
- kubeadm의 동작 원리 이해
- kubeadm을 사용한 클러스터 구축 실습
- 인증서 생성 및 관리 방법 학습
- Kubernetes 버전 업그레이드 전략 및 실습
- 프로덕션 환경을 위한 모니터링 설정
실습 환경¶
가상머신 구성¶
| 호스트명 | IP | 역할 | vCPU | Memory | OS |
|---|---|---|---|---|---|
| k8s-ctr | 192.168.10.100 | Control Plane | 4 | 3GB | Rocky Linux 10.0 |
| k8s-w1 | 192.168.10.101 | Worker | 2 | 2GB | Rocky Linux 10.0 |
| k8s-w2 | 192.168.10.102 | Worker | 2 | 2GB | Rocky Linux 10.0 |
네트워크 설정¶
- Pod CIDR: 10.244.0.0/16
- Service CIDR: 10.96.0.0/16
- CNI: Flannel v0.27.3 (VXLAN)
컴포넌트 버전¶
- OS: Rocky Linux 10.0 (Kernel 6.12)
- Container Runtime: containerd v2.1.5
- Runc: v1.3.3
- Kubernetes: v1.32.11
- Helm: v3.18.6
Kubeadm Deep Dive¶
Kubeadm이란?¶
kubeadm은 Kubernetes Cluster Lifecycle 프로젝트의 핵심 도구로, 클러스터의 생성부터 업그레이드, 관리까지 전체 라이프사이클을 담당한다.
주요 기능¶
kubeadm init: Control Plane 노드 초기화kubeadm join: Worker 노드를 클러스터에 참여시킴kubeadm upgrade: 클러스터 버전 업그레이드kubeadm reset: kubeadm init/join으로 만든 변경사항 되돌리기
Kubeadm의 특징¶
- Control Plane as Static Pod: Control Plane 컴포넌트를 Static Pod로 구성
- 사전 설치 필요: CRI(containerd)와 kubelet은 별도로 설치 필요
- 광범위한 활용: minikube, kind, ClusterAPI, kubespray 등에서 사용
Kubeadm이 배포하는 컴포넌트¶
| 배포 방식 | 컴포넌트 |
|---|---|
| Static Pod로 배포 | etcd, kube-apiserver, kube-controller-manager, kube-scheduler |
| 애드온으로 배포 | CoreDNS (Deployment), kube-proxy (DaemonSet) |
Kubeadm 실행 흐름¶
Kubeadm Init 실행 단계¶
flowchart TD
A[kubeadm init] --> B["1. Preflight Checks"]
B --> C["2. 인증서 생성"]
C --> D["3. Kubeconfig 생성"]
D --> E["4. Static Pod 매니페스트 생성"]
E --> F["5. Kubelet 시작 및 대기"]
F --> G["6. ClusterConfiguration 저장"]
G --> H["7. 노드 라벨링/태인트"]
H --> I["8. Bootstrap 토큰 생성"]
I --> J["9. 필수 애드온 설치"]
J --> K[클러스터 준비 완료]
C --> C1["/etc/kubernetes/pki/"]
D --> D1["/etc/kubernetes/*.conf"]
E --> E1["/etc/kubernetes/manifests/"]
G --> G1["ConfigMap: kubeadm-config"]
H --> H1["control-plane 라벨<br>NoSchedule 태인트"]
I --> I1["TLS Bootstrap 설정"]
J --> J1["CoreDNS<br>kube-proxy"]
1. Preflight Checks¶
클러스터 구축 전 사전 점검: - CRI(containerd) 연결 확인 - Root 권한 확인 - kubelet 버전 확인 - 필수 포트 사용 가능 여부 - 커널 모듈 및 파라미터 확인
2. 인증서 생성¶
/etc/kubernetes/pki/ 디렉터리에 다음 인증서들을 생성:
| 인증서 | 유효기간 | 용도 |
|---|---|---|
| ca.crt/ca.key | 10년 | Root CA |
| etcd/ca.crt/ca.key | 10년 | etcd CA |
| apiserver.crt | 1년 | API Server TLS |
| apiserver-kubelet-client.crt | 1년 | API → Kubelet 통신 |
| front-proxy-ca.crt | 10년 | Aggregation Layer CA |
| sa.key/sa.pub | - | Service Account 토큰 서명 |
3. Kubeconfig 파일 생성¶
/etc/kubernetes/ 디렉터리에 각 컴포넌트용 kubeconfig 생성:
- admin.conf (kubectl용)
- kubelet.conf
- controller-manager.conf
- scheduler.conf
4. Static Pod 매니페스트 생성¶
/etc/kubernetes/manifests/ 디렉터리에 Control Plane 컴포넌트 매니페스트 생성:
- etcd.yaml
- kube-apiserver.yaml
- kube-controller-manager.yaml
- kube-scheduler.yaml
5. Kubelet 시작 및 API Server 헬스 체크 대기¶
kubelet이 Static Pod를 실행하고, API Server가 정상 동작할 때까지 대기한다.
6. ClusterConfiguration 저장¶
ConfigMap에 클러스터 설정 정보 저장:
- kube-system/kubeadm-config: 클러스터 설정
- kube-system/kubelet-config: kubelet 설정
7. 노드 라벨링 및 태인트 설정¶
Control Plane 노드에 다음 설정 적용:
- 라벨: node-role.kubernetes.io/control-plane=""
- 태인트: node-role.kubernetes.io/control-plane:NoSchedule
8. Bootstrap 토큰 생성¶
Worker 노드가 클러스터에 참여할 수 있도록 TLS Bootstrap 설정: - Bootstrap 토큰 생성 (24시간 유효) - RBAC 설정 (system:bootstrappers 그룹)
9. 필수 애드온 설치¶
- CoreDNS: 클러스터 내부 DNS
- kube-proxy: 서비스 네트워킹
Kubeadm Join 실행 단계¶
flowchart TD
A[kubeadm join] --> B["1. Preflight Checks"]
B --> C["2. Discovery"]
C --> D["3. Shared Token Discovery"]
D --> E["4. TLS Bootstrap"]
E --> F["5. Kubelet 설정"]
F --> G[노드 등록 완료]
C --> C1["cluster-info ConfigMap 조회"]
D --> D1["CA 인증서 해시 검증"]
E --> E1["CSR 생성 및 자동 승인"]
F --> F1["kubelet.conf 생성<br>노드 등록"]
1. Discovery 단계¶
Control Plane의 cluster-info ConfigMap을 조회하여 API Server 정보를 가져옵니다.
Shared Token Discovery 방식:
kubeadm join 192.168.10.100:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1234...
2. TLS Bootstrap¶
kubelet이 자신의 인증서를 자동으로 발급받는 과정:
- Bootstrap 토큰으로 CSR(Certificate Signing Request) 생성
- API Server에 CSR 제출
- kube-controller-manager가 자동으로 승인
- 인증서 발급 및 kubelet.conf 생성
클러스터 구축 절차¶
1. 사전 설정 (모든 노드)¶
Time/NTP 설정¶
# KST 타임존 설정
> kubeadm을 활용한 Kubernetes 클러스터 구축 및 업그레이드를 학습한다.
timedatectl set-timezone Asia/Seoul
# Chrony NTP 설정
systemctl enable --now chronyd
SELinux 설정¶
# Permissive 모드로 변경
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
Firewalld 비활성화¶
Swap 완전 비활성화¶
# 즉시 비활성화
swapoff -a
# 영구 비활성화
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# zram swap 비활성화
systemctl disable --now zram-swap.service
| 이유 | 설명 |
|---|---|
| 리소스 예측 불가능 | Pod가 메모리를 초과해도 죽지 않고 디스크를 사용하게 됨 |
| K8s 관리 철학 위배 | 메모리 부족 시 즉시 OOMKilled 후 재시작하는 것이 K8s 철학 |
| 클러스터 성능 저하 | 스케줄링 판단에 오류 발생 가능 |
커널 모듈 로드¶
cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
커널 파라미터 설정¶
cat <<EOF | 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
sysctl --system
hosts 파일 설정¶
2. Container Runtime 설치 (Containerd)¶
Docker CE Repository 추가¶
Containerd 설치¶
Containerd 설정¶
# 기본 설정 파일 생성
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
# SystemdCgroup 설정 변경 (매우 중요!)
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' \
/etc/containerd/config.toml
# Containerd 시작
systemctl enable --now containerd
# Snapshotter 확인
ctr plugin ls | grep overlayfs
3. Kubeadm, Kubelet, Kubectl 설치¶
Kubernetes Repository 추가¶
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.32/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.32/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF
설치¶
dnf install -y kubelet-1.32.11 kubeadm-1.32.11 kubectl-1.32.11 \
--disableexcludes=kubernetes
systemctl enable --now kubelet
crictl 설정¶
cat <<EOF > /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
EOF
4. Control Plane 초기화 (k8s-ctr)¶
kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/16 \
--apiserver-advertise-address=192.168.10.100
kubectl 설정¶
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
CNI 설치 (Flannel)¶
5. Worker 노드 참여 (k8s-w1, k8s-w2)¶
Control Plane 초기화 후 출력된 join 명령어를 각 Worker 노드에서 실행:
kubeadm join 192.168.10.100:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1234...
클러스터 확인¶
OverlayFS와 Snapshotter¶
OverlayFS란?¶
OverlayFS는 여러 파일시스템 레이어를 하나로 겹쳐 보이게 하는 Union Filesystem 기술이다.
graph TB
subgraph "OverlayFS 구조"
A["Merged View<br>컨테이너에서 보이는 통합 파일시스템"] --> B["Upper Layer<br>쓰기 가능 레이어<br>컨테이너의 변경사항"]
A --> C["Lower Layer 3<br>읽기 전용 이미지 레이어"]
A --> D["Lower Layer 2<br>읽기 전용 이미지 레이어"]
A --> E["Lower Layer 1<br>읽기 전용 이미지 레이어<br>Base Image"]
end
F["Container Write"] -.-> B
G["Image Layers"] -.-> C
G -.-> D
G -.-> E
장점:
- 디스크 공간 절약: 이미지 레이어 공유
- 빠른 컨테이너 시작: 레이어 재사용
동작 방식:
| Layer | 설명 |
|---|---|
| Lower Layer | 읽기 전용 이미지 레이어 (여러 개 가능) |
| Upper Layer | 쓰기 가능한 컨테이너 레이어 |
| Merged View | 사용자에게 보이는 통합된 파일시스템 |
Snapshotter란?¶
Snapshotter는 컨테이너 이미지 레이어를 스냅샷 단위로 관리하는 컴포넌트이다.
flowchart LR
A[Image Pull] --> B[Snapshotter]
B --> C[레이어별 스냅샷 생성]
C --> D[컨테이너 실행 시]
D --> E[스냅샷 체인 마운트]
E --> F[OverlayFS 구성]
F --> G[컨테이너 실행]
H[컨테이너 삭제] --> I[Upper Layer 스냅샷 삭제]
I --> J[Lower Layer 유지]
Snapshotter 종류:
- overlayfs (기본, 권장): OverlayFS 기반
- native: 심플한 디렉터리 복사
- btrfs: Btrfs 파일시스템 스냅샷
- zfs: ZFS 파일시스템 스냅샷
- devmapper: Device Mapper thin provisioning
동작 시점: 1. 이미지 pull 시: 레이어별 스냅샷 생성 2. 컨테이너 실행 시: 스냅샷 체인을 OverlayFS로 마운트 3. 컨테이너 삭제 시: Upper Layer 스냅샷만 삭제 (Lower Layer 유지)
인증서 관리¶
생성되는 인증서 목록¶
kubeadm init 시 /etc/kubernetes/pki/ 디렉터리에 다음 인증서들이 생성된다:
| 인증서 | CN | O | 유효기간 | 용도 |
|---|---|---|---|---|
| ca.crt | kubernetes | - | 10년 | Root CA |
| etcd/ca.crt | etcd-ca | - | 10년 | etcd CA |
| apiserver.crt | kube-apiserver | - | 1년 | TLS Web Server |
| apiserver-kubelet-client.crt | kube-apiserver-kubelet-client | kubeadm:cluster-admins | 1년 | TLS Web Client |
| apiserver-etcd-client.crt | kube-apiserver-etcd-client | system:masters | 1년 | etcd 클라이언트 |
| front-proxy-ca.crt | front-proxy-ca | - | 10년 | Aggregation Layer CA |
| front-proxy-client.crt | front-proxy-client | - | 1년 | Aggregation Layer |
| sa.key / sa.pub | service-accounts | - | - | SA 토큰 서명 |
Kubelet 인증서¶
Server 인증서 (TLS Web Server):
- CN: <nodename>@<timestamp>
- 유효기간: 1년
- 위치: /var/lib/kubelet/pki/kubelet-server-*.crt
Client 인증서 (TLS Web Client):
- CN: system:node:<nodename>
- O: system:nodes
- 유효기간: 1년
- 자동 갱신: kubelet이 만료 전 자동으로 갱신
인증서 확인¶
# 모든 인증서 만료일 확인
kubeadm certs check-expiration
# 특정 인증서 상세 확인
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout
인증서 갱신 (Manual Renewal)¶
갱신 명령어¶
갱신 영향도¶
다운타임: - K8s API 요청: 수초~수십 초 중단 - kubectl: 일시적 실패 가능 - 워크로드: 영향 없음 (Pod는 계속 실행)
재시작 필요: - Static Pod 재시작 필수 (새 인증서 로드) - admin.conf kubeconfig 재적용 필요
주의사항: - CA는 갱신되지 않음 (10년 유효, 만료 시 클러스터 재구축 필요) - HA 환경에서는 모든 Control Plane 노드에서 실행 - kubelet 인증서는 자동 갱신되므로 수동 갱신 불필요
Static Pod 재시작¶
# Static Pod 매니페스트 touch (자동 재시작)
touch /etc/kubernetes/manifests/kube-apiserver.yaml
touch /etc/kubernetes/manifests/kube-controller-manager.yaml
touch /etc/kubernetes/manifests/kube-scheduler.yaml
# 또는 kubelet 재시작
systemctl restart kubelet
admin.conf 재적용¶
인증서 체인 구조¶
graph TD
subgraph "Kubernetes CA"
CA["CA<br>kubernetes<br>10년"] --> API["apiserver.crt<br>kube-apiserver<br>1년"]
CA --> APIKUBE["apiserver-kubelet-client.crt<br>kube-apiserver-kubelet-client<br>O: kubeadm:cluster-admins<br>1년"]
CA --> ADMIN["admin.crt<br>kubernetes-admin<br>O: kubeadm:cluster-admins<br>1년"]
CA --> KUBELET["kubelet-client.crt<br>system:node:k8s-ctr<br>O: system:nodes<br>자동 갱신"]
end
subgraph "etcd CA"
ETCDCA["etcd/ca.crt<br>etcd-ca<br>10년"] --> ETCD["etcd/server.crt<br>k8s-ctr<br>1년"]
ETCDCA --> ETCDPEER["etcd/peer.crt<br>k8s-ctr<br>1년"]
ETCDCA --> APIETCD["apiserver-etcd-client.crt<br>kube-apiserver-etcd-client<br>O: system:masters<br>1년"]
end
subgraph "Front Proxy CA"
FRONTCA["front-proxy-ca.crt<br>front-proxy-ca<br>10년"] --> FRONT["front-proxy-client.crt<br>front-proxy-client<br>1년"]
end
subgraph "SA Token"
SA["sa.key / sa.pub<br>service-accounts<br>Private/Public Key Pair"]
end
모니터링 설정¶
Metrics Server 설치¶
Metrics Server는 kubelet으로부터 메트릭을 수집하여 kubectl top 명령어를 사용할 수 있게 한다.
helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/
helm install metrics-server metrics-server/metrics-server \
--set 'args[0]=--kubelet-insecure-tls' \
-n kube-system
--kubelet-insecure-tls 옵션:
- kubelet의 서버 인증서를 검증하지 않음
- 테스트 환경에서 사용 (프로덕션에서는 적절한 인증서 설정 필요)
확인¶
Kube-Prometheus-Stack 설치¶
Kube-Prometheus-Stack은 Prometheus, Grafana, Alertmanager를 포함한 완전한 모니터링 솔루션이다.
helm repo add prometheus-community \
https://prometheus-community.github.io/helm-charts
helm install kube-prometheus-stack \
prometheus-community/kube-prometheus-stack \
-n monitoring --create-namespace \
--set prometheus.service.type=NodePort \
--set prometheus.service.nodePort=30001 \
--set grafana.service.type=NodePort \
--set grafana.service.nodePort=30002
접속 정보¶
| 서비스 | URL | 인증 정보 |
|---|---|---|
| Prometheus | http://192.168.10.100:30001 | - |
| Grafana | http://192.168.10.100:30002 | 사용자: admin 비밀번호: prom-operator |
권장 Grafana 대시보드¶
| 대시보드 ID | 설명 |
|---|---|
| 15661 | Kubernetes Cluster Monitoring (Prometheus) |
| 15757 | Kubernetes / Views / Global |
| 13922 | x509 Certificate Exporter (인증서 만료 모니터링) |
Control Plane 메트릭 수집 설정¶
기본적으로 kube-controller-manager와 kube-scheduler는 localhost에서만 메트릭을 제공한다. Prometheus가 수집할 수 있도록 bind-address를 변경한다.
kube-controller-manager 설정¶
spec:
containers:
- command:
- kube-controller-manager
- --bind-address=0.0.0.0 # 127.0.0.1 → 0.0.0.0
kube-scheduler 설정¶
etcd 메트릭 설정¶
spec:
containers:
- command:
- etcd
- --listen-metrics-urls=http://127.0.0.1:2381,http://192.168.10.100:2381
확인¶
# kube-controller-manager 메트릭
curl http://192.168.10.100:10257/metrics
# kube-scheduler 메트릭
curl http://192.168.10.100:10259/metrics
# etcd 메트릭
curl http://192.168.10.100:2381/metrics
x509 Certificate Exporter 설치¶
인증서 만료를 모니터링하는 Prometheus Exporter이다.
helm repo add enix https://charts.enix.io
helm install x509-certificate-exporter enix/x509-certificate-exporter \
-n monitoring \
--set hostPathsExporter.daemonSets.cp.nodeSelector."node-role\.kubernetes\.io/control-plane"="" \
--set hostPathsExporter.daemonSets.cp.tolerations[0].effect=NoSchedule \
--set hostPathsExporter.daemonSets.cp.tolerations[0].key=node-role.kubernetes.io/control-plane \
--set hostPathsExporter.daemonSets.cp.watchDirectories={/etc/kubernetes/pki} \
--set hostPathsExporter.daemonSets.nodes.watchDirectories={/var/lib/kubelet/pki}
| DaemonSet | 대상 노드 | 감시 디렉터리 |
|---|---|---|
| cp | Control Plane | /etc/kubernetes/pki |
| nodes | Worker | /var/lib/kubelet/pki |
Grafana 대시보드 13922¶
- 경고 레벨:
- Warning: 28일 이하
- Critical: 14일 이하
Kubernetes Version Skew Policy¶
버전 정책¶
Kubernetes는 1년에 3개의 마이너 버전을 출시하며, 최근 3개 버전을 지원한다.
- 현재 지원 버전 (예시): 1.35, 1.34, 1.33
- 버전 형식: 메이저.마이너.패치 (예: 1.32.11)
컴포넌트별 버전 호환성¶
graph TB
subgraph "Version Skew Policy"
API["kube-apiserver<br>1.32"] --> KCM["kube-controller-manager<br>1.32 ~ 1.31<br>-1 마이너 버전"]
API --> SCHED["kube-scheduler<br>1.32 ~ 1.31<br>-1 마이너 버전"]
API --> KUBELET["kubelet<br>1.32 ~ 1.29<br>-3 마이너 버전"]
API --> PROXY["kube-proxy<br>1.32 ~ 1.29<br>-3 마이너 버전"]
KUBECTL["kubectl<br>1.33 ~ 1.31<br>±1 마이너 버전"] -.-> API
KUBELET -.-> PROXY2["kube-proxy와<br>최대 ±3 마이너 버전 차이"]
end
subgraph "HA Control Plane"
API2["kube-apiserver<br>1.32 NEW"]
API3["kube-apiserver<br>1.31 OLD"]
API2 -.-> API3
end
kube-apiserver (HA 환경)¶
- 업그레이드 시 NEW 버전과 OLD 버전이 동시 운영 가능
- 예: 1.32 + 1.31 동시 운영
kubelet¶
- apiserver보다 NEW 불가
- apiserver보다 최대 3개 마이너 버전 OLD 가능
- 예: apiserver 1.32 → kubelet 1.32/1.31/1.30/1.29
kube-controller-manager, kube-scheduler, cloud-controller-manager¶
- apiserver보다 NEW 불가
- apiserver보다 최대 1개 마이너 버전 OLD 가능
- 예: apiserver 1.32 → kcm/scheduler 1.32/1.31
kube-proxy¶
- apiserver보다 NEW 불가
- apiserver보다 최대 3개 마이너 버전 OLD 가능
- kubelet보다 최대 3개 마이너 버전 NEW/OLD 가능
kubectl¶
- apiserver보다 최대 1개 마이너 버전 NEW/OLD 가능
- 예: apiserver 1.32 → kubectl 1.33/1.32/1.31
Kubernetes 버전 업그레이드¶
업그레이드 전략¶
1. In-Place Upgrade¶
기존 클러스터를 순차적으로 업그레이드하는 방식이다.
장점: - 리소스 절약 (추가 클러스터 불필요) - Version Skew Policy 활용 가능
단점: - 업그레이드 중 다운타임 발생 가능 - 롤백이 복잡함
적합한 경우: - 리소스가 제한적인 환경 - 테스트/개발 환경
2. Blue-Green Upgrade¶
신규 클러스터를 생성한 후 트래픽을 전환하는 방식이다.
장점: - 빠른 롤백 가능 - 다운타임 최소화 - 업그레이드 테스트 용이
단점: - 2배의 리소스 필요 - 스토리지 마이그레이션 복잡
적합한 경우: - 프로덕션 환경 - 무중단 업그레이드 필요
graph LR
subgraph "In-Place Upgrade"
A1["v1.32 Cluster"] --> A2["v1.33 Cluster<br>순차 업그레이드"]
A2 --> A3["v1.34 Cluster"]
end
subgraph "Blue-Green Upgrade"
B1["Blue: v1.32 Cluster<br>현재 운영"] --> B2["Green: v1.34 Cluster<br>신규 생성"]
B2 --> B3["트래픽 전환<br>Blue → Green"]
B3 --> B4["Blue 클러스터 제거"]
end
업그레이드 절차 (In-Place)¶
예시: 1.32 → 1.34 업그레이드¶
업그레이드 경로: 1.32 → 1.33 → 1.34
주의: 한 번에 1개 마이너 버전씩만 업그레이드 가능
사전 준비¶
1. ETCD 백업¶
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
2. CNI 업그레이드 (Flannel)¶
# Flannel 버전 확인
kubectl get ds -n kube-flannel kube-flannel-ds -o yaml | grep image:
# 최신 버전으로 업그레이드
kubectl apply -f \
https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
3. 업그레이드 계획 확인¶
Control Plane 업그레이드 (k8s-ctr)¶
1단계: 1.32 → 1.33¶
# 1. OS/Kernel 업그레이드 (선택)
dnf update -y && reboot
# 2. Containerd 업그레이드 (선택)
dnf update containerd.io -y
systemctl restart containerd
# 3. kubeadm 1.33 설치
dnf install -y kubeadm-1.33.* --disableexcludes=kubernetes
# 4. 업그레이드 계획 확인
kubeadm upgrade plan
# 5. 업그레이드 실행
kubeadm upgrade apply v1.33.0
# 6. kubelet, kubectl 업그레이드
dnf install -y kubelet-1.33.* kubectl-1.33.* --disableexcludes=kubernetes
systemctl daemon-reload
systemctl restart kubelet
# 7. 확인
kubectl get nodes
2단계: 1.33 → 1.34¶
# 1. kubeadm 1.34 설치
dnf install -y kubeadm-1.34.* --disableexcludes=kubernetes
# 2. 업그레이드 실행
kubeadm upgrade apply v1.34.0
# 3. kubelet, kubectl 업그레이드
dnf install -y kubelet-1.34.* kubectl-1.34.* --disableexcludes=kubernetes
systemctl daemon-reload
systemctl restart kubelet
# 4. 확인
kubectl get nodes
Worker 노드 업그레이드 (k8s-w1, k8s-w2)¶
각 Worker 노드를 순차적으로 업그레이드한다.
1단계: 1.32 → 1.33¶
Control Plane에서 실행 (k8s-ctr):
Worker 노드에서 실행 (k8s-w1):# 1. OS/Kernel 업그레이드 (선택)
dnf update -y && reboot
# 2. Containerd 업그레이드 (선택)
dnf update containerd.io -y
systemctl restart containerd
# 3. kubeadm 1.33 설치
dnf install -y kubeadm-1.33.* --disableexcludes=kubernetes
# 4. 노드 업그레이드
kubeadm upgrade node
# 5. kubelet 업그레이드
dnf install -y kubelet-1.33.* --disableexcludes=kubernetes
systemctl daemon-reload
systemctl restart kubelet
2단계: 1.33 → 1.34¶
위 단계를 반복하여 1.34로 업그레이드한다.
# Drain
kubectl drain k8s-w1 --ignore-daemonsets --delete-emptydir-data
# Worker 노드에서
dnf install -y kubeadm-1.34.* --disableexcludes=kubernetes
kubeadm upgrade node
dnf install -y kubelet-1.34.* --disableexcludes=kubernetes
systemctl daemon-reload
systemctl restart kubelet
# Uncordon
kubectl uncordon k8s-w1
업그레이드 흐름도¶
flowchart TD
A[업그레이드 준비] --> B["ETCD 백업"]
B --> C["CNI 업그레이드"]
C --> D[업그레이드 계획 확인]
D --> E1["Control Plane 1<br>1.32 → 1.33 → 1.34"]
E1 --> E2{"HA 구성?"}
E2 -->|Yes| E3["Control Plane 2<br>1.32 → 1.33 → 1.34"]
E2 -->|No| F1
E3 --> E4["Control Plane 3<br>1.32 → 1.33 → 1.34"]
E4 --> F1
F1["Worker 1 Drain"] --> F2["Worker 1<br>1.32 → 1.33 → 1.34"]
F2 --> F3["Worker 1 Uncordon"]
F3 --> G1["Worker 2 Drain"]
G1 --> G2["Worker 2<br>1.32 → 1.33 → 1.34"]
G2 --> G3["Worker 2 Uncordon"]
G3 --> H[업그레이드 완료]
업그레이드 고려사항¶
1. 호환성 확인¶
- Addon 호환성: CNI, CSI, 모니터링 도구 등
- API 리소스 버전 변경: Deprecated API 확인
- OS/CRI/Kubelet 호환성: 지원 매트릭스 확인
2. 워크로드 영향¶
- PodDisruptionBudget: 최소 가용 Pod 수 설정
- StatefulSet: 순차적 업그레이드 보장
- DaemonSet: 노드 Drain 시 자동 재생성
- Static Pod: Control Plane 업그레이드 시 자동 재시작
3. 데이터 백업¶
- ETCD 백업: 하위 호환성 유지 (복원 가능)
- PersistentVolume: 스토리지 백업
- ConfigMap/Secret: 중요 설정 백업
4. 무중단 서비스 확인¶
- LoadBalancer: 트래픽 분산 확인
- Readiness Probe: Pod 준비 상태 체크
- Liveness Probe: Pod 헬스 체크
- RollingUpdate: 점진적 배포 설정
주요 개념 상세 설명¶
Kubelet Sysctl 파라미터 변경¶
kubeadm은 kubelet 시작 시 특정 커널 파라미터를 변경한다.
Kubelet 적용 파라미터¶
# Kernel Panic 발생 시 10초 후 재부팅
kernel.panic = 0 → 10
# Oops 발생 시 Panic 유도 (유지)
kernel.panic_on_oops = 1
# 메모리 오버커밋 허용
vm.overcommit_memory = 0 → 1
# OOM 시 Panic 방지 (유지)
vm.panic_on_oom = 0
# Root 사용자 최대 키 수 (유지)
kernel.keys.root_maxkeys = 1000000
# Root 사용자 키 최대 바이트 (유지)
kernel.keys.root_maxbytes = 25000000
Kube-proxy 적용 파라미터¶
# Connection Tracking 최대 수
net.nf_conntrack_max = 65536 → 131072
# TCP Close-Wait 타임아웃 (초)
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60 → 3600
# TCP Established 타임아웃 (초)
net.netfilter.nf_conntrack_tcp_timeout_established = 432000 → 86400
--protect-kernel-defaults 옵션¶
- false (기본): kubeadm이 커널 파라미터 변경 - true: 기본값과 다르면 kubelet 시작 실패 (프로덕션 권장)공식 문서¶
- kubeadm 공식 문서
- Kubernetes Version Skew Policy
- Kubernetes Upgrade Guide
- Certificate Management
- etcd Backup and Restore
모니터링¶
CNI¶
컨테이너 런타임¶
마치며¶
Week 3에서는 kubeadm을 사용하여 Kubernetes 클러스터를 구축하고, 버전 업그레이드를 수행하는 방법을 학습했다.
핵심 포인트:
- kubeadm의 동작 원리: init/join 프로세스의 각 단계 이해
- 인증서 관리: 생성, 확인, 갱신 절차
- 모니터링: Prometheus, Grafana, x509 Exporter 설정
- Version Skew Policy: 컴포넌트별 버전 호환성
- 업그레이드 전략: In-Place vs Blue-Green
Week 1에서 "The Hard Way"로 K8s의 내부를 깊이 이해했고, Week 3에서 kubeadm을 통해 실무에서 사용하는 효율적인 클러스터 운영 방법을 익혔다!