DevOps/Kubernetes

[kubernetes] ubuntu에 kubeadm으로 K8s 설치하기 (cgroup, coredns 해결)

Henu 2022. 4. 5. 23:57

1. Docker 설치

 

[Docker] Ubuntu 도커 설치

Ubuntu와 Docker 이 글에서는 Ubuntu 도커 설치와 관련된 내용을 다룬다. Docker는 리눅스를 기반으로 하기 때문에 리눅스 운영체제 위에서 돌아가야한다. Ubuntu는 Linux계열 운영체제로 바로 설치가 가능

myjamong.tistory.com

위 블로그 따라서 Docker를 먼저 설치한다.

 

 

설치가 끝났다면 docker ps 명령어를 입력해 보자.

 

위와 같은 에러가 날 수 있다.

해당 문제는 사용자가 /var/run/docker.sock 에 접근하려고 했지만 권한이 없어 발생하는 문제로, 사용자가 root:docker 권한을 가지고 있어야 한다.

 

root 권한을 가지고 실행하는 것은 권장되지 않으므로, 사용자를 docker group에 포함시켜주면 된다.
($USER 환경 변수는 현재 로그인한 사용자 아이디를 나타내므로 그대로 입력하면 된다.)

sudo usermod -a -G docker $USER

서버를 reboot 한 후 id를 입력해보자

현재 사용자의 그룹에 docker가 포함되었다. 이제 docker ps 등의 명령어를 사용할 수 있다.

 

 


2. kubeadm 설치

  1. apt 패키지 색인을 업데이트하고, 쿠버네티스 apt 리포지터리를 사용하는 데 필요한 패키지를 설치한다.
  2. sudo apt-get update
    sudo apt-get install -y apt-transport-https ca-certificates curl
    
  3. 구글 클라우드의 공개 사이닝 키를 다운로드 한다.
  4. sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
    
  5. 쿠버네티스 apt 리포지터리를 추가한다.
  6. 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
    
  7. apt 패키지 색인을 업데이트하고, kubelet, kubeadm, kubectl을 설치하고 해당 버전을 고정한다.
  8. sudo apt-get update && 
    
    sudo apt-get install -y kubelet kubeadm kubectl && 
    
    sudo apt-mark hold kubelet kubeadm kubectl

 

 

경고:

컨테이너 런타임과 kubelet의 cgroup 드라이버를 일치시켜야 하며, 그렇지 않으면 kubelet 프로세스에 오류가 발생한다.

 


3. cgroup 드라이버 구성

개념

cgroup이란?

cgroup은 control group의 준말로 컨테이너 생성에 있어서 기초되는 개념이다.
컨테이너가 생성될 때 저수준 런타임 단계에서 linux kernel의 namespace와 cgroup을 이용해서 컨테이너를 만들고 실행시킨다.

 

컨테이너라는 격리된 공간에서 자원을 격리된 것처럼 사용할 수 있는 것이다.

cgroups(Control Groups)는 자원(resources)에 대한 제어를 가능하게 해주는 리눅스 커널의 기능이다.

cgroups는 다음 리소스를 제어할 수 있다.

  • 메모리
  • CPU
  • I/O
  • 네트워크
  • device 노드(/dev/)

 

cgroup 드라이버

Control group은 프로세스에 할당된 리소스를 제한하는데 사용된다.

리눅스 배포판의 init 시스템이 systemd인 경우,

init 프로세스root control group(cgroup)을 생성 및 사용하는 cgroup 관리자로 작동한다.

Systemd는 cgroup과의 긴밀한 통합을 통해 프로세스당 cgroup을 할당한다.

그리고 cgroup 드라이버로 cgroupfs가 존재하는데,

컨테이너 런타임kubelet만이 cgroupfs를 사용하도록 설정할 수 있다.

systemd와 함께 cgroupfs를 사용하면 두 개의 서로 다른 cgroup 관리자가 존재하게 된다는 뜻이다.

 

  • cgroupfs driver
    cgroupfs는 cgroup을 제어하기 위해 만들어진 특수한 file system 방식
  • systemd driver
    systemd 자체가 init process 역할도 하면서, cgroup 또한 제어

 

단일 cgroup 관리자는 할당되는 리소스가 무엇인지를 단순화하고, 기본적으로 사용할 수 있는 리소스와 사용 중인 리소스를 일관성있게 볼 수 있다.

