Install Kubernetes on CentOS/RHEL

1. Overview

이번 문서에서는 Kubernetes(k8s)를 centos위에서 구성해보도록 하겠습니다.

2. Prerequisites

본문에서 사용한 spec :
OS : CentOS v7.6
Arch : x86

k8s클러스터는 1마스터 2노드로 구성하겠습니다.

Master : 4cpu, ram16G
Node : 2cpu, ram4G

3. Steps

(M,N) : Master와 Node 전부 적용

3.1 Set Hostname on Nodes (M,N)

각 Master, Node들마다 자신의 hostname을 결정해줍니다.

$ hostnamectl set-hostname {호스트이름}

그 다음, 결정한 이름을 각 노드의 hosts파일에 ip와 함께 기재해줍니다.

$ vim /etc/hosts

# kubernetes cluster
x.x.x.x kube-m
x.x.x.x kube-n01
x.x.x.x kube-n02

3.2 Install Docker (M,N)

k8s클러스터를 구성하기 위해서는 도커가 필요합니다. 전체 노드에 도커를 설치해줍니다.
도커가 이미 깔려있는 상태라면 다음단계로 넘어가주세요.

# Docker 설치
$ yum install -y yum-utils device-mapper-persistent-data lvm2
$ yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ yum install docker-ce
$ systemctl start docker && systemctl enable docker

3.3 Configure Firewall (M,N)

방화벽을 끄지 않고 마스터와 노드의 포트를 설정할수는 있지만, 이번 문서에서는 그냥 방화벽을 끄고 진행하겠습니다.

# firewalld 비활성화
$ systemctl stop firewalld
$ systemctl disable firewalld
$ systemctl status firewalld

image

3.4 Update Iptables Settings (M,N)

iptable 설정을 해줍니다.

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

$ sysctl --system

net.bridge.bridge-nf-call-iptables = 1 의 의미 :

centOS와 같은 리눅스 배포판은 net.bridge.bridge-nf-call-iptables의 default값이 0이다.
이는 bridge 네트워크를 통해 송수신 되는 패킷이 iptable 설정을 우회한다는 의미.
하지만 컨테이너의 네트워크 패킷이 호스트머신의 iptable 설정에 따라 제어되도록 하는 것이 바람직하며, 이를 위해서는 값을 1로 설정해야한다.

image

3.5 Disable SELinux (M,N)

SELinux는 Linux의 보안을 강화해주는 보안 커널이며, application의 취약점으로 인한 해킹을 방지해주는 핵심 구성 요소입니다.

총 세가지 모드가 있습니다.

  • enforce (Default) : SELinux의 rule에 어긋나는 operation은 거부
  • permissive : rule에 어긋나는 동작이 있을 경우 audit log를 남기고 operation은 허용
  • disable : 제한없음

production서버일 경우 SELinux를 끄기 보다는 서비스가 SELinux하에서 잘 동작하도록 하는것이 바람직하며, 개발서버일 경우 Permissive모드로 진행하다가 추후에 enforce모드로 전환하는것이 편합니다.

그래서 편의를 위해 이 문서에서는 Permissive모드로 진행하도록 하겠습니다.

$ setenforce 0
$ sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

3.6 Disable SWAP (M,N)

다음으로, kubelet이 제대로 동작하기 위해 SWAP을 disable시켜줍니다.

$ swapoff -a
$ vim /etc/fstab
# 아래 부분을 찾아서 주석처리 해줍니다. 
# LABEL=SWAP-xvdb1 swap swap defaults    0 0

$ reboot

image

3.7 Kubernetes Repo 추가 (M,N)

$ cat <<EOF > /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
EOF

3.8 kubelet, kubeadm, kubectl 설치 (M,N)

$ yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
$ systemctl enable kubelet && systemctl start kubelet

3.9 Master 초기화 (M)

다음명령어를 사용하여 마스터를 초기화시킵니다.

--pod-network-cidr 옵션은 Container Network Interface으로 어떤걸 사용할지에따라 달라집니다.

Container Network Interface(CNI)?
컨테이너 런타임과 컨테이너 네트워크 사이의 표준 API
image

이 문서에서는 CNI로 calico를 사용하기로 하고, 다른 CNI들을 사용하려면 다음 링크를 참조하여 작성하시면 됩니다.

Kubernetes : Installing a pod network add-on

