Kubernetes 시작하기
Sep 07, 2024
컨테이너를 오케스트레이션하는 일종의 운영체제
쿠버네티스는 ‘조타수(숙련된 선원)’라는 뜻을 갖는 그리스어다.
구글이 내부에서 사용하던 컨테이너 관리 시스템에서 파생되었으며 ,2014년 오픈소스로 제공하게 된다. 현재는 CNCF(Cloud Native Computing Foundation)에서 관리하고 있다. 쿠버네티스(Kubernetes)는 컨테이너 오케스트레이션 도구로 컨테이너화된 애플리케이션의 배포, 확장 및 운영을 자동화하며, Go lang으로 작성되었다.
- 도커 클러스터 관리에 필요한 기능적 요건
- 물리적인 호스트의 자원부족을 해결하는 방법으로 여러 서버를 병렬 확장하여 클러스터로 구성
- 새로운 서버, 컨테이너 추가에 대한 발견
- 컨테이너 스케줄링 기능
- 서버 다운시 고가용성 보장
- 주요 개념
- 클러스터(Cluster)
- 노드(Node)
- control plane(master node)
- 워커 노드들의 상태 관리/제어
- 하나 또는 하나 이상으로 구성 가능
- worker node
- 파드(Pod)
- pod당 하나의 IP 할당
- 스케줄링 최소 단위
- 특정 네임스페이스에 launch
- 네임스페이스(Namespace)
- 볼륨(Volume)
- API version
컨테이너화된 애플리케이션을 실행하기 위한 물리적 또는 가상 컴퓨팅 리소스(노드)의 모음으로, 일반적으로 Control plane(마스터 노드)와 Data plane(워커 노드)로 구분
도커 플랫폼을 통해 컨테이너를 동작하며 실제 서비스 제공
배포와 관리의 기본 단위로, 네트워크와 스토리지를 공유하는 하나 이상의 컨테이너 세트
하나의 클러스터를 여러 개의 논리적인 단위로 나눠서 사용하게 될 때의 단위이며, 일반적으로 용도에 따라 실행해야 하는 앱을 구분할 때 사용한다. 네임스페이스 삭제시 내부 자원들도 모두 삭제된다.
Kubernetes 리소스 및 기능이 어떻게 변경되고 발전하는지 관리하기 위해 사용되는 체계로, kubernetes object 정의시 api version이 필요하다. 각 리소스나 기능은 특정 API 그룹에 속하며, 이 그룹은 API 버전으로 구분된다. 주요 api 버전으로는 v1, alpha, beta, stable이 있다.
- Self healing
- Liveness Probe
- httpGet probe
- tcpSocket probe
- exec probe
지정한 IP 주소, 포트, 경로에 GET 요청을 보내, 해당 컨테이너의 응답 여부를 확인하며, 반환코드가 200이 아닐 경우, 오류라고 판단하고 컨테이너를 종료후 다시 시작한다.
지정된 포트 TCP 연결을 시도하며, 연결되지 않으면 컨테이너를 다시 시작한다.
exec 명령을 전달하고 명령의 종료코드가 0이 아니면 컨테이너를 다시 시작한다.
구성요소

