docker, kubernetes

쿠버네티스 는 버전 v1.20 이후 Docker 에 대해 컨테이너 런타임 으로 사용 중지를 알렸습니다.

GKE 및 EKS 등의 관리 Kubernetes 서비스를 사용하는 경우 오퍼레이터에서 지원되는 버전의 런타임을 사용하는 것을 확인하고 쿠버네티스 릴리스에서 도커 지원이 만료되기 전에 변경 해야합니다. CRI에 지원하는 한 컨테이너 런타임은 cri-o 와 containerd 가 있습니다.

기존 도커 같은 경우 다음과 같이 도커심이라는 구성요소를 사용해 kubernetes와 연결을 지원하였다. 이유는 도커가 컨테이너 런타임 인터페이스인 CRI를 준수하지 않았기 때문이다. 쿠버네티스 v1.23부터는 이 도커심의 지원이 제거된다. 그렇다면 v1.20 부터 Docker로 빌드한 이미지를 사용 불가능할까?

그것은 아니다. docker build 한 이미지는 kubernetes 클러스터에서 계속 실행할 수 있다. 쿠버네티스가 지원하는 다른 컨테이너 런타임인 containerd 와 CRI-O 가 도커 이미지를 가져와 실행하는 법을 알고 있기 때문이다.

쿠버네티스 1.22 이상으로 갈 경우 기존에 이미 서버가 구성되어있고 도커를 계속 사용하고 싶을 때는 containerdKaniko 조합을, 아예 도커를 사용하지 않고 싶을 경우 CRI_Obuildah, Podman, skopeo 조합을 사용하는 것이 좋을 것 같다.

  • 쿠버네티스 사용자 - 평소처럼 YAML 만들고 배포하세요
  • 클라우드 쿠버네티스 서비스 관리자 - 컨테이나 런타임 설치를 클라우드에서 관리하기 때문에 버전 업데이트하면 자동으로 바뀝니다.
  • 자체구축 쿠버네티스 서비스 관리자 - 컨테이너 런타임 변경 또는 Dockershim 설치

Dockershim은 2021년 말에 최종 deprecated 될 예정이지만, Mirantis에서 지원 (opens new window)할 예정입니다.

도커는 여전히 개발용, 이미지 빌드 역할로 많이 사용될 것입니다.

image-20220210144957624

설치 서버: Rocky Linux

[root@localhost ~]# cat /etc/redhat-release Rocky Linux release 8.5 (Green Obsidian)

방화벽 상태: firewall-cmd –state running

docker , 쿠버네티스 설치

쿠버네티스를 설치하기 전에 우선 docker를 설치합니다. Docker 설치 가이드 중 Rocky Linux에 대한 가이드가 없어 Centos 설치 가이드를 참고합니다.

쿠버네티스 설치작업을 수행하는 계정은 root 권한이 있어야합니다.

노드(서버) 호스트네임 설정

# hostnamectl set-hostname kube-node1
# hostname


# hostnamectl set-hostname kube-node2
# hostname
...

#vim /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
xxx.xxx.xxx.xxx kube-node1

기존 버전 삭제(선택)

# sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

저장소 설정

# sudo yum install -y yum-utils
# sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

Docker 엔진 설치

# sudo yum install docker-ce docker-ce-cli containerd.io

Docker 실행

# systemctl start docker && systemctl enable docker

# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2022-02-10 01:26:49 EST; 17s ago
     Docs: https://docs.docker.com
 Main PID: 724829 (dockerd)
    Tasks: 9
   Memory: 33.4M
   CGroup: /system.slice/docker.service
           └─724829 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

$  docker version
Client: Docker Engine - Community
 Version:           20.10.12
 API version:       1.41
 Go version:        go1.16.12
 Git commit:        e91ed57
 Built:             Mon Dec 13 11:45:22 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

iptable설정 & br_netfilter활성화

# cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

# sysctl --system

# lsmod | grep br_netfilter

SWAP 비활성화

쿠버네티스는 Pod를 생성할 때, 필요한 만큼의 리소스를 할당 받아서 사용하는 구조입니다. 따라서 메모리 Swap을 고려하지 않고 설계되었기 때문에, 쿠버네티스 클러스터 Node들은 모두 Swap 메모리를 비활성화 해줘야 합니다.

