RKE2 " 차세대 엔터프라이즈 Kubernetes 배포판
보안 측면에서 세 가지 핵심 요소를 제공한다.
첫째, CIS Kubernetes Benchmark 준수한다.
둘째, FIPS 140-2 규정 준수를 지원한다.
셋째, 빌드 파이프라인에서 Trivy를 사용하여 구성 요소의 CVE를 정기적으로 스캔한다.
컨트롤 플레인 구성 요소는 kubelet이 관리하는 정적 Pod로 실행되며, 내장 컨테이너 런타임은 containerd다.
RKE2의 전체 구성 요소

RKE2 내부의 K3s 레이어에서 가장 핵심적인 역할을 하는 건 Helm Controller다.
GitOps 스타일의 경량 배포 컨트롤러로, RKE2 클러스터 부팅 시 필수 Helm 차트를 자동으로 설치하고 유지한다.
동작 방식은 단순하다. /var/lib/rancher/rke2/server/manifests 디렉토리를 감시하다가, HelmChart YAML 파일이 생기면 자동으로 Helm chart를 설치/업데이트한다.
tree /var/lib/rancher/rke2/server/manifests
├── rke2-canal-config.yaml
├── rke2-canal.yaml
├── rke2-coredns-config.yaml
├── rke2-coredns.yaml
├── rke2-metrics-server.yaml
└── rke2-runtimeclasses.yaml
Helm Controller와 ArgoCD의 역할 차이를 명확히 구분할 필요가 있다.
| 구분 | Helm Controller | Argo CD |
|---|---|---|
| 목적 | 부트스트랩 (필수 애드온 자동 설치) | GitOps (애플리케이션 배포) |
| 트리거 | 디렉토리 파일 감시 | Git 레포지토리 동기화 |
| 사용 시점 | 클러스터 부팅 시 | 애플리케이션 배포 라이프사이클 전반 |
표준 Kubernetes 구성 요소를 그대로 포함한다. 컨트롤 플레인은 API Server, Controller Manager, Scheduler로 구성되고, 워커 노드에는 Proxy와 Kubelet이 동작한다.
etcd → containerd → runc 구조로 동작한다. etcd가 클러스터 상태를 저장하고, containerd가 컨테이너 라이프사이클을 관리하며, runc가 실제 컨테이너 프로세스를 생성한다.
RKE2의 기본 CNI는 Canal이다. Canal은 Flannel과 Calico를 결합한 하이브리드 CNI로, 네트워크 연결은 Flannel이, 네트워크 정책 및 보안은 Calico가 담당한다.
Canal DaemonSet 파드 내부를 보면 두 컨테이너가 함께 실행되는 것을 확인할 수 있다.
kubectl describe pod -n kube-system -l k8s-app=canal | grep Image: | uniq
Image: rancher/hardened-calico:v3.31.3-build20260119
Image: rancher/hardened-flannel:v0.28.0-build20260119
Canal 외에도 Cilium, Calico 단독, Flannel 단독, 그리고 멀티 네트워크를 위한 Multus를 지원한다.
| 구성 요소 | 역할 |
|---|---|
| CoreDNS | 클러스터 내부 DNS |
| Ingress NGINX Controller | HTTP(S) 인그레스 처리 |
| Traefik | 대안 인그레스 컨트롤러 |
| Metrics Server | 리소스 사용량 수집 (HPA 기반) |
| Helm | 패키지 관리 |
RKE2는 K3s에서 출발했지만 목적이 다르다.
단순하게 말하면, K3s의 개발 경험(DX) + 엔터프라이즈 보안 요건을 모두 잡은 배포판이 RKE2다.
RKE2 Process Lifecycle — 부팅부터 데몬 실행까지
- RKE2가 기동될 때 내부적으로 어떤 순서로 구성 요소가 올라오는지 추적한다.
- 크게 4단계로 나뉜다:
Content Bootstrap → Initialize Server → Initialize Agent → Daemon Process.
rke2-runtime 컨테이너 이미지다. /var/lib/rancher/rke2/agent/images/ 디렉토리를 스캔해서 *.tar 파일을 찾는다. runtime-image.txt에 명시되어 있다.cat /var/lib/rancher/rke2/agent/images/runtime-image.txt
index.docker.io/rancher/rke2-runtime:v1.34.3-rke2r3
해당 디렉토리에는 각 컴포넌트별 이미지 참조 파일도 함께 있다.
tree /var/lib/rancher/rke2/agent/images/
├── etcd-image.txt
├── kube-apiserver-image.txt
├── kube-controller-manager-image.txt
├── kube-proxy-image.txt
├── kube-scheduler-image.txt
└── runtime-image.txt
rke2-runtime 이미지는 두 가지를 담고 있다.
# rke2-runtime 이미지 내부
├── bin/
│ ├── containerd
│ ├── containerd-shim-runc-v2
│ ├── crictl
│ ├── ctr
│ ├── kubectl
│ ├── kubelet
│ └── runc
└── charts/
├── rke2-canal.yaml
├── rke2-cilium.yaml
├── rke2-coredns.yaml
├── rke2-ingress-nginx.yaml
├── rke2-metrics-server.yaml
├── rke2-traefik.yaml
└── ... (총 19개 차트)
RKE2가 정상 작동하려면 런타임 이미지는 최소한 containerd, containerd-shim-runc-v2, kubelet, runc 네 가지를 제공해야 한다. 운영 도구로는 crictl, ctr, kubectl도 포함된다.
이미지에서 /bin/을 추출해서 아래 경로로 평탄화한다. ${RKE2_DATA_KEY}는 이미지 버전을 식별하는 고유 문자열이다.
/var/lib/rancher/rke2/data/${RKE2_DATA_KEY}/bin/
# 예시
/var/lib/rancher/rke2/data/v1.34.3-rke2r3-5b8349de68df/bin/
├── containerd
├── containerd-shim-runc-v2
├── crictl
├── ctr
├── kubectl
├── kubelet
└── runc
바이너리 추출 완료 후, 이미지의 charts/에서 실제로 활성화할 차트만 /var/lib/rancher/rke2/server/manifests/로 복사한다. 기본 CNI(Canal)와 필수 애드온만 배치되는 것을 확인할 수 있다.
tree /var/lib/rancher/rke2/server/manifests/
├── rke2-canal-config.yaml
├── rke2-canal.yaml
├── rke2-coredns-config.yaml
├── rke2-coredns.yaml
├── rke2-metrics-server.yaml
└── rke2-runtimeclasses.yaml
임베디드 K3s 엔진 서버에는 특수 에이전트 프로세스가 포함되어 있다.
노드의 컨테이너 런타임이 올라올 때까지 다음 단계는 지연된다.
컨트롤 플레인 컴포넌트는 의존 관계에 따라 순차적으로 정적 파드 정의를 작성한다. 각각 goroutine을 통해 비동기로 대기하다가 선행 조건이 충족되면 /var/lib/rancher/rke2/agent/pod-manifests/에 YAML을 기록한다.
| 컴포넌트 | 대기 조건 | 정적 파드 작성 |
|---|---|---|
| kube-apiserver | etcd 준비 완료 | pod-manifests/kube-apiserver.yaml |
| kube-controller-manager | kube-apiserver 준비 완료 | pod-manifests/kube-controller-manager.yaml |
| kube-scheduler | kube-apiserver 준비 완료 | pod-manifests/kube-scheduler.yaml |
| etcd | kubelet 준비 완료 | pod-manifests/etcd.yaml |
| helm-controller | kube-apiserver 준비 완료 | (embedded, goroutine으로 시작) |
실제 파일 상태를 보면 작성 순서가 타임스탬프에 그대로 찍혀있다.
ls -ltr /var/lib/rancher/rke2/agent/pod-manifests/
-rw-r--r--. 1 root root 3279 Feb 14 16:32 etcd.yaml
-rw-r--r--. 1 root root 2325 Feb 14 16:32 kube-proxy.yaml
-rw-r--r--. 1 root root 9337 Feb 14 16:33 kube-apiserver.yaml
-rw-r--r--. 1 root root 3724 Feb 14 16:33 kube-scheduler.yaml
-rw-r--r--. 1 root root 6325 Feb 14 16:33 kube-controller-manager.yaml
컴포넌트 준비가 끝나면 goroutine으로 HTTP 서버를 띄워서 다른 서버/에이전트 노드의 합류 요청을 수신한다. 이 시점부터 클러스터 초기화 또는 기존 클러스터 조인이 시작된다.
# /usr/lib/systemd/system/rke2-server.service
ExecStart=/usr/bin/rke2 server
KillMode=process # rke2 프로세스만 종료, 자식 프로세스(containerd, shim 등)는 systemd가 건드리지 않음
Delegate=yes # cgroup 관리를 systemd가 아닌 rke2 자신이 직접 담당
Restart=always
RestartSec=5s
KillMode=process가 핵심이다. rke2 바이너리가 종료되더라도 containerd와 컨테이너 shim 프로세스는 살아있어 실행 중인 컨테이너가 즉시 중단되지 않는다. Delegate=yes는 cgroup 계층 구조를 rke2가 직접 관리하도록 위임해서, Kubernetes의 파드별 리소스 격리가 제대로 동작하게 한다.
pstree -al
├─rke2
│ ├─containerd -c /var/lib/rancher/rke2/agent/etc/containerd/config.toml
│ ├─kubelet --containerd=/run/k3s/containerd/containerd.sock ...
│ └─{rke2 worker threads}
에이전트 프로세스의 진입점이다. 서버 노드의 경우 임베디드 K3s 엔진이 직접 호출한다.
containerd 프로세스를 생성하고 종료를 감시한다. containerd가 종료되면 rke2 프로세스 자체도 종료된다.
kubelet을 spawn해서 감시(supervise)한다. kubelet이 종료되면 rke2가 재시작을 시도한다. kubelet이 정상 작동하기 시작하면, pod-manifests/에 있는 모든 정적 파드가 순서대로 기동된다.
서버 노드의 경우 etcd → kube-apiserver 순서로 연속 기동되고, 이후 나머지 컴포넌트들이 kube-apiserver에 연결되어 처리를 시작한다.
서버 노드에서 helm-controller가 활성화되면, /var/lib/rancher/rke2/server/manifests/의 차트들을 클러스터에 순서대로 적용한다.
| 차트 | 종류 | 비고 |
|---|---|---|
| rke2-canal / cilium / calico / flannel | DaemonSet | CNI, bootstrap |
| rke2-coredns | Deployment | bootstrap |
| rke2-ingress-nginx / traefik | Deployment | 인그레스 |
| rke2-metrics-server | Deployment | HPA 기반 |
| rke2-runtimeclasses | — | 런타임 클래스 등록 |
| rke2-snapshot-controller | Deployment | 볼륨 스냅샷 |
SIGTERM 또는 SIGKILL을 받거나, 관리 중인 컨테이너 프로세스가 종료될 때까지 무기한 실행된다.