[Docker&K8S] 2. Centos7에 Docker와 K8S 설치

VM의 리눅스에 도커와 쿠버네티스 환경을 구축해 볼 것이다.

설치환경

name desc
가상머신 VMware Workstation Pro
운영체제 Centos7


K8S 클러스터 구성

클러스터 구성은 아래와 같이 3개 서버를 클러스터링 할 것이다.

효율성을 위하여 서버 하나에 공통세팅을 완료하고 Clone 하는 방법을 택하였다.

hostname ip role
master 192.168.50.133 control-plane node
k8s-worker1 192.168.50.134 worker node
k8s-worker2 192.168.50.135 worker node

설치 방법은 kops, kubeadm, kubespray, GKE, EKS 여러가지가 있다. 그 중 가장 잘 알려져 있는(?) kubeadm으로 구축하는 방법을 알아보자.


1. VM에 Centos7 설치

도커와 쿠버네티스를 공부하기 시작하는 IT 종사자라면 할 수 있을 것이라고 생각하고 자세한 설명은 생략.

VM 세팅

설치를 하며 만난 설치환경 리소스 관련하여 해결한 에러들이다.

1. ERROR NumCPU

설치하다보니 CPU를 1로 잡았더니 아래 에러가 발생했다.

[ERROR NumCPU]: the number of available CPUs 1 is less than the required 2 

kubeadm을 사용하여 인프라 구축을 할 때, 쿠버네티스는 최소 CPU가 2개는 있어야 해 발생하는 문제이다.

물론 kubeadm init --ignore-preflight-errors=NumCPU를 사용하여 해당 에러를 무시할 수 있지만 CPU를 2로 늘려주었다.


2. deployment 0/1(READY) 및 pod pending 현상

쿠버네티스 클러스에 서비스 배포를 하다보니 deployment는 잘 돌아가다가 0/1(READY) 상태이고, pod들은 pending과 terminating 상태로 변경되어 있는 것을 확인하였다.

메모리가 4GB 이하인 인스턴스에서 종종 발생하는 문제이다. 메모리 증설이 답인것 같지만, 필자는 개인 노트북에서 개인공부정도로만 사용하기 때문에 2GB로 세팅하였다.


Docker 및 K8S 설치 전 노드 기본 설정

VM에 Centos7까지 설치가 끝났다.

이제 쿠버네티스 클러스터를 위한 노드 기본 설정을 하나씩 살펴보자.

1) SELinux

SELinux(Security-Enhanced Linux)는 관리자가 시스템 접근 권한을 제어하기 위한 리눅스 커널 보안 모듈이다. enforce, permissive, disable 세 가지 모드로 동작하고 기본적으로 enforce 모드로 동작한다.

쿠버네티스가 Pod 네트워크에 필요한 호스트 파일시스템에 접근하기 위해서 우린 SELinux 를 permissive 모드로 설정해 줄 것이다.

쿠버네티스 설치 관련 문서에서는 다음과 같이 설명해주고 있다.

  • setenforce 0 및 sed … 를 실행하여 permissive 모드로 SELinux를 설정하면 효과적으로 비활성화된다. 컨테이너가 호스트 파일시스템(예를 들어, 파드 네트워크에 필요한)에 접근하도록 허용하는 데 필요하다. kubelet에서 SELinux 지원이 개선될 때까지 이 작업을 수행해야 한다.
  • 구성 방법을 알고 있는 경우 SELinux를 활성화된 상태로 둘 수 있지만 kubeadm에서 지원하지 않는 설정이 필요할 수 있다.
[root@master ~]# vim /etc/sysconfig/selinux

SELINUX=disabledSELINUX=permissive로 변경, 저장 후 서버를 reboot해야 적용된다.

상태 확인 명령어는 sestatus


2) 방화벽 해제

개인 개발환경에서 하는거니 보안이슈는 빠른 쿠버네티스 클러스터 구축을 위해 접어두자.

firewalld 비활성화
[root@master ~]# systemctl stop firewalld && systemctl disable firewalld
NetworkManager 비활성화
[root@master ~]# systemctl stop NetworkManager && systemctl disable NetworkManager


3) SWAP 비활성화

Swap 메모리는 실제 메모리가 부족할 경우 메모리처럼 사용하는 메모리다.

