[K8S Deploy] kubeadm

진웅·2026년 1월 24일

k8s deploy

목록 보기
10/20
post-thumbnail

Kubeadm Deep Dive

  • Kubeadm 기반 k8s 설치 실습 환경 구성 정리

Kubeadm이란?

  • Kubeadm은 노드 부트스트래퍼(Node Bootstrapper)다.
  • 머신 프로비저닝은 별도로 해야 하고, kubeadm은 해당 머신에 Kubernetes 노드를 생성하는 역할만 담당한다.

SIG Cluster Lifecycle 프로젝트이며, 설계 철학은 Be Simple, Be Extensible이다.

? Bootstrapper는 시스템이나 프로그램을 실행하기 위해 가장 먼저 실행되어 필요한 환경을 준비해주는 작은 초기화 도구를 의미한다.

핵심 명령어

명령어설명
kubeadm initControl Plane 노드 부트스트랩
kubeadm joinWorker 또는 추가 Control Plane 노드를 클러스터에 조인
kubeadm upgrade클러스터를 새 버전으로 업그레이드
kubeadm resetinit 또는 join으로 변경된 내용을 되돌림

Kubeadm이 하는 것 vs 하지 않는 것

kubeadm이 배포/관리하는 것

컴포넌트유형설명
etcdStatic Pod클러스터 상태 저장소
kube-apiserverStatic PodAPI 서버
kube-controller-managerStatic Pod컨트롤러 매니저
kube-schedulerStatic Pod스케줄러
corednsDeployment클러스터 DNS (addon)
kube-proxyDaemonSet네트워크 프록시 (addon)

사전 설치가 필요한 것 (kubeadm이 하지 않음)

컴포넌트설명
Container Runtimecontainerd, CRI-O 등
kubelet노드 에이전트 (바이너리 설치)
CNI pluginFlannel, Calico, Cilium 등 (별도 설치)


누가 Kubeadm을 사용하나?

  • minikube - 로컬 개발 환경
  • kind - Docker 기반 로컬 클러스터
  • Cluster API - 선언적 클러스터 관리
  • kubespray - Ansible 기반 배포

kubeadm은 Composable Solution의 일부로, Cluster API, cluster-addons, etcdadm, ComponentConfig, image builder 등과 함께 k8s cluster provisioners를 구성한다.

참고: etcdadm repo는 현재 archived 상태
https://github.com/kubernetes-retired/etcdadm


실습 환경 구성

버전 정보

항목버전호환성
Rocky Linux10.0RHEL 10 기반
containerdv2.1.5k8s 1.32~1.35 지원
runcv1.3.3OCI 런타임
kubeletv1.32.11
kubeadmv1.32.11
kubectlv1.32.11
helmv3.18.6k8s 1.30.x~1.33.x
flannelv0.27.3k8s 1.28+

노드 구성

노드호스트명IPCPUMemory
Control Planek8s-ctr192.168.10.10043GB
Worker 1k8s-w1192.168.10.10122GB
Worker 2k8s-w2192.168.10.10222GB

Vagrant 환경 준비

사전 요구사항

  • VirtualBox 7.2.4+
  • Vagrant 2.4.9+

macOS/Windows에서 bento/rockylinux-10.0 구동 실패 시 최신 버전 설치 필요

Vagrantfile

BOX_IMAGE = "bento/rockylinux-10.0"
BOX_VERSION = "202510.26.0"
N = 2

