k8s 구성을 kubeadm을 통해서 해보자. 지지난 주에는 k8s 구성을 좀 빡센 방법으로 했다면. 이번에는 조금 순한 맛이랄까.

 

언제나 그렇듯. 컨트롤 플레인 구성하는 것이 가장 중요하다. 컨트롤 플레인 구성하는 부분부터 살펴보자.

 

컨트롤 플레인 구성전 세팅 점검 사항

본격적인 컨트롤 플레인 구성에 앞서 몇 가지 세팅을 진행하려고 한다. 

1. 타임 세팅

# timedatectl 정보 확인
timedatectl status # RTC in local TZ: yes -> Warning:...
timedatectl set-local-rtc 0
timedatectl status
timedatectl set-timezone Asia/Seoul

# systemd가 시간 동기화 서비스(chronyd) 를 관리하도록 설정되어 있음 : ntpd 대신 chrony 사용 (Rocky 9/10 기본)
timedatectl status
timedatectl set-ntp true # System clock synchronized: yes -> NTP service: active

chronyc sources -v
chronyc tracking

 

2. SELinux 설정, firewalld(방화벽) 끄기

k8s에서는 SELinux는 Permissive로 세팅하는 것을 권장한다.

setenforce 0
getenforce
sestatus      # Current mode:                   permissive

# 재부팅 시에도 Permissive 적용
cat /etc/selinux/config | grep ^SELINUX
sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config
cat /etc/selinux/config | grep ^SELINUX

# firewalld(방화벽) 끄기
systemctl status firewalld
systemctl disable --now firewalld
systemctl status firewalld

 

3. (중요) Swap 비활성화

이게 좀 특이할 수도 있다. k8s 구성 시 swap 비활성화는 k8s의 사상에 따라 매우 중요하다. 

k8s에서 노드를 통째로 관리하고자 한다. swap 영역이 활성화되어 있으면 여러 개의 노드가 실행되고 있을 때 swap을 쓰면서 계속 버티고 버텨서 결국에는 전체의 노드의 성능을 낮추게 된다는 것이다. k8s 입장에서 리소스 관리 차원에서 메모리가 부족하면 Pod를 종료하고 다른 노드에서 시작하면 그만이다. 그런데 swap 영역이 활성화되어 있으면 메모리 부족 시에 그 판단을 하지 못하고 느린 상태로 계속 실행되고 있게 된다.

# Swap 비활성화
swapoff -a

# 재부팅 시에도 'Swap 비활성화' 적용되도록 /etc/fstab에서 swap 라인 삭제
cat /etc/fstab | grep swap
sed -i '/swap/d' /etc/fstab
cat /etc/fstab | grep swap

 

4. OverlayFS 모듈 활성화

OverlayFS 모듈 활성화도 해야 한다. OverlayFS란 도커 이미지의 사이즈를 절약하기 위해 사용한다. 보통 Dockerfile 작성할 때 한 줄 한 줄이 모두 레이어 단위로 생성되는데, OverlayFS는 이것을 하나로 묶어준다. 가령 아래와 같이 우분투 이미지를 하나 사용하는 컨테이너1, 2, 3이 있다고 해보자. 

# 같은 Base Image 사용하는 컨테이너 100개
ubuntu:20.04 (100MB) ← 이건 한번만 저장
  ↓
Container 1 (변경사항만 1MB)
Container 2 (변경사항만 2MB)
Container 3 (변경사항만 1MB)
...

 OverlayFS가 없으면 100MB짜리 이미지가 3개 사용되지만, OverlayFS가 있으면 100MB에 각 컨테이너 별 변동 사항(1+2+1MB) 만 사용되면 된다. 

# 커널 모듈 로드
modprobe overlay
modprobe br_netfilter
lsmod | grep -iE 'overlay|br_netfilter'

# 
cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
tree /etc/modules-load.d/

# 커널 파라미터 설정 : 네트워크 설정 - 브릿지 트래픽이 iptables를 거치도록 함
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
tree /etc/sysctl.d/

# 설정 적용
sysctl --system

# 적용 확인
sysctl net.bridge.bridge-nf-call-iptables
sysctl net.ipv4.ip_forward

 

5. CRI 설치하기

파드가 노드에서 실행될 수 있도록 클러스터의 각 노드에 컨테이너 런타임을 설치해야 한다. 이 때 설치해야 하는 것이 containerd이다. 

dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf repolist
dnf makecache

# 설치 가능한 모든 containerd.io 버전 확인
dnf list --showduplicates containerd.io

# containerd 설치
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
cat /etc/containerd/config.toml
tree /usr/lib/systemd/system | grep containerd
cat /usr/lib/systemd/system/containerd.service

# 기본 설정 생성 및 SystemdCgroup 활성화 (매우 중요)
containerd config default | tee /etc/containerd/config.toml