시스템에 두 개의 cgroup 관리자가 있으면, 이런 리소스도 두 개의 관점에서 보게 된다.

그런데 실무에서 kubelet과 도커에 cgroupfs를 사용하고, 나머지 프로세스는 systemd를 사용하도록 노드가 설정된 경우, 리소스가 부족할 때 불안정해지는 사례가 있다고 한다.

 

문제를 해결하기 위해서 컨테이너 런타임과 kubelet의 cgroup 드라이버로 systemd를 선택하도록 설정을 변경하면 시스템을 안정화 할 수 있다.

도커(컨테이너 런타임)에 대해 cgroup을 systemd로 구성하려면, native.cgroupdriver=systemd를 설정한다.

(설정 방법은 아래에.)

 

k8s나 docker를 접하게 되면, cgroup driver를 cgroupfs 또는 systemd로 설정하는 부분을 마주하게 된다.

이 때 cgroup을 systemd로 맞추는 것을 권장하고, 이는 위에서 언급했듯이 시스템을 안정적으로 운영하기 위함이다.

 

 

설정

$ sudo vi /usr/lib/systemd/system/docker.service

 

아래 docker.service 파일에서 

ExecStart=/usr/bin/dockerd --exec-opt native.cgroupdriver=systemd

ExecStart 부분을 위와 같이 바꿔주고 저장한다.

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service containerd.service
Wants=network-online.target
Requires=docker.socket containerd.service

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd --exec-opt native.cgroupdriver=systemd
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always

# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3

# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity

# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes

# kill only the docker process, not all processes in the cgroup
KillMode=process
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target

 

ExecStart 부분을 수정했다면 :wq로 저장하고 나오자.

 

 

아래 명령어를 순서대로 입력한다.

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

$ docker info | grep "Cgroup Driver"
Cgroup Driver: systemd

맨 아래 출력처럼 나온다면 성공이다. 

 


K8s 설치

$ sudo kubeadm init --pod-network-cidr=192.168.0.0/16

...
Your Kubernetes control-plane has initialized successfully!

 

아래 작업을 통해 kubectl 권한을 획득한다.

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

 

kubectl get node, kubectl get all -A

명령어를 입력해서 기본 컴포넌트들이 잘 만들어졌는지 확인한다.

$ kubectl get node
NAME               STATUS   ROLES                  AGE   VERSION
ip-172-31-43-149   Ready    control-plane,master   29s   v1.23.5


$ kubectl get all -A
NAMESPACE     NAME                                           READY   STATUS              RESTARTS   AGE
kube-system   pod/coredns-64897985d-8j9sl                    0/1     ContainerCreating   0          2m31s
kube-system   pod/coredns-64897985d-pt4gh                    0/1     ContainerCreating   0          2m31s
kube-system   pod/etcd-ip-172-31-43-149                      1/1     Running             3          2m36s
kube-system   pod/kube-apiserver-ip-172-31-43-149            1/1     Running             3          2m36s
kube-system   pod/kube-controller-manager-ip-172-31-43-149   1/1     Running             3          2m36s
kube-system   pod/kube-proxy-gjc47                           1/1     Running             0          2m31s
kube-system   pod/kube-scheduler-ip-172-31-43-149            1/1     Running             3          2m36s

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  2m38s
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   2m37s

NAMESPACE     NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/kube-proxy   1         1         1       1            1           kubernetes.io/os=linux   2m36s

NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns   0/2     2            0           2m37s

NAMESPACE     NAME                                DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-64897985d   2         2         0       2m32s

 

coredns ContainerCreating 에러가 발생할 것이다

 

CNI 설정이 제대로 되지 않아서 그런것이므로 

CNI를 calico로 설정해주면 해결할 수 있다.

$ curl https://projectcalico.docs.tigera.io/manifests/calico.yaml -O

$ kubectl apply -f calico.yaml

// master 노드에는 기본적으로 pod가 생성되지 않는데, 제한을 풀어주는 명령어(taint)
$ kubectl taint nodes --all node-role.kubernetes.io/master-

 

설치 완료 확인

$ kubectl get all -A

