노드마다 고유한 hostname·MAC·product_uuid, control plane 2 CPU·2 GiB 이상과 충분한 worker 자원
KUBERNETES FOUNDATION
kubeadm·containerd Kubernetes 클러스터 구성
Ubuntu 24.04 노드의 사전 조건과 containerd CRI·systemd cgroup을 확인하고 Kubernetes v1.37 패키지, kubeadm 초기화, 검토된 CNI, worker join을 백업·검증·복구 순서로 구성합니다.BEFORE YOU START
시작 전에 준비하세요
모든 노드 간 양방향 통신, 고정 control-plane endpoint와 공식 Kubernetes·선택한 CNI 저장소 egress
sudo·콘솔 접속, 서버 스냅샷 또는 중요 데이터 백업과 승인된 점검 시간
충돌하지 않는 Service CIDR·Pod CIDR과 해당 범위를 지원하는 CNI의 고정 버전·검증된 manifest
control plane 장애 시 etcd snapshot·인증서·kubeadm 설정을 복구할 별도 보관 위치
권장 대상 테스트·사내 환경의 자체 관리 Kubernetes를 kubeadm으로 구성하고 버전·네트워크·복구 경계를 직접 운영할 인프라 엔지니어
FOLLOW THE RECIPE
8단계 구성·점검 레시피
지원 OS·아키텍처·노드 식별 확인
공식 kubeadm 전제와 현재 릴리스를 먼저 고정합니다. 이 레시피는 2026-09 현재 Kubernetes v1.37 문서와 Ubuntu 24.04를 기준으로 하며 containerd는 지원 중인 patch와 실제 통합 시험 결과를 함께 확인해야 합니다. 다른 minor는 해당 문서·저장소로 바꿉니다.
cat /etc/os-releaseuname -r
dpkg --print-architecturenproc
free -hhostnamectl --static
ip link
sudo cat /sys/class/dmi/id/product_uuidMAC·product_uuid는 인프라 식별정보입니다. 외부 공유 전 마스킹합니다.- Ubuntu 24.04 LTS와 지원 아키텍처임을 확인했습니다.
- control plane은 2 CPU·2 GiB 이상의 최소 조건과 실제 workload 여유를 갖췄습니다.
- 모든 노드의 hostname·MAC·product_uuid가 중복되지 않습니다.
- Kubernetes v1.37과 지원 중인 containerd 2.3 LTS 최신 patch의 CRI v1 호환성을 공식 문서와 사전 통합 시험에서 재확인했습니다.
커스텀·구형 커널, 중복 식별값, 2 GiB 미만 control plane이면 preflight를 건너뛰지 말고 기반 환경을 먼저 수정합니다.
네트워크·포트·swap·기존 런타임을 읽기 전용으로 점검합니다.
네트워크·swap·기존 설치 사전 점검
기본 경로, 노드 주소, 필수 포트 충돌, swap, 커널 forwarding, 기존 Kubernetes·runtime을 확인해 초기화 전에 중단 조건을 찾습니다.
ip -brief address
ip route showsudo ss -lntup | grep -E ':(6443|2379|2380|10250|10257|10259|30000)\b'출력이 없을 수 있습니다. NodePort 전체 범위와 선택한 CNI 포트는 별도 방화벽 정책으로 확인합니다.swapon --show
free -hsysctl net.ipv4.ip_forward
lsmod | grep -E '^(overlay|br_netfilter)\b'dpkg-query -W kubeadm kubelet kubectl containerd containerd.io 2>/dev/null
systemctl status containerd.service kubelet.service --no-pager -l- control-plane endpoint와 노드 주소가 재부팅 뒤에도 유지됩니다.
- Pod CIDR·Service CIDR이 사내망·VPN·Docker 네트워크와 겹치지 않습니다.
- swap이 켜져 있다면 메모리 여유와 영구 비활성화 또는 지원되는 NodeSwap 설계를 별도 승인했습니다.
- 기존 kubeadm 클러스터·컨테이너 workload·포트 소유자가 없습니다.
포트 충돌, CIDR 중복, 기존 cluster state, 부족한 메모리 또는 고정되지 않은 endpoint가 있으면 설치를 진행하지 않습니다.
공식 pkgs.k8s.io minor 저장소와 검토된 containerd 패키지를 설치합니다.
containerd와 Kubernetes v1.37 패키지 설치
공식 Kubernetes minor별 저장소의 키를 파일로 내려받아 확인하고 kubelet·kubeadm·kubectl 버전을 함께 고정합니다. 기존 저장소·키 파일은 덮어쓰기 전에 백업합니다.
sudo apt update
apt-cache policy containerd containerd.io kubelet kubeadm kubectlcontainerd 1.7은 2026-09 지원 종료 예정이고 2.x에도 지원 종료된 minor가 있으므로 이름만 보고 설치하지 않습니다. 조직이 검증한 2.3 LTS 최신 patch 후보가 없으면 저장소를 임의 추가하지 말고 설치를 중단합니다.sudo apt install containerd=<APPROVED_SUPPORTED_CONTAINERD_VERSION>승인된 정확한 package version이 containerd 2.3 LTS의 지원 중인 patch이고 Kubernetes v1.37 통합 시험을 통과한 경우에만 설치합니다. 조직이 Docker 공식 containerd.io 등 다른 공급원을 표준화했다면 공급원을 혼용하지 않습니다.sudo cp --archive --no-clobber /etc/apt/sources.list.d/kubernetes.list /etc/apt/sources.list.d/kubernetes.list.<BACKUP_SUFFIX>
sudo cp --archive --no-clobber /etc/apt/keyrings/kubernetes-apt-keyring.gpg /etc/apt/keyrings/kubernetes-apt-keyring.gpg.<BACKUP_SUFFIX>각 원본이 실제로 존재하고 <BACKUP_SUFFIX> 대상은 아직 없을 때만 실행합니다.sudo install -d -m 0755 /etc/apt/keyrings
curl -fL -o /tmp/kubernetes-v1.37-Release.key https://pkgs.k8s.io/core:/stable:/v1.37/deb/Release.key
gpg --show-keys --with-fingerprint /tmp/kubernetes-v1.37-Release.keyHTTPS 오류를 무시하지 말고, 출력된 키와 공식 설치 문서의 현재 저장소 지침을 대조합니다.sudo gpg --dearmor --yes --output /etc/apt/keyrings/kubernetes-apt-keyring.gpg /tmp/kubernetes-v1.37-Release.key
sudoedit /etc/apt/sources.list.d/kubernetes.list파일에는 공식 문서의 signed-by와 v1.37 URL 한 줄만 넣고 다른 minor 저장소를 섞지 않습니다.sudo apt update
apt-cache madison kubeadm kubelet kubectl
sudo apt install kubelet=<APPROVED_1_37_PACKAGE_VERSION> kubeadm=<APPROVED_1_37_PACKAGE_VERSION> kubectl=<APPROVED_1_37_PACKAGE_VERSION>
sudo apt-mark hold kubelet kubeadm kubectl세 패키지의 minor를 1.37로 맞추고 출력된 실제 후보 문자열을 사용합니다. 업그레이드는 kubeadm 공식 순서를 따라 별도 변경으로 수행합니다.- 저장소 URL이 pkgs.k8s.io의 v1.37 전용 경로이고 signed-by가 지정됐습니다.
- kubeadm·kubelet·kubectl의 설치 minor가 모두 1.37입니다.
- containerd가 CRI v1을 제공하는 지원 버전입니다.
- 기존 저장소·키가 있었다면 고유한 백업 파일과 변경 기록을 남겼습니다.
NO_PUBKEY·TLS·저장소 오류를 무시하거나 trusted=yes를 추가하지 않습니다. 다른 minor 후보가 보이면 저장소 파일과 apt policy를 먼저 고칩니다.
containerd cgroup, IPv4 forwarding, swap와 kubeadm init 파일을 구성합니다.
containerd·kernel·kubeadm 설정 백업과 편집
기존 설정을 백업하고 containerd major에 맞는 한 가지 systemd cgroup 경로만 적용합니다. swap 변경은 OS OOM 위험을 확인한 뒤 수행하며 kubeadm init 값은 고정 endpoint·CIDR과 일치시킵니다.
containerd --version
sudo ctr plugins ls | grep -E 'io.containerd.grpc.v1.cri|io.containerd.cri.v1'sudo cp --archive --no-clobber /etc/containerd/config.toml /etc/containerd/config.toml.<BACKUP_SUFFIX>
sudoedit /etc/containerd/config.toml기존 파일이 없다면 배포판의 containerd config default 결과를 별도 파일에서 검토한 뒤 생성합니다. 1.x와 2.x 예시를 동시에 넣지 않습니다.sudo cp --archive --no-clobber /etc/sysctl.d/99-kubernetes-cri.conf /etc/sysctl.d/99-kubernetes-cri.conf.<BACKUP_SUFFIX>
sudoedit /etc/sysctl.d/99-kubernetes-cri.confsudo cp --archive --no-clobber /etc/fstab /etc/fstab.<BACKUP_SUFFIX>
sudoedit /etc/fstab
swapon --showkubelet 기본 failSwapOn 정책을 사용할 때만 정확한 swap 항목을 주석 처리합니다. NodeSwap을 설계했다면 해당 공식 문서를 따릅니다.sudo swapoff -aavailable 메모리가 충분하고 swap 사용 페이지를 RAM으로 회수해도 OOM이 없다는 확인 뒤에만 실행합니다.sudo install -d -m 0700 /etc/kubernetes
sudoedit /etc/kubernetes/kubeadm-init.yamlversion = 3
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
SystemdCgroup = true이 가이드의 신규 v1.37 구성에서는 검증된 containerd 2.3 LTS 최신 patch에만 사용합니다. 기존 전체 설정을 이 조각으로 덮어쓰지 말고 정확한 section에 병합합니다.version = 2
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true신규 v1.37 설치의 기본값이 아닙니다. 1.7은 2026-09 지원 종료 예정이므로 기존 환경에서 공급자 지원·호환성을 별도 확인하고 2.3 LTS 전환 계획이 있을 때만 참고합니다. disabled_plugins에 cri가 있으면 원인을 확인합니다.net.ipv4.ip_forward = 1선택한 CNI가 요구하는 추가 module·sysctl은 그 CNI의 고정 버전 공식 문서에서 별도로 검증합니다.apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: "<CONTROL_PLANE_IP>"
bindPort: 6443
nodeRegistration:
criSocket: unix:///run/containerd/containerd.sock
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.37.0
controlPlaneEndpoint: "<STABLE_CONTROL_PLANE_ENDPOINT>:6443"
networking:
podSubnet: "<CNI_POD_CIDR>"
serviceSubnet: "<SERVICE_CIDR>"실제 패치 버전, 고정 endpoint, 충돌 없는 CIDR을 넣습니다. HA cluster라면 load balancer와 다중 control plane 설계를 별도 적용합니다.- 지원 중인 containerd 2.3 LTS 최신 patch와 v1.37 통합 시험을 확인하고 major에 맞는 설정 조각 하나만 사용했습니다.
- containerd·sysctl·fstab 기존 파일을 고유한 suffix로 백업했습니다.
- swap 비활성화 뒤 available 메모리가 안전하고 swapon 출력이 비었습니다.
- advertise address·stable endpoint·Pod/Service CIDR이 실제 설계와 일치합니다.
CRI plugin이 없거나 config parse가 실패하면 kubeadm을 시작하지 않습니다. controlPlaneEndpoint와 CIDR 변경은 초기화 뒤 단순 수정하기 어렵습니다.
설정 검증 뒤 containerd·kubelet을 시작하고 kubeadm preflight를 수행합니다.
runtime 검증과 control plane 초기화
sysctl과 containerd를 반영하고 CRI·kubeadm 설정을 검증한 뒤에만 control plane을 초기화합니다. init에서는 bootstrap token 출력을 생략하고 worker join 직전에 짧은 TTL token을 별도로 생성합니다.
sudo sysctl --system
sudo systemctl restart containerd.service
systemctl is-active containerd.servicesudo crictl --runtime-endpoint unix:///run/containerd/containerd.sock info
sudo crictl --runtime-endpoint unix:///run/containerd/containerd.sock info | grep -i systemdCgroupsudo systemctl enable --now kubelet.service
kubeadm version -o short
kubelet --version
kubectl version --clientkubeadm init 전 kubelet이 재시작을 반복하는 것은 예상될 수 있습니다. 다른 최초 오류가 없는지는 journal로 확인합니다.sudo kubeadm config validate --config /etc/kubernetes/kubeadm-init.yaml
sudo kubeadm config images list --config /etc/kubernetes/kubeadm-init.yamlsudo kubeadm init --config /etc/kubernetes/kubeadm-init.yaml --skip-token-printpreflight 오류를 --ignore-preflight-errors로 건너뛰지 않습니다. worker join token은 검증 단계에서 짧은 TTL로 생성하며 채팅·티켓·shell history에 넣지 않습니다.- net.ipv4.ip_forward=1이며 containerd가 active입니다.
- CRI v1 정보와 SystemdCgroup=true를 확인했습니다.
- kubeadm·kubelet·kubectl minor가 control plane v1.37과 정책 범위 안입니다.
- kubeadm init가 preflight 무시 없이 완료됐습니다.
CRI endpoint·cgroup 불일치나 preflight 실패는 init 재시도 전에 수정합니다. init 일부 완료 뒤 반복 실행하지 말고 로그와 cluster state를 확인합니다.
관리용 kubeconfig를 제한된 권한으로 배치하고 고정 버전 CNI를 적용합니다.
kubeconfig·CNI·worker join과 상태 검증
admin.conf를 운영 관리자 전용 경로에 두고, 로컬에서 검토·고정한 CNI manifest를 적용합니다. CNI가 Ready가 된 뒤 worker를 한 대씩 join합니다.
install -d -m 0700 <ADMIN_HOME>/.kube
sudo install -o <ADMIN_USER> -g <ADMIN_GROUP> -m 0600 /etc/kubernetes/admin.conf <ADMIN_HOME>/.kube/configadmin.conf는 cluster-admin 자격증명입니다. 일반 사용자·CI에 배포하지 않습니다.kubectl get --raw='/readyz?verbose'
kubectl get nodes -o wide
kubectl get pods -n kube-system -o widekubectl diff --server-side -f <LOCAL_PINNED_CNI_MANIFEST.yaml>
kubectl apply --server-side -f <LOCAL_PINNED_CNI_MANIFEST.yaml>선택한 CNI 공식 사이트에서 고정 버전을 받아 checksum·RBAC·CIDR을 검토한 로컬 파일만 사용합니다. 원격 latest URL을 바로 apply하지 않습니다.kubectl get pods -n kube-system -o wide
kubectl rollout status deployment/coredns -n kube-system --timeout=5msudo kubeadm token create --print-join-command --ttl 15m출력은 15분간 유효한 비밀입니다. 승인된 worker 콘솔에서만 실행하고 로그·문서에 저장하지 않습니다. worker의 kubeadm minor를 control plane과 맞춥니다.- API readyz가 성공하고 control plane component가 정상입니다.
- CNI Pod와 CoreDNS가 Running·Ready입니다.
- worker를 한 대씩 join했고 모든 Node가 Ready입니다.
- Pod 간·Service DNS·외부 egress를 비운영 테스트 workload로 검증했습니다.
CNI 전 control plane NotReady는 예상될 수 있으나 적용 뒤에도 지속되면 kubelet·CNI 이벤트를 확인합니다. CoreDNS Ready만으로 전체 네트워크를 검증했다고 보지 않습니다.
bootstrap 자격증명, API 접근, 백업·업그레이드·모니터링 기준을 잠급니다.
자격증명·API 노출·백업·운영 보안 점검
cluster-admin kubeconfig와 bootstrap token을 최소화하고 API 6443을 관리망으로 제한합니다. etcd snapshot과 인증서 복구를 실제로 시험할 계획을 세웁니다.
sudo kubeadm token list | awk 'NR == 1 { print; next } { $1 = substr($1, 1, 6) ".<redacted>"; print }'token ID만 남기고 secret 부분은 화면에 표시하지 않습니다. 원문이 필요한 경우에도 출력·캡처하지 말고 사용 후 즉시 삭제하거나 만료를 확인합니다.sudo stat -Lc '%A %a %U:%G %n' /etc/kubernetes/admin.conf <ADMIN_HOME>/.kube/configkubectl auth can-i --list
kubectl auth can-i --as=system:anonymous --listForbidden이거나 제한된 non-resource URL만 보이는지 조직 정책과 비교합니다.sudo ss -lntp 'sport = :6443'
sudo kubeadm certs check-expirationkubectl events -n kube-system --types=Warning- API 6443은 승인된 관리망·control plane 노드에서만 접근할 수 있습니다.
- admin.conf는 0600이며 일반 workload·CI에는 최소 RBAC ServiceAccount만 사용합니다.
- bootstrap token은 짧은 TTL이며 사용 후 만료·삭제를 확인합니다.
- etcd snapshot·PKI·kubeadm config의 암호화 외부 백업과 복원 시험 일정이 있습니다.
- Kubernetes 보안 패치와 kubeadm 순차 업그레이드를 minor 단위로 수행하는 정책이 있습니다.
- Node Ready·Pressure, API·etcd, 인증서 만료, Pod restart·Pending을 모니터링합니다.
cluster-admin kubeconfig가 넓게 배포됐거나 API가 인터넷 전체에 열려 있으면 workload 배포보다 자격증명 회수·네트워크 제한을 우선합니다.
신규 클러스터 철회와 개별 설정 원복 경계를 확인합니다.
신규 노드 초기화 철회와 설정 복원
kubeadm reset은 해당 노드의 Kubernetes 상태와 로컬 stacked etcd를 제거할 수 있는 위험 작업입니다. 새로 만든 비운영 클러스터이고 workload·PV·etcd 복구 자료를 확인한 경우에만 노드별로 수행합니다.
kubectl get nodes,pods,pv,pvc --all-namespaces
sudo kubeadm certs check-expiration
sudo find /var/lib/etcd -maxdepth 1 -mindepth 1 -print | headPV·etcd 데이터가 하나라도 필요하면 reset하지 말고 공급자·백업 복구 절차를 먼저 수행합니다.sudo kubeadm reset --dry-runcontrol plane과 worker를 혼동하지 말고 노드명·IP·역할을 다시 확인합니다.sudo kubeadm reset운영 workload가 없고 etcd/PV/인증서 복구가 검증된 신규 클러스터에만 실행합니다. CNI iptables·설정과 사용자 kubeconfig는 자동으로 모두 정리되지 않습니다.sudo cp --archive /etc/containerd/config.toml.<BACKUP_SUFFIX> /etc/containerd/config.toml
sudo systemctl restart containerd.service작업 전 실제 백업 파일과 checksum을 확인하고 기존 containerd workload의 영향을 승인받은 뒤 실행합니다.sudo cp --archive /etc/fstab.<BACKUP_SUFFIX> /etc/fstab
sudo cp --archive /etc/sysctl.d/99-kubernetes-cri.conf.<BACKUP_SUFFIX> /etc/sysctl.d/99-kubernetes-cri.conf
sudo sysctl --system
swapon --show
systemctl is-active containerd.service원래 파일이 있었고 이번 작업의 정확한 백업임을 확인한 경우에만 복원합니다. swap은 fstab 복원만으로 즉시 켜지지 않을 수 있습니다.- reset 전에 workload·PV·etcd·PKI 복구 필요 여부를 책임자가 승인했습니다.
- 정확한 신규 노드와 역할을 확인했고 kubeadm reset 출력과 로그를 보관했습니다.
- containerd·fstab·sysctl은 작업 전 백업이 있던 파일만 복원했습니다.
- 기존 containerd workload와 네트워크에 회귀가 없는지 확인했습니다.
reset은 외부 load balancer, cloud 자원, CNI 규칙, PV와 사용자 kubeconfig를 완전 복구하지 않습니다. 각 공급자·CNI의 철회 절차를 별도 확인합니다.
철회 이유, 제거한 cluster identity, 남은 cloud·storage·network 자원과 백업 보존 기간을 기록합니다.
SECURITY CHECK
운영 전 마지막 보안 점검
- kubeadm preflight 오류를 무시하지 않고 package minor·CRI·cgroup·swap 조건을 맞춥니다.
- API 6443과 etcd 포트는 승인된 control plane·관리망 외부에 공개하지 않습니다.
- admin.conf·join token·certificate key·Secret 원문을 채팅·shell history·일반 티켓에 남기지 않습니다.
- <...> 자리표시자는 승인된 리터럴 값으로 직접 치환하고 외부 입력으로 shell 명령을 조립하거나 eval하지 않습니다.
- CNI는 고정 버전·checksum·RBAC·CIDR을 검토한 로컬 manifest로 설치합니다.
- etcd snapshot과 PKI 복원은 백업 생성뿐 아니라 격리 환경 복구 시험으로 검증합니다.
- Kubernetes는 지원 minor와 version-skew 정책 안에서 kubeadm 공식 업그레이드 순서를 따릅니다.
COMMON ERRORS
자주 막히는 지점
container runtime is not running 또는 CRI v1 오류
- 증상
- kubeadm preflight가 unknown service runtime.v1.RuntimeService 또는 container runtime is not running으로 중단됩니다.
- 가능한 원인
- containerd의 CRI plugin 비활성화, 잘못된 socket, 설정 문법 오류 또는 service 실패일 수 있습니다.
- 확인 순서
- containerd status·journal, ctr plugins, crictl info와 config major별 plugin section을 확인하고 preflight를 우회하지 않습니다.
CNI 적용 뒤에도 Node가 NotReady
- 증상
- kubelet은 실행되지만 Node Ready=False이고 CoreDNS가 Pending 또는 ContainerCreating입니다.
- 가능한 원인
- Pod CIDR 불일치, CNI daemonset 실패, kernel module·sysctl·방화벽 또는 Node pressure일 수 있습니다.
- 확인 순서
- Node condition, kube-system 이벤트, CNI Pod 로그와 선택한 CNI 공식 요구 포트를 확인합니다.
Pod가 CrashLoopBackOff 또는 OOMKilled
- 증상
- 클러스터는 Ready지만 배포한 workload가 반복 재시작하거나 probe 실패를 냅니다.
- 가능한 원인
- 애플리케이션 설정, resource limit, startup·liveness probe가 실제 기동 특성과 맞지 않을 수 있습니다.
- 확인 순서
- 이전 로그, lastState, resource와 probe를 분리하는 Pod 재시작 가이드로 이어갑니다.
이미지를 가져오지 못해 workload가 시작되지 않음
- 증상
- Pod가 ErrImagePull 또는 ImagePullBackOff이고 unauthorized·x509·manifest unknown이 보입니다.
- 가능한 원인
- 이미지 참조, registry 인증, Node DNS·TLS·egress 중 하나가 맞지 않을 수 있습니다.
- 확인 순서
- Secret 값을 출력하지 말고 이벤트 문구별 ImagePullBackOff 가이드로 분기합니다.
PRIMARY REFERENCES
공식 문서
- Kubernetes v1.37 · Installing kubeadm
- Kubernetes v1.37 · Container Runtimes
- containerd · Release support and Kubernetes matrix
- Kubernetes v1.37 · Creating a cluster with kubeadm
- Kubernetes · kubeadm Configuration v1beta4
- Kubernetes · Version Skew Policy
- Kubernetes · kubeadm reset
- Kubernetes · Authenticating with Bootstrap Tokens
설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.