지난 포스팅에서 kubeadm으로 k8s 클러스터를 구성해봤다. 이제 이 클러스터에 워커 노드를 추가해보자.
워커 노드 2개를 Join해 볼건데, 각각을 join 시키는 방법은 같기 때문에 하나만 예를 들어서 봐보자.
워커노드 Join 하기 전 세팅 과정은 이전 포스팅과 유사하다. 시간 설정하고, 방화벽 해제하고, Swap 비활성화 하고, OverlayFS 켜고, hosts 설정하고, containerd, kubeadm, kubelet, kubectl 등 설치하는 것.
# Time, NTP 설정
timedatectl set-local-rtc 0
# 시스템 타임존(Timezone)을 한국(KST, UTC+9) 으로 설정 : 시스템 시간은 UTC 기준 유지, 표시만 KST로 변환
timedatectl set-timezone Asia/Seoul
# SELinux 설정 : Kubernetes는 Permissive 권장
setenforce 0
# 재부팅 시에도 Permissive 적용
sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config
# firewalld(방화벽) 끄기
systemctl disable --now firewalld
# Swap 비활성화
swapoff -a
# 재부팅 시에도 'Swap 비활성화' 적용되도록 /etc/fstab에서 swap 라인 주석 처리
sed -i '/swap/d' /etc/fstab
# 커널 모듈 로드
modprobe overlay
modprobe br_netfilter
cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
# 커널 파라미터 설정 : 네트워크 설정 - 브릿지 트래픽이 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
# 설정 적용
sysctl --system >/dev/null 2>&1
# hosts 설정
sed -i '/^127\.0\.\(1\|2\)\.1/d' /etc/hosts
cat << EOF >> /etc/hosts
192.168.10.100 k8s-ctr
192.168.10.101 k8s-w1
192.168.10.102 k8s-w2
EOF
cat /etc/hosts
# ---> CRI 설치 : containerd(runc) v2.1.5
# Docker 저장소 추가
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# containerd 설치
dnf install -y containerd.io-2.1.5-1.el10
# 기본 설정 생성 및 SystemdCgroup 활성화 (매우 중요)
containerd config default | tee /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
# systemd unit 파일 최신 상태 읽기
systemctl daemon-reload
# containerd start 와 enabled
systemctl enable --now containerd
# ---> kubeadm, kubelet 및 kubectl 설치 v1.32.11
# repo 추가
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 install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
# kubelet 활성화 (실제 기동은 kubeadm init 후에 시작됨)
systemctl enable --now kubelet
# /etc/crictl.yaml 파일 작성
cat << EOF > /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
EOF
워커노드 Join 하기
위 과정까지 진행했으면, 실제로 Join하는 과정은 yaml 파일 하나 만들어서 kubeadm 한번 실행시키면 된다.
NODEIP=$(ip -4 addr show enp0s9 | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
echo $NODEIP
cat << EOF > kubeadm-join.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: JoinConfiguration
discovery:
bootstrapToken:
token: "123456.1234567890123456"
apiServerEndpoint: "192.168.10.100:6443"
unsafeSkipCAVerification: true
nodeRegistration:
criSocket: "unix:///run/containerd/containerd.sock"
kubeletExtraArgs:
- name: node-ip
value: "$NODEIP"
EOF
cat kubeadm-join.yaml
# join
kubeadm join --config="kubeadm-join.yaml"
위와 같이 진행 후 다시 컨트롤 플레인으로 접근해서 노드 상태를 살펴보면 워커노드가 제대로 추가됐음을 알 수 있다.
# at 컨트롤 플레인
$ kubectl get node -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-ctr Ready control-plane 6h58m v1.32.11 192.168.10.100 <none> Rocky Linux 10.0 (Red Quartz) 6.12.0-55.39.1.el10_0.aarch64 containerd://2.1.5
k8s-w1 Ready <none> 2m29s v1.32.11 192.168.10.101 <none> Rocky Linux 10.0 (Red Quartz) 6.12.0-55.39.1.el10_0.aarch64 containerd://2.1.5
k8s-w2 Ready <none> 2m29s v1.32.11 192.168.10.102 <none> Rocky Linux 10.0 (Red Quartz) 6.12.0-55.39.1.el10_0.aarch64 containerd://2.1.5
프로메테우스 설치
자 이제는 컨트롤 플레인에 프로메테우스 설치해서 리소스 모니터링을 할 수 있도록 해보자.
프로메테우스 설치는 딱히 별거 없다. 그냥 명령어 적절히 해서 설치하면 바로 된다.
helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/
helm upgrade --install metrics-server metrics-server/metrics-server --set 'args[0]=--kubelet-insecure-tls' -n kube-system
# 확인
kubectl top node
kubectl top pod -A --sort-by='cpu'
kubectl top pod -A --sort-by='memory'
# repo 추가
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
# 파라미터 파일 생성
cat <<EOT > monitor-values.yaml
prometheus:
prometheusSpec:
scrapeInterval: "20s"
evaluationInterval: "20s"
externalLabels:
cluster: "myk8s-cluster"
service:
type: NodePort
nodePort: 30001
grafana:
defaultDashboardsTimezone: Asia/Seoul
adminPassword: prom-operator
service:
type: NodePort
nodePort: 30002
alertmanager:
enabled: true
defaultRules:
create: true
kubeProxy:
enabled: false
prometheus-windows-exporter:
prometheus:
monitor:
enabled: false
EOT
cat monitor-values.yaml
# 배포
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 80.13.3 -f monitor-values.yaml --create-namespace --namespace monitoring
# 확인
helm list -n monitoring
kubectl get pod,svc,ingress,pvc -n monitoring
kubectl get prometheus,servicemonitors,alertmanagers -n monitoring
kubectl get crd | grep monitoring
helm 통해서 설치하면 된다.


앱 배포하기
앱 배포하는 것도 간단하다. kubectl apply 사용해서 하면 된다.
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: webpod
spec:
replicas: 2
selector:
matchLabels:
app: webpod
template:
metadata:
labels:
app: webpod
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- sample-app
topologyKey: "kubernetes.io/hostname"
containers:
- name: webpod
image: traefik/whoami
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: webpod
labels:
app: webpod
spec:
selector:
app: webpod
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
EOF
이렇게 하면 아래와 같이 pod가 생성됨을 확인할 수 있다
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
webpod-697b545f57-4cgrg 1/1 Running 0 87s
webpod-697b545f57-nr5xs 1/1 Running 0 87s
# --> 다른 NAMESPACE에 있는거 조회하지 않도록 주의
$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-7498b9bb4c-dctts 1/1 Running 1 (2m13s ago) 26m
calico-node-5lxhq 1/1 Running 0 16m
calico-node-h8nzl 1/1 Running 0 19m
calico-node-jg5fc 1/1 Running 0 26m
coredns-668d6bf9bc-hkfnb 1/1 Running 0 33m
coredns-668d6bf9bc-zbnjl 1/1 Running 0 33m
etcd-k8s-ctr 1/1 Running 0 2m7s
kube-apiserver-k8s-ctr 1/1 Running 0 34m
kube-controller-manager-k8s-ctr 1/1 Running 0 2m7s
kube-proxy-kstr5 1/1 Running 0 19m
kube-proxy-w9xld 1/1 Running 0 16m
kube-proxy-zxlxc 1/1 Running 0 33m
kube-scheduler-k8s-ctr 1/1 Running 0 2m7s
metrics-server-5dd7b49d79-2bf5n 1/1 Running 0 14m
이제 됐다. 지난번 포스팅에 이어서 kubeadm으로 k8s 구성 후 노드 join 시키고 앱 배포하는 것까지 해봤다.
'Kubernetes' 카테고리의 다른 글
| kubeadm으로 k8s 구성하기 (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 |