Vagrant.configure("2") do |config|
  # Control Plane Node
  config.vm.define "k8s-ctr" do |subconfig|
    subconfig.vm.box = BOX_IMAGE
    subconfig.vm.box_version = BOX_VERSION
    subconfig.vm.provider "virtualbox" do |vb|
      vb.customize ["modifyvm", :id, "--groups", "/K8S-Upgrade-Lab"]
      vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"]
      vb.name = "k8s-ctr"
      vb.cpus = 4
      vb.memory = 3072
      vb.linked_clone = true
    end
    subconfig.vm.host_name = "k8s-ctr"
    subconfig.vm.network "private_network", ip: "192.168.10.100"
    subconfig.vm.network "forwarded_port", guest: 22, host: "60000", auto_correct: true, id: "ssh"
    subconfig.vm.synced_folder "./", "/vagrant", disabled: true
  end

  # Worker Nodes
  (1..N).each do |i|
    config.vm.define "k8s-w#{i}" do |subconfig|
      subconfig.vm.box = BOX_IMAGE
      subconfig.vm.box_version = BOX_VERSION
      subconfig.vm.provider "virtualbox" do |vb|
        vb.customize ["modifyvm", :id, "--groups", "/K8S-Upgrade-Lab"]
        vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"]
        vb.name = "k8s-w#{i}"
        vb.cpus = 2
        vb.memory = 2048
        vb.linked_clone = true
      end
      subconfig.vm.host_name = "k8s-w#{i}"
      subconfig.vm.network "private_network", ip: "192.168.10.10#{i}"
      subconfig.vm.network "forwarded_port", guest: 22, host: "6000#{i}", auto_correct: true, id: "ssh"
      subconfig.vm.synced_folder "./", "/vagrant", disabled: true
    end
  end
end

VM 실행

# Vagrantfile 다운로드
curl -O https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/k8s-kubeadm/Vagrantfile

# VM 생성 및 시작
vagrant up

# 상태 확인
vagrant status

# SSH 접속
vagrant ssh k8s-ctr

클러스터 구성 절차 개요

1. [공통] 사전 설정
2. [공통] CRI 설치 (containerd)
3. [공통] kubeadm, kubelet, kubectl 설치
4. [Control Plane] kubeadm init → CNI 설치
5. [Worker] kubeadm join
6. 모니터링 툴 설치
7. 샘플 애플리케이션 배포
8. 인증서 갱신

1. [모든 노드] 사전 설정

# swap 비활성화
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab

# 방화벽 비활성화 (테스트 환경)
sudo systemctl stop firewalld
sudo systemctl disable firewalld

# SELinux permissive 모드
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

# 커널 모듈 로드
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# 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
단계명령/설정하는 일
Swap 비활성화swapoff -a, /etc/fstab 수정메모리 swap 기능을 끄고 재부팅 후에도 swap이 켜지지 않도록 설정
방화벽 비활성화systemctl stop firewalld, systemctl disable firewalld테스트 환경에서 방화벽을 끄고, 부팅 시 자동 실행되지 않도록 설정
SELinux Permissive 모드setenforce 0, /etc/selinux/config 수정SELinux를 강제(enforcing) 모드에서 완화(permissive) 모드로 변경
커널 모듈 로드overlay, br_netfilter컨테이너 및 네트워크 브리지 관련 기능을 지원하는 커널 모듈 활성화
sysctl 네트워크 설정bridge-nf-call-iptables, bridge-nf-call-ip6tables, ip_forward브리지 네트워크 패킷을 iptables로 처리하고, IPv4 패킷 포워딩을 허용

2. [모든 노드] containerd 설치

Docker 저장소 추가

containerd는 Docker 저장소에서 설치한다. dockerd는 설치하지 않고 containerd만 설치한다.

# dnf == yum 확인
dnf --version

# Docker 저장소 추가
dnf repolist
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf repolist
cat /etc/yum.repos.d/docker-ce.repo
dnf makecache

설치 가능한 버전 확인

# 설치 가능한 모든 containerd.io 버전 확인
dnf list --showduplicates containerd.io
Available Packages
containerd.io.aarch64    1.7.23-3.1.el10    docker-ce-stable
containerd.io.aarch64    1.7.24-3.1.el10    docker-ce-stable
...
containerd.io.aarch64    2.1.5-1.el10       docker-ce-stable
containerd.io.aarch64    2.2.0-2.el10       docker-ce-stable
containerd.io.aarch64    2.2.1-1.el10       docker-ce-stable

containerd 설치

# containerd 2.1.5 설치
dnf install -y containerd.io-2.1.5-1.el10