[출처: 쿠버네티스 공식 홈페이지]
Control Plane(Master node)
4인방(Static Pod)이 존재한다.
- API server
- 모든 요청을 수신
- k8s API를 사용하도록 요청을 받고 요청이 유효한지 검사
- 클러스터의 현재 상태를 etcd에 저장하고 이를 바탕으로 상태를 관리
- 복수개 허용(active-active)
쿠버네티스 클러스터의 모든 명령과 요청을 처리하는 중앙 통제소
- Scheduler
- 클러스터의 리소스 사용 현황을 모니터링하고, Pod를 배치할 노드를 선택
- active-standby
- etcd
- 분산된 환경에서 데이터의 일관성과 신뢰성을 보장
- 여러 복제본을 유지하여 데이터 손실을 방지하고 고가용성을 제공
쿠버네티스 클러스터의 모든 데이터(설정 및 상태 정보)를 저장하는 분산 키-값 저장소
- Cloud controller manager (optional)
- pod를 관찰하며 개수를 보장
- active-standby
클라우드에 쿠버네티스 구축시 클라우드 서비스 제공자(CSP)의 스토리지, 네트워크 등의 서비스 간의 상호 작용을 관리하는 역할
Data Plane(Worker node)
3인방이 존재한다.
Kubelet
자신의 노드 내 pod와 컨테이너의 생명주기를 관리하는 통제소
- API 서버로부터 Pod 사양을 받아서 해당 노드에서 실행되는 컨테이너를 시작하고 모니터링
- 각 Pod와 컨테이너의 상태를 지속적으로 확인하고, 문제가 발생하면 재시작하거나 복구 조치를 취함
- 노드의 상태 정보를 API 서버에 보고하여 클러스터 관리가 가능하게 함
Kube-proxy
쿠버네티스 클러스터의 네트워킹을 관리하여, 서비스 간의 통신을 가능하게 한다. API 서버와 상호작용하여 서비스와 엔드포인트 간의 네트워크 트래픽을 라우팅한다.
- 로드 밸런싱
서비스에 대한 요청을 여러 Pod에 분산시켜 부하를 분산
- IP주소 및 포트 관리
- 서비스의 ClusterIP와 NodePort를 관리하여 외부 및 내부 트래픽을 처리
- 네트워크 규칙 관리
- 엔드포인트 연결을 위한 iptables를 구성
iptables 또는 IPVS를 사용하여 클러스터 내의 네트워크 규칙을 관리한다. 이러한 규칙은 서비스와 엔드포인트 간의 트래픽 흐름을 정의하며, kube-proxy는 이 규칙들을 동적으로 업데이트하여 클러스터 상태의 변화를 반영한다.
⇒ 클라이언트의 service API 요청시 iptables rule이 생성
Container run time
컨테이너의 실제 실행을 담당하는 소프트웨어로, containerd, CRI(Container Runtime Interface)-O 등이 있다.
- 컨테이너 관리
컨테이너의 생성, 실행, 중지 등을 담당
- 이미지 관리
컨테이너 이미지를 다운로드하고 저장하며, 이를 기반으로 컨테이너를 실행
초기 설정
온프레미스 환경에서 master, worker 각 노드에 대해 아래의 과정을 진행한다. master 노드에서 먼저 최적화 과정을 진행한 후, 해당 파일을 복사하여 worker 노드들을 생성할 것이다.
컨트롤 플레인 설정
- 호스트 이름 설정
각 노드를 식별하기 위한 작업으로, 루트 사용자로 전환하고 호스트 이름을 설정한다.
sudo -i
vi /etc/sudoers # 진입 후 %sudo ALL=(ALL:ALL) NOPASSWD:ALL 라인 추가
hostnamectl set-hostname 호스트명# 호스트명은 'master', 'control-plane' 등이 될 수 있겠다.
exec bash
- 로컬 DNS 설정
1에서 설정한 호스트 이름과 해당 호스트명이 속하는 노드의 IP 주소를
/etc/hosts
파일에 추가한다. 이는 각 노드가 서로를 호스트 이름으로 참조할 수 있도록 하여 클러스터 내부 통신을 용이하게 한다.# 예시
192.168.142.128 호스트명 # ip a 명령 결과 확인된 ip로 작성
192.168.142.129 worker1 # 임의로 129, 130,... 등의 방법으로 ip를 지정
# 필요에 따라 더 많은 worker 노드를 명시할 수 있음
- 네트워크 설정
- ubuntu
- RHEL
클러스터 노드 간의 통신을 안정적으로 유지하기 노드에 고정 IP를 부여한다. 이를 위해
/etc/netplan/00-installer-config.yaml
파일을 수정한다. network:
version: 2
ethernets:
ens33:
dhcp4: false
addresses: [192.168.142.128/24]
routes:
- to: default
via: 192.168.142.2
nameservers:
addresses: [192.168.142.128, 8.8.8.8]
netplan apply
# 설정이 잘 적용되었는지 확인
ip a
ip r
nmcli 도구 활용
sudo nmcli con mod <인터페이스 이름> ipv4.addresses 192.168.1.10/24
sudo nmcli con mod <인터페이스 이름> ipv4.gateway 192.168.1.1
sudo nmcli con mod <인터페이스 이름> ipv4.dns "8.8.8.8 8.8.4.4"
sudo nmcli con mod <인터페이스 이름> ipv4.method manual
sudo nmcli con up <인터페이스 이름>
# 설정이 잘 적용되었는지 확인
ip a
ip r
- 방화벽 비활성화
- ubuntu
- RHEL
원활한 네트워크 통신을 위해 방화벽을 비활성화한다.
ufw status disable
ufw status # 아래와 같이 나오면 성공
# Status: inactive
sudo systemctl disable --now firewalld
- 스왑 비활성화
쿠버네티스는 메모리 스왑을 지원하지 않는다.
⇒ 쿠버네티스 성능과 안정성을 위해 스왑 메모리를 비활성화한다.
sudo swapoff -a # 일시적 비활성화
sudo sed -i '/swap/s/^/#/' /etc/fstab # 영구적 비활성화
swapon -s # 확인
- 시스템 업데이트
시스템의 안정성과 보안을 위해 전체 OS를 업데이트하여 최신화한다.
sudo apt update sudo apt upgrade -y
- 컨테이너 런타임 설치
- Docker
- containerd (Docker 공식 저장소를 사용한)
- CRI-O
쿠버네티스는 컨테이너를 실행하기 위해 Docker, containerd, CRI-O 등을 사용한다.
CRIcontainerd의 CRI(Container Runtime Interface) 플러그인으로, 쿠버네티스가 다양한 컨테이너 런타임과 상호작용할 수 있도록 설계된 표준 인터페이스이다. 쿠버네티스는 CRI를 통해 컨테이너 런타임과 통신하여 컨테이너를 관리한다.
curl -s https://get.docker.com | sh
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
sudo apt-get install -y containerd.io
containerd는 원래 도커의 하위 모듈이었으나 이후 독립적인 모듈로 분리됐다.
/etc/containerd/config.toml
파일을 수정한다. 아래의 라인을 주석처리한다.# disabled_plugins = ["cri"]
containerd config default | tee /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
service containerd restart
KUBERNETES_VERSION=v1.30 CRIO_VERSION=v1.30
- 커널 모듈 및 네트워크 설정
- overlay
- netfilter
필요한 커널 모듈을 로드하고 네트워크 설정을 업데이트한다.
트래픽 제어 시스템
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system # 즉시 적용
- 쿠버네티스 패키지 설치
- kubectl
- kubeadm
- kubelet
kubectl
, kubeadm
, kubelet
패키지를 설치한다.클러스터를 관리하기 위한 명령줄 도구로, 이것을 통해 컨트롤 플레인과 소통한다.
클러스터 생성/관리 도구
각 노드에서 컨테이너를 관리하는 에이전트
# 공식 패키지 인증
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# sources.list에 추가
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo systemctl enable --now kubelet
패키지 버전 수동 설치apt-cache madison kubeadm
로 버전들을 확인하고, 아래와 같이 변수로 넘겨주어 설치한다.
export VER=1.29.2-1.1 sudo apt -y install kubelet=$VER kubeadm=$VER kubectl=$VER
워커 노드 생성
컨트롤 플레인의 리눅스 배포판 이미지를 복사하여 워커 노드에도 적용해줄 것이다. 이렇게 하면 위의 초기화 과정을 반복하지 않아도 돼서 편리하다.
- lock 폴더를 제외한 모든 파일 압축
알집 등의 압축 도구를 사용하여
.lck
확장자를 지닌 폴더를 제외한 모든 파일을 묶어 압축한다.
- 가상머신들을 모아두는 폴더 등 자신이 원하는 곳에 워커 노드에 해당하는 폴더를 만들고(압축을 풀 때 하위 폴더로 생성해도 된다.) 압축을 풀어준다.
- 워커 노드 폴더에 들어가
.vmx
확장자를 지닌 파일을 실행하면 VMware가 실행되면서 노드가 가상머신 상에 올라갈 것이다.

