Kubernetes 란?
- 컨테이너의 배포, 관리, 확장 및 네트워킹을 자동화하는 오픈소스 컨테이너 오케스트레이션 플랫폼
- 컨테이너는 환경과 상관없이 실행을 위해 필요한 모든 요소를 포함하는 소프트웨어 패키지
Kubernetes 기본 개념
Control Plane
- Data Plane(워커 노드)와 클러스터내의 pod들을 관리하고 제어
Control Plane(마스터 노드) 구성 요소
• kube-apiserver - 쿠버네티스 API 서버로서 클러스터 내부 및 외부에서의 모든 API 호출을 받고 처리
• kube-controller-manager - 여러 개의 컨트롤러가 클러스터 상태를 감시하고 관리
• kube-scheduler - 새 pod가 어떤 노드에 배치되어야 하는지를 노드 상태와 설정 환경을 고려하여 결정
• etcd - 클러스터의 상태와 관련된 정보가 키-값 형식으로 저장된 데이터베이스
Data Plane
- pod을 통해 애플리케이션을 실행하고 네트워크 트래픽을 라우팅하며 데이터를 처리하는 데 중점
Data Plane(워커 노드) 구성 요소
• kubelet - Control Plane과 통신하여 kube-scheduler가 특정 노드에 Pod를 할당시 해당 Pod에서 컨테이너 실행
• kube-proxy - 네트워크 프록시로서, Service를 통해 Pod에 접근할 수 있도록 하고 로드 밸런싱을 수행
• container runtime engine - 컨테이너 실행을 위한 엔진 역할, 대표적으로 Docker
Object
- Kubernetes에서는 다양한 종류의 Object를 사용하여 클러스터의 상태를 관리
- 각 오브젝트는 YAML 또는 JSON 형식으로 정의되며, 클러스터 상태를 설명하고 관리하는 데 사용
기본 Object
• Pod - 컨테이너화된 애플리케이션을 실행하는 가장 작은 배포 단위로 독립적인 공간과 IP를 가진다.
• Service - Pod 집합에 대한 네트워크 엔드포인트를 제공하고 로드 밸런싱을 수행
• Namespace - 쿠버네티스 클러스터에서 사용되는 리소소들을 구분해서 관리하는 그룹
• Volume - 컨테이너가 사용하는 데이터를 저장하고 공유하기 위한 디렉토리 또는 저장소
컨트롤러 Object
• Deployment - ReplicaSet의 상위 개념으로, Pod와 ReplicaSet에 대한 배포를 관리할 때 사용
• StatefulSet - Pod가 삭제되었다 새로 생성되어도 기존의 상태를 유지하도록 관리할 때 사용
• DaemonSet - 각 노드에 하나의 Pod를 배치하여 클러스터 전체의 노드에서 특정한 역할을 수행하도록 사용
• Job - 일회성 작업을 정의하고 실행하는 데 사용
• CronJob - 정기적으로 반복되는 작업을 정의하고 실행
Kubernetes 설치
- CPU : Dual Core / Memory : 2GB 이상
swap 비활성화
## swap 메모리 비활성화
# swap 메모리 상태 확인, 출력값이 없으면 swap 메모리 비활성화 상태
sudo swapon -s
# 현재 활성화되어 있는 모든 swap 공간을 비활성화
sudo swapoff -a
# /etc/fstab 파일에서 스왑 관련 항목을 찾아서 주석 처리합니다. 이렇게 하면 시스템이 부팅될 때 스왑을 사용하지 않도록 설정
sudo sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab
# swap 메모리가 0인지 확인
sudo free -m
swap 비활성화 이유
• kubelet은 swap 메모리를 고려하지 않고 개발
• swap 메모리 사용은 노드 할당 자원이 일관되지 않아 안정성을 위해 swap off를 권장
방화벽 설정
## 방화벽 설정
# http, https 허용
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
# master node port 허용
firewall-cmd --permanent --add-port=2379-2380/tcp
firewall-cmd --permanent --add-port=6443/tcp
firewall-cmd --permanent --add-port=10250-10252/tcp
firewall-cmd --permanent --add-port=8285/udp
firewall-cmd --permanent --add-port=8472/udp
# worker node port 허용
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=30000-32767/tcp
firewall-cmd --permanent --add-port=8285/udp
firewall-cmd --permanent --add-port=8472/udp
firewall-cmd --permanent --add-port=26443/tcp
# 설정 적용
firewall-cmd --reload
# 열린 포트 확인
sudo firewall-cmd --list-all
master node port별 용도
• 2379-2380/tcp - etcd 클러스터 통신을 위한 포트
• 6443/tcp - kube-apiserver에 접속하기 위한 포트
• 10250-10252/tcp - kube-apiserver 포트 범위, 노드의 kubelet과 통신
• 8285/udp - Flannel CNI 플러그인에 대한 포트
• 8472/udp - Flannel CNI 플러그인에 대한 포트
worker node port별 용도
• 10250/tcp - Kubelet API 서버에 접속하기 위한 포트. worker node의 Kubelet은 master node와 통신하여
노드의 상태를 보고하고, 컨테이너 관련 작업을 수행
• 30000-32767/tcp - 서비스 유형이 NodePort인 서비스의 포트 범위로 외부에서 클러스터의 서비스에 접근하기 위한 포트
• 26443/tcp - kube-proxy가 서비스를 로드밸런싱하기 위해 사용하는 포트
• 8285/udp - Flannel CNI 플러그인에 대한 포트
• 8472/udp - Flannel CNI 플러그인에 대한 포트
SELinux 설정
## permissive 모드로 SELinux 설정
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
네트워크 설정
## 부팅 시에 overlay와 br_netfilter라는 두 가지 모듈을 로드하도록 설정
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
# overlay 커널 모듈을 즉시 로드합니다. 컨테이너 오버레이 파일 시스템에 사용
sudo modprobe overlay
# br_netfilter 커널 모듈을 즉시 로드합니다. 브리지 네트워크 필터링 모듈로
# 가상 네트워크 인터페이스와 호스트 시스템 간의 네트워크 패킷을 필터링하고 전달하는 역할
sudo modprobe br_netfilter
## iptables 커널 활성화
# net.bridge.bridge-nf-call-iptables는 iptables이 브리지 트래픽을 처리할 수 있도록 하는 설정
# net.ipv4.ip_forward는 IP 패킷 전달을 활성화
# Kubernetes에서는 컨테이너 간 통신 및 외부 통신을 관리하기 위해 iptables를 사용하므로, 이 설정이 필요
cat <<EOF | sudo 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
## 설정했던 값을 적용
sudo sysctl --system
# 모듈 활성화 확인
lsmod | grep br_netfilter
lsmod | grep overlay
# iptables 설정 1 로 되어 있는 지 확인
sudo sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward
컨테이너 런타임 설치
cri-dockerd 설치 방법(Ubuntu)
## docker 설치
# gig 키 추가
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# repo 추가
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
# docker 패키지 설치
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
# docker 실행
sudo systemctl enable docker
sudo systemctl start docker
# docker 실행 확인
sudo systemctl status docker
## cri-dockerd 설치
# go 설치
wget https://go.dev/dl/go1.22.3.linux-amd64.tar.gz
export GOROOT=/path/to/your/go/directory
export PATH=$PATH:$GOROOT/bin
# git에서 cri-dockerd 소스 복사
git clone https://github.com/Mirantis/cri-dockerd.git
# cri-dockerd 빌드
cd cri-dockerd
mkdir bin
go build -o bin/cri-dockerd
# /usr/local/bin 으로 빌드파일 복사
sudo mkdir -p /usr/local/bin
sudo install -o root -g root -m 0755 bin/cri-dockerd /usr/local/bin/cri-dockerd
# systemd에 서비스 등록
sudo cp -a packaging/systemd/* /etc/systemd/system
sudo sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service
# cri-dockerd 실행
sudo systemctl daemon-reload
sudo systemctl enable cri-docker.service
sudo systemctl enable --now cri-docker.socket
sudo systemctl restart docker && sudo systemctl restart cri-docker
# cri-dockerd 실행 확인
sudo systemctl status cri-docker.socket --no-pager
Kubernetes 패키지 설치
1.24 이상 버전 설치 방법(Ubuntu)
# apt 업데이트
sudo apt-get update
# 필수 패키지 설치
sudo apt-get install -y apt-transport-https ca-certificates curl
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
# 1.24이상 레파지토리 URL 변경
sudo curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo apt-get update
# Kubernetes 패키지 설치
sudo apt-get install -y kubelet kubeadm kubectl
# Kubernetes 패키지 설치 확인
kubelet --version
kubeadm version
kubectl version
# kubelet service 확인
sudo systemctl status kubelet.service
자동완성 기능 적용
# bash-completion 패키지를 설치
apt-get install bash-completion
# bash 쉘의 자동 완성 기능을 활성화
source /usr/share/bash-completion/bash_completion
# kubectl 명령어의 자동 완성을 활성화하기 위해 ~/.bashrc 파일에 kubectl 자동 완성 설정을 추가
echo 'source <(kubectl completion bash)' >>~/.bashrc
# ubectl 명령을 더 간단하게 입력할 수 있도록 'k'를 kubectl의 엘리어스로 설정
echo 'alias k=kubectl' >>~/.bashrc
# 'k' 엘리어스에 대한 자동 완성 기능을 활성화
echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
# 현재 쉘을 새로운 bash 쉘로 교체하여 변경된 설정이 즉시 적용
exec bash
Kubernetes 클러스터 구축
Control Plane 구축
kubeadm init [옵션]
-- Kubernetes 클러스터를 초기화하여 새로운 Control Plane을 생성하는 명령어
-- 별도의 옵션을 설정하지 않으면 기본 디폴트 값으로 적용
옵션 목록
• --config : 초기화에 사용할 구성 파일을 지정
• --token : 새로운 노드를 클러스터에 추가할 때 사용(Data Plane용)
• --pod-network-cidr : 클러스터에 대한 Pod 네트워크 CIDR 범위를 지정(CNI별로 범위 값 상이)
• --apiserver-advertise-address : 클라이언트가 API 서버에 연결할 때 사용할 IP 주소를 설정
• --apiserver-cert-extra-sans : Control Plane의 인증을 위해 사용되는 서버 인증서에 추가할 DNS 이름을 지정
• --control-plane-endpoint : 다중 Control Plane 간의 통신에 사용할 엔드포인트를 설정
• --cri-socket : Kubernetes가 사용할 컨테이너 런타임 인터페이스(CRI) 소켓을 지정
## Kubernetes 클러스터 init
# CNI = Flannel, CRI = cri-dockerd일 경우 init 명령어 예시
sudo kubeadm init --cri-socket unix:///var/run/cri-dockerd.sock --pod-network-cidr=10.244.0.0/16
# 클러스터 구축 확인
kubectl config get-clusters
# 노드 확인
kubectl get nodes
# Data Plane(워커 노드) join을 위한 토큰 생성
kubeadm token create --print-join-command
## Kubernetes 클러스터 초기화 명령어
# --v5=5 로그 출력의 상세 수준을 설정합니다. 여기서 5는 가장 상세한 레벨
sudo kubeadm reset --cri-socket unix:///var/run/cri-dockerd.sock --v5=5
kubeadm init error 발생 시
더보기
• Get http://localhost:10248/healthz: dial tcp 127.0.0.1:10248: connect: connection refused.
## container’s cgroups에 systemd를 사용하도록 Docker 데몬을 구성한다.
# docker가 cgroup으로 관리하게 되어 있는데,
# 이를 Kubernetes는 systemd에서 관리하도록 되어 있어 이를 동일하게 만들어 줘야 안정적
sudo mkdir /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl restart kubelet.service
• The connection to the server localhost:8080 was refused - did you specify the right host or port?
## root계정외에 현재 사용자 계정에서도 Kubernetes 권한 설정
# 현재 사용자의 홈 디렉토리에 .kube 디렉토리를 생성, Kubernetes 구성 파일을 저장하는 데 사용
mkdir -p $HOME/.kube
# /etc/kubernetes/admin.conf 파일을 로컬 사용자의 .kube/config 파일로 복사
# admin.conf 파일은 클러스터의 관리자 구성 파일로, 클러스터와 통신하기 위한 인증 및 구성 정보를 포함
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# $HOME/.kube/config 파일의 소유자를 현재 사용자로 변경
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 현재 세션에 대한 Kubeconfig 파일 경로를 설정
export KUBECONFIG=$HOME/.kube/config
CNI 설치
- 컨테이너 간의 네트워크를 제어할 수 있는 플러그인, 컨테이너 런타임에서 컨테이너의 네트워크를 사용하게 해주는 인터페이스
- Kubernetes에서는 Pod 간의 통신을 위해서 CNI(Container Network Interface) 를 사용
주요 CNI CIDR범위
- Flannel - 10.244.0.0/16
- Calico - 192.168.0.0/16
- Weave Net - 10.32.0.0/12
## flannel 설치 예시
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 설치 확인
kubectl get all --all-namespaces | grep flannel
## weave 설치 예시
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
# 설치 확인
kubectl get all --all-namespaces | grep weave
## calico 설치 예시
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
# 설치 확인
kubectl get all --all-namespaces | grep calico
Data Plane 구축
## Kubernetes 클러스터 join
sudo kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash> --cri-socket=unix:///var/run/cri-dockerd.sock
# Control Plane(마스터 노드)에서 join 확인
kubectl get nodes
## Data Plane(워커 노드)에서 명령어 사용
# 현재 사용자의 홈 디렉토리에 .kube 디렉토리를 생성
mkdir -p $HOME/.kube
# scp 명령을 사용하여 Control Plane의 /etc/kubernetes/admin.conf 파일을 로컬 시스템의 $HOME/.kube/config 파일로 복사
scp [master IP]:/etc/kubernetes/admin.conf $HOME/.kube/config
# Data Plane에서 join 확인
kubectl get nodes
참고 사이트
• https://kubernetes.io/ko/
• https://wooono.tistory.com/700
• https://gajy.tistory.com/31
• https://yang1s.tistory.com/32