앞선 글에서는 Kubernetes의 기본 개념과 Docker와 Kubernetes의 차이, Pod와 Deployment의 역할에 대해 알아보았습니다. 이번에는 실제 시스템 엔지니어 실습 환경을 구축해 보겠습니다.
이번 과정의 목표는 Rocky Linux 서버 여러 대를 이용하여 Kubernetes 클러스터를 구성하는 것입니다. 하나의 서버는 Kubernetes 클러스터를 관리하는 Control Plane으로 사용하고, 나머지 서버는 실제 애플리케이션이 실행되는 Worker Node로 구성합니다.
이번 실습을 완료하면 다음과 같은 구조의 Kubernetes 환경을 만들 수 있습니다.
Kubernetes Cluster
│
│
┌────────┴────────┐
│ Control Plane │
│ 192.168.10.10 │
└────────┬────────┘
│
┌─────────────┴─────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Worker Node1 │ │ Worker Node2 │
│192.168.10.11 │ │192.168.10.12 │
└──────────────┘ └──────────────┘
│ │
▼ ▼
Pod Pod
Pod Pod
실습 환경에서는 VMware, Hyper-V, Proxmox 등의 가상화 환경을 사용할 수 있습니다. 각 서버는 Rocky Linux 가상 머신으로 구성합니다.
먼저 Kubernetes 클러스터를 구성할 서버를 준비합니다.
권장 구성은 다음과 같습니다.
| 서버 | 역할 | IP 주소 | CPU | 메모리 |
|---|---|---|---|---|
| k8s-master | Control Plane | 192.168.10.10 | 2 Core 이상 | 4GB 이상 |
| k8s-worker1 | Worker Node | 192.168.10.11 | 2 Core 이상 | 2GB 이상 |
| k8s-worker2 | Worker Node | 192.168.10.12 | 2 Core 이상 | 2GB 이상 |
실습 환경에서는 최소 1개의 Control Plane과 1개의 Worker Node만으로도 시작할 수 있습니다.
Control Plane
│
│ Kubernetes Cluster Network
│
▼
Worker Node
모든 서버는 서로 통신할 수 있어야 합니다.
먼저 각 서버에서 IP 주소를 확인합니다.
ip addr
기본 게이트웨이도 확인합니다.
ip route
서버 간 통신 여부를 확인합니다.
Control Plane에서 Worker Node로 Ping을 보냅니다.
ping -c 3 192.168.10.11
Worker Node에서도 Control Plane으로 통신을 확인합니다.
ping -c 3 192.168.10.10
Kubernetes 클러스터에서는 노드 간 통신이 매우 중요합니다. 따라서 방화벽, DNS, 라우팅 문제를 설치 전에 먼저 해결하는 것이 좋습니다.
각 서버를 쉽게 구분하기 위해 Hostname을 설정합니다.
Control Plane 서버에서 실행합니다.
sudo hostnamectl set-hostname k8s-master
Worker Node 1입니다.
sudo hostnamectl set-hostname k8s-worker1
Worker Node 2입니다.
sudo hostnamectl set-hostname k8s-worker2
설정을 확인합니다.
hostnamectl
재로그인하거나 다음 명령어를 사용하여 확인합니다.
hostname
실습 환경에서는 각 서버의 이름을 IP 주소와 연결하면 관리가 편리합니다.
모든 노드에서 /etc/hosts 파일을 수정합니다.
sudo vi /etc/hosts
다음 내용을 추가합니다.
192.168.10.10 k8s-master
192.168.10.11 k8s-worker1
192.168.10.12 k8s-worker2
이제 서버 이름으로 통신할 수 있습니다.
ping -c 3 k8s-master
ping -c 3 k8s-worker1
실제 기업 환경에서는 /etc/hosts보다 DNS를 사용하는 것이 일반적입니다. 하지만 학습 및 소규모 실습 환경에서는 /etc/hosts 설정이 간단하고 편리합니다.
이제 모든 Control Plane과 Worker Node에서 공통으로 설정해야 할 작업을 진행합니다.
먼저 시스템을 최신 상태로 업데이트합니다.
sudo dnf update -y
필요한 기본 패키지를 설치합니다.
sudo dnf install -y \
curl \
wget \
vim \
net-tools \
conntrack-tools
설치가 완료되면 시스템을 재부팅합니다.
sudo reboot
Kubernetes를 구성하기 전에 중요한 설정 중 하나가 Swap 비활성화입니다.
현재 Swap 상태를 확인합니다.
free -h
또는 다음과 같이 확인할 수 있습니다.
swapon --show
현재 Swap을 비활성화합니다.
sudo swapoff -a
하지만 서버를 재부팅하면 다시 활성화될 수 있으므로 /etc/fstab도 수정해야 합니다.
sudo vi /etc/fstab
Swap 항목을 찾아 주석 처리합니다.
예를 들어 다음과 같은 항목이 있다면,
/dev/mapper/rl-swap none swap defaults 0 0
앞에 #을 추가합니다.
#/dev/mapper/rl-swap none swap defaults 0 0
다시 확인합니다.
swapon --show
출력이 없다면 Swap이 비활성화된 것입니다.
Rocky Linux는 기본적으로 SELinux가 활성화되어 있습니다.
현재 상태를 확인합니다.
getenforce
실습 환경에서는 다음과 같이 Permissive 모드로 설정할 수 있습니다.
sudo setenforce 0
재부팅 후에도 적용되도록 설정합니다.
sudo vi /etc/selinux/config
다음과 같이 변경합니다.
SELINUX=permissive
설정을 확인합니다.
getenforce
출력은 다음과 같습니다.
Permissive
중요한 점은 실제 운영 환경에서 단순히 보안 문제를 해결하기 위해 SELinux를 무조건 비활성화하는 것은 권장되지 않는다는 것입니다. 실습에서는 설치와 구성 과정을 단순화하기 위해 Permissive 설정을 사용할 수 있지만, 운영 환경에서는 보안 정책을 충분히 검토해야 합니다.
Kubernetes는 여러 포트를 사용합니다.
실습 환경에서는 방화벽을 일시적으로 비활성화하는 방법이 가장 간단합니다.
sudo systemctl disable --now firewalld
상태를 확인합니다.
sudo systemctl status firewalld
다만 실제 운영 환경에서는 방화벽을 끄는 것이 아니라 Kubernetes에 필요한 포트만 허용해야 합니다.
이번 과정은 Kubernetes 구조와 구축 방법을 학습하기 위한 실습 환경을 기준으로 설명합니다.
Kubernetes 네트워크를 정상적으로 사용하기 위해 필요한 Kernel 모듈을 설정합니다.
먼저 모듈 설정 파일을 생성합니다.
sudo vi /etc/modules-load.d/k8s.conf
다음 내용을 입력합니다.
overlay
br_netfilter
모듈을 즉시 적용합니다.
sudo modprobe overlay
sudo modprobe br_netfilter
정상적으로 로드되었는지 확인합니다.
lsmod | grep overlay
lsmod | grep br_netfilter
Kubernetes와 컨테이너 네트워크가 정상적으로 동작하도록 Kernel 파라미터를 설정합니다.
설정 파일을 생성합니다.
sudo vi /etc/sysctl.d/k8s.conf
다음 내용을 입력합니다.
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
설정을 적용합니다.
sudo sysctl --system
확인합니다.
sysctl net.ipv4.ip_forward
다음과 같이 출력되면 정상입니다.
net.ipv4.ip_forward = 1
Kubernetes는 컨테이너를 실행하기 위한 Container Runtime이 필요합니다.
과거에는 Docker Engine을 많이 사용했지만 Kubernetes 환경에서는 현재 containerd를 사용하는 구성이 일반적입니다.
먼저 Docker 저장소를 추가합니다.
sudo dnf config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
containerd를 설치합니다.
sudo dnf install -y containerd.io
기본 설정 파일을 생성합니다.
sudo mkdir -p /etc/containerd
sudo containerd config default | \
sudo tee /etc/containerd/config.toml
config.toml 파일을 수정합니다.
sudo vi /etc/containerd/config.toml
다음 설정을 찾습니다.
SystemdCgroup = false
다음과 같이 변경합니다.
SystemdCgroup = true
containerd를 시작합니다.
sudo systemctl enable --now containerd
상태를 확인합니다.
sudo systemctl status containerd
정상적으로 실행되면 다음과 같이 표시됩니다.
active (running)
이제 Kubernetes 패키지를 설치할 준비를 합니다.
모든 노드에서 Kubernetes 저장소를 설정합니다.
현재 Kubernetes는 패키지 저장소 체계가 변경될 수 있으므로 사용하려는 Kubernetes 버전에 맞는 공식 저장소를 확인하여 설정하는 것이 중요합니다.
예를 들어 pkgs.k8s.io 기반 저장소를 사용할 수 있습니다.
sudo cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.34/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.34/rpm/repodata/repomd.xml.key
EOF
이후 패키지 목록을 확인합니다.
sudo dnf makecache
Kubernetes를 구축하기 위해 다음 세 가지 핵심 프로그램을 설치합니다.
kubeadm
│
└── Kubernetes Cluster 구축
kubelet
│
└── Node에서 Pod 관리
kubectl
│
└── Kubernetes Cluster 관리
설치합니다.
sudo dnf install -y \
kubelet \
kubeadm \
kubectl
자동 업데이트로 인한 버전 변경을 방지하기 위해 버전을 고정할 수 있습니다.
설치 후 kubelet 서비스를 활성화합니다.
sudo systemctl enable kubelet
이 시점에서 kubelet이 정상적으로 실행되지 않을 수 있습니다. 아직 Kubernetes 클러스터에 연결되지 않았기 때문에 초기 단계에서는 오류처럼 보이는 상태가 발생할 수 있습니다.
버전을 확인합니다.
kubeadm version
kubectl version --client
이제 Control Plane 서버에서 Kubernetes 클러스터를 초기화합니다.
반드시 k8s-master에서 실행합니다.
예제에서는 다음 네트워크를 사용합니다.
Control Plane
192.168.10.10
Pod Network
10.244.0.0/16
다음 명령어를 실행합니다.
sudo kubeadm init \
--apiserver-advertise-address=192.168.10.10 \
--pod-network-cidr=10.244.0.0/16
명령어가 실행되면 다음과 같은 작업이 진행됩니다.
kubeadm init
│
├── Kubernetes API Server 구성
│
├── etcd 구성
│
├── Controller Manager 구성
│
├── Scheduler 구성
│
└── Control Plane 초기화
설치가 성공하면 마지막 부분에 Worker Node를 클러스터에 연결하기 위한 명령어가 표시됩니다.
예시는 다음과 같습니다.
kubeadm join 192.168.10.10:6443 \
--token xxxxxxxxx \
--discovery-token-ca-cert-hash sha256:xxxxxxxx
이 명령어는 반드시 별도로 복사해 두어야 합니다.
Worker Node에서 이 명령어를 실행하면 Kubernetes 클러스터에 참여할 수 있습니다.
Control Plane 초기화가 완료되면 일반 사용자 계정에서 kubectl을 사용할 수 있도록 설정합니다.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf \
$HOME/.kube/config
현재 사용자에게 권한을 설정합니다.
sudo chown \
$(id -u):$(id -g) \
$HOME/.kube/config
이제 클러스터 상태를 확인합니다.
kubectl get nodes
초기 상태에서는 다음과 같이 표시될 수 있습니다.
NAME STATUS ROLES AGE
k8s-master NotReady control-plane 5m
이는 아직 Pod Network 플러그인이 설치되지 않았기 때문입니다.
Kubernetes에서 Pod 간 네트워크 통신을 위해 CNI(Container Network Interface) 플러그인이 필요합니다.
이번 실습에서는 앞에서 10.244.0.0/16 네트워크를 지정했으므로 Flannel과 같은 CNI 구성을 사용할 수 있습니다.
구조는 다음과 같습니다.
Worker Node 1
│
├── Pod A
│
└── Pod B
│
│ CNI Network
│
Worker Node 2
│
├── Pod C
│
└── Pod D
CNI를 설치한 후 상태를 확인합니다.
kubectl get pods -A
Control Plane의 시스템 Pod가 정상적으로 실행되어야 합니다.
NAMESPACE NAME STATUS
kube-system coredns-xxxxx Running
kube-system kube-apiserver-k8s-master Running
kube-system kube-controller-manager Running
kube-system kube-scheduler-k8s-master Running
Node 상태도 확인합니다.
kubectl get nodes
정상적으로 구성되면 다음과 같이 표시됩니다.
NAME STATUS ROLES AGE
k8s-master Ready control-plane 10m
이제 Worker Node를 클러스터에 연결합니다.
k8s-worker1 서버에 접속합니다.
Control Plane 초기화 과정에서 확인한 kubeadm join 명령어를 실행합니다.
sudo kubeadm join 192.168.10.10:6443 \
--token xxxxxxxxx \
--discovery-token-ca-cert-hash sha256:xxxxxxxx
Worker Node 2에서도 동일하게 실행합니다.
sudo kubeadm join 192.168.10.10:6443 \
--token xxxxxxxxx \
--discovery-token-ca-cert-hash sha256:xxxxxxxx
Control Plane 서버로 돌아와 노드 상태를 확인합니다.
kubectl get nodes
정상적인 결과는 다음과 같습니다.
NAME STATUS ROLES AGE
k8s-master Ready control-plane 30m
k8s-worker1 Ready <none> 5m
k8s-worker2 Ready <none> 3m
이제 기본적인 Kubernetes 클러스터가 완성되었습니다.
시스템 엔지니어는 설치가 끝난 후 반드시 각 구성 요소의 상태를 확인해야 합니다.
먼저 노드 상태입니다.
kubectl get nodes -o wide
Pod 상태를 확인합니다.
kubectl get pods -A
클러스터 정보를 확인합니다.
kubectl cluster-info
노드 상세 정보를 확인합니다.
kubectl describe node k8s-worker1
이 명령어를 통해 다음과 같은 정보를 확인할 수 있습니다.
CPU Capacity
Memory Capacity
Allocated Resources
Pod Capacity
Node Conditions
Container Runtime
Kubernetes Version
클러스터가 정상적으로 구성되었는지 확인하기 위해 Nginx 애플리케이션을 배포해 보겠습니다.
먼저 Deployment를 생성합니다.
kubectl create deployment nginx \
--image=nginx
Pod 상태를 확인합니다.
kubectl get pods
예상 결과입니다.
NAME READY STATUS RESTARTS
nginx-xxxxxxxxxx-xxxxx 1/1 Running 0
Deployment 상태를 확인합니다.
kubectl get deployments
Pod가 어떤 Node에서 실행되고 있는지도 확인할 수 있습니다.
kubectl get pods -o wide
예상 구조입니다.
Kubernetes Cluster
│
▼
Nginx Deployment
│
▼
Nginx Pod
│
▼
Worker Node 1
Pod 개수를 3개로 늘려 보겠습니다.
kubectl scale deployment nginx \
--replicas=3
상태를 확인합니다.
kubectl get pods -o wide
여러 Worker Node에 Pod가 배치될 수 있습니다.
Worker Node 1
├── Nginx Pod
└── Nginx Pod
Worker Node 2
└── Nginx Pod
Kubernetes 구축 과정에서는 여러 문제가 발생할 수 있습니다.
먼저 CNI 상태를 확인합니다.
kubectl get pods -n kube-system
다음과 같은 상태라면 네트워크 문제가 있을 수 있습니다.
CrashLoopBackOff
Pending
ContainerCreating
CNI 설정과 Pod Network CIDR이 서로 일치하는지 확인해야 합니다.
Control Plane의 API Server 포트 연결을 확인합니다.
nc -zv 192.168.10.10 6443
네트워크 상태도 확인합니다.
ping -c 3 192.168.10.10
필요한 경우 kubelet 로그를 확인합니다.
sudo journalctl -u kubelet -f
Pod 상태를 확인합니다.
kubectl get pods
상세 정보를 확인합니다.
kubectl describe pod Pod이름
이벤트와 오류 메시지를 확인할 수 있습니다.
ImagePullBackOff
CrashLoopBackOff
Pending
ErrImagePull
컨테이너 로그도 확인합니다.
kubectl logs Pod이름
기본적인 클러스터를 구축했다면 다음 항목을 확인해야 합니다.
[ ] 모든 Node가 Ready 상태인가?
[ ] Control Plane이 정상 동작하는가?
[ ] kubelet 서비스가 실행 중인가?
[ ] containerd가 실행 중인가?
[ ] CNI 네트워크가 정상인가?
[ ] CoreDNS가 정상인가?
[ ] Pod가 Worker Node에 정상적으로 배치되는가?
[ ] Pod 간 통신이 가능한가?
[ ] 외부에서 Service에 접근할 수 있는가?
[ ] etcd 백업 계획이 있는가?
[ ] Kubernetes 인증서 관리 계획이 있는가?
[ ] 모니터링 시스템이 구성되어 있는가?
[ ] 로그 수집 시스템이 구성되어 있는가?
실제 운영 환경에서는 단순히 Kubernetes를 설치하는 것만으로 충분하지 않습니다. 고가용성 Control Plane, 인증서 관리, etcd 백업, 네트워크 정책, RBAC 권한 관리, Ingress, 모니터링, 로그 관리까지 함께 고려해야 합니다.
이번 글에서는 Rocky Linux 환경에서 Kubernetes 클러스터를 구축하는 기본적인 실습 과정을 살펴보았습니다.
전체 과정은 다음과 같이 정리할 수 있습니다.
Rocky Linux 설치
│
▼
Hostname 및 Network 설정
│
▼
Swap 비활성화
│
▼
SELinux 및 방화벽 설정
│
▼
Kernel Module 설정
│
▼
containerd 설치
│
▼
kubeadm / kubelet / kubectl 설치
│
▼
Control Plane 초기화
│
▼
CNI Network 설치
│
▼
Worker Node Join
│
▼
Cluster 상태 확인
│
▼
첫 번째 Pod와 Deployment 배포
가장 중요한 것은 Kubernetes를 단순한 명령어 모음으로 학습하지 않는 것입니다. 시스템 엔지니어의 관점에서는 각 구성 요소가 어떤 역할을 수행하는지 이해해야 합니다.
kubeadm
│
└── 클러스터 구축
kubelet
│
└── Node와 Pod 관리
kubectl
│
└── Kubernetes 관리
containerd
│
└── 컨테이너 실행
Control Plane
│
└── 클러스터 전체 관리
Worker Node
│
└── 실제 애플리케이션 실행
CNI
│
└── Pod 네트워크 구성