- 컨트롤 플레인의 ‘네트워크 설정’ 부분과 마찬가지로 워커노드의 네트워크도 설정한다. 이 때, 컨트롤 플레인과는 다른 ip 주소(같은 대역의)를 할당한다.
/etc/hosts
에 명시했던 워커 노드의 이름으로 호스트명을 변경한다.
hostnamectl set-hostname workerN
exec bash
컨트롤 플레인(master 노드) 설정
- 컨트롤 플레인 초기화
마스터 노드를 초기화하여 쿠버네티스 클러스터의 컨트롤 플레인 구성 요소(API 서버, 컨트롤러 매니저, 스케줄러)를 설정한다. Pod 네트워크 CIDR을 지정하여 네트워크 플러그인이 사용할 네트워크 범위를 설정한다.
sudo kubeadm init --pod-network-cidr=172.20.0.0/16
위 명령어는 반드시 컨트롤 플레인에서만 실행하도록 한다.
초기화 과정중
kubeadm join 192.168.52.128:6443 --token 토큰값 \
--discovery-token-ca-cert-hash sha256:<해시>
와 같은 라인을 던져주는데 이는 워커노드 조인시 필요한 명령어이므로 따로 기록해둔다.- kubeconfig 설정 후 컨트롤 플레인 상태 확인
루트 사용자도
kubectl
명령어를 사용할 수 없다. 따라서, 특정 사용자로 하여금 쿠버네티스 클러스터를 관리를 위해kubectl
을 사용할 수 있게 하려면 kubeconfig 파일을 설정해야 한다.