# 설치된 파일 확인
which runc && runc --version
which containerd && containerd --version
which containerd-shim-runc-v2 && containerd-shim-runc-v2 -v
which ctr && ctr --version

기본 설정 생성 및 SystemdCgroup 활성화

# 기본 설정 생성
containerd config default | tee /etc/containerd/config.toml

생성된 설정 파일 구조 (containerd 2.x는 version = 3):

version = 3
root = '/var/lib/containerd'
state = '/run/containerd'
...

containerd 버전별 설정 차이

  • containerd 2.x: version = 3, [plugins.'io.containerd.cri.v1.images']
  • containerd 1.x: version = 2, [plugins."io.containerd.grpc.v1.cri".containerd]

SystemdCgroup 활성화 (매우 중요!)

# 현재 설정 확인
cat /etc/containerd/config.toml | grep -i systemdcgroup

# SystemdCgroup = true로 변경
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml

# 변경 확인
cat /etc/containerd/config.toml | grep -i systemdcgroup

왜 SystemdCgroup = true가 필요한가?

  • cgroupfs 드라이버는 kubelet의 기본 cgroup 드라이버지만, systemd가 init 시스템인 경우 권장되지 않는다.
  • systemd는 시스템에 단 하나의 cgroup 관리자만 있을 것으로 기대한다.
  • cgroup v2를 사용할 경우에도 systemd cgroup 드라이버를 사용해야 한다.
  • kubelet과 containerd의 cgroup 드라이버가 일치하지 않으면 Pod가 정상 동작하지 않는다.

containerd 시작

# systemd unit 파일 최신 상태 읽기
systemctl daemon-reload

# containerd 시작 및 부팅 시 자동 시작 활성화
systemctl enable --now containerd

# 상태 확인
systemctl status containerd --no-pager
journalctl -u containerd.service --no-pager

containerd 소켓 및 플러그인 확인

# containerd 유닉스 도메인 소켓 확인
# kubelet과 containerd client(ctr, nerdctl, crictl)가 이 소켓을 사용
containerd config dump | grep -n containerd.sock
ls -l /run/containerd/containerd.sock
ss -xl | grep containerd

# 플러그인 확인
ctr --address /run/containerd/containerd.sock version
ctr plugins ls
TYPE                            ID          PLATFORMS       STATUS
io.containerd.content.v1        content     -               ok        # 이미지 레이어 저장
io.containerd.snapshotter.v1    overlayfs   linux/arm64/v8  ok        # K8s 기본 snapshotter
io.containerd.metadata.v1       bolt        -               ok        # 메타데이터 DB
...

프로세스 및 cgroup 확인

# 프로세스 트리 확인
pstree -alnp

# cgroup 계층 구조 확인
systemd-cgls --no-pager
단계명령/설정하는 일
저장소 추가dnf config-manager --add-repo ...Docker 공식 저장소를 추가하여 containerd 패키지를 설치할 수 있게 함
containerd 설치dnf install -y containerd.iocontainerd 런타임을 시스템에 설치
기본 설정 생성containerd config default > /etc/containerd/config.tomlcontainerd 기본 설정 파일을 생성
systemd cgroup 드라이버 활성화sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' ...containerd가 systemd 기반 cgroup을 사용하도록 설정 (Kubernetes 호환성 위해 중요)
서비스 시작 및 자동 실행systemctl enable --now containerdcontainerd 데몬을 즉시 실행하고, 부팅 시 자동으로 시작되도록 설정

👉 containerd 런타임을 설치하고, Kubernetes와 호환되도록 systemd cgroup을 활성화한 뒤 서비스로 등록하는 과정

중요: systemd 기반 시스템에서는 반드시 SystemdCgroup = true 설정이 필요하다.
kubelet과 container runtime의 cgroup 드라이버가 일치해야 한다.


cgroupfs vs systemd cgroup 드라이버

개요

Linux에서 cgroup(control group)은 프로세스의 리소스(CPU, 메모리, I/O 등)를 제한하고 격리하는 커널 기능이다. Kubernetes에서 kubelet과 container runtime이 cgroup을 관리하는 방식에 두 가지 드라이버가 있다.