cat /etc/containerd/config.toml | grep -i systemdcgroup
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
cat /etc/containerd/config.toml | grep -i systemdcgroup

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

# containerd start 와 enabled
systemctl enable --now containerd

# 
systemctl status containerd --no-pager
journalctl -u containerd.service --no-pager
pstree -alnp
systemd-cgls --no-pager

# containerd의 유닉스 도메인 소켓 확인 : kubelet에서 사용 , containerd client 3종(ctr, nerdctr, crictl)도 사용
containerd config dump | grep -n containerd.sock
ls -l /run/containerd/containerd.sock
ss -xl | grep containerd
ss -xnp | grep containerd

# 플러그인 확인
ctr --address /run/containerd/containerd.sock version

 

6. kubeadm, kubelet 및 kubectl 설치

이제 kubeadm, kubelet, kubectl 삼총사 설치다. 

dnf repolist
tree /etc/yum.repos.d/
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 makecache

## 버전 정보 미지정 시, 제공 가능 최신 버전 설치됨.
dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetes


# kubelet 활성화 (실제 기동은 kubeadm init 후에 시작됨)
systemctl enable --now kubelet
ps -ef |grep kubelet

# 설치 파일들 확인
which kubeadm && kubeadm version -o yaml
which kubectl && kubectl version --client=true
which kubelet && kubelet --version


# cri-tools
which crictl && crictl version

# /etc/crictl.yaml 파일 작성
cat << EOF > /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
EOF

#
systemctl is-active kubelet
systemctl status kubelet --no-pager
journalctl -u kubelet --no-pager
tree /usr/lib/systemd/system | grep kubelet -A1

 

컨트롤 플레인 구성하기

이제 컨트롤 플레인을 본격적으로 구성해보자. 시작은 kubeadm init 를 통해서 할 수 있다. init을 통해 마스터 노드가 설치되고(컨트롤 플레인), API 서버, 스케줄러, 컨트롤러 매니저 등 핵심 구성 요소가 컨테이너로 실행된다. 그리고 결과적으로 워커 노드들이 join할 수 있는 상태를 만들어 준다. 

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
cat kubeadm-init.yaml

# (옵션) 컨테이너 이미지 미리 다운로드 : 특히 업그레이드 작업 시, 작업 시간 단축을 위해서 수행할 것
kubeadm config images pull

# k8s controlplane 초기화 설정 수행
kubeadm init --config="kubeadm-init.yaml"

kubeadm init을 통해서 아래와 같이 컨테이너 이미지 들이 받아지고, 실행된다.

$ crictl images
IMAGE                                     TAG                 IMAGE ID            SIZE
registry.k8s.io/coredns/coredns           v1.11.3             c69fa2e9cbf5f       18.6MB
registry.k8s.io/etcd                      3.5.24-0            8cb12dd0c3e42       23.7MB
registry.k8s.io/kube-apiserver            v1.32.11            7757c58248a29       29.1MB
registry.k8s.io/kube-controller-manager   v1.32.11            0175d0a8243db       26.7MB
registry.k8s.io/kube-proxy                v1.32.11            4d8fb2dc57519       31.2MB
registry.k8s.io/kube-scheduler            v1.32.11            23d6a1fb92fda       21.1MB
registry.k8s.io/pause                     3.10                873ed75102791       320kB

$ crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                      ATTEMPT             POD ID              POD                               NAMESPACE
292892b19d9f9       4d8fb2dc57519       21 seconds ago      Running             kube-proxy                0                   89e451c3bf121       kube-proxy-zb866                  kube-system
f50ef12c64408       0175d0a8243db       43 seconds ago      Running             kube-controller-manager   0                   caf30030971b9       kube-controller-manager-k8s-ctr   kube-system
72740e8e7377e       8cb12dd0c3e42       43 seconds ago      Running             etcd                      0                   8d389a0ae1ea1       etcd-k8s-ctr                      kube-system
d3856ede49213       23d6a1fb92fda       43 seconds ago      Running             kube-scheduler            0                   f276d7991ed95       kube-scheduler-k8s-ctr            kube-system
02519515fe4e8       7757c58248a29       43 seconds ago      Running             kube-apiserver            0                   2351d78edf708       kube-apiserver-k8s-ctr            kube-system

이제 클러스터의 상태와 노드의 상태를 확인해보면 아래와 같다.

$ kubectl cluster-info
Kubernetes control plane is running at https://192.168.10.100:6443
CoreDNS is running at https://192.168.10.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

$ kubectl get node -owide
NAME      STATUS     ROLES           AGE    VERSION    INTERNAL-IP      EXTERNAL-IP   OS-IMAGE                        KERNEL-VERSION                 CONTAINER-RUNTIME
k8s-ctr   NotReady   control-plane   2m7s   v1.32.11   192.168.10.100   <none>        Rocky Linux 10.0 (Red Quartz)   6.12.0-55.39.1.el10_0.x86_64   containerd://2.1.5

 

