사전 진행
필자는 AWS 계정에서 두 대의 EC2를 만들어 진행함
1. 전제 조건
- 최소 2개의 리눅스 머신 노드 (master 노드 1, worker 노드 1개)가 필요, 요구 사항에 따라 더 많은 작업자 노드가 필요할 수 있음
- master 노드에는 최소 2개의 vCPU와 2GB RAM이 있어야하며, worker 노드는 최소 1vCPU 및 2GB RAM 권장
- 클러스터의 모든 노드는 서로 통신이 가능해야함
- 클러스터의 모든 노드는 스왑 비활성화 (활성화 되어 있으면 kubelet이 제대로 작동하지 않음)
- 클러스터의 모든 노드는 고유한 호스트 이름, MAC 주소 및 product_uuid 가져야함
2. 포트 허용
아래 그림을 참고해 마스터 노드(컨트롤 플레인) 및 워커 노드의 포트를 허용, 필자는 ec2간 방화벽 정책을 모든 트래픽 허용으로 했으며 src/dist check를 비활성으로 했다. 그 이유는 발생한 이슈에 적어두었다.
참고 글) https://kubernetes.io/docs/reference/networking/ports-and-protocols/
3. 모든 노드에서 iptables 브리지 트래픽 활성화
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# sysctl params required by setup, params persist across reboots
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
# Apply sysctl params without reboot
sudo sysctl --system
4. 모든 노드에서 스왑 비활성화
sudo swapoff -a
(crontab -l 2>/dev/null; echo "@reboot /sbin/swapoff -a") | crontab - || true
5. 모든 노드에서 컨테이너 런타임 설치
파드에서 컨테이너를 실행하기 위해, 쿠버네티스는 컨테이너 런타임 인터페이스(CRI)을 사용한다. 쿠버네티스는 CRI를 사용해 사용자가 지정한 컨테이너 런타임과 연결한다. 아래의 컨테이너 런타임이 있다.
- CRI-O
- containerd
- docker-engine (cri-dockerd 사용)
런타임을 지정하지 않으면, kubeadm은 잘 알려진 엔드포인트(소켓 위치)를 스캔하여 설치된 컨테이너 런타임을 자동으로 감지하려고 한다. 만약 컨테이너 런타임이 여러 개 감지되거나 하나도 감지되지 않은 경우, kubeadm은 에러를 반환하고 사용자가 어떤 것을 사용할지를 명시하도록 요청한다. 쿠버네티스의 컨테이너 런타임으로 도커 엔진을 사용하려면 추가적으로 cri-dockerd를 설치해야한다. 도커 엔진의 컨테이너 런타임이 CRI를 만족하지 않기 때문이다. 아래 표는 리눅스의 잘 알려진 엔드포인트이다.
CRI-O | /var/run/crio/crio.sock |
containerd | /var/run/containerd/containerd.sock |
docker-engine (cri-dockerd 사용) | /var/run/cri-dockerd.sock |
이 글에서는 컨테이너 런타임으로 CRI-O를 사용한다. 아래와 같이 CRI-O를 설치하자. 필자는 우분투(22.04)를 사용한다.
cri-o 버전 1.28에 대한 cri-o 저장소 활성화
OS="xUbuntu_22.04"
VERSION="1.28"
cat <<EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /
EOF
cat <<EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /
EOF
CRI-O용 GPG 키를 시스템의 신뢰할 수 있는 키 목록에 추가
curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
업데이트하고 crio, cri-tools 설치
sudo apt-get update -y
sudo apt-get install cri-o cri-o-runc cri-tools -y
systemd 구성을 다시 로드하고 cri-o를 활성화
sudo systemctl daemon-reload
sudo systemctl enable crio --now
모든 노드에 kubeadm, kubelet, kubectl 설치
쿠버네티스를 사용하려면 kubelet, kubeadm, kubectl 패키지가 필요하다.
- kubelet : 클러스터의 모든 노드에서 실행되는 컴포넌트로 파드 및 컨테이너의 생성 / 실행 등과 같은 작업을 수행
- kubeadm : 쿠버네티스의 클러스터를 구축하기 위해 사용
- kubectl : 클러스터와 통신하기 위한 커맨드라인 유틸
필요한 종속성을 설치
sudo apt-get update -y
sudo apt-get install -y apt-transport-https ca-certificates curl -y
Kubernetes APT 저장소의 GPG 키를 다운로드
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://dl.k8s.io/apt/doc/apt-key.gpg
Kubernetes APT 저장소를 시스템에 추가
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
저장소 업데이트
sudo apt-get update -y
설치
# 최신 버전 설치
sudo apt-get install kubelet kubeadm kubectl -y
# 버전 지정 설치
sudo apt-get install kubelet=1.28.2-00 kubectl=1.28.2-00 kubeadm=1.28.2-00 -y
업그레이드 방지 (갑자기 업그레이드 되면 노드 간의 버전이 달라져 문제가 발생할 수 있음)
sudo apt-mark hold kubelet kubeadm kubectl
KUBELET_EXTRA_ARGS를 노드의 사설 ip로 설정한다.
private_ip="your_private_ip"
sudo bash -c "echo KUBELET_EXTRA_ARGS=--node-ip=$private_ip > /etc/default/kubelet"
마스터 노드에서 kubeadm 초기화
아래의 환경 변수 설정
IPADDR=$private_ip
NODENAME=$(hostname -s)
POD_CIDR="192.168.0.0/16"
kubeadm init 명령어 수행, 앞에서 이미 swap을 비활성화했기에 --ignore-preflight-errors Swap은 굳이 안써도 된다. kubeadm init시 아래와 같이--apiserver-advertise-address 옵션으로 사설 ip를 사용할 수도 있고 --control-plane-endpoint 옵션으로 공인 ip를 지정할수도 있지만 왠만하면 사설 ip를 사용하는 것이 좋다. 공인 ip를 사용하면 누구나 클러스터에 연결을 시도할 수 있기 때문이다. 클러스터의 모든 노드는 같은 내부망을 가지고 내부망에서만 서로 통신하는 것이 안전하다.
sudo kubeadm init --apiserver-advertise-address=$IPADDR --apiserver-cert-extra-sans=$IPADDR --pod-network-cidr=$POD_CIDR --node-name $NODENAME --ignore-preflight-errors Swap
초기화에 성공하면 아래 그림과 같이 출력된다. 토큰이 포함된 join 명령을 복사해 따로 저장한다. 해당 명령은 worker 노드가 마스터에 연결되기 위해 필요하다.
위 로그에서 말하는대로 아래 명령어를 수행한다.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
기본적으로 마스터 노드에서는 파드가 실행되지 않는다. 마스터 노드에도 Pod를 실행시킬려면 아래의 명령어를 수행한다.
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
kubectl get po -n kube-system을 수행하여 pod를 확인할 수 있다.
kubectl get po -n kube-system
아래 명령을 사용하여 모든 클러스터 구성 요소 상태를 확인할 수 있다.
kubectl get --raw='/readyz?verbose'
아래 명령을 사용하여 클러스터 정보를 확인할 수 있다.
kubectl cluster-info
마스터 노드에서 CNI 플러그인 설치
서로 다른 노드에 있는 Pod들이 통신하기 위해서는 오버레이 네트워크가 필요하다. 오버레이 네트워크란 노드에서 사용하는 물리적인 네트워크 위에 가상의 네트워크를 구성하는 것이다. 오버레이 네트워크가 구축되면 클러스터로 묶인 모든 노드에 떠 있는 파드 간 통신이 가능하다.
쿠버네티스에서 오버레이 네트워크를 구성하기 위해 CNI 플러그인을 설치해야한다. CNI 플러그인에는 플라넬, 칼리코, 실리움, 멀터스 등이 있으며 이 글에서는 칼리코(Calico)를 설치한다.
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml
curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml -O
kubectl create -f custom-resources.yaml
워커 노드를 마스터 노드에 조인
워커 노드를 클러스터에 포함시킨다. 앞에서 kubeadm init 명령어를 수행해 얻은 join 명령어를 입력한다. 만약 join 명령 복사를 놓친경우 아래의 명령어를 마스터 노드에 수행해 다시 명령어를 얻는다.
kubeadm token create --print-join-command
아래의 명령어를 워커 노드에서 수행해 워커 노드를 클러스터에 포함시킨다.
sudo kubeadm join 10.128.0.37:6443 --token j4eice.33vgvgyf5cxw4u8i \
--discovery-token-ca-cert-hash sha256:37f94469b58bcc8f26a4aa44441fb17196a585b37288f85e22475b00c36f1c61
성공적으로 수행되면 아래와 같이 클러스터에 조인됬다는 문구가 뜬다.
이제 마스터 노드에서 kubectl 명령을 실행하여 해당 노드가 마스터에 추가되었는지 확인한다.
kubectl get nodes
root@master-node:/home/vagrant# kubectl get nodes
NAME STATUS ROLES AGE VERSION
controlplane Ready control-plane 14m v1.28.2
node01 Ready <none> 2m13s v1.28.2
node02 Ready <none> 2m5s v1.28.2
간편하게 구축
앞에 설명한 명령어를 하나의 sh 파일로 만들어두면 쉽게 마스터 노드, 워커 노드를 만들 수 있다.
master.sh (변수 값만 적절히 수정)
#!/bin/bash
# Variables, 적절한 값으로 수정
KUBERNETES_VERSION="1.28.2-00"
OS="xUbuntu_22.04"
VERSION="1.28"
private_ip="your_private_ip"
# iptables 브리지 트래픽 활성화
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
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
# 스왑 비활성화
sudo swapoff -a
(crontab -l 2>/dev/null; echo "@reboot /sbin/swapoff -a") | crontab - || true
# 컨테이너 런타임, CRI-O 설치
cat <<EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /
EOF
cat <<EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /
EOF
curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
sudo apt-get update -y
sudo apt-get install cri-o cri-o-runc cri-tools -y
sudo systemctl daemon-reload
sudo systemctl enable crio --now
# kubeadm, kubelet, kubectl 설치
sudo apt-get update -y
sudo apt-get install -y apt-transport-https ca-certificates curl -y
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://dl.k8s.io/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update -y
sudo apt-get install kubelet="$KUBERNETES_VERSION" kubectl="$KUBERNETES_VERSION" kubeadm="$KUBERNETES_VERSION" -y
sudo apt-mark hold kubelet kubeadm kubectl
sudo bash -c "echo KUBELET_EXTRA_ARGS=--node-ip=$private_ip > /etc/default/kubelet"
# kubeadm 초기화
IPADDR=$private_ip
NODENAME=$(hostname -s)
POD_CIDR="192.168.0.0/16"
sudo kubeadm init --apiserver-advertise-address=$IPADDR --apiserver-cert-extra-sans=$IPADDR --pod-network-cidr=$POD_CIDR --node-name $NODENAME --ignore-preflight-errors Swap
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
# Calico 설치
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml
curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml -O
kubectl create -f custom-resources.yaml
worker.sh (변수 값만 적절히 수정)
워커 노드에서는 아래 sh을 수행하고 위 글에서 "워커 노드를 마스터 노드에 조인" 파트만 추가로 수행하면 된다.
#!/bin/bash
# Variables, 적절한 값으로 수정
KUBERNETES_VERSION="1.28.2-00"
OS="xUbuntu_22.04"
VERSION="1.28"
private_ip="your_private_ip"
# iptables 브리지 트래픽 활성화
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
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
# 스왑 비활성화
sudo swapoff -a
(crontab -l 2>/dev/null; echo "@reboot /sbin/swapoff -a") | crontab - || true
# 컨테이너 런타임, CRI-O 설치
cat <<EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /
EOF
cat <<EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /
EOF
curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
sudo apt-get update -y
sudo apt-get install cri-o cri-o-runc cri-tools -y
sudo systemctl daemon-reload
sudo systemctl enable crio --now
# kubeadm, kubelet, kubectl 설치
sudo apt-get update -y
sudo apt-get install -y apt-transport-https ca-certificates curl -y
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://dl.k8s.io/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update -y
sudo apt-get install kubelet="$KUBERNETES_VERSION" kubectl="$KUBERNETES_VERSION" kubeadm="$KUBERNETES_VERSION" -y
sudo apt-mark hold kubelet kubeadm kubectl
sudo bash -c "echo KUBELET_EXTRA_ARGS=--node-ip=$private_ip > /etc/default/kubelet"
발생한 이슈
1. 쿠버네티스 공식 문서에서 나온 대로 포트를 허용하고 쿠버네티스 클러스터를 구축했지만 쿠버네티스 상에서 노드 간 통신이 되지 않았다. 아래 글을 읽어보고 해결했다. aws 네트워크 정책와 cailco 공부가 필요할 것 같다.
2. 서로 다른 사용자를 가진 AWS EC2를 묶어 쿠버네티스 클러스터를 구축하려했지만 연결되지 않았다. 아래 참고글의 aws에서 cailco 구성 글을 이해해야 될 것 같다.
3. 윈도우에서 sh 파일을 작성하고 우분투로 복사했더니, 줄 바꿈 문자에서 오류가 났다. 윈도우는 줄 바꿈 문자로 CR(carriage return)와 LF(line feed)를 모두 사용하지만, 리눅스에서는 LF만 사용하기에 sh에 포함된 CR 문자를 인식하지 못해 오류가 났다. 아래 명령어로 sh에 포함된 CR 문자를 모두 제거했다.
sed -i 's/\r//' your_script.sh
참고 글
쿠버네티스 공식 글 : https://kubernetes.io/docs/setup/production-environment/container-runtimes/
쿠버네티스 공식 글 : https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
cri-o 공식 글 : https://cri-o.io/
설치 관련 블로그 글 : https://devopscube.com/setup-kubernetes-cluster-kubeadm/
칼리코 설치 : https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart
calico the hard way : https://docs.tigera.io/calico/latest/getting-started/kubernetes/hardway/standing-up-kubernetes
aws에서 calico 구성 : https://docs.tigera.io/calico/latest/reference/public-cloud/aws
쉽게 시작하는 쿠버네티스(서지영) 책 참고