cgroupfs 드라이버

동작 방식:

  • kubelet과 container runtime이 직접 cgroup 파일시스템(/sys/fs/cgroup)에 접근하여 cgroup을 생성하고 관리한다.
  • cgroup 계층 구조를 직접 조작한다.

특징:

  • 단순하고 직접적인 방식
  • systemd가 없는 환경에서 사용 가능
  • container runtime과 kubelet이 독립적으로 cgroup을 관리

문제점:

  • systemd 기반 시스템에서 두 개의 cgroup 관리자가 공존하게 됨
  • systemd도 자체적으로 cgroup을 관리하므로 충돌 가능성
  • 리소스 관리가 불안정해질 수 있음

systemd cgroup 드라이버

동작 방식:

  • kubelet과 container runtime이 systemd API를 통해 cgroup을 관리한다.
  • systemd가 cgroup의 단일 관리자 역할을 수행한다.

특징:

  • systemd 기반 Linux 배포판에서 권장
  • 단일 cgroup 관리자로 일관성 유지
  • systemd의 slice, scope, service 단위로 cgroup 관리

장점:

  • cgroup 관리의 일관성 보장
  • systemd와의 통합으로 안정적인 리소스 관리
  • 시스템 전체의 리소스 뷰가 명확함

비교 표

항목cgroupfssystemd
cgroup 관리 주체kubelet/runtime 직접systemd를 통해 간접
권장 환경systemd 없는 환경systemd 기반 배포판 (대부분)
안정성systemd와 충돌 가능단일 관리자로 안정적
Kubernetes 권장비권장 (v1.22+)권장
cgroup 경로/sys/fs/cgroup/... 직접systemd slice 기반

Kubernetes 권장 사항

Kubernetes v1.22부터 systemd cgroup 드라이버가 기본값으로 권장된다.

systemd 기반 Linux 배포판(Ubuntu, RHEL, Rocky Linux 등)에서는 반드시 kubelet과 container runtime 모두 동일한 cgroup 드라이버를 사용해야 한다.


설정 방법

containerd 설정 (/etc/containerd/config.toml)

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    SystemdCgroup = true

kubelet 설정 (/var/lib/kubelet/config.yaml)

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd

kubeadm 사용 시 (kubeadm-config.yaml)

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd

불일치 시 발생하는 문제

kubelet과 container runtime의 cgroup 드라이버가 다르면:

  • Pod가 CrashLoopBackOff 상태에 빠짐
  • kubelet 로그에 cgroup 관련 에러 발생
  • 노드가 NotReady 상태가 될 수 있음
  • 리소스 제한(limits)이 제대로 적용되지 않음

요약

상황권장 드라이버
Ubuntu, RHEL, Rocky Linux 등systemd
systemd 없는 환경 (컨테이너 내부 등)cgroupfs
Kubernetes v1.22+systemd (기본값)

대부분의 프로덕션 환경에서는 systemd cgroup 드라이버를 사용하는 것이 올바른 선택이다.


3. [모든 노드] kubeadm, kubelet, kubectl 설치

# Kubernetes 저장소 추가
cat <<EOF | sudo 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

# 설치
sudo dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

# kubelet 활성화
sudo systemctl enable --now kubelet
단계명령/설정하는 일
저장소 추가/etc/yum.repos.d/kubernetes.repo 생성Kubernetes 공식 패키지 저장소를 등록하여 패키지 설치 가능하게 함
Kubernetes 패키지 설치dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetesKubernetes 핵심 구성 요소 설치
- kubelet: 노드에서 Pod 실행 관리
- kubeadm: 클러스터 초기화 및 관리 도구
- kubectl: 클러스터 제어용 CLI
kubelet 활성화systemctl enable --now kubeletkubelet 서비스를 즉시 실행하고, 부팅 시 자동 시작되도록 설정

👉 Kubernetes 저장소를 추가하고, 클러스터 운영에 필요한 핵심 패키지(kubelet, kubeadm, kubectl)를 설치 및 활성화하는 단계