# swapoff -a
# vim /etc/fstab
해당 파일에서 swap부분을 #으로 주석처리.
#/dev/mapper/rl-swap     none                    swap    defaults        0 0

SELinux 모드 변경

SELinux(Security-Enhanced Linux)는 관리자가 시스템 액세스 권한을 효과적으로 제어할 수 있게 하는리눅스 시스템용 보안 아키텍처이며, permissive로 변경하는 이유는 컨테이너가 호스트 파일시스템에 접근하는 것을 용이하게 하게 위해서 입니다.

# setenforce 0
# sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   permissive
Mode from config file:          permissive
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33

쿠버네티스 Yum Repository 설정

# 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
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

쿠버네티스 설치

최신버전

# sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

특정 버전

# sudo yum install -y kubeadm-1.15.5-0.x86_64 kubectl-1.15.5-0.x86_64 kubelet-1.15.5-0.x86_64 --disableexcludes=kubernetes 
# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:32:1f:7b:5a  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 211.xxx.xxx.xxx  netmask 255.255.255.240  broadcast 211.240.6.15
        inet6 fe80::250:56ff:feb7:38c9  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:b7:38:c9  txqueuelen 1000  (Ethernet)
        RX packets 11617450  bytes 1503153167 (1.3 GiB)
        RX errors 0  dropped 20  overruns 0  frame 0
        TX packets 4499753  bytes 701298057 (668.8 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

업데이트

# yum update -y

방화벽 오픈을 하지 않고 아래 단계를 실행하면 다음과 같은 메시지를 만납니다.

firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly.

# firewall-cmd --permanent --add-port=6443/tcp && sudo firewall-cmd --permanent --add-port=10250/tcp && sudo firewall-cmd --reload

master node 에서sudo kubeadm init --pod-network-cidr=10.244.0.0/16 명령어를 통해 클러스터를 생성할수 있습니다. pod network로 10.244.0.0/16 블록을 사용하는 이유는 이후 설치할 CNI인 Flannel의 기본 pod network 블록이기 때문입니다.

# kubeadm init --pod-network-cidr=10.244.0.0/16 

아래와 같은 오류가 발생하였습니다.

 Unfortunately, an error has occurred:
 timed out waiting for the condition

This error is likely caused by:
- The kubelet is not running
- The kubelet is unhealthy due to a misconfiguration of the node in some way (required cgroups disabled)

If you are on a systemd-powered system, you can try to troubleshoot the error with the following commands:
- 'systemctl status kubelet'
- 'journalctl -xeu kubelet'

Additionally, a control plane component may have crashed or exited when started by the container runtime.
To troubleshoot, list all containers using your preferred container runtimes CLI.

이유는 쿠버네티스 1.22버전부터 Docker를 지원하지 않기 때문에 그런건지… 이와 관련된 쿠버네티스 공식 홈페이지 내용을 참조하세요.

아무튼 해결 방법은 아래와 같이 설정을 하면 됩니다.

# systemctl daemon-reload
# systemctl restart docker
# kubeadm reset
# systemctl restart kubelet
 # kubeadm init --pod-network-cidr=10.244.0.0/16
[init] Using Kubernetes version: v1.23.3
[preflight] Running pre-flight checks
        [WARNING Firewalld]: firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly
        [WARNING FileExisting-tc]: tc not found in system path
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kube-node1 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 211.xxx.xxx.xxx]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [kube-node1 localhost] and IPs [211.xxx.xxx.xxx 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [kube-node1 localhost] and IPs [211.xxx.xxx.xxx 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 5.502493 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.23" in namespace kube-system with the configuration for the kubelets in the cluster
NOTE: The "kubelet-config-1.23" naming of the kubelet ConfigMap is deprecated. Once the UnversionedKubeletConfigMap feature gate graduates to Beta the default name will become just "kubelet-config". Kubeadm upgrade will handle this transition transparently.
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node kube-node1 as control-plane by adding the labels: [node-role.kubernetes.io/master(deprecated) node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node kube-node1 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: pf6aa7.zfxw3l04mivm2siw
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

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 211.xxx.xxx.xxx:6443 --token pf6aa7.zfxw3l04mivm2siw \
        --discovery-token-ca-cert-hash sha256:92ba1947d0d088854526aedcdd5c84a1b3c571b072e7ac73bb162c83c89490ab

kubectl 허용

  • root 사용자일 경우

    # export KUBECONFIG=/etc/kubernetes/admin.conf
    
  • root 사용자가 아닐 경우

    # mkdir -p $HOME/.kube
    # sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    # sudo chown $(id -u):$(id -g) $HOME/.kube/config
    

Flannel 설정

Flannel 은 Kubernetes 요구 사항을 충족하는 매우 간단한 오버레이 네트워크입니다. 많은 사람들이 Flannel과 Kubernetes로 성공했다고 보고했습니다.

# kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

쿠버네티스 설치 확인

# sudo kubectl get nodes
NAME         STATUS   ROLES                  AGE   VERSION
kube-node1   Ready    control-plane,master   26m   v1.23.3

# kubectl get pod --all-namespaces
NAMESPACE     NAME                                 READY   STATUS    RESTARTS        AGE
kube-system   coredns-64897985d-6zxk4              1/1     Running   0               27m
kube-system   coredns-64897985d-fd4jq              1/1     Running   0               27m
kube-system   etcd-kube-node1                      1/1     Running   1               27m
kube-system   kube-apiserver-kube-node1            1/1     Running   1               27m
kube-system   kube-controller-manager-kube-node1   1/1     Running   1               27m
kube-system   kube-flannel-ds-9f4fb                1/1     Running   0               3m38s
kube-system   kube-flannel-ds-amd64-pkwkm          1/1     Running   6 (4m12s ago)   7m16s
kube-system   kube-proxy-vb7qd                     1/1     Running   0               27m
kube-system   kube-scheduler-kube-node1            1/1     Running   1               27m

모든 pod들의 status가 Running이고 Ready가 1/1 이면 클러스터가 정상적으로 구축되었고 master node에서 해야할일은 끝났습니다.

노드 추가

kubeadm init으로 초기화를 할 때 출력된 kubeadm join 명령어를 입력하여 노드서버를 쿠버네티스 클러스터로 결합시킬 수 있다.

# kubeadm join 211.xxx.xxx.xxx:6443 --token pf6aa7.zfxw3l04mivm2siw \
        --discovery-token-ca-cert-hash sha256:92ba1947d0d088854526aedcdd5c84a1b3c571b072e7ac73bb162c83c89490ab

토큰값의 유효기간은 24시간이며 토큰을 재생성하려면 아래와 같이 진행합니다.

# kubeadm token create

토큰 값 확인
# kubeadm token list
TOKEN                     TTL         EXPIRES                USAGES                   DESCRIPTION                                                EXTRA GROUPS
pf6aa7.zfxw3l04mivm2siw   23h         2022-02-11T09:43:23Z   authentication,signing   The default bootstrap token generated by 'kubeadm init'.   system:bootstrappers:kubeadm:default-node-token

sha256 값 확인
# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

92ba1947d0d088854526aedcdd5c84a1b3c571b072e7ac73bb162c83c89490ab

오류 발생

# kubeadm join 211.xxx.xxx.xxx:6443 --token pf6aa7.zfxw3l04mivm2siw \
>         --discovery-token-ca-cert-hash sha256:92ba1947d0d088854526aedcdd5c84a1b3c571b072e7ac73bb162c83c89490ab
[preflight] Running pre-flight checks
        [WARNING FileExisting-tc]: tc not found in system path
error execution phase preflight: [preflight] Some fatal errors occurred:
        [ERROR FileAvailable--etc-kubernetes-kubelet.conf]: /etc/kubernetes/kubelet.conf already exists
        [ERROR Port-10250]: Port 10250 is in use
        [ERROR FileAvailable--etc-kubernetes-pki-ca.crt]: /etc/kubernetes/pki/ca.crt already exists
[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

참고:

https://tommypagy.tistory.com/180

https://docs.docker.com/engine/install/centos/

https://kubernetes.io/ko/docs/tasks/tools/

https://kubernetes.io/ko/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

https://subicura.com/2019/05/19/kubernetes-basic-1.html

쿠버네티스 도커 중단 안내 관련: https://kubernetes.io/blog/2020/12/02/dockershim-faq/