AmazonLinux2에 EC2에 쿠버네티스 설치하기.
AWS EC2에 Kubernetes를 설치하는 방법에 대해 설명합니다.
OS는 AmazonLinux2을 사용합니다.
(AmazonLinux2023은 Kubernetes Cluster 설치가 안되더군요. 버그인지는 모르겠지만... 8시간 삽질하다가 포기했습니다....)
1. Docker 설치
Kubernetes는 CRI(Container runtime interfaece)가 있어야 컨테이너를 실행시키고 관리할 수 있게 됩니다.
2023년 기준 docker내부에서는 containerd 라는 CRI를 사용하고 있고, docker를 설치하면 containerd를 쿠버네티스가 사용할 수 있게됩니다.
하지만 docker자체를 설치하는 것만으로도 오버헤드를 줄 수 있지만, 여기선 간단하게 구성하는 것을 목표로 하기 때문에 ,
별다른 설정 없이 docker만 설치하도록 합니다.
sudo yum -y install docker
sudo systemctl start docker
2. kubelet, kubeadm, kubectl 설치
위 Service들은 다음과 같은 기능을 가지고 있습니다.
- kubelet: 쿠버네티스 노드의 주요 프로세스로, 각 노드에서 실행되며 쿠버네티스 API 서버와 통신합니다. kubelet은 PodSpecs를 받아 컨테이너가 올바르게 동작하는지 확인하고, 노드의 상태를 주기적으로 업데이트합니다.
(systemctl status kubelet 으로 상태를 확인할 수 있습니다.) - kubeadm: 쿠버네티스 클러스터를 쉽게 설치하고 구성할 수 있게 도와주는 도구입니다. kubeadm을 사용하면 클러스터를 초기화하거나, 노드를 클러스터에 추가하거나, 클러스터 설정을 업그레이드하는 등의 작업을 수행할 수 있습니다.
(비슷한 것으로 kops, Kubespray가 있습니다.) - kubectl: 쿠버네티스 클러스터를 제어하기 위한 커맨드 라인 인터페이스(CLI) 도구입니다. kubectl을 통해 클러스터의 상태를 조회하거나, 쿠버네티스 리소스를 생성, 수정, 삭제하는 등의 작업을 수행할 수 있습니다.
AmazonLinux2에는 Kubernetes를 설치할 repo가 리스트에 없기 때문에 yum repo를 만들어줘야 합니다.
그 후 k8s관련된 패키지를 설치해줍니다.
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
# Set SELinux in permissive mode (effectively disabling it)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable --now kubelet
설치가 다 완료되면, 부가적인 셋팅을 해줍니다.
sudo swapoff -a
sudo yum install -y iproute-tc
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
- sudo swapoff -a: 이 명령은 Linux 시스템에서 스왑을 비활성화합니다. 쿠버네티스는 노드에서 스왑이 비활성화되어 있는 것을 요구합니다. 그 이유는, 스왑이 활성화된 상태에서는 쿠버네티스의 스케줄러가 노드의 메모리 사용량을 정확히 파악할 수 없기 때문입니다. 즉, 노드의 메모리 부족 상황을 미리 예측하고 대응하기 어렵습니다.
※ 스왑(swap)은 리눅스 시스템에서 물리적인 메모리(RAM)가 부족할 때 사용되는 추가적인 메모리 영역입니다. 이는 하드 디스크의 특정 부분을 RAM처럼 사용하는 것을 말합니다.그러나 스왑 메모리는 하드 디스크에 위치해 있으므로 물리적인 RAM보다 속도가 훨씬 느립니다. 리눅스 시스템은 메모리 사용량이 많아져서 물리적인 RAM이 충분하지 않을 때, 잘 사용되지 않는 메모리 페이지를 스왑 공간으로 이동시킵니다. 이를 페이징(paging)이라고 하며, 이를 통해 물리 메모리를 더 효율적으로 사용할 수 있습니다.
쿠버네티스는 노드의 메모리 사용량을 정확히 파악하고 메모리 리소스를 효율적으로 관리하기 위해 스왑을 비활성화하는 것을 권장합니다. 스왑이 활성화된 상태에서는 메모리 사용량을 정확히 추적하거나 예측하기 어렵기 때문입니다. - sudo yum install -y iproute-tc: 이 명령은 iproute-tc 패키지를 설치하는 것으로, 이 패키지는 Linux 네트워킹 툴인 tc를 포함하고 있습니다. tc는 트래픽 제어나 네트워크 리소스 할당 등을 수행할 수 있게 해줍니다. 쿠버네티스에서는 이 도구를 사용하여 네트워크 트래픽을 제어하고, 파드간의 통신을 관리합니다.
많은 네트워크 플러그인은 해당 패키지를 사용하고 있습니다. 해당 패키지 없이 일부는 잘 동작할 순 있으나, 일부는 제대로 동작을 안할 수 있습니다. 때문에 kubeadm을 init할 때 다음과 같은 경고 문을 띄워줍니다.
[preflight] Running pre-flight checks
[WARNING FileExisting-tc]: tc not found in system path
- overlay와 br_netfilter 모듈 로딩: 이 두 모듈은 Docker와 쿠버네티스에서 사용되는 컨테이너 네트워킹에 필요합니다. overlay는 Docker의 overlay 네트워크를 사용하기 위한 커널 모듈입니다. br_netfilter는 Linux의 브리지 네트워킹을 사용하는데 필요한 모듈로, 브리지 네트워크 트래픽에 대한 iptables 규칙을 활성화합니다.
- overlay 커널 모듈: containerd가 오버레이 파일 시스템을 사용할 경우 이 모듈이 필요합니다.
- br_netfilter 커널 모듈: 쿠버네티스의 네트워크 정책 기능을 사용하려면 이 모듈이 필요합니다. calico는 이 네트워크 정책 기능을 사용하여 트래픽 제어를 수행합니다.
- sysctl 설정: 이 설정들은 쿠버네티스가 정상적으로 네트워킹을 수행하기 위해 필요합니다. net.bridge.bridge-nf-call-iptables와 net.bridge.bridge-nf-call-ip6tables는 브리지 네트워크 트래픽에 대한 iptables/IP6tables 규칙을 활성화하는 것을 허용합니다. net.ipv4.ip_forward는 IPv4 트래픽 포워딩을 활성화합니다. 이러한 설정이 없으면, 포드 간의 통신이나 서비스로의 트래픽 라우팅 등이 제대로 작동하지 않을 수 있습니다.
이제 클러스터를 초기화 시켜 줍니다.
sudo kubeadm init --pod-network-cidr=192.168.0.0/16
// 사양이 안된다면 다음과 같은 옵션을 줍니다.
sudo kubeadm init --pod-network-cidr=192.168.0.0/16 --ignore-preflight-errors=NumCPU,Mem
※ 다음과 같은 오류가 나올 수 있습니다.
[root@ip-172-31-33-187 ec2-user]# sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --ignore-preflight-errors=NumCPU,Mem
[init] Using Kubernetes version: v1.27.3
[preflight] Running pre-flight checks
[WARNING NumCPU]: the number of available CPUs 1 is less than the required 2
[WARNING Mem]: the system RAM (949 MB) is less than the minimum 1700 MB
[WARNING FileExisting-tc]: tc not found in system path
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR CRI]: container runtime is not running: output: E0617 11:58:38.182317 25650 remote_runtime.go:616] "Status from runtime service failed" err="rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing dial unix /var/run/containerd/containerd.sock: connect: no such file or directory\""
time="2023-06-17T11:58:38Z" level=fatal msg="getting status of runtime: rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing dial unix /var/run/containerd/containerd.sock: connect: no such file or directory\""
, error: exit status 1
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables does not exist
[ERROR FileContent--proc-sys-net-ipv4-ip_forward]: /proc/sys/net/ipv4/ip_forward contents are not set to 1
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher
[root@ip-172-31-33-187 ec2-user]#
- [ERROR CRI]: 이 오류는 Container Runtime Interface (CRI)가 실행되고 있지 않다는 것을 나타냅니다. 쿠버네티스는 도커, containerd, CRI-O 등의 CRI를 사용하여 컨테이너를 관리하므로 이 중 하나가 실행되고 있어야 합니다. 보통 도커가 기본값으로 설정되어 있습니다. 만약 도커가 설치되어 있다면 sudo systemctl start docker을 실행하여 도커 서비스를 시작할 수 있습니다. 아니면 containerd나 CRI-O를 설치하고 설정해야 합니다.
- [ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: 이 오류는 Linux 커널의 iptables 설정과 관련되어 있습니다. /proc/sys/net/bridge/bridge-nf-call-iptables가 존재하지 않는 것은 iptables가 제대로 설정되지 않았음을 나타냅니다. 이 파일은 iptables를 통해 브리지 네트워크 트래픽을 제어하는데 필요합니다. 이 파일을 만들기 위해 sudo modprobe br_netfilter를 실행하고, 다음 명령을 실행하여 해당 파일의 값을 1로 설정할 수 있습니다: echo 1 | sudo tee /proc/sys/net/bridge/bridge-nf-call-iptables.
- [ERROR FileContent--proc-sys-net-ipv4-ip_forward]: 이 오류는 IP 포워딩이 활성화되지 않았음을 나타냅니다. /proc/sys/net/ipv4/ip_forward 파일의 값이 1이 아닌 것으로 보입니다. IP 포워딩은 패킷을 적절한 네트워크 인터페이스로 전달하는데 필요합니다. 다음 명령을 실행하여 IP 포워딩을 활성화할 수 있습니다: echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward.
명령어가 성공적으로 실행 되었다면 다음과 같은 Log가 보여집니다.
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 172.31.33.187:6443 --token 7r0qj7.s76ajw402k8o8nlx \
--discovery-token-ca-cert-hash sha256:66e1040459f140e3cd61f357cb84449d948b5cd03f08ab7ba3c8fb68a3957c5c
로컬 사용자에 대한 설정파일을 생성해줍니다.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
※ 만약 root 유저로 실행하고 있다면 export명령어를 사용해 줍니다.
export KUBECONFIG=/etc/kubernetes/admin.conf
1~2 분정도 기다린 후 다음 명령어를 하면 아래와 같이 나올겁니다.
[ec2-user@ip-172-31-62-120 ~]$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-5d78c9869d-ksdrs 0/1 Pending 0 3m14s
kube-system coredns-5d78c9869d-lf684 0/1 Pending 0 3m14s
kube-system etcd-ip-172-31-62-120.ap-northeast-2.compute.internal 1/1 Running 0 3m29s
kube-system kube-apiserver-ip-172-31-62-120.ap-northeast-2.compute.internal 1/1 Running 0 3m29s
kube-system kube-controller-manager-ip-172-31-62-120.ap-northeast-2.compute.internal 1/1 Running 0 3m31s
kube-system kube-proxy-wjmlw 1/1 Running 0 3m14s
kube-system kube-scheduler-ip-172-31-62-120.ap-northeast-2.compute.internal 1/1 Running 0 3m29s
3. 네트워크 플러그인 설치
Kubernetes를 사용하려면 네트워크 플러그인을 설치해야 합니다.
설치를 하지 않으면 파드간 통신, 노드간 통신, 클러스터간 통신 등을 직접 설정하고 구현해야 합니다.
네트워크 플러그인을 설치하면 다음과 같은 혜택이 있습니다.
- 파드 간 통신: 쿠버네티스 클러스터에서 동작하는 모든 파드는 서로 통신할 수 있어야 합니다. 네트워크 플러그인은 이를 가능하게 합니다.
- 서비스 통신: 서비스는 파드 그룹에 대한 안정적인 네트워크 인터페이스를 제공합니다. 네트워크 플러그인은 이 서비스 네트워크를 구현합니다.
- 네트워크 정책: 네트워크 플러그인은 파드 간, 서비스 간의 네트워크 트래픽을 제어하는 네트워크 정책을 구현하는데 사용될 수 있습니다.
- 네트워크 격리: 일부 네트워크 플러그인은 네트워크 네임스페이스를 제공하여 파드 그룹 간의 네트워크 트래픽을 격리시킬 수 있습니다.
- 클러스터 외부 연결: 쿠버네티스 클러스터와 외부 네트워크 간의 연결을 관리합니다. 이는 LoadBalancer 타입의 서비스나 Ingress 컨트롤러 등을 통해 구현됩니다.
네트워크 플러그인 다음과 같은 것들이 있습니다.
- Calico: Calico는 네트워크 정책 enforcement와 IP 라우팅을 제공하는 네트워크 플러그인입니다. 이 플러그인은 간단하고 확장성이 높으며, 네트워크 정책을 통해 뛰어난 보안을 제공합니다. 그러나 Calico의 BGP 기반 라우팅은 일부 사용자에게는 복잡하게 느껴질 수 있습니다.
- Weave: Weave는 오버레이 네트워크를 제공하는 플러그인으로, 클러스터 간 또는 클라우드 제공자 간의 네트워크 연결을 간단하게 만들어 줍니다. 이 플러그인은 설치와 사용이 간편하지만, 오버레이 네트워크는 네트워크 성능에 약간의 오버헤드를 추가할 수 있습니다.
- Flannel: Flannel은 간단하고 쉽게 사용할 수 있는 오버레이 네트워크 플러그인입니다. 이 플러그인은 다양한 백엔드를 지원하며, 쿠버네티스 클러스터를 빠르게 설정할 수 있게 해줍니다. 그러나 Flannel은 네트워크 정책을 지원하지 않으며, 오버레이 네트워크는 네트워크 성능에 약간의 오버헤드를 추가할 수 있습니다.
- Cilium: Cilium은 BPF (Berkeley Packet Filter)를 기반으로 하여 높은 네트워크 성능과 보안을 제공하는 네트워크 플러그인입니다. 이 플러그인은 세밀한 네트워크 정책을 지원하며, 서비스 메시와의 통합도 제공합니다. 그러나 BPF는 새로운 기술이므로 일부 사용자에게는 복잡하게 느껴질 수 있습니다.
- Amazon VPC CNI: Amazon VPC CNI는 AWS 환경에서의 쿠버네티스 클러스터에 사용되는 플러그인입니다. 이 플러그인은 각 파드에 Amazon VPC IP를 할당함으로써 네트워크 오버헤드를 줄이고 보안을 강화하는데 초점을 맞춥니다. AWS 환경에서는 높은 성능과 통합을 제공하지만, AWS 외부에서는 사용할 수 없습니다.
- Azure CNI: Azure CNI는 Azure 환경에서 사용되는 네트워크 플러그인으로, 각 파드에 Azure VNet IP를 할당합니다. 이로 인해 Azure 리소스와의 네트워크 통신이 단순화되고 성능이 향상됩니다. 그러나 이 플러그인은 Azure 환경에서만 사용할 수 있습니다.
※ 여기서 말하는 Overlay Network는 가상의 네트워크를 말합니다.
Overlay Network에는 비구조화, 구조화 Overlay가 있습니다.
비구조화는 비트코인, 이더리움같은 네트워크 구조를 말하며, 구조화는 일반적인 라우터 네트워크 구조를 생각하면 됩니다.
저는 calico를 선택해서 설치하도록 하겠습니다.
(calico를 선택한 이유는 대중적이기도 하고, 많은 것들을 제공하며, 유연성이 크기 때문입니다.)
2023 기준의 k8s cni benchmark 를 찾으려 해봤지만 없네요...
다음 명령어를 차례대로 실행해 줍니다.
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml
1~2 분 정도 기다리면 아래와 같이 출력 될 겁니다.
[ec2-user@ip-172-31-62-120 ~]$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
calico-apiserver calico-apiserver-6ddbcb8d96-9smtw 1/1 Running 0 24s
calico-apiserver calico-apiserver-6ddbcb8d96-gp6gh 1/1 Running 0 24s
calico-system calico-kube-controllers-66d6db7b56-m57zq 1/1 Running 0 83s
calico-system calico-node-fmmbg 1/1 Running 0 83s
calico-system calico-typha-84dd558ccc-klrsn 1/1 Running 0 84s
calico-system csi-node-driver-4mmbq 2/2 Running 0 83s
kube-system coredns-5d78c9869d-ksdrs 1/1 Running 0 29m
kube-system coredns-5d78c9869d-lf684 1/1 Running 0 29m
kube-system etcd-ip-172-31-62-120.ap-northeast-2.compute.internal 1/1 Running 0 29m
kube-system kube-apiserver-ip-172-31-62-120.ap-northeast-2.compute.internal 1/1 Running 0 29m
kube-system kube-controller-manager-ip-172-31-62-120.ap-northeast-2.compute.internal 1/1 Running 0 29m
kube-system kube-proxy-wjmlw 1/1 Running 0 29m
kube-system kube-scheduler-ip-172-31-62-120.ap-northeast-2.compute.internal 1/1 Running 0 29m
tigera-operator tigera-operator-5f4668786-sdg4m
※ calico quick start 문서에 보면 다음 명령어를 실행하라고 나옵니다.
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
kubectl taint nodes --all node-role.kubernetes.io/master-
해당 명령어는 마스터 노드도 스케쥴링 하겠다라는 명령어 입니다.
다시 말해서 마스터 노드에 어플리케이션 파드를 띄워서 사용하겠다는 뜻입니다.
하지만 저는 마스터 노드에 어플리케이션 파드를 띄우진 않을 것이기 때문에 사용하지 않겠습니다.
이렇게 하면 k8s를 통해 기본적인 셋팅이 모두 끝났습니다.
이제 새로운 ec2를 띄워서 위와 비슷한 설치를 한 후 아래 명령어를 실행해주면, 마스터 노드에 해당 워커 노드가 포함되게 됩니다.
kubeadm join 172.31.33.187:6443 --token 7r0qj7.s76ajw402k8o8nlx \
--discovery-token-ca-cert-hash sha256:66e1040459f140e3cd61f357cb84449d948b5cd03f08ab7ba3c8fb68a3957c5c
Reference
https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart
https://kubernetes.io/ko/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
https://kubernetes.io/ko/docs/setup/production-environment/container-runtimes