지난 포스팅에서 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
Posted by 빛나유
,