kubelet이 제대로 동작하기 위해서는 아래 명령어로 swap 메모리를 비활성화 시켜주어야 한다.

[root@master ~]# swapoff -a

그리고 /etc/fstab에서 swap과 관련된 문장을 주석처리 해준다.

/etc/fstab은 리눅스 시스템에서 부팅시 자동으로 마운트되는 정보를 저장하고 있다.

[root@master ~]# sed -i '/ swap / s/^/#/' /etc/fstab


4) Iptables 커널 옵션 활성화

iptables는 리눅스에서 방화벽 설정을 도와주는 도구다.

Centos7에서는 net.bridge.bridge-nf-call-iptables의 기본값이 0으로 되어있다. 이것은 bridge 네트워크를 통해 송수신되는 패킷들이 iptables의 설정을 우회하는 것인데, 그래서 사용시 iptables가 무시되어 트래픽이 잘못 라우팅되는 문제가 발생한다고 한다.

따라서, iptables가 bridge 네트워크 트래픽을 제대로 보기 위해서, net.bridge.bridge-nf-call-iptables 값이 1로 되어야 한다는 것이다.

우선, iptables에서 올바른 트래픽을 보기 위해 br_netfilter를 활성화해야 한다. 이 기능이 활성화 되어야 Docker가 default로 사용하는 bridge driver를 사용하여 생성되는 pod끼리의 통신이 가능하다.

lsmod 명령어로 활성화 확인 후, 되어있지 않으면 활성화 해준다.

[root@master ~]# lsmod | grep br_netfilter
[root@master ~]# modprobe br_netfilter
[root@master ~]# lsmod | grep br_netfilter
br_netfilter           22256  0
bridge                151336  1 br_netfilter

아래 명령어로 /etc/sysctl.d/에 쿠버네티스 설정 파일을 추가한다.

(sysctl은 커널이 실행될 때 사용자가 추가해줄 수 있는 선택사항이다.)

[root@master ~]# vim /etc/sysctl.d/k8s.conf

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

다음은 아래 명령어로 커널 매개변수 값을 변경해준다.

[root@master ~]# sysctl --system


5) 쿠버네티스 YUM Repository 설정

쿠버네티스를 설치하기 위한 저장 공간을 만들어 준다.

[root@master ~]# vim /etc/yum.repos.d/kubernetes.repo

[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
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


6) Centos Package Update

yum update

만약 yum update가 안되면 gpg 키 인증때문에 그럴 수 있다. 내 경우, repo 설정에 rep_gpgcheck를 0으로 설정해 주고 진행하였다.


4. Docker와 K8S 설치

도커 설치 전에 필요한 패키지를 설치한다.

[root@master ~]# yum install -y yum-utils device-mapper-persistent-data lvm2

그리고 도커를 설치하기 위한 레퍼지토리를 설정해준다.

