RKE2 & Cluster API¶
Week 7 학습 주제: Rancher Government의 보안 강화 Kubernetes 배포판 RKE2와 선언적 클러스터 관리를 위한 Cluster API를 학습한다.
RKE2 소개¶
1. RKE2¶
RKE2 (RKE Government) = Rancher Kubernetes Engine 2
- Rancher에서 개발한 보안 강화 Kubernetes 배포판
- 미국 연방 정부 요구사항 충족 (FIPS 140-2, STIG)
- CIS Kubernetes Benchmark 기본 준수
- RKE1의 후속 버전 (완전히 다시 작성)
2. RKE vs RKE2¶
| 특징 | RKE1 | RKE2 |
|---|---|---|
| 배포 방식 | Docker 컨테이너 기반 | systemd 서비스 기반 |
| Container Runtime | Docker | containerd (기본) |
| 설치 방법 | rke CLI | 바이너리 설치 |
| 보안 준수 | 선택적 | 기본 강화 (FIPS, CIS) |
| etcd | Docker 컨테이너 | Static Pod |
| Control Plane | Docker 컨테이너 | Static Pod |
3. 주요 특징¶
3.1 Security First¶
3.2 내장 컴포넌트¶
| 컴포넌트 | 설명 |
|---|---|
| CNI | Canal (Calico + Flannel) 기본, Cilium/Calico/Multus 선택 가능 |
| Ingress Controller | Nginx Ingress Controller |
| Service Load Balancer | Klipper LB (개발 환경용) |
| Metrics Server | 기본 포함 |
| CoreDNS | DNS 서버 |
3.3 간편한 설치¶
# Server 노드 설치 (단일 명령)
curl -sfL https://get.rke2.io | sh -
systemctl enable rke2-server.service
systemctl start rke2-server.service
# Agent 노드 설치
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE="agent" sh -
systemctl enable rke2-agent.service
systemctl start rke2-agent.service
4. 보안 강화 기능¶
4.1 CIS Hardened¶
# /etc/rancher/rke2/config.yaml
# CIS Profile 자동 적용
profile: cis-1.23
# 자동으로 적용되는 설정:
# - Pod Security Standards (Restricted)
# - Network Policies 활성화
# - Audit Logging 활성화
# - 안전한 kubelet 설정
4.2 SELinux/AppArmor 지원¶
# SELinux (RHEL/CentOS)
setenforce 1
# RKE2가 자동으로 SELinux 정책 적용
# AppArmor (Ubuntu/Debian)
# RKE2가 자동으로 AppArmor 프로필 로드
4.3 FIPS 140-2 모드¶
# FIPS 모드 활성화
export INSTALL_RKE2_FIPS=true
curl -sfL https://get.rke2.io | sh -
# 검증
rke2 --version
# rke2 version v1.28.x+rke2r1-fips
RKE2 아키텍처¶
1. Server 노드 구성¶
Server 노드 = Control Plane 노드
이 그림에서 눈여겨볼 것은 control plane 컴포넌트들이 systemd 유닛이 아니라 kubelet의 Static pods 경계 안쪽에 그려져 있다는 점이다. 실제로 supervisor가 직접 관리하는 프로세스는 kubelet 하나뿐이고, etcd·api-server·scheduler는 그 kubelet이 static pod로 띄운다. 반대로 kube-proxy·CoreDNS·CNI(canal)는 서버 노드 프로세스가 아니라 Helm 또는 raw manifest로 배포되는 워크로드로 분류돼 있다.
서버 노드가 부팅될 때 이 컴포넌트들이 어떤 순서로 올라오는지는 아래와 같다.
선형 스크립트가 아니라 goroutine 의존 사슬이라는 게 핵심이다. 모든 컴포넌트 goroutine이 대기 상태로 먼저 등록된 뒤(etcd는 kubelet 대기, apiserver는 etcd 대기, kcm·scheduler·helm-controller는 apiserver 대기) 앞 단계의 ready 신호를 받아야 차례로 풀린다. 특히 마지막 par 블록에서 kcm·scheduler·helm-controller 셋이 apiserver ready 하나로 동시에 해제된다. encryption-provider-config가 apiserver 기동보다 먼저 작성된다는 점도 함께 드러난다.
컴포넌트 구성¶
graph TB
subgraph "RKE2 Server Node"
subgraph "systemd"
RKE2S[rke2-server.service]
end
subgraph "Static Pods"
ETCD[etcd]
API[kube-apiserver]
CM[kube-controller-manager]
SCHED[kube-scheduler]
CP[cloud-provider]
end
subgraph "Containerd"
CONT[containerd]
CNI[CNI Plugin<br/>Canal/Cilium]
KUBELET[kubelet]
PROXY[kube-proxy]
end
subgraph "Add-ons"
NGINX[nginx-ingress]
METRICS[metrics-server]
COREDNS[coredns]
end
end
RKE2S --> CONT
RKE2S --> ETCD
RKE2S --> API
RKE2S --> CM
RKE2S --> SCHED
CONT --> KUBELET
CONT --> CNI
KUBELET --> PROXY
KUBELET --> NGINX
KUBELET --> METRICS
KUBELET --> COREDNS
/var/lib/rancher/rke2/
├── agent/ # kubelet, containerd 데이터
├── bin/ # Kubernetes 바이너리
├── server/
│ ├── manifests/ # Static Pod 매니페스트
│ ├── tls/ # 인증서
│ └── token # Node Join Token
└── etc/ # 설정 파일
2. Agent 노드 구성¶
Agent 노드 = Worker 노드
Server 시퀀스와 나란히 보면 Agent 경로가 확연히 짧다. Initialize Server 단계 자체가 없고 Initialize Agent가 곧 진입점이며, 런타임 이미지에서 bin/만 꺼내고 charts/는 꺼내지 않는다. Canal DaemonSet에 "server의 helm-controller가 배포한" 주석이 붙어 있는 것도 그래서다. 에이전트는 차트를 직접 렌더링하지 않는다.
컴포넌트 구성¶
graph TB
subgraph "RKE2 Agent Node"
subgraph "systemd"
RKE2A[rke2-agent.service]
end
subgraph "Containerd"
CONT[containerd]
CNI[CNI Plugin]
KUBELET[kubelet]
PROXY[kube-proxy]
end
subgraph "Workloads"
POD1[Pod 1]
POD2[Pod 2]
POD3[Pod 3]
end
end
RKE2A --> CONT
RKE2A --> KUBELET
KUBELET --> CNI
KUBELET --> PROXY
KUBELET --> POD1
KUBELET --> POD2
KUBELET --> POD3
3. 내장 컴포넌트¶
3.1 CNI 옵션¶
# /etc/rancher/rke2/config.yaml
# 옵션 1: Canal (기본값)
cni: canal
# 옵션 2: Cilium (eBPF 기반, 고성능)
cni: cilium
# 옵션 3: Calico (NetworkPolicy 강력)
cni: calico
# 옵션 4: Multus (Multi-NIC)
cni: multus,canal
# 옵션 5: CNI 없음 (수동 설치)
cni: none
3.2 Ingress Controller¶
# nginx-ingress (기본 포함)
# - NodePort 30080 (HTTP), 30443 (HTTPS)
# - HostPort 80, 443 (Bare-Metal)
# 비활성화
disable: rke2-ingress-nginx
3.3 Service LoadBalancer¶
# Klipper LB (개발 환경용)
# - NodePort를 호스트 포트로 포워딩
# - LoadBalancer Service 지원
# 비활성화 (MetalLB 등 사용 시)
disable: rke2-servicelb
4. 고가용성(HA) 구성¶
하나의 Fixed Registration Address가 서로 다른 두 종류의 트래픽을 받는다는 점이 중요하다. Agent가 클러스터에 등록할 때도 이 주소를 쓰고, 사용자가 kubectl로 API를 호출할 때도 같은 주소를 쓴다. 반면 Server들끼리는 점선 메시로 직접 연결돼 embedded etcd 쿼럼을 유지하므로 이 로드밸런서에 의존하지 않는다. 결국 첫 Agent가 join하기 전에 이 주소가 먼저 존재해야 한다.
4.1 Embedded etcd (권장)¶
graph TB
subgraph "HA RKE2 Cluster"
LB[Load Balancer<br/>192.168.56.10:9345]
subgraph "Server 1"
S1[rke2-server]
E1[etcd]
end
subgraph "Server 2"
S2[rke2-server]
E2[etcd]
end
subgraph "Server 3"
S3[rke2-server]
E3[etcd]
end
A1[Agent 1]
A2[Agent 2]
end
LB -.->|9345| S1
LB -.->|9345| S2
LB -.->|9345| S3
E1 <-->|Raft| E2
E2 <-->|Raft| E3
E3 <-->|Raft| E1
A1 -->|Join| LB
A2 -->|Join| LB
설정:
# Server 1 (First Node)
# /etc/rancher/rke2/config.yaml
cluster-init: true
tls-san:
- rke2-server1
- 192.168.56.11
- 192.168.56.10 # VIP/LB
# Server 2, 3 (Additional Nodes)
# /etc/rancher/rke2/config.yaml
server: https://192.168.56.11:9345
token: K10xxx::server:yyy # Server 1의 토큰
tls-san:
- rke2-server2 # 각 노드명
- 192.168.56.12 # 각 노드 IP
- 192.168.56.10 # 공통 VIP/LB
4.2 외부 Datastore (PostgreSQL/MySQL)¶
# /etc/rancher/rke2/config.yaml
datastore-endpoint: "postgres://user:pass@host:5432/dbname"
# 또는
datastore-endpoint: "mysql://user:pass@tcp(host:3306)/dbname"
RKE2 설치 및 구성¶
1. Server 노드 설치¶
1.1 시스템 준비¶
# 방화벽 포트 오픈
firewall-cmd --permanent --add-port=6443/tcp # K8s API
firewall-cmd --permanent --add-port=9345/tcp # RKE2 Supervisor
firewall-cmd --permanent --add-port=10250/tcp # Kubelet
firewall-cmd --permanent --add-port=2379-2380/tcp # etcd
firewall-cmd --reload
# SELinux Permissive (선택)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
# Swap 비활성화
swapoff -a
sed -i '/ swap / s/^/#/' /etc/fstab
1.2 RKE2 설치¶
# RKE2 설치 스크립트 다운로드 및 실행
curl -sfL https://get.rke2.io | sh -
# 설치 확인
ls -l /usr/local/bin/rke2
rke2 --version
1.3 설정 파일 작성¶
# /etc/rancher/rke2/config.yaml
mkdir -p /etc/rancher/rke2
cat > /etc/rancher/rke2/config.yaml <<EOF
# Server 설정
write-kubeconfig-mode: "0644"
tls-san:
- "rke2-server1"
- "192.168.56.11"
# CNI 선택
cni: cilium
# CIS Profile (선택)
profile: cis-1.23
# Add-on 비활성화 (선택)
# disable:
# - rke2-ingress-nginx
# - rke2-servicelb
# Node 설정
node-label:
- "node-role=control-plane"
node-taint:
- "node-role.kubernetes.io/control-plane=true:NoSchedule"
EOF
1.4 RKE2 시작¶
# systemd 서비스 활성화 및 시작
systemctl enable rke2-server.service
systemctl start rke2-server.service
# 로그 확인
journalctl -u rke2-server -f
# 상태 확인
systemctl status rke2-server.service
1.5 kubectl 설정¶
# kubeconfig 복사
mkdir -p ~/.kube
cp /etc/rancher/rke2/rke2.yaml ~/.kube/config
# kubectl 심볼릭 링크
ln -s /var/lib/rancher/rke2/bin/kubectl /usr/local/bin/kubectl
# 확인
kubectl get nodes
kubectl get pods -A
1.6 Node Token 확인¶
# Agent 노드 Join에 필요한 Token
cat /var/lib/rancher/rke2/server/node-token
# 예: K10xxx::server:yyy
# 또는
cat /var/lib/rancher/rke2/server/token
2. Agent 노드 설치¶
2.1 RKE2 Agent 설치¶
# Agent 타입으로 설치
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE="agent" sh -
# 설치 확인
ls -l /usr/local/bin/rke2
2.2 설정 파일 작성¶
# /etc/rancher/rke2/config.yaml
mkdir -p /etc/rancher/rke2
cat > /etc/rancher/rke2/config.yaml <<EOF
# Server 주소
server: https://192.168.56.11:9345
# Node Token (Server에서 복사)
token: K10xxx::server:yyy
# Node 설정
node-label:
- "node-role=worker"
EOF
2.3 RKE2 Agent 시작¶
# systemd 서비스 활성화 및 시작
systemctl enable rke2-agent.service
systemctl start rke2-agent.service
# 로그 확인
journalctl -u rke2-agent -f
# 상태 확인
systemctl status rke2-agent.service
2.4 노드 확인 (Server에서)¶
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# rke2-server1 Ready control-plane,etcd,master 10m v1.28.x+rke2r1
# rke2-agent1 Ready <none> 2m v1.28.x+rke2r1
3. 설정 파일 구조¶
3.1 주요 설정 옵션¶
# /etc/rancher/rke2/config.yaml
# === Server 전용 옵션 ===
# 클러스터 초기화 (첫 번째 Server만)
cluster-init: true
# 추가 Server가 Join할 주소 (두 번째 Server부터)
server: https://192.168.56.11:9345
# etcd 스냅샷 (백업)
etcd-snapshot-schedule-cron: "0 */6 * * *" # 6시간마다
etcd-snapshot-retention: 10 # 10개 유지
# === Server/Agent 공통 옵션 ===
# Node Token
token: K10xxx::server:yyy
# TLS SAN (추가 인증서 주체 대체 이름)
tls-san:
- "192.168.56.10" # VIP
- "rke2.example.com"
# kubeconfig 권한
write-kubeconfig-mode: "0644"
# CNI 선택
cni:
- cilium
# Node 설정
node-name: "custom-node-name"
node-label:
- "key=value"
node-taint:
- "key=value:NoSchedule"
# CIS Profile
profile: cis-1.23
# Kubelet 옵션
kubelet-arg:
- "max-pods=200"
- "eviction-hard=memory.available<500Mi"
# Kube-APIServer 옵션
kube-apiserver-arg:
- "audit-log-path=/var/log/kubernetes/audit.log"
- "audit-log-maxage=30"
# Add-on 비활성화
disable:
- rke2-ingress-nginx
- rke2-metrics-server
4. CNI 선택 (Cilium)¶
4.1 Cilium 설정¶
4.2 Cilium 확인¶
# Cilium Pods 확인
kubectl get pods -n kube-system -l k8s-app=cilium
# Cilium CLI 설치
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-amd64.tar.gz
tar xzvf cilium-linux-amd64.tar.gz
sudo mv cilium /usr/local/bin/
# Cilium 상태 확인
cilium status
cilium connectivity test
RKE2 업그레이드¶
1. 수동 업그레이드¶
1.1 업그레이드 흐름¶
graph LR
A[현재 버전<br/>v1.28.5] --> B[Server 1<br/>Upgrade]
B --> C[Server 2<br/>Upgrade]
C --> D[Server 3<br/>Upgrade]
D --> E[Agent 1<br/>Upgrade]
E --> F[Agent 2<br/>Upgrade]
F --> G[완료<br/>v1.28.8]
1.2 Server 노드 업그레이드¶
# 1. 업그레이드할 버전 확인
curl -s https://update.rke2.io/v1-release/channels | jq -r '.data[] | select(.id=="stable") | .latest'
# 2. Server 노드 업그레이드 (한 번에 1개씩!)
# Server 1
systemctl stop rke2-server
curl -sfL https://get.rke2.io | INSTALL_RKE2_VERSION=v1.28.8+rke2r1 sh -
systemctl start rke2-server
# 3. 확인
kubectl get nodes
journalctl -u rke2-server -f
# 4. Server 2, 3도 동일하게 순차 업그레이드
1.3 Agent 노드 업그레이드¶
# Agent 노드 업그레이드 (한 번에 1개씩 또는 Rolling)
systemctl stop rke2-agent
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE="agent" INSTALL_RKE2_VERSION=v1.28.8+rke2r1 sh -
systemctl start rke2-agent
# 확인
kubectl get nodes
2. Automated 업그레이드 (System Upgrade Controller)¶
2.1 System Upgrade Controller 설치¶
# SUC 설치
kubectl apply -f https://github.com/rancher/system-upgrade-controller/releases/latest/download/system-upgrade-controller.yaml
# 확인
kubectl get pods -n system-upgrade
2.2 Server 업그레이드 Plan¶
# server-plan.yaml
apiVersion: upgrade.cattle.io/v1
kind: Plan
metadata:
name: server-plan
namespace: system-upgrade
spec:
# 동시 업그레이드 노드 수
concurrency: 1
# Server 노드 선택
nodeSelector:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: Exists
# RKE2 서비스 이름
serviceAccountName: system-upgrade
# Cordon & Drain
cordon: true
drain:
force: true
skipWaitForDeleteTimeout: 60
# 업그레이드 대상 버전
version: v1.28.8+rke2r1
# 업그레이드 스크립트
upgrade:
image: rancher/rke2-upgrade
2.3 Agent 업그레이드 Plan¶
# agent-plan.yaml
apiVersion: upgrade.cattle.io/v1
kind: Plan
metadata:
name: agent-plan
namespace: system-upgrade
spec:
concurrency: 2 # 동시 2개
# Agent 노드 선택
nodeSelector:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: DoesNotExist
serviceAccountName: system-upgrade
# Server 업그레이드 완료 후 실행
prepare:
image: rancher/rke2-upgrade
args: ["prepare", "server-plan"]
cordon: true
drain:
force: true
skipWaitForDeleteTimeout: 60
version: v1.28.8+rke2r1
upgrade:
image: rancher/rke2-upgrade
2.4 업그레이드 실행¶
# Plan 적용
kubectl apply -f server-plan.yaml
kubectl apply -f agent-plan.yaml
# 업그레이드 진행 모니터링
kubectl get plans -n system-upgrade
kubectl get jobs -n system-upgrade
kubectl logs -n system-upgrade -l upgrade.cattle.io/plan=server-plan -f
# 노드 상태 확인
kubectl get nodes -w
3. 업그레이드 순서¶
graph TB
START[업그레이드 시작] --> BACKUP[etcd 백업]
BACKUP --> S1[Server 1 업그레이드]
S1 --> S1C{Server 1<br/>정상?}
S1C -->|Yes| S2[Server 2 업그레이드]
S1C -->|No| ROLLBACK[Rollback]
S2 --> S2C{Server 2<br/>정상?}
S2C -->|Yes| S3[Server 3 업그레이드]
S2C -->|No| ROLLBACK
S3 --> S3C{Server 3<br/>정상?}
S3C -->|Yes| AGENT[Agent 업그레이드<br/>동시 1-2개]
S3C -->|No| ROLLBACK
AGENT --> VERIFY[검증 및 완료]
업그레이드 Best Practices:
1. etcd 백업 필수
2. Server 노드 먼저, 한 번에 1개씩
3. 각 Server 업그레이드 후 정상 동작 확인
4. Agent 노드 나중, 동시 1-2개
5. Drain & Cordon으로 워크로드 안전하게 이동
RKE2 인증서 관리¶
1. 인증서 위치¶
# 인증서 저장 위치
/var/lib/rancher/rke2/server/tls/
# 주요 인증서
├── server-ca.crt # Server CA
├── server-ca.key
├── client-ca.crt # Client CA
├── client-ca.key
├── request-header-ca.crt # Request Header CA
├── request-header-ca.key
├── serving-kube-apiserver.crt # API Server 서빙
├── serving-kube-apiserver.key
├── client-kube-apiserver.crt # API Server 클라이언트
├── client-admin.crt # Admin 클라이언트
└── ...
2. 인증서 갱신¶
2.1 자동 갱신¶
# RKE2는 인증서를 자동으로 갱신 (만료 90일 전)
# - rke2-server 재시작 시 자동 체크
# - 만료 임박 시 자동 갱신
# 수동 갱신 트리거 (재시작)
systemctl restart rke2-server
2.2 인증서 확인¶
# API Server 인증서 만료일 확인
openssl x509 -in /var/lib/rancher/rke2/server/tls/serving-kube-apiserver.crt -noout -enddate
# notAfter=Feb 21 12:00:00 2027 GMT
# 모든 인증서 만료일 확인
for cert in /var/lib/rancher/rke2/server/tls/*.crt; do
echo "=== $cert ==="
openssl x509 -in $cert -noout -enddate
done
3. Custom CA 사용¶
3.1 기존 CA로 서명된 인증서 사용¶
# /etc/rancher/rke2/config.yaml
# (현재 RKE2는 Custom CA 직접 지원 제한적)
# Workaround: cert-manager 사용
# 1. RKE2 설치 전 기존 인증서 배치
mkdir -p /var/lib/rancher/rke2/server/tls/
cp custom-ca.crt /var/lib/rancher/rke2/server/tls/server-ca.crt
cp custom-ca.key /var/lib/rancher/rke2/server/tls/server-ca.key
# 2. RKE2 시작 (기존 CA 사용)
systemctl start rke2-server
Cluster API (CAPI) 소개¶
1. Cluster API¶
Cluster API (CAPI) = Kubernetes를 사용하여 Kubernetes 클러스터를 관리하는 프로젝트
- 선언적 API: Kubernetes 리소스로 클러스터 정의
- GitOps 친화적: YAML 기반 Infrastructure as Code
- 멀티 클라우드: AWS, Azure, GCP, vSphere, OpenStack 등 지원
- 일관된 경험: 모든 인프라에서 동일한 API 사용
2. CAPI 주요 개념¶
apps/v1의 Deployment → ReplicaSet → Pod 3계층을 cluster.x-k8s.io/v1beta1이 MachineDeployment → MachineSet → Machine으로 그대로 옮겨온 구조다. 다만 오른쪽 트리를 보면 매핑이 대칭이 아니다. Worker Nodes는 3계층을 온전히 거치지만 Master Nodes는 중간 계층이 없어 KubeadmControlPlane이 Machine을 직접 소유한다. 컨트롤 플레인에는 MachineSet이 존재하지 않는다.
주목할 것은 아래쪽 ownerReferences 화살표가 infrastructureRef 화살표들과 반대 방향이라는 점이다. 참조는 Cluster에서 말단으로 내려가지만 소유권은 말단에서 Cluster로 올라온다. Cluster 오브젝트 하나만 지워도 그 아래 모든 AWSMachine과 EC2 인스턴스가 가비지 컬렉션되는 이유가 이 역방향 간선에 있다.
2.1 Management Cluster vs Workload Cluster¶
graph TB
subgraph "Management Cluster"
CAPI[Cluster API<br/>Controllers]
CAPA[Infrastructure Provider<br/>AWS/Azure/etc]
end
subgraph "Workload Cluster 1"
WC1[Kubernetes Cluster]
end
subgraph "Workload Cluster 2"
WC2[Kubernetes Cluster]
end
CAPI -->|Create/Manage| WC1
CAPI -->|Create/Manage| WC2
CAPA -->|Provision| WC1
CAPA -->|Provision| WC2
- Management Cluster: Cluster API 컨트롤러가 실행되는 클러스터
- Workload Cluster: 관리 대상 클러스터 (실제 워크로드 실행)
2.2 주요 리소스¶
| 리소스 | 설명 | 예시 |
|---|---|---|
| Cluster | 클러스터 전체 정의 | 클러스터 이름, 네트워크 CIDR |
| Machine | 단일 노드 (VM/인스턴스) | Control Plane 노드, Worker 노드 |
| MachineDeployment | 노드 그룹 (ReplicaSet 유사) | 3개의 Worker 노드 |
| MachineSet | Machine의 ReplicaSet | Auto-scaling |
| KubeadmControlPlane | Control Plane 노드 그룹 | HA Control Plane |
| InfrastructureTemplate | 인프라별 설정 | AWS EC2 인스턴스 타입 |
3. CAPI 아키텍처¶
Core System과 각 Provider를 잇는 화살표가 점선이고 방향이 Provider → Core라는 점이 중요하다. Core가 Provider를 명령형으로 호출하는 게 아니라, Provider가 Core의 리소스를 watch하며 reconcile한다. 또 AWS에 만든 클러스터와 IDC(BYOH)에 만든 클러스터가 똑같이 v1.25로 표기돼 있다 — Provider만 갈아끼우면 동일한 매니페스트로 퍼블릭 클라우드와 온프레미스에 버전이 같은 클러스터를 얻는다.
graph TB
subgraph "User"
USER[kubectl apply<br/>cluster.yaml]
end
subgraph "Management Cluster"
API[Kube-APIServer]
subgraph "CAPI Controllers"
CC[Cluster Controller]
MC[Machine Controller]
KCP[KubeadmControlPlane<br/>Controller]
end
subgraph "Provider Controllers"
INFRA[Infrastructure Provider<br/>AWS/Docker/etc]
BOOT[Bootstrap Provider<br/>Kubeadm]
CP[Control Plane Provider<br/>Kubeadm]
end
end
subgraph "Infrastructure (AWS/vSphere/etc)"
VM1[VM 1<br/>Control Plane]
VM2[VM 2<br/>Worker]
end
USER --> API
API --> CC
API --> MC
API --> KCP
CC --> INFRA
MC --> INFRA
KCP --> INFRA
KCP --> BOOT
KCP --> CP
INFRA -->|Provision| VM1
INFRA -->|Provision| VM2
BOOT -->|cloud-init| VM1
BOOT -->|cloud-init| VM2
4. Provider 종류¶
4.1 Infrastructure Providers¶
| Provider | 설명 | 환경 |
|---|---|---|
| CAPA | AWS Provider | AWS EC2 |
| CAPZ | Azure Provider | Azure VM |
| CAPG | GCP Provider | GCP GCE |
| CAPV | vSphere Provider | VMware vSphere |
| CAPO | OpenStack Provider | OpenStack |
| CAPD | Docker Provider | Docker 컨테이너 (개발/테스트) |
Provider 선택이 하나의 축이 아니라 Bootstrap·Control Plane·Infrastructure 세 축의 독립적인 조합이라는 점이 이 카탈로그에서 드러난다. 같은 Kubeadm을 Bootstrap과 Control Plane 양쪽에 쓰면서 Infrastructure만 따로 고를 수 있고, 어느 필드가 무엇을 선택하는지는 우측 YAML의 controlPlaneRef와 infrastructureRef가 보여준다.
앞의 self-provisioned 구성과 비교하면 관리형 Provider는 이름만 바뀌는 게 아니라 그래프 모양 자체가 달라진다. AWSManagedCluster에 (dummy)가 붙은 것은 인프라를 AWS가 소유하기 때문이고, VPC·NAT·IGW 책임은 AWSManagedControlPlane 안으로 들어간다. 무엇보다 MachineDeployment → MachineSet → Machine 사슬이 MachinePool → AWSManagedMachinePool 하나로 접혀 EKS 관리형 노드그룹에 대응되므로, EC2 인스턴스마다 대응하는 Machine 오브젝트가 아예 존재하지 않는다.
4.2 Bootstrap Providers¶
| Provider | 설명 |
|---|---|
| Kubeadm | kubeadm을 사용한 클러스터 부트스트랩 (기본) |
| Talos | Talos Linux 사용 |
4.3 Control Plane Providers¶
| Provider | 설명 |
|---|---|
| Kubeadm | kubeadm 기반 Control Plane 관리 (기본) |
| Kamaji | 멀티 테넌트 Control Plane |
| K3s | K3s Control Plane |
| RKE2 | RKE2 Control Plane |
Cluster API 실습¶
1. Management Cluster 구성¶
1.1 Kind로 Management Cluster 생성¶
# Kind 설치
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# Management Cluster 생성
kind create cluster --name capi-mgmt
# 확인
kubectl cluster-info
kubectl get nodes
2. clusterctl 설치¶
# clusterctl 설치
curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.6.0/clusterctl-linux-amd64 -o clusterctl
chmod +x ./clusterctl
sudo mv ./clusterctl /usr/local/bin/clusterctl
# 확인
clusterctl version
# clusterctl version: &version.Info{Major:"1", Minor:"6", GitVersion:"v1.6.0"}
3. Provider 초기화¶
3.1 Docker Provider 초기화 (로컬 테스트용)¶
# Docker Provider 초기화
clusterctl init --infrastructure docker
# 설치된 Provider 확인
clusterctl config provider
kubectl get pods -n capi-system
kubectl get pods -n capi-kubeadm-bootstrap-system
kubectl get pods -n capi-kubeadm-control-plane-system
kubectl get pods -n capd-system
3.2 AWS Provider 초기화 (프로덕션 예시)¶
# AWS 자격증명 설정
export AWS_REGION=us-east-1
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=yyy
export AWS_B64ENCODED_CREDENTIALS=$(clusterawsadm bootstrap credentials encode-as-profile)
# AWS Provider 초기화
clusterctl init --infrastructure aws
# 확인
kubectl get pods -n capa-system
4. Workload Cluster 생성¶
4.1 클러스터 템플릿 생성 (Docker Provider)¶
# 클러스터 YAML 생성
export CLUSTER_NAME="capi-quickstart"
export KUBERNETES_VERSION="v1.28.0"
clusterctl generate cluster ${CLUSTER_NAME} \
--kubernetes-version ${KUBERNETES_VERSION} \
--control-plane-machine-count=1 \
--worker-machine-count=2 \
> capi-quickstart.yaml
4.2 생성된 YAML 확인¶
# capi-quickstart.yaml (간략화)
---
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: capi-quickstart
spec:
clusterNetwork:
pods:
cidrBlocks: ["192.168.0.0/16"]
services:
cidrBlocks: ["10.96.0.0/12"]
controlPlaneRef:
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
name: capi-quickstart-control-plane
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerCluster
name: capi-quickstart
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerCluster
metadata:
name: capi-quickstart
---
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
metadata:
name: capi-quickstart-control-plane
spec:
replicas: 1
version: v1.28.0
machineTemplate:
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerMachineTemplate
name: capi-quickstart-control-plane
---
apiVersion: cluster.x-k8s.io/v1beta1
kind: MachineDeployment
metadata:
name: capi-quickstart-md-0
spec:
clusterName: capi-quickstart
replicas: 2
selector:
matchLabels: null
template:
spec:
bootstrap:
configRef:
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
kind: KubeadmConfigTemplate
name: capi-quickstart-md-0
clusterName: capi-quickstart
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerMachineTemplate
name: capi-quickstart-md-0
version: v1.28.0
4.3 Workload Cluster 생성¶
# 클러스터 생성
kubectl apply -f capi-quickstart.yaml
# 생성 진행 모니터링
clusterctl describe cluster capi-quickstart
kubectl get cluster
kubectl get kubeadmcontrolplane
kubectl get machinedeployment
kubectl get machines
# 상세 로그
kubectl get events --sort-by='.lastTimestamp' -A
4.4 Workload Cluster 접속¶
# Workload Cluster kubeconfig 가져오기
clusterctl get kubeconfig capi-quickstart > capi-quickstart.kubeconfig
# CNI 설치 (Calico)
kubectl --kubeconfig=./capi-quickstart.kubeconfig \
apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
# Workload Cluster 노드 확인
kubectl --kubeconfig=./capi-quickstart.kubeconfig get nodes
# NAME STATUS ROLES AGE VERSION
# capi-quickstart-control-plane-xxxxx Ready control-plane 5m v1.28.0
# capi-quickstart-md-0-xxxxx-yyyyy Ready <none> 3m v1.28.0
# capi-quickstart-md-0-xxxxx-zzzzz Ready <none> 3m v1.28.0
5. Cluster 관리¶
5.1 Worker 노드 스케일링¶
# MachineDeployment 스케일
kubectl scale machinedeployment capi-quickstart-md-0 --replicas=5
# 확인
kubectl get machines
clusterctl describe cluster capi-quickstart
5.2 Control Plane 스케일링 (HA)¶
# KubeadmControlPlane 스케일
kubectl patch kubeadmcontrolplane capi-quickstart-control-plane \
--type merge -p '{"spec":{"replicas":3}}'
# 확인
kubectl get kubeadmcontrolplane
kubectl get machines -l cluster.x-k8s.io/control-plane
5.3 Kubernetes 버전 업그레이드¶
# Control Plane 업그레이드
kubectl patch kubeadmcontrolplane capi-quickstart-control-plane \
--type merge -p '{"spec":{"version":"v1.29.0"}}'
# Worker 업그레이드
kubectl patch machinedeployment capi-quickstart-md-0 \
--type merge -p '{"spec":{"template":{"spec":{"version":"v1.29.0"}}}}'
# 진행 상황 모니터링
kubectl get machines -w
clusterctl describe cluster capi-quickstart
5.4 Cluster 삭제¶
# Workload Cluster 삭제
kubectl delete cluster capi-quickstart
# 확인 (모든 리소스 자동 삭제)
kubectl get machines
kubectl get cluster
핵심 개념 정리¶
1. RKE2의 보안 강화 포인트¶
1.1 FIPS 140-2 준수¶
graph LR
A[FIPS 140-2<br/>요구사항] --> B[승인된<br/>암호화 모듈]
B --> C[TLS 1.2+]
B --> D[AES-256]
B --> E[RSA 2048+]
C --> F[RKE2<br/>인증된 바이너리]
D --> F
E --> F
준수 항목:
- NIST 승인 알고리즘: 승인된 암호화 알고리즘만 사용
- FIPS 140-2 라이브러리: BoringCrypto 인증 암호화 라이브러리
- TLS 1.2+ 강제: TLS 1.2 이상만 허용
- 안전하지 않은 암호화 비활성화: 취약한 알고리즘 차단
1.2 CIS Benchmark 기본 준수¶
# profile: cis-1.23 적용 시 자동 설정
# 1. Pod Security
PodSecurityStandard: restricted
# 2. RBAC
# - 최소 권한 원칙
# - system:masters 그룹 제한
# 3. Network Policies
# - 기본 Deny
# - 명시적 Allow만 허용
# 4. Audit Logging
# - API 요청 모두 기록
# - 민감 정보 마스킹
# 5. Kubelet 강화
# - Anonymous auth 비활성화
# - Authorization mode: Webhook
# - Read-only port 비활성화
1.3 SELinux/AppArmor 통합¶
2. Cluster API의 장점¶
2.1 선언적 인프라 관리¶
# 기존 방식 (명령형)
# 1. terraform apply (인프라 생성)
# 2. ansible-playbook (K8s 설치)
# 3. kubectl apply (워크로드 배포)
# CAPI 방식 (선언적)
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: prod-cluster
spec:
# 모든 것이 하나의 YAML로!
- GitOps 친화적: Git = Single Source of Truth
- 재현 가능: 동일한 YAML = 동일한 클러스터
- 버전 관리: Git History
- 자동화: CI/CD 통합
2.2 멀티 클라우드 일관성¶
graph TB
subgraph "동일한 CAPI YAML"
YAML[cluster.yaml]
end
YAML -->|Provider: AWS| AWS[AWS EKS]
YAML -->|Provider: Azure| AZURE[Azure AKS]
YAML -->|Provider: GCP| GCP[GCP GKE]
YAML -->|Provider: vSphere| VSPHERE[vSphere]
장점:
- 동일한 API: 모든 클라우드를 하나의 API로 관리
- 멀티 클라우드 전략: 클라우드 간 이동 용이
- Vendor Lock-in 회피: 특정 클라우드 종속성 제거
2.3 Self-Healing¶
# MachineHealthCheck로 자동 복구
apiVersion: cluster.x-k8s.io/v1beta1
kind: MachineHealthCheck
metadata:
name: worker-health-check
spec:
clusterName: capi-quickstart
maxUnhealthy: 40%
nodeStartupTimeout: 10m
unhealthyConditions:
- type: Ready
status: Unknown
timeout: 5m
- type: Ready
status: "False"
timeout: 5m
| 기능 | 설명 |
|---|---|
| Unhealthy 노드 감지 | 자동으로 비정상 노드 탐지 |
| 새 노드 교체 | 자동으로 새 노드 생성 및 교체 |
| Workload 재스케줄링 | 자동으로 워크로드 이동 |
3. RKE2 vs K3s vs kubeadm¶
| 특징 | RKE2 | K3s | kubeadm |
|---|---|---|---|
| 대상 환경 | Enterprise, 정부 | Edge, IoT, Dev | 커스터마이징 필요 시 |
| 보안 준수 | FIPS, CIS 기본 | 선택적 | 수동 설정 |
| 바이너리 크기 | ~200MB | ~50MB | 분산 다운로드 |
| Container Runtime | containerd (내장) | containerd (내장) | 별도 설치 |
| 설치 복잡도 | 매우 쉬움 | 매우 쉬움 | 중간 |
| HA 구성 | Embedded etcd | Embedded etcd | 외부 etcd 필요 |
| Add-on | 풍부 (Ingress, LB) | 기본 (Traefik, LB) | 없음 (수동) |
| 리소스 사용 | 중간 | 낮음 | 중간 |
| 업그레이드 | 쉬움 (SUC) | 쉬움 | 수동 |
선택 가이드:
| 도구 | 적합한 환경 |
|---|---|
| RKE2 | 보안 준수, 프로덕션, Enterprise |
| K3s | Edge, 리소스 제약, 빠른 배포 |
| kubeadm | 완전한 제어, 커스터마이징, 학습 |
작성일: 2026-02-21 학습 주제: RKE2 & Cluster API 실습 환경: VirtualBox, Ubuntu 22.04, RKE2 v1.28.x, Cluster API v1.6.x








