이번 포스팅에서는 kubeadm
을 활용하여 AWS EC2 인스턴스에 직접 kubernetes 클러스터를 구축하는 과정을 다루었습니다.
공식 문서에 따르면 kubernetes 노드를 실행하기 위해서는 다음가 같은 환경이 요구됩니다.
Ubuntu
, CentOS
kubernetes는 컨테이너 자원을 제한하고 해당 워크로드를 수용할 수 있는 노드에 스케쥴링 함으로써 노드의 자원을 최대한으로 활용하는 것을 목표로 합니다. 그러나, swap 기능은 가용 자원을 모두 소진한 노드가 부가적인 워크로드를 수행하는 것을 야기할 수 있습니다. 따라서, 정상적인 kubelet
실행을 위해 swap 기능 사용을 제한해야 합니다. 관련 질문: Why disable swap on kubernetes?
아래의 명령어를 사용하면, swap 기능을 사용하지 않도록 관련 설정을 수정할 수 있습니다.
$ sudo su # root 권한으로 실행
$ swapoff -a
$ echo 0 > /proc/sys/vm/swappiness
$ sed -e '/swap/ s/^#*/#/' -i /etc/fstab
$ exit
kubernetes는 네트워크 인터페이스의 MAC 주소와, product_uuid
를 사용하여 노드를 식별합니다. 따라서, 동일한 하드웨어 머신에서 kubernetes
노드들을 추가하는 경우에는 해당 값이 고유한지 여부를 확인해야 합니다.
# MAC 주소 확인
$ ip link
$ ifconfig - a
# product_uuid 확인
$ sudo cat /sys/class/dmi/id/product_uuid
kubernetes 컴포넌트(ex, kubelet
, kube-apiserver
) 간 통신을 위해 EC2 인스턴스와 연결된 security group
에서 해당 포트를 허용해야 합니다.
kube-apiserver
: 6443kubelet
: 10250etcd
: 2379, 2380kubelet
: 10250kubernetes 클러스터를 구성하기 위해서는 아래의 프로그램들을 설치해야 합니다.
kubeadm
: 클러스터 초기화 및 부스트래핑kubelet
: 컨테이너 런타임 및 팟의 라이프사이클 관리kubectl
: kubernetes control-plane
과 통신하기 위한 클라이언트다음으로 우분투 환경에서 kubeadm
, kubelet
, kubectl
을 설치해보도록 하겠습니다. 리눅스 계열별 설치 명령어는 링크 에서 확인하실 수 있습니다.
# 1. apt 패키지 업데이트 및 필수 패키지 설치
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
# 2. 공개 사이닝 키 다운로드
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
# 3. ppa 추가
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
# 4. kubeadm, kubelet, kubectl 설치 및 버전 고정
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
kubelet
은 컨테이너 리소스 제어를 위한 cgroup driver로 systemd
를 기본 값(v1.22 이후)으로 사용합니다. 반면, Docker 내부에서 직접적인 컨테이너 관리를 담당하는 runc는 cgroup driver로 cgroupsfs
를 사용합니다. 따라서, Docker를 컨테이너 런타임으로 사용할 경우에는 /etc/docker/daemon.json
파일을 수정하여 Docker의 cgroup driver를 systemd
로 변경해주어야 합니다.
# /etc/docker/daemon.json
{
...
"exec-opts": ["native.cgroupdriver=systemd"]
}
설정을 변경한 후에는 Docker를 재시작한 후, 바뀐 설정이 잘 적용되었는지 확인합니다.
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
$ docker info | grep "Cgroup Driver"
Cgroup Driver: systemd
systemd
와 cgroupfs
는 모두 /sys/fs/cgroup
경로 하위에 리소스 관련 정보를 마운트 하는데, cgroup 경로를 정하는 방식에서 차이를 보입니다. cgroupfs
는 리소스를 직접 매핑하는 방식으로 flat한 파일 시스템 형태로 리소스를 관리하는 반면, systemd
는 slice/scope/service 의 계층 구조로 이를 관리합니다. 따라서, 이 둘을 혼용하여 사용할 경우 서로 다른 네이밍 정책으로 인해 충돌을 일으킬 수 있습니다. 이와 관련된 자세한 설명은 링크에서 확인하실 수 있습니다.
다음으로 kubeadm init
명령어를 실행하여 control-plane이 위치할 마스터 노드를 생성합니다. 저는AWS EC2
에 control-plane
노드를 설치하고 로컬 머신에서 이에 접근하는 환경을 구성하였습니다.
--pod-network-cidr
은 우리가 사용할 calico
공식문서와 동일하게 192.168.0.0/16
을 사용합니다.
--upload-certs
옵션을 추가하면 control-plane
의 SSL 인증서가 kubernetes cluster에 secret으로 저장됩니다. 해당 secret은 2시간 후 자동으로 사라지지만, kubeadm join
명령어를 사용하여 새로운 control-plane
노드를 추가할 때, 번거롭게 인증서를 복사하지 않아도 되어 편리합니다. 하나의 control-plane
노드만을 사용할 경우에는 해당 옵션을 추가하지 않아도 됩니다.
--control-plane-endpoint
옵션은 여러 개의 control-plane
노드로 HA를 구성하는 경우에 사용합니다. 값으로 control-plane
노드들 앞단에 위치한 로드 밸런서의 IP 주소 혹은 도메인 명을 입력합니다.
--apiserver-cert-extra-sans
옵션은 control-plane
노드가 외부에 위치한 경우(ex, AWS EC2
), 로컬 머신에서 kubernetes 클러스터의 API 서버에 접근하기 위해 필요합니다. 해당 옵션은 SSL 인증서의 SAN에 IP, 도메인 명을 추가로 등록합니다.
$ kubeadm init \
--pod-network-cidr=192.168.0.0/16 \
--control-plane-endpoint=<ec2-ip> \
--apiserver-cert-extra-sans=<ec2-ip> \
...
마스터 노드를 생성 과정에서, 새로운 노드를 추가하기 위한 명령어가 콘솔에 출력됩니다. 해당 명령어는 복사하여 새롭게 추가할 노드에서 실행하면 클러스터에 노드를 추가할 수 있습니다.
# master-node
Your Kubernetes control-plane has initialized successfully!
...
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join <ec2-ip>:6443 --token ... \
--discovery-token-ca-cert-hash sha256:...
---------------------------------------
# worker-node
$ kubeadm join <ec2-ip>:6443 --token ... \
--discovery-token-ca-cert-hash sha256:...
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
###
마스터 노드에서 kubectl get nodes
명령어를 실행하면 새로운 노드가 클러스터에 추가된 것을 확인할 수 있습니다.
이후, 아래의 명령어로 클러스터 어드민 접속 정보를 현재 접속한 계정에서 사용할 수 있도록 ~/.kube/config
경로로 복사합니다.
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
마스터 노드 생성 과정에서 control-plane
이 위치한 EC2 머신의 IP를 SAN에 등록하였기 때문에, 해당 config 파일을 로컬 머신으로 복사하면, 로컬 머신에서도 동일하게 클러스터에 접근할 수 있습니다.
마지막으로 calico
네트워크 플러그인을 설치합니다. :)
$ kubectl apply -f https://projectcalico.docs.tigera.io/manifests/calico.yaml
마스터 노드에서 Pod이 정상적으로 생성되었는지 확인합니다.
$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-566dc76669-xfw8x 1/1 Running 0 2m38s
calico-node-nj75b 1/1 Running 0 2m38s
calico-node-3vjd4 1/1 Running 0 2m38s
coredns-64897985d-6gsgv 1/1 Running 0 8m43s
coredns-64897985d-h7r9x 1/1 Running 0 8m43s
etcd 1/1 Running 7 8m58s
kube-apiserver 1/1 Running 7 8m58s
kube-controller-manager 1/1 Running 5 8m58s
kube-proxy-bqzn4 1/1 Running 0 8m44s
kube-proxy-rif03 1/1 Running 0 4m12s
kube-scheduler 1/1 Running 7 8m58s
이번 포스팅에서는 kubeadm
을 활용하여 kubernetes 클러스터를 설치하는 내용을 다루었습니다. 감사합니다