4. [Control Plane] kubeadm init으로 클러스터 초기화

kubeadm init 수행 단계

kubeadm init은 다음 단계를 순차적으로 수행한다:

단계하는 일
Preflight ChecksCRI(Container Runtime Interface) 엔드포인트 확인, 루트 권한 확인, kubelet 버전 검증
Certificates/etc/kubernetes/pki 경로에 클러스터용 인증서 및 키 생성
Kubeconfig/etc/kubernetes 경로에 kubeconfig 파일 생성 (API 서버와 통신용)
Static PodsControl Plane 컴포넌트(API Server, Controller Manager, Scheduler) 매니페스트 생성 후 kubelet이 Static Pod으로 실행
kubelet 시작API Server의 healthz 엔드포인트가 정상 응답할 때까지 대기
ConfigMap 저장kubeadm-config ConfigMap을 클러스터에 저장 (설정 공유 목적)
노드 라벨/Taint해당 노드에 control-plane 라벨 부여 및 NoSchedule taint 적용 (워커 노드 스케줄 방지)
Bootstrap Token워커 노드가 클러스터에 조인할 수 있도록 토큰 및 RBAC 권한 설정
Addons 설치기본 애드온(CoreDNS, kube-proxy) 배포

👉 kubeadm init은 클러스터 제어 플레인 노드를 준비하기 위해 인증서 → 설정 → 컨트롤 플레인 Static Pod → 기본 애드온 설치까지 자동으로 처리하는 과정

기본 환경 정보 저장 (init 전)

# init 전 상태 저장 (나중에 비교용)
crictl images
crictl ps
tree /etc/kubernetes  | tee -a etc_kubernetes-1.txt
tree /var/lib/kubelet | tee -a var_lib_kubelet-1.txt
pstree -alnp | tee -a pstree-1.txt
systemd-cgls --no-pager | tee -a systemd-cgls-1.txt
ip addr | tee -a ip_addr-1.txt 
ss -tnlp | tee -a ss-1.txt

kubeadm Configuration 파일 작성

cat << EOF > kubeadm-init.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
bootstrapTokens:
- token: "123456.1234567890123456"
  ttl: "0s"
  usages:
  - signing
  - authentication
nodeRegistration:
  kubeletExtraArgs:
    - name: node-ip
      value: "192.168.10.100"  # 미설정 시 10.0.2.15 맵핑됨
  criSocket: "unix:///run/containerd/containerd.sock"
localAPIEndpoint:
  advertiseAddress: "192.168.10.100"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: "1.32.11"
networking:
  podSubnet: "10.244.0.0/16"
  serviceSubnet: "10.96.0.0/16"
EOF

kubeadm init 실행

# (옵션) 컨테이너 이미지 미리 다운로드 - 업그레이드 시 시간 단축
kubeadm config images pull

# dry-run으로 먼저 확인
kubeadm init --config="kubeadm-init.yaml" --dry-run

# 실제 init 수행
kubeadm init --config="kubeadm-init.yaml"

init 실행 시 출력 내용:

[init] Using Kubernetes version: v1.32.11
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [k8s-ctr kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.10.100]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
...
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
...
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

crictl로 컨테이너 확인

crictl images
IMAGE                                     TAG        IMAGE ID       SIZE
registry.k8s.io/coredns/coredns           v1.11.3    2f6c962e7b831  16.9MB
registry.k8s.io/etcd                      3.5.24-0   1211402d28f58  21.9MB
registry.k8s.io/kube-apiserver            v1.32.11   58951ea1a0b5d  26.4MB
registry.k8s.io/kube-controller-manager   v1.32.11   82766e5f2d560  24.2MB
registry.k8s.io/kube-proxy                v1.32.11   dcdb790dc2bfe  27.6MB
registry.k8s.io/kube-scheduler            v1.32.11   cfa17ff3d6634  19.2MB
registry.k8s.io/pause                     3.10       afb61768ce381  268kB
crictl ps
CONTAINER      IMAGE          CREATED         STATE     NAME                      POD ID         POD
a04be00090580  dcdb790dc2bfe  26 seconds ago  Running   kube-proxy                1fd91b0a982bb  kube-proxy-7w44b
b005f34739da5  82766e5f2d560  37 seconds ago  Running   kube-controller-manager   555d146c3ec07  kube-controller-manager-k8s-ctr
eb42b9c47fdce  cfa17ff3d6634  37 seconds ago  Running   kube-scheduler            e649514d0a1b7  kube-scheduler-k8s-ctr
bbe8495d2a205  58951ea1a0b5d  37 seconds ago  Running   kube-apiserver            be25c00dd555c  kube-apiserver-k8s-ctr
c00a944599500  1211402d28f58  37 seconds ago  Running   etcd                      ce6b89dea28da  etcd-k8s-ctr

