이전 장에서 쿠버네티스(Kubernetes)의 개념 및 아키텍쳐에 대해 정리를 해 보았다. 이번 장에서는 이제 실제 리눅스(CentOS) 환경에서 쿠버네티스를 설치를 해보도록 하겠다.
1. 쿠버네티스 설치 전 준비사항
우선 쿠버네티스를 설치하기 위해서는 아래와 같은 준비가 필요하다
1-1. 서버, OS 준비
쿠버네티스 설치를 위한 서버와 OS를 준비하자. 필자는 vultr.com 에서 VPS를 생성해서 서버를 구성하였다. (마스터서버보다 노드서버가 사양이 더 좋은 이유는 마스터 서버를 아래와 같이 구성 후 단일 서버로 운영하다가 노드서버를 나중에 추가하게 되었는데, 이것저것 설치하다보니 생각보다 리소스가 많이 소모되어 노드서버는 리소스를 좀 크게 잡게 되었다.)
- 마스터서버 : CPU 2core, Memory 4G, Storage 80G(SSD)
- 노드서버 : CPU 4core, Memory 8G, Storage 160G(SSD)
- OS : CentOS 7 x64
1-2. 각 서버의 호스트명 변경
필수는 아니지만 변경해놓는게 추후 운영하는데 좀 더 편한 것 같다. 마스터서버는 k8s-master, 노드서버는 k8s-node1로 호스트명을 변경했다.
- 명령어 : hostnamectl set-hostname (호스트명)
[root@k8s-master ~]# hostnamectl set-hostname k8s-master
[root@k8s-master ~]# hostname
k8s-master
[root@k8s-node1 ~]# hostnamectl set-hostname k8s-node1
[root@k8s-node1 ~]# hostname
k8s-node1
1-3. root 권한 부여
쿠버네티스 설치작업을 수행하는 계정은 root 권한이 있어야 한다. 리눅스 계정에 root권한을 주는 방법은 (https://twofootdog.tistory.com/9)를 참고하자. root권한이 주어졌으면 해당 계정으로 접속하여 아래 작업들을 수행하자.
1-4. 기존 설치된 쿠버네티스 및 도커 삭제
해당 작업은 만약에 현재 서버에 쿠버네티스와 도커가 설치되어 있다면 삭제를 하고 설치를 해보자. 삭제를 하는 방법은 ()를 참고하자.
1-5. 서버 재기동
변경된 설정값 적용을 위해 서버를 재기동한다.
[root@k8s-master ~]# reboot
2. Docker 설치
쿠버네티스를 설치하기 전에 우선 docker를 설치해야 한다(쿠버네티스가 도커 컨테이너를 관리하기 위한 툴이니 당연한 거겠쥬?). 아래 명령어로 docker를 설치해보자.
[root@k8s-master ~]# yum install -y yum-utils device-mapper-persistent-data lvm2
[root@k8s-master ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
[root@k8s-master ~]# yum install docker-ce
[root@k8s-master ~]# systemctl start docker && systemctl enable docker
3. kubeadm 설치준비
kubeadm을 설치를 위한 사전 준비를 해보자. kubeadm은 쿠버네티스 클러스터 구축/관리를 해주는 툴로서 kubeadm 이외에도 kops, minikube, kubespray등이 있지만, 이번 포스트에서는 kubeadm으로 진행을 해 볼 것이다(클라우드에서는 kops에 대한 레퍼런스가 많지만 클라우드가 아닌 경우는 kubeadm과 minikube에 대한 레퍼런스가 많기 때문에 kubeadm을 선택하게 되었다). 해당 작업은 마스터 서버와 노드서버에서 작업을 수행한다.
3-1. SELinux설정을 permissive 모드로 변경
설명 :
SELinux(Security-Enhanced Linux) : 관리자가 시스템 액세스 권한을 효과적으로 제어할 수 있게 하는리눅스 시스템용 보안 아키텍쳐다. enforce, permissive, disable 세 가지 동작 모드가 있으며 설치하면 기본적으로 enforce 모드로 동작한다.
SELinux 설정을 permissive로 변경하는 이유는 컨테이너가 호스트 파일시스템에 접근하는 것을 용이하게 하게 위함이다(예를 들면 파드 간 네트워크에 사용되는 파일시스템 등). 아래 명령어를 수행해서 SELinux모드를 permissive로 변경하자.
- setenforce 0 => 현재 동작모드 변경
- sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config => 동작모드 영구 변경
- sestatus => 동작모드 확인
[root@k8s-master k8s]# setenforce 0
[root@k8s-master k8s]# sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
[root@k8s-master k8s]# sestatus
3-2. br_netfilter활성화 & iptables 설정
설명 :
iptables는 리눅스상의 방화벽을 설정하는 도구이다. iptables는 커널상에서의 netfilter 패킷필터링 기능을 사용자 공간에서 제어하는 수준으로 사용할 수 있다.
그런데 CentOS같은 리눅스 배포판은 net.bridge.bridge-nf-call-iptables값이 디폴트 0이다. 이는 bridge 네트워크를 통해 송수신되는 패킷이 iptables 설정을 우회한다는 뜻이다. 컨테이너의 네트워크패킷이 호스트머신의 iptables의 설정에 따라 제어되는 것이 바람직하며 이를 위해서는 1로 설정해야 한다. 그런데 iptables의 설정을 따라가기 위해서는 br_netfilter를 enable 시켜줘야 한다.
- lsmod | grep br_netfilter => br_netfilter 상태 확인
- modprobe br_netfilter => br_netfilter 활성화
- sysctl --system => 런타임 중 커널 매개변수값 변경(--system : 모든 시스템 디렉토리의 값 읽기)
[root@k8s-node1 ~]# lsmod | grep br_netfilter
[root@k8s-node1 ~]# modprobe br_netfilter
[root@k8s-node1 ~]# lsmod | grep br_netfilter
br_netfilter 22256 0
bridge 151336 1 br_netfilter
[root@k8s-node1 ~]#
[root@k8s-master k8s]# cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
[root@k8s-master k8s]#
[root@k8s-master k8s]# sysctl --system
3-3. SWAP 비활성화
설명 :
swap메모리는 하드디스크에 swap파일시스템장치를 실제메모리가 모자랄경우 메모리처럼 사용하는 메모리다. kubelet이 정상 동작하기 위해서는 swap메모리를 비활성화시켜야 한다.
swapoff -a로 swap을 비활성화시키고 /etc/fstab에서 "/dev/mapper/centos-swap swap swap defaults 0 0" 문장을 주석 처리한다. 해당 문장이 없으면 주석처리는 생략한다.
[root@k8s-master k8s]# swapoff -a
[root@k8s-master k8s]# vi /etc/fstab
[root@k8s-master k8s]#
3-4. 서버 재기동
변경된 설정값으로 서버를 재기동시킨다.
[root@k8s-master k8s]# reboot
3-5. 쿠버네티스 YUM 레파지토리 설정
쿠버네티스 yum install을 위한 yum 레파지토리 설정을 한다.
[root@k8s-master ~]# 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
exclude=kube*
EOF
3-6. kubeadm, kubectl, kubelet 설치
설명 :
Kubeadm은 Kubelet 과 Kubectl 을 설치하지 않기 때문에 직접 설치해야 한다. Kubectl 은 클러스터에게 명령을 내리기 위한 CLI 유틸이며 kubelet은 각 노드마다 구동되는 에이전트로 쿠버네티스 마스터와 통신한다.
[root@k8s-master ~]# yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
[root@k8s-master ~]# systemctl enable kubelet && systemctl start kubelet
4. 쿠버네티스 마스터(Master)서버 설정
4-1. kubeadm 수행
설명 :
마스터와 노드에 kubeadm을 설치했으니, 이제 마스터와 노드 각각 개별로 설정을 진행해보자. 마스터서버에서는 kubeadm을 초기화하고 컨테이너 간 네트워크를 담당하는 CNI(Container Network Interface)를 설치할 것이다. 필자는 CNI는 flannel을 사용할 것이다. CNI로 flannel을 사용할 경우 kubeadm init 수행 시 "--pod-network-cidr=10.244.0.0/16" 옵션을 주어야 한다.
# kubeadm init --pod-network-cidr=10.244.0.0/16
마스터 서버에서 명령어를 수행하면 kubeadm join 명령어가 화면에 나오게 되는데, 해당 명령어를 사용하여 클러스터 구성 시 작업노드에서 마스터로 연결할 수 있다.
4-2. kubectl 허용
설치 완료 후 kubectl 명령어를 사용하게 되면 아래와 같은 메시지를 받게 된다.
이 문제를 해결하기 위해서는 root유저인 경우는 export KUBECONFIG=/etc/kubernetes/admin.conf 명령어로 환경변수를 등록하고, 일반 유저인 경우는 kubeadm init 후 나온 .kube 디렉토리 및 config 생성 명령어를 실행하면 된다(위 그림에 빨간색으로 표시). 하지만 root인 경우도 동일 명령어를 수행해도 되므로, 필자는 해당 명령어로 kubectl을 허용하도록 하겠다(export로 등록한 환경변수는 로그아웃을 한 경우 초기화가 되고, profile 수정은 귀찮아서..).
# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config
4-3. CNI 설치
이 글에서는 CNI로 Flannel을 설치한다(위에 kubeadm init 수행 시 Flannel 적용 옵션을 넣었었음).
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml
4-4. 마스터 실행 확인
kubectl 명령어로 쿠버네티스 마스터 실행을 확인한다. STATUS가 Running이면 정상 실행된 것이다.
# kubectl get pod --all-namespaces
5. 쿠버네티스 노드(Node)서버 설정
쿠버네티스를 제어하는 쿠버네티스 마스터서버 설정을 완료했으니 이제는 어플리케이션 컨테이너들이 올라갈 쿠버네티스 노드서버를 설정해보자. 방법은 간단하다. 쿠버네티스 마스터서버에서 생성한 쿠버네티스 클러스터로 쿠버네티스 노드서버를 결합시키면 된다.
5-1. kubeadm join 실행
마스터서버에서 kubeadm init으로 초기화를 할 때 출력된 kubeadm join 명령어를 입력하여 노드서버를 쿠버네티스 클러스터로 결합시킬 수 있다.
# kubeadm join 66.42.43.41:6443 --token iepxy1.ppp5xpanyvf04pe9 \
--discovery-token-ca-cert-hash sha256:2ba7b4cca8eaaa157931b4e053585e66932782c86b200a1f715e0008d00275ba
만약 해당 명령어를 복사해 놓지 않아 지워진 경우라면 아래 명령어를 통해 token 정보를 확인할 수 있다.
# kubeadm token list
하지만 해당 토큰은 24시간만 사용 가능하므로 24시간 이후에는 아래 명령어로 token을 새로 생성해서 join하면 된다.
# kubeadm token create
맨 마지막 parameter인 sha256값 확인은 아래 명령어를 실행하면 된다.
# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
5-2. kubectl 허용
결합 완료 후 노드서버에서도 kubectl을 허용해준다. 허용해주는 방법은 마스터서버의 $HOME/.kube/config파일을 노드서버의 $HOME/.kube/config파일로 옮겨주면 된다.
5-3. 노드 실행 확인
kubectl 명령어로 노드서버에서 정상적으로 쿠버네티스가 동작하는지 확인한다.
- kubectl get nodes : 쿠버네티스 node정보 확인
- kubectl get pod : 쿠버네티스 pod정보 확인-o -wide 옵션을 주면 파드(pod)가 구동되는 노드명(서버명)까지 확인할 수 있다.
# kubectl get nodes
# kubectl get pod --all-namespaces -o wide
6. 간단한 파드(pod) 배포하기
마스터서버에서 간단한 pod를 배포해보자. test.yaml 파일을 만들고 아래 코드를 기입해보자.
apiVersion: v1
kind: Pod
metadata:
name: test-pod
labels:
app: testapp
spec:
containers:
- name: test-container
image: busybox
command: ['sh', '-c', 'echo test && sleep 360']
그리고 아래 명령어로 해당 pod를 배포해보자.
# kubectl apply -f test.yaml
그리고 배포된 결과를 확인해보자. 아래 명령어를 실행하면 해당 pod가 정상적으로 k8s-node1 노드에 올라간 것을 확인할 수 있다.
# kubectl get pod --all-namespaces -o wide
다음으로 pod가 정상 동작한지 확인해보자. 아래 명령어를 통해 해당 pod의 로그를 확인할 수 있다.
# kubectl logs test-pod
7. 추가사항(Taint & Toleration)
노드서버 없이 마스터서버 한개로 쿠버네티스 클러스터를 구동하게 될 경우가 있을 수 있다(필자가 맨 처음엔 그랬다). 그럴 경우 쿠버네티스 클러스터 구동 후 마스터서버에 컨테이너를 추가로 올리게 되면 컨테이너가 구동이 되지 않는 현상이 있었다. 확인 결과 쿠버네티스 마스터는 처음 구동이 되면 Taints가 "node-role.kubernetes.io/master:NoSchedule"로 설정이 되어 있다(kubectl get nodes 명령어로 확인 가능하다). Taint가 이렇게 설정이 되어 있을 경우 마스터에서는 컨테이너가 추가적으로 구동이 될 수 없다.
Taint란 쉽게 말해서 Node에 정의해 놓는 pod 스케쥴링 제어 정책이다. 해당 Node에 Taint가 정의되어 있으면 pod는 배포될 수 없다. 단 pod에 Taint에 맞는 Toleration이 pod에 설정되어 있으면 해당 pod는 배포될 수 있다.
다시 본론으로 넘어와서, 한개의 서버로 쿠버네티스를 구동하게 될 경우 이 Taint와 Toleration 옵션을 변경하지 않으면 추가적으로 컨테이너가 구동되지 않는다.
따라서 필자는 마스터 서버의 Taint를 아래와 같이 해제 처리했다.
<Taint 해제 처리>
# kubectl taint nodes --all node-role.kubernetes.io/master-
Taint 해제 처리를 하게 되면 값은 <none>으로 변경되며 추가적인 컨테이너가 구동될 수 있다. 만약 Taint를 해제처리하지 않으려면 아래와 같이 Taint를 변경 처리한 후 그 뒤로 올리는 컨테이너의 yaml파일에 Toleration을 주면 된다.
# kubectl taint node -l [LABEL_KEY]=[LABEL_VALUE] [KEY]=[VALUE]:[EFFECT]
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
예를들면 label이 node_label=master인 Node의 Taint 변경하고, 클러스터에 추가하려는 컨테이너 yaml파일에 toleration 옵션을 추가하려면 아래와 같이 작성하면 된다.
# kubectl taint node -l node_label=master key01=value01:NoSchedule
tolerations:
- key: "key01"
operator: "Equal"
value: "value01"
effect: "NoSchedule"
마무리
이번장에서는 kubeadm을 활용하여 쿠버네티스를 설치하였다. 그 후 쿠버네티스 마스터와 쿠버네티스 노드를 연결하여 쿠버네티스 클러스터를 구성하였고, 간단한 pod를 배포하여 클러스터가 정상 동작하는지 확인하였다. 다음 장에서는 쿠버네티스 명령어에 대해서 간단하게 정리를 하고 다음 실습을 이어나가도록 하겠다.
참고
https://javacan.tistory.com/entry/k8s-install-in-centos7
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
'IT > PaaS' 카테고리의 다른 글
쿠버네티스 시작하기(7) - CI/CD 파이프라인 만들기(1/3) - 쿠버네티스 클러스터에 jenkins 설치 및 설정 (18) | 2020.01.02 |
---|---|
쿠버네티스 시작하기(6) - 쿠버네티스 기본 명령어 (0) | 2019.12.27 |
쿠버네티스 시작하기(4) - 쿠버네티스 아키텍쳐 (0) | 2019.12.20 |
쿠버네티스 시작하기(3) - 쿠버네티스 구성요소(2/2) (0) | 2019.12.19 |
쿠버네티스 시작하기(2) - 쿠버네티스 구성요소(1/2) (0) | 2019.12.19 |
댓글