외부접속이 안되는 폐쇄망에서 Kubernetes 클러스터 구성해야하는 작업이 생겨서 이를 위한 테스트를 진행하였습니다. 이를 위한 과정을 기록합니다. 이를 위해 EC2를 사용하여 클러스터를 구성하고 폐쇠망 환경을 구현하기 위해 아웃바운드 정책으로 80, 443를 제외하였습니다. 전체적인 설치 과정을 다음과 같습니다.
- Docker 설치
- Kube-system 에 설치 되는 파드 이미지 load
- Kubeadm, Kubelet, Kubctl 설치
- 마스터 노드 join
- 워커 노드 Join
설치 환경은 다음과 같습니다.
- sudo 권한을 가진 Non-root user
- OS rhel 7.9
- offline 환경
- master 3대 worker 3대
- kubernetes v1.21.9
클러스터 구성을 위해 열어줘야 하는 포트는 다음과 같습니다.
- 6443 - api-server
- 2379 - etcd
- 2380 - etcd
- 4443 - metric-server
- 179 -calico
- 10250 - kubelet API
외부 접속이 안되기 때문에 docker, kubelet 과 같은 설치 패키지를 따로 압축 파일로 가져가는데 Online 환경에서는 이러한 과정 없이 yum repository 설정을 통해 다운받으면 됩니다. 도커 이미지 또한 docker hub와 직접 통신이 안되기 때문에 실제 Kube-system 네임스페이스에 생성되는 파드들이 사용하는 이미지를 전부 다운받았습니다.
1. Docker 설치
도커 설치는 docker-ce, docker-ce-cli, container.io 를 설치해야하는데 이를 설치하기 위한 디펜던시가 필요합니다. 전체 설치를 위한 rpm 리스트는 다음과 같습니다.
conntrack-tools-1.4.4-7.el7.x86_64.rpm
container-selinux-2.107-1.el7_6.noarch.rpm
containerd.io-1.5.11-3.1.el7.x86_64.rpm
docker-ce-20.10.14-3.el7.x86_64.rpm
docker-ce-cli-20.10.14-3.el7.x86_64.rpm
docker-ce-rootless-extras-20.10.14-3.el7.x86_64.rpm
docker-scan-plugin-0.17.0-3.el7.x86_64.rpm
fuse-overlayfs-0.7.2-6.el7_8.x86_64.rpm
fuse3-libs-3.6.1-4.el7.x86_64.rpm
libnetfilter_cthelper-1.0.0-11.el7.x86_64.rpm
libnetfilter_cttimeout-1.0.0-7.el7.x86_64.rpm
libnetfilter_queue-1.0.2-2.el7_2.x86_64.rpm
slirp4netns-0.4.3-4.el7_8.x86_64.rpm
socat-1.7.3.2-2.el7.x86_64.rpm
다음과 같이 설치 한후 서비스에 등록해 도커를 실행합니다. 또한 해당 유저가 sudo없이 사용할 수 있도록 docker group에 추가합니다.
sudo systemctl enable docker
sudo systemctl start docker
sudo usermod -aG docker $USER
이후 SSH 재접속후 docker 명령어 입력시 정상적으로 실행되는 것을 확인 할 수 있습니다.
2. 도커 이미지 추가
쿠버네티스 클러스터를 구성하기 위해 Kube-system에서 파드가 생성됩니다. 인터넷 접속이 가능한 환경에서는 이를 이미지를 외부에서 다운받아 사용하지만 외부 접속이 가능하지 않기 때문에 이를 위한 이미지를 local repository에 올려 다운받지 않도록 합니다.
docker.io/calico/kube-controllers:v3.21.4
docker.io/calico/node:v3.21.4
k8s.gcr.io/coredns/coredns:v1.8.0
k8s.gcr.io/etcd:3.4.13-0
k8s.gcr.io/kube-apiserver:v1.21.9
k8s.gcr.io/kube-controller-manager:v1.21.9
k8s.gcr.io/kube-proxy:v1.21.9
k8s.gcr.io/kube-scheduler:v1.21.9
k8s.gcr.io/metrics-server/metrics-server:v0.6.1
클러스터 버전에 맞는 이미지를 다운받아 docker load 명령어를 통해 올렸습니다.
3. kubelet. kubeadm, kubectl 설치
홈페이지를 참조해 v1.21.9 설치를 위한 kubelet.service, kubeadm,kubectl 파일을 다운받습니다. 클라이언트와 서버의 버전은 달라도 실행이 가능하지만 맞추는것을 권장하기 때문에 모두 1.21.9로 설치하였습니다. 해당 파일을 다음과 같이 설정합니다.
sudo mv ./k8s-packages/kubelet.service /etc/systemd/system/kubelet.service
sudo mkdir -p /etc/systemd/system/kubelet.service.d/
sudo mv k8s-packages/10-kubeadm.conf /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
sudo install -o root -g root -m 0755 k8s-packages/kubectl /usr/bin/kubectl
sudo install -o root -g root -m 0755 k8s-packages/kubeadm /usr/bin/kubeadm
sudo install -o root -g root -m 0755 k8s-packages/kubelet /usr/bin/kubelet
sudo systemctl daemon-reload
sudo systemctl enable --now kubelet
실행이 완료된 후 kubelet status를 확인하면 서비스가 등록되었지만 클러스터가 구성되지 않았기 때문에 제대로 실행된 것으로는 보이지 않습니다.
4. 추가 설정
이후 Kubelet init으로 클러스터 구성 시 발생하는 이슈를 제거하기 위해 docker 설정을 변경하고 추가적으로 필요한 kubernetes config를 수정합니다.
echo "--------------------------------------------------------------------"
echo "swap off"
echo "--------------------------------------------------------------------"
swapoff -a && sed -i '/swap/s/^/#/' /etc/fstab
echo "--------------------------------------------------------------------"
echo "add daemon.json config"
echo "--------------------------------------------------------------------"
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 daemon-reload
sudo systemctl restart docker
sudo systemctl enable docker
echo "--------------------------------------------------------------------"
echo "add k8s config"
echo "--------------------------------------------------------------------"
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system
멀티 마스터 구조이기 때문에 이 과정을 쉘 파일로 만들어 다른 Master2, Master3 에서 실행하였습니다.
5. Master 설정
`kubeadm init --control-plane-endpoint “[master1 IP]:6443" --upload-certs`
리더 마스터에서 위의 명령어를 실행해 클러스터를 구성합니다.
결과로 나온 내용을 복사해 다른 Master에서 실행합니다. 위의 내용은 아래 커맨드를 통해서도 확인 해 조합하여 사용할 수 도 있습니다.
#join command 출력
kubeadm token create --print-join-command
# Certificate key 출력
kubeadm init phase upload-certs --upload-certs
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
join이 완료되면 다음과 같이 control plane으로 노드가 추가된 것을 확인 할 수 있습니다.
6. Worker 설정
마스터와 동일하게 docker 설치등을 진행하지만 kubectl을 설치할 필요는 없기 때문에 해당 부분만 제외하고 동일하게 실행합니다. 이미지도 master와 다르게 사용하지 않는 것도 있지만 큰 문제가 되지 않기 떄문에 동일하게 실행하였습니다.
설치 후 위의 join 커맨드에서 control-plain 파라미터를 제외하여 실행합니다. 이후 노드들이 클러스터에 조인 된 것을 확인 할 수 있습니다.
하지만 노드의 상태가 NotReady 이고, Kube-system의 파드를 보면 coredns 파드가 Pending 상태인 것을 볼 수 있습니다. 이를 해결하기 위해 CNI를 설치합니다. 저는 Calico를 설치하고 이를 위한 yaml
파일을 다운받아 적용하였습니다. calico 파드가 생성되면 Node는 Ready상태가 됩니다.
'Kubernetes' 카테고리의 다른 글
Kubernetes에서 학습용 Job 생성하기 (0) | 2023.10.12 |
---|---|
Kubeflow JupyterNoteBook (0) | 2023.10.12 |
Kubernetes CI/CD 구축(Jenkins,Nexus) (0) | 2023.10.12 |
Kubeflow V1.4 설치 및 초기 설정(User 추가, CORS, dex DB 분리) (0) | 2023.10.12 |
Kubernetes API server OOM 장애기록 (0) | 2023.10.12 |