NAMESPACE          NAME                                           READY   STATUS    RESTARTS   AGE
calico-apiserver   pod/calico-apiserver-8749ccd5-vbmzk            1/1     Running   0          4m5s
calico-apiserver   pod/calico-apiserver-8749ccd5-x7k2w            1/1     Running   0          4m5s
calico-system      pod/calico-kube-controllers-67f85d7449-gwxhm   1/1     Running   0          5m6s
calico-system      pod/calico-node-77xh2                          1/1     Running   0          5m6s
calico-system      pod/calico-typha-5758d546fc-f7vkb              1/1     Running   0          5m6s
kube-system        pod/coredns-64897985d-8sjs2                    1/1     Running   0          5m38s
kube-system        pod/coredns-64897985d-lbg6g                    1/1     Running   0          5m38s
kube-system        pod/etcd-ip-172-31-43-149                      1/1     Running   4          5m49s
kube-system        pod/kube-apiserver-ip-172-31-43-149            1/1     Running   4          5m49s
kube-system        pod/kube-controller-manager-ip-172-31-43-149   1/1     Running   0          5m52s
kube-system        pod/kube-proxy-bmmqx                           1/1     Running   0          5m38s
kube-system        pod/kube-scheduler-ip-172-31-43-149            1/1     Running   4          5m49s
tigera-operator    pod/tigera-operator-b876f5799-mv2lk            1/1     Running   0          5m29s

NAMESPACE          NAME                                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE
calico-apiserver   service/calico-api                        ClusterIP   10.108.215.250   <none>        443/TCP                  4m5s
calico-system      service/calico-kube-controllers-metrics   ClusterIP   10.108.221.232   <none>        9094/TCP                 4m13s
calico-system      service/calico-typha                      ClusterIP   10.110.229.56    <none>        5473/TCP                 5m6s
default            service/kubernetes                        ClusterIP   10.96.0.1        <none>        443/TCP                  5m53s
kube-system        service/kube-dns                          ClusterIP   10.96.0.10       <none>        53/UDP,53/TCP,9153/TCP   5m50s

NAMESPACE       NAME                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
calico-system   daemonset.apps/calico-node   1         1         1       1            1           kubernetes.io/os=linux   5m6s
kube-system     daemonset.apps/kube-proxy    1         1         1       1            1           kubernetes.io/os=linux   5m50s

NAMESPACE          NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
calico-apiserver   deployment.apps/calico-apiserver          2/2     2            2           4m5s
calico-system      deployment.apps/calico-kube-controllers   1/1     1            1           5m6s
calico-system      deployment.apps/calico-typha              1/1     1            1           5m6s
kube-system        deployment.apps/coredns                   2/2     2            2           5m50s
tigera-operator    deployment.apps/tigera-operator           1/1     1            1           5m29s

NAMESPACE          NAME                                                 DESIRED   CURRENT   READY   AGE
calico-apiserver   replicaset.apps/calico-apiserver-8749ccd5            2         2         2       4m5s
calico-system      replicaset.apps/calico-kube-controllers-67f85d7449   1         1         1       5m6s
calico-system      replicaset.apps/calico-typha-5758d546fc              1         1         1       5m6s
kube-system        replicaset.apps/coredns-64897985d                    2         2         2       5m38s
tigera-operator    replicaset.apps/tigera-operator-b876f5799            1         1         1       5m29s

 

 


레퍼런스

 

Installing kubeadm

This page shows how to install the kubeadm toolbox. For information on how to create a cluster with kubeadm once you have performed this installation process, see the Using kubeadm to Create a Cluster page. Before you begin A compatible Linux host. The Kub

kubernetes.io

 

 

Creating a cluster with kubeadm

Using kubeadm, you can create a minimum viable Kubernetes cluster that conforms to best practices. In fact, you can use kubeadm to set up a cluster that will pass the Kubernetes Conformance tests. kubeadm also supports other cluster lifecycle functions, su

kubernetes.io

 

 

kubenetes설치 실패 시 초기화방법

k8s을 설치하고 재 설치 시 전에 있던 데이터가 남아 있어서 문제가 생긴다. $ kubeadm init 필자의 경우 위 명령어가 time out으로 계속 실패하여 원인을 찾는데 많은 시간을 소비했다. 아래 명령어를

likefree.tistory.com

 

 

Quickstart for Calico on Kubernetes

Install Calico on a single-host Kubernetes cluster for testing or development in under 15 minutes.

projectcalico.docs.tigera.io