[root@master ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

이제 Docker를 설치한다.

[root@master ~]# yum update && yum install docker-ce

K8S를 설치한다.

[root@master ~]# yum install -y --disableexcludes=kubernetes kubeadm kubectl kubelet


K8S 1.24 docker 지원 중단 이슈

k8s 1.24 이후 버전에서는 더이상 Docker를 컨테이너 런타임으로 지원하지 않는다. 하여 containerd 또는 CRI-O와 같은 다른 호환 가능한 컨테이너 런타임 중 하나로 전환해야 한다.

해당 내용은 K8S Container Runtime 전환 방법 를 참고하자.

마스터 노드에서 kubeadm init으로 K8S 클러스터를 시작할 것인데 그냥 해주면 아래 경고가 뜨며 에러가 난다.

[WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd".

linux에는 시스템에 독립 뷰 제공을 가능하게 하는 namespace프로세스의 가용 리소스(cpu, 메모리, 네트워크 등)을 제한할 수 있는 cgroups가 있다. 이 두가지 덕분에 docker와 kubernetes가 가능한 것이다.

위 에러에서 Docker cgroup driver가 cgroupfs인데 systemd 사용을 추천한다고 되어있다.

다음 명령어를 사용하여 cgroup driver를 확인하게 되면 cgroupfs라고 되어있을 것이다.

[root@master ~]# systemctl docker start
[root@master ~]# docker info | grep -i cgroup
Cgroup Driver: cgroupfs

쿠버네티스에서 권장하는 Docker 데몬 드라이버가 systemd라고 하니 Docker 데몬이 사용하는 드라이버를 cgroupfs 대신 systemd를 사용하도록 설정해준다.

[root@master ~]# mkdir /etc/docker
[root@master ~]# vim /etc/docker/daemon.json

{
    "exec-opts": ["native.cgroupdriver=systemd"]
}

[root@master ~]# docker info | grep -i cgroup
Cgroup Driver: systemd


5. VM clone

도커와 K8S 설치가 완료되었다면 원하는 worker node의 개수만큼 VM clone을 해준다. 방법은 VM마다 다르니 생략…


완료되었으면 각 노드들의 hostname 변경 및 등록 작업을 해주어야 한다. 다음 작업들을 하지 않으면 나중에 kubeadm init을 할 때 호스트 이름으로 ip를 찾을 수 없다고 에러가 나거나, 클러스터링 후에 연결 확인시 worker 노드가 연결이 안되어 있을 수 있다.

각 노드들의 hostname을 각 노드 역할에 맞게 구분하여 바꿔준다. hostname 영구 변경 명령어는 아래와 같다.

[root@master ~]# hostnamectl set-hostname <변경 호스트명>

그리고 마스터 노드 1개와 워커노드 2개의 호스트명과 ip를 등록해줘야 한다.

/etc/hosts에 각자 해당하는 노드들의 호스트명과 ip를 추가해준다.

[root@master ~]# vim /etc/hosts

192.168.50.133	master
192.168.50.134	k8s-worker1
192.168.50.135	k8s-worker2


6. Master Node 설정

1) Docker, K8S 실행

[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl enable --now docker
[root@master ~]# systemctl enable --now kubelet

docker는 activating(running) 상태일 것이고, kubelet은 activating(auto-restart) 상태일 것이다. init 후 클러스터링이 완료 되면 kubelet 또한 activating(running) 상태로 바뀔 것이다.


2) K8S 클러스터 구축

kubeadm init을 사용하여 쿠버네티스 클러스터를 빠르게 구축 가능하다.

[root@master ~]# kubeadm init --pod-network-cidr=172.16.0.0/16

위 명령어를 실행하면 “kudeadm join ……” 라는 메세지가 출력된다. worker node에 실행할 명령어이니 잘 복사해준다.


3) 환경변수 설정

다음은 kubectl(K8S를 조작하기 위한 CLI tool)을 실행하기 위한 환경변수를 설정해준다.

이 부분을 해주지 않으면

The connection to the server localhost:8080 was refused - did you specify the right host or port?

와 같은 오류가 나온다. kubeadm init의 결과 메세지로 나오는 문구대로 반드시 해주자.

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

(위 명령어에서 계정이 kubernetes로 바뀌었는데, 신경쓰지 않고 root에서 해도 상관 없다.)


7. Worker Node 설정

1) Docker, K8S 실행

[root@k8s-worker1 ~]# systemctl daemon-reload
[root@k8s-worker1 ~]# systemctl enable --now docker
[root@k8s-worker1 ~]# systemctl enable --now kubelet


2) Node 연결

Master Node에서 kubeadm init으로 나왔던 “kudeadm join ……“를 붙여 놓고 실행한다.

그렇다면 kubectl get nodes 를 통해 Master Node에서 연결 확인하라는 메세지가 마지막에 보일 것이다.


8. Node 연결 여부 확인

아래 명령어의 hostname을 보면 알겠지만 연결 여부 확인은 Master Node에서 해준다.

[kubernetes@master ~]$ kubectl get nodes
NAME          STATUS   ROLES    AGE     VERSION
k8s-worker1   Ready    <none>   4d21h   v1.15.5
k8s-worker2   Ready    <none>   4d21h   v1.15.5
master        Ready    master   4d21h   v1.15.5
[kubernetes@master ~]$ 
[kubernetes@master ~]$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   coredns-5c98db65d4-2rrnj                   1/1     Running   4          4d21h
kube-system   coredns-5c98db65d4-x2qq2                   1/1     Running   4          4d21h
kube-system   etcd-master                                1/1     Running   2          4d21h
kube-system   kube-apiserver-master                      1/1     Running   2          4d21h
kube-system   kube-controller-manager-master             1/1     Running   2          4d21h
kube-system   kube-proxy-4rdg6                           1/1     Running   2          4d21h
kube-system   kube-proxy-vnhrd                           1/1     Running   2          4d21h
kube-system   kube-proxy-wk5dk                           1/1     Running   2          4d21h
kube-system   kube-scheduler-master                      1/1     Running   2          4d21h
kube-system   kubernetes-dashboard-6b8c96cf8c-5mj7m      1/1     Running   2          4d21h