# CNI는 calico사용 (192.168.0.0/16)
$ kubeadm init --pod-network-cidr=192.168.0.0/16 --apiserver-advertise-address={ip address}

위 명령어를 실행해 마스터를 초기화시키고나면 성공적으로 초기화 시켰다는 로그와 함께 노드가 마스터에 join할 수 있게 하는 커맨드가 뜨게 됩니다.

다음 커맨드와 유사한 메세지가 뜰테니 어딘가에 복사해둡시다.

kubeadm join x.x.x.x:6443 --token b0em0n.b8v9b760cmz8nmty \
    --discovery-token-ca-cert-hash sha256:dd5ae0bb6c4f6e7aff5f8ac34d63383d50e1f374a36c9530cec756c406bec4e7

환경변수 설정

그 다음 root계정으로 kubectl명령어를 사용하기 위해 환경변수 설정을 해줍니다.

$ export KUBECONFIG=/etc/kubernetes/admin.conf

CNI 설치

마스터 노드를 초기화할때 calico로 설치하는 것으로 설정을 했으니, 다음 명령어를 통해 설치합니다.

$ kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml

다른 CNI들은 이곳을 참조

확인

$ kubectl get pods --all-namespaces

image

3.10 Node join (N)

위에서 Master를 초기화시킬때 복사해둔 kubeadm join~을 사용할 차례입니다.

복사한 명령어를 각 노드로 가서 입력해줍니다.

kubeadm join x.x.x.x:6443 --token b0em0n.b8v9b760cmz8nmty \
    --discovery-token-ca-cert-hash sha256:dd5ae0bb6c4f6e7aff5f8ac34d63383d50e1f374a36c9530cec756c406bec4e7

.....
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

성공적으로 join했다는 메세지가 뜨면 마스터로 가서 확인해봅시다.

Master 에서

$ kubectl get nodes

image

마스터 하나에 노드 두개로 클러스터가 구성된 것을 확인할 수 있습니다.

4. Cluster test (nginx)

클러스터가 구성이 되었으니 간단한 예제를 하나 실행해봅시다.

nginx앱을 클러스터에 올려서 외부에서 접속해보는 테스트를 진행해보겠습니다.

4.1 Docker image

먼저 쿠버네티스 클러스터에 올릴 nginx이미지를 docker hub에서 pull받습니다.

$ docker image pull nginx

4.2 pod 실행

받은 이미지를 pod에 띄워보겠습니다.

# nginx-test는 임의의 이름
$ kubectl run nginx-test --image=nginx --port 80 --generator=run-pod/v1

pod/nginx-test created

4.3 service 실행

pod만 띄우면 끝나는 것이 아니라 pod가 포함한 컨테이너에 연결할 수 있도록 서비스를 생성시켜줘야 합니다.

$ kubectl expose pod nginx-test

service/nginx-test exposed

get service를 통해 생성된 서비스들을 확인해봅시다.

$ kubectl get service

image

현재는 쿠버네티스와 방금전에 올린 nginx-test 서비스만 올라와 있습니다.

서비스 nginx-test의 TYPE은 ClusterIP인데 이는 내부 클러스터에만 ip가 열려있는 상태를 뜻합니다.

즉 외부에서 접근하지 못한다는 것이죠.

외부에서 접근할 수 있게 하려면 여러가지 방법이 있지만, 이번엔 Type만 바꾸는 방법으로 진행하겠습니다.

4.4 Service Type 변경

kubectl edit을 통해 현재 떠있는 서비스를 수정할 수 있습니다.

$ kubectl edit service nginx-test

image

빨갛게 밑줄쳐져있는 부분을 ClusterIP에서 NodePort로 변경해줍니다.

변경 후, get service하면
image
외부포트가 지정된 것을 확인할 수 있습니다.

30657로 접근하면 nginx-test서비스가 바라보고있는 nginx앱의 8080으로 연결된다는 것입니다.

4.5 결과 확인

IP:port로 접속하면 아래와 같은 화면을 보실 수 있습니다.

이때 ip는 마스터의 ip이든 노드의 ip든 상관없습니다.

image

성공!

5. Kubernetes 종료

쿠버네티스 클러스터를 삭제하는 방법입니다.

Master에서 :

$ kubectl drain {노드이름} --delete-local-data --force --ignore-daemonsets
$ kubectl delete node {노드이름}

$ kubeadm reset

Node에서 :

$ kubeadm reset

댓글남기기