kubeconfig 설정

mkdir -p /root/.kube
cp -i /etc/kubernetes/admin.conf /root/.kube/config
chown $(id -u):$(id -g) /root/.kube/config

# 확인
kubectl cluster-info
kubectl get node -owide
NAME      STATUS     ROLES           AGE   VERSION    INTERNAL-IP      OS-IMAGE                        KERNEL-VERSION                CONTAINER-RUNTIME
k8s-ctr   NotReady   control-plane   6m    v1.32.11   192.168.10.100   Rocky Linux 10.0 (Red Quartz)   6.12.0-55.39.1.el10.aarch64   containerd://2.1.5

NotReady 상태인 이유: CNI가 아직 설치되지 않았기 때문

cluster-info ConfigMap 확인

# cluster-info는 '신원 확인 전, 최소한의 신뢰 부트스트랩 데이터'
kubectl -n kube-public get configmap cluster-info
kubectl -n kube-public get configmap cluster-info -o yaml

# 인증 없이도 접근 가능 (kubeadm join 전 노드가 사용)
curl -s -k https://192.168.10.100:6443/api/v1/namespaces/kube-public/configmaps/cluster-info | jq

5. [Control Plane] 편의성 설정

# vagrant 접속 시 자동 root 전환
echo "sudo su -" >> /home/vagrant/.bashrc

# kubectl/kubeadm 자동 완성
source <(kubectl completion bash)
source <(kubeadm completion bash)
echo 'source <(kubectl completion bash)' >> /etc/profile
echo 'source <(kubeadm completion bash)' >> /etc/profile

# alias 설정
alias k=kubectl
complete -o default -F __start_kubectl k
echo 'alias k=kubectl' >> /etc/profile
echo 'complete -o default -F __start_kubectl k' >> /etc/profile

# kubecolor 설치 (컬러 출력)
dnf install -y 'dnf-command(config-manager)'
dnf config-manager --add-repo https://kubecolor.github.io/packages/rpm/kubecolor.repo
dnf install -y kubecolor
alias kc=kubecolor
echo 'alias kc=kubecolor' >> /etc/profile

# kubectx & kubens 설치
dnf install -y git
git clone https://github.com/ahmetb/kubectx /opt/kubectx
ln -s /opt/kubectx/kubens /usr/local/bin/kubens
ln -s /opt/kubectx/kubectx /usr/local/bin/kubectx

# kube-ps1 설치 (프롬프트에 컨텍스트/네임스페이스 표시)
git clone https://github.com/jonmosco/kube-ps1.git /root/kube-ps1
cat << "EOT" >> /root/.bash_profile
source /root/kube-ps1/kube-ps1.sh
KUBE_PS1_SYMBOL_ENABLE=true
function get_cluster_short() {
  echo "$1" | cut -d . -f1
}
KUBE_PS1_CLUSTER_FUNCTION=get_cluster_short
KUBE_PS1_SUFFIX=') '
PS1='$(kube_ps1)'$PS1
EOT

# helm 설치
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | DESIRED_VERSION=v3.18.6 bash
helm version

# k9s 설치
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
wget https://github.com/derailed/k9s/releases/latest/download/k9s_linux_${CLI_ARCH}.tar.gz
tar -xzf k9s_linux_*.tar.gz
mv k9s /usr/local/bin/
chmod +x /usr/local/bin/k9s