만일 에러없이 여기까지 왔는데, kubectl get nodes에서 master밖에 뜨지 않는다면 각 노드의 hostname이나 /etc/hosts를 확인하기 바란다.

또한 필자는 다 구축을 해놓고 포스트를 작성하기 때문에 status 들이 ready, running이지만, 아마 not ready거나 coredns가 pending 상태일 것이다. 통신 네트워크 연결을 아직 하지 않았기 때문이다.

하지만 통신 여부와 상관 없이 클러스터링으로 정상 구축된 것이다.

다음은 네트워크 통신을 위해 CNI 설정을 해보자.


9. K8S Cluster Network 설정

우선 네트워크 설정을 하기 전 CNI라는 것부터 간단히 알아보자.

1. CNI(Container Network Interface)

1) CNI란?

컨테이너가 발전함에 따라 컨테이너 사이의 네트워크 계층을 구현하는 방식이 다양하게 분리되어 각자만의 방식으로 발전하게 되는 것을 피하기 위해 공통된 인터페이스를 제공할 필요성이 생겼다. 그래서 나온 것이 CNI이다.

CNI(Container Network Interface)란 컨테이너 간의 네트워킹을 제어할 수 있는 플러그인을 만들기 위한 표준이다. 네트워크 인터페이스의 표준으로 사용된다고 보면 될 것 같다.


2) 서드파티 CNI 플러그인

K8S에서도 kubenet이라는 자체 CNI 플러그인을 기본제공한다. 하지만 kubenet 자체로는 컨테이너간의 노드간의 교차 네트워킹조차 지원하지 않는 등 기능이 너무 부족하다.

K8S 클러스터 네트워킹을 정상 동작하게 만들기 위해서 Calico, Cilium, Flannel 등의 다양한 서드파티 CNI 플러그인을 사용한다.

그 중 쿠버네티스의 클러스터 네트워킹 플러그인중 하나의 Calico를 이용하여 K8S 네트워크 설정을 할 것이다.


2. Calico 설치(Master node)

K8S 클러스터 네트워킹 Plug-in 중 하나인 Calico를 Master node에 설치한다.

[kubernetes@master ~]$ curl -O https://docs.projectcalico.org/manifests/calico.yaml
[kubernetes@master ~]$ sed s/192.168.0.0\\/16/172.16.0.0\\/16/g -i calico.yaml
[kubernetes@master ~]$ kubectl apply -f calico.yaml

Calico의 관련 pod의 status가 running이 될 때까지 아래 명령어로 확인한다.(시간 꽤 걸림)

[kubernetes@master ~]$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-75dbcbbf8b-zxg96   1/1     Running   2          4d23h
kube-system   calico-node-bclzs                          1/1     Running   2          4d23h
kube-system   calico-node-dsfhs                          1/1     Running   2          4d23h
kube-system   calico-node-s9fds                          1/1     Running   2          4d23h
kube-system   coredns-5c98db65d4-2rrnj                   1/1     Running   4          4d23h
kube-system   coredns-5c98db65d4-x2qq2                   1/1     Running   4          4d23h
kube-system   etcd-master                                1/1     Running   2          4d23h
kube-system   kube-apiserver-master                      1/1     Running   2          4d23h
kube-system   kube-controller-manager-master             1/1     Running   2          4d23h
kube-system   kube-proxy-4rdg6                           1/1     Running   2          4d23h
kube-system   kube-proxy-vnhrd                           1/1     Running   2          4d23h
kube-system   kube-proxy-wk5dk                           1/1     Running   2          4d23h
kube-system   kube-scheduler-master                      1/1     Running   2          4d23h
kube-system   kubernetes-dashboard-6b8c96cf8c-5mj7m      1/1     Running   2          4d23h

Leave a comment