# 쿠버네티스 클러스터와 상호작용하기 위해 필요한 인증 정보를 포함한 설정 파일
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 # 사용자가 인증되었으므로 kubectl 명령어로 클러스터를 관리할 수 있음

네트워크 플러그인이 설치되지 않았으므로 STATUS는 NotReady 상태일 것이다.
- 네트워크 플러그인 설치
- Calico 설치
custom-resources.yaml
수정 및 적용- cilium 설치
클러스터 내 Pod 간 네트워크 통신이 가능하도록 네트워크 플러그인을 설치해야 한다. 플라넬(flannel), 위브넷(weavenet)과 같은 다른 플러그인도 존재하지만, 예시는 calico, clilium로 들겠다.
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/tigera-operator.yaml wget https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/custom-resources.yaml
cidr 설정 부분의 ip를 위에서 설정한 cidr로 수정 후,
kubectl create -f custom-resources.yaml
명령어로 적용한다.helm이 없다면 helm 설치 후, 진행한다.
helm repo add cilium https://helm.cilium.io/ helm repo update helm install cilium cilium/cilium --namespace=kube-system
워커 노드의 클러스터 조인
마스터 노드 초기화 후 출력된 조인 명령어를 사용하여 워커 노드를 클러스터에 조인한다.
kubeadm join 192.168.142.128:6443 --token <토큰> \
--discovery-token-ca-cert-hash sha256:<해시>
조인시 오류컨트롤 플레인이나 워커노드 조인시 오류가 발생할 경우, 마스터 플레인에서 초기화 작업을 재실행한다.sudo kubeadm reset -y
- kubeconfig 파일 설정
워커 노드에서도
kubectl
명령어를 사용하기위해 컨트롤 플레인에서 설정한 admin.conf 파일을 워커 노드에 심어준다.# 컨트롤 플레인에서 아래 명령 실행
scp $HOME/.kube/config <워커노드 사용자명>@<워커노드 호스트명>:/home/<워커노드 사용자명>
# 워커 노드에서 아래 명령 실행
mkdir -p $HOME/.kube
mv /home/<워커노드 사용자명>/config $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
명령어 자동완성
쿠버네티스 관련 명령어 입력시 자동완성 기능을 사용하기 위해 아래 명령어를 입력한다.
echo "source <(kubectl completion bash)" >> ~/.bashrc
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc
Share article