재접속 후:

exit
exit
vagrant ssh k8s-ctr

# 컨텍스트 이름 변경
kubectl config rename-context "kubernetes-admin@kubernetes" "HomeLab"
kubens default

6. [Control Plane] Flannel CNI 설치 (v0.27.3)

CNI가 설치되어야 노드가 Ready 상태가 되고, coredns Pod도 정상 기동된다.

현재 클러스터 CIDR 확인

# kube-controller-manager에서 cluster-cidr 확인
kc describe pod -n kube-system kube-controller-manager-k8s-ctr | grep cluster-cidr
# --cluster-cidr=10.244.0.0/16

# 노드별 Pod CIDR 확인
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}'
# k8s-ctr	10.244.0.0/24

Helm으로 Flannel 설치

# Flannel Helm repo 추가
helm repo add flannel https://flannel-io.github.io/flannel
helm repo update

# namespace 생성
kubectl create namespace kube-flannel

# values 파일 작성
cat << EOF > flannel.yaml
podCidr: "10.244.0.0/16"
flannel:
  cniBinDir: "/opt/cni/bin"
  cniConfDir: "/etc/cni/net.d"
  args:
  - "--ip-masq"
  - "--kube-subnet-mgr"
  - "--iface=enp0s9"    # Vagrant private network 인터페이스
  backend: "vxlan"
EOF

# Flannel 설치
helm install flannel flannel/flannel --namespace kube-flannel --version 0.27.3 -f flannel.yaml

# 확인
helm list -A
kubectl get ds,pod,cm -n kube-flannel -owide

CNI 설치 확인

# CNI 바이너리 확인
ls -l /opt/cni/bin/
# -rwxr-xr-x. 1 root root 2974540 Jan 17 01:35 flannel

# CNI 설정 확인
cat /etc/cni/net.d/10-flannel.conflist | jq

# crictl로 CNI 상태 확인
crictl info | jq '.status.conditions'
[
  { "type": "RuntimeReady", "status": true },
  { "type": "NetworkReady", "status": true }
]

coredns 및 노드 상태 확인

# coredns Pod 정상 기동 확인
kubectl get pod -n kube-system -owide
NAME                       READY   STATUS    RESTARTS   IP           NODE
coredns-668d6bf9bc-bmdjw   1/1     Running   0          10.244.0.3   k8s-ctr
coredns-668d6bf9bc-cbtn9   1/1     Running   0          10.244.0.2   k8s-ctr
etcd-k8s-ctr               1/1     Running   0          192.168.10.100   k8s-ctr
kube-apiserver-k8s-ctr     1/1     Running   0          192.168.10.100   k8s-ctr
...
# 노드 Ready 상태 확인
kubectl get nodes
NAME      STATUS   ROLES           AGE   VERSION
k8s-ctr   Ready    control-plane   10m   v1.32.11

네트워크 정보 확인

# 라우팅 테이블
ip -c route | grep 10.244.

# 네트워크 인터페이스 (cni0, flannel.1 확인)
ip addr

# 브릿지 링크
bridge link

# iptables 규칙
iptables -t nat -S | head -20

7. [Control Plane] 인증서 확인

인증서 만료일 확인

kubeadm certs check-expiration
CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY
admin.conf                 Jan 16, 2027 14:33 UTC   364d            ca
apiserver                  Jan 16, 2027 14:33 UTC   364d            ca
apiserver-etcd-client      Jan 16, 2027 14:33 UTC   364d            etcd-ca
apiserver-kubelet-client   Jan 16, 2027 14:33 UTC   364d            ca
controller-manager.conf    Jan 16, 2027 14:33 UTC   364d            ca
...

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME
ca                      Jan 14, 2036 14:33 UTC   9y
etcd-ca                 Jan 14, 2036 14:33 UTC   9y
front-proxy-ca          Jan 14, 2036 14:33 UTC   9y

참고: CA 인증서는 10년, 일반 인증서는 1년 유효

인증서 파일 구조

tree /etc/kubernetes/pki
/etc/kubernetes/pki
├── apiserver.crt
├── apiserver.key
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
├── apiserver-kubelet-client.crt
├── apiserver-kubelet-client.key
├── ca.crt
├── ca.key
├── etcd
│   ├── ca.crt
│   ├── ca.key
│   ├── healthcheck-client.crt
│   ├── healthcheck-client.key
│   ├── peer.crt
│   ├── peer.key
│   ├── server.crt
│   └── server.key
├── front-proxy-ca.crt
├── front-proxy-ca.key
├── front-proxy-client.crt
├── front-proxy-client.key
├── sa.key
└── sa.pub

인증서 상세 확인

# CA 인증서 확인
cat /etc/kubernetes/pki/ca.crt | openssl x509 -text -noout | grep -A2 "Subject:"
# Subject: CN=kubernetes
# CA:TRUE

# API Server 인증서 확인 (SAN 포함)
cat /etc/kubernetes/pki/apiserver.crt | openssl x509 -text -noout | grep -A5 "Subject Alternative Name"
# DNS:k8s-ctr, DNS:kubernetes, DNS:kubernetes.default, ...
# IP Address:10.96.0.1, IP Address:192.168.10.100

8. [Control Plane] Static Pod 확인

Static Pod 매니페스트는 /etc/kubernetes/manifests/에 위치한다.

tree /etc/kubernetes/manifests/
/etc/kubernetes/manifests/
├── etcd.yaml
├── kube-apiserver.yaml
├── kube-controller-manager.yaml
└── kube-scheduler.yaml

kubelet 설정에서 staticPodPath 확인

cat /var/lib/kubelet/config.yaml | grep staticPodPath
# staticPodPath: /etc/kubernetes/manifests

주요 Static Pod 설정 확인

# etcd - client/metrics 포트 확인
cat /etc/kubernetes/manifests/etcd.yaml | grep -E "listen-client|listen-metrics"
# --listen-client-urls=https://127.0.0.1:2379,https://192.168.10.100:2379
# --listen-metrics-urls=http://127.0.0.1:2381

# kube-apiserver - 포트 및 etcd 연결 확인
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep -E "secure-port|etcd-servers"
# --secure-port=6443
# --etcd-servers=https://127.0.0.1:2379

# Listen 포트 확인
ss -tnlp | grep -E "apiserver|scheduler|controller|etcd"

9. [Control Plane] Addon 확인 (CoreDNS, kube-proxy)

CoreDNS

kubectl get deploy,svc -n kube-system -l k8s-app=kube-dns
NAME                      READY   UP-TO-DATE   AVAILABLE
deployment.apps/coredns   2/2     2            2

NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)
service/kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP
# CoreDNS 설정 확인
kc describe cm -n kube-system coredns

kube-proxy

kubectl get ds -n kube-system kube-proxy
NAME         DESIRED   CURRENT   READY   UP-TO-DATE   NODE SELECTOR
kube-proxy   1         1         1       1            kubernetes.io/os=linux
# kube-proxy 설정 확인
kc describe cm -n kube-system kube-proxy | grep -E "mode:|clusterCIDR:"
# clusterCIDR: 10.244.0.0/16
# mode: ""  # 기본값: iptables

# conntrack 도구 설치 및 확인
dnf install -y conntrack-tools
conntrack -L | head

10. [Worker Nodes] 클러스터 조인

# Control Plane에서 토큰 확인
kubeadm token list

# 토큰 만료 시 재생성
kubeadm token create --print-join-command

# Worker 노드에서 실행
sudo kubeadm join 192.168.10.100:6443 \
  --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>

11. 클러스터 확인

# 노드 상태
kubectl get nodes -o wide

# 시스템 Pod 확인
kubectl get pods -n kube-system -o wide

# 클러스터 정보
kubectl cluster-info

Kubeadm 워크플로우 요약

초기화 워크플로우

업그레이드 워크플로우


참고 링크

profile
bytebliss

0개의 댓글