이제 작업의 편리성을 위한 alias 설정이나 kubecolor, kubectx, kubens, kube-ps, helm, k9s 등을 설치해보자.

echo "sudo su -" >> /home/vagrant/.bashrc

# Source the completion
source <(kubectl completion bash)
source <(kubeadm completion bash)
echo 'source <(kubectl completion bash)' >> /etc/profile
echo 'source <(kubeadm completion bash)' >> /etc/profile
# kubectl get <tab 2번>

# Alias kubectl to k
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
k get node

# kubecolor 설치 : https://kubecolor.github.io/setup/install/
dnf install -y 'dnf-command(config-manager)'
dnf config-manager --add-repo https://kubecolor.github.io/packages/rpm/kubecolor.repo
dnf repolist
dnf install -y kubecolor
kubecolor get node

alias kc=kubecolor
echo 'alias kc=kubecolor' >> /etc/profile
kc get node
kc describe node

# Install 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


# Install Kubeps & Setting 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

kubectl config rename-context "kubernetes-admin@kubernetes" "HomeLab"
kubens default

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

# k9s 설치 : https://github.com/derailed/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
ls -al k9s
chown root:root k9s
mv k9s /usr/local/bin/
chmod +x /usr/local/bin/k9s
# k9s



# ---> [k8s-ctr] Flannel CNI 설치 v0.27.3
# 현재 k8s 클러스터에 파드 전체 CIDR 확인
kc describe pod -n kube-system kube-controller-manager-k8s-ctr


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



# Deploying Flannel with Helm
# https://github.com/flannel-io/flannel/blob/master/Documentation/configuration.md
helm repo add flannel https://flannel-io.github.io/flannel
helm repo update

kubectl create namespace kube-flannel
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"  
  backend: "vxlan"
EOF

helm install flannel flannel/flannel --namespace kube-flannel --version 0.27.3 -f flannel.yaml

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

# flannel cni 바이너리 설치 확인
ls -l /opt/cni/bin/

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

# cni 설치 후 아래 상태(conditions) 정상 확인
crictl info | jq

여기까지 실행하면 coredns 가 정상적으로 실행된다.

$ crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                      ATTEMPT             POD ID              POD                                        NAMESPACE
2f0ab103a3d29       5e785d005ccc1       20 minutes ago      Running             calico-kube-controllers   0                   fddf38adda54d       calico-kube-controllers-7498b9bb4c-4wrgb   kube-system
c8f835582e200       c69fa2e9cbf5f       20 minutes ago      Running             coredns                   0                   bc064c8bf7f8a       coredns-668d6bf9bc-bv5pj                   kube-system
e50e390260ee4       c69fa2e9cbf5f       21 minutes ago      Running             coredns                   0                   4581742a31a86       coredns-668d6bf9bc-mhxr5                   kube-system
6e9bfdc3bef00       08616d26b8e74       21 minutes ago      Running             calico-node               0                   5253a657ddf86       calico-node-6kjzd                          kube-system
5b2f7851119ca       4d8fb2dc57519       33 minutes ago      Running             kube-proxy                0                   9fa051aa68bb9       kube-proxy-krvgr                           kube-system
b9d4fb053a535       23d6a1fb92fda       33 minutes ago      Running             kube-scheduler            0                   a1d3adc9deccb       kube-scheduler-k8s-ctr                     kube-system
e7ec4646e8643       8cb12dd0c3e42       33 minutes ago      Running             etcd                      0                   5344400bd942d       etcd-k8s-ctr                               kube-system
14c967a56d607       0175d0a8243db       33 minutes ago      Running             kube-controller-manager   0                   7983ea6661deb       kube-controller-manager-k8s-ctr            kube-system
aafaa8dbd170b       7757c58248a29       33 minutes ago      Running             kube-apiserver            0                   750ff351df496       kube-apiserver-k8s-ctr                     kube-system

 

사실, 바로 실행되진 않았고, coredns가 containercreating 상태로 뜨면서 계속 Running 상태가 안됐었다. 

$ kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

 

위와 같이 실행하니 Running 상태로 떴다. coredns는 반드시 네트워크 플러그인이 적용되어야 실행되는데 Flannel이 잘 설정이 안됐는지 에러가 났다. Calico를 통해서 네트워크 플러그인 적용하니 해결돼었다. (Flannel은 다음에 좀 더 보는걸로...)

 

이제 워커 노드를 Join할 준비가 됐다.이것부터는 다음 포스팅에서 작성해보련다.

'Kubernetes' 카테고리의 다른 글

워커 노드 Join 하기  (0) 2026.01.25
Ansible: 사용해보기  (0) 2026.01.18
Ansible: 에이전트 없이 완성하는 자동화  (0) 2026.01.18
On-Premise K8s Hands-on Study 1주차  (1) 2026.01.11
Posted by 빛나유
,