Kubespray 간단한 소개
Kubernetes를 장인 정신으로 한땀한땀 소중히 구성하는 것도 좋은 접근입니다....만 여러 노드에 구성하고 잘 운영한다는건 매우매우매우 많은 노력을 요합니다.
그래서 Kubespray는 Ansible Playbook, Inventory, Provisioning 도구와 일반적인 운영체제, Kubernetes Cluster 설정 관리 작업을 위해 개발되었습니다.
AWS, GCE, Azure, OpenStack, vSphere, Equinix Metal (bare metal), Oracle Cloud Infrastructure (Experimental), or 베어메탈을 지원하며, 고가용성 클러스터를 구성할 수 있습니다.
자 Kubespray로 쉽게 가시죠!
다른 글에 비해 서론이 유난히 무척 긴 듯한 기분은 착각입니다.
본 문서에서는 Kubernetes Cluster 구성을 위하여 kubespray를 이용합니다.
Kubernetes Cluster 구성에는 kubeadm, kubespray, kops, minikube 등 여러 방법이 있습니다.
차이점이 자세하게 궁금하다면 이 문서를 읽어봅시다.
가장 큰 차이는 Kubespray는 Ansible을 이용하여 프로비저닝하고 관리한다.
Kubespray의 특징으로 Ansible과 Python3가 필요합니다.
그리고 설치 환경은 제 최애 CentOS입니다.
VM은 AWS, Azure, GCP, Oracle Cloud 등 클라우드에서 프로비저닝하셔도 좋지만, 저는 가난한 관계로 로컬 환경에서 Vagrant를 이용하여 VM을 구성합니다. 만약 Vagrant로 구성하고자 한다면 Prepare CentOS 7 with Vagrant & VirtualBox 참고하여 주세요.
Kubernetes Cluster를 구성하는 컴포넌트는 다음과 같습니다.
출처: Kubernetes Components
Control Plane Componenets은 etcd, kube-apiserver, kube-scheduler, kube-controller-manager 등 클러스터를 관리하는 Master Node입니다.
그리고 kubelet 등 실제 서비스를 배포하는
Node Components는 모든 노드에서 실행되어 실행 중인 포드를 유지 관리하고 Kubernetes 런타임 환경을 제공하는 Worker Node입니다.
본 문서에서 VM 2개를 구성하며 아래와 같은 아키텍처로 구성합니다.
나중에 여유가 되면 가용성 테스트를 위해 마스터 3, 워커 3으로 구성해보겠습니다.
마스터 노드와 워커 노드에 설정이 차이가 있습니다.
우선 모든 서버에 공통적으로 적용하는 설정부터 시작하겠습니다.
Swap은 메모리가 부족하면 Disk Storage를 메모리처럼 사용하는 방식이지만, 메모리에 비해 I/O 속도가 떨어지기 때문에 오히려 장애가 발생할 수 있습니다.
끄도록 합니다.
sudo swapoff -a
# 설정 확인
cat /proc/sys/net/ipv4/ip_forward
0
# 설정 변경
sudo sysctl -w net.ipv4.ip_forward=1
cat /proc/sys/net/ipv4/ip_forward
1
각 VM의 IP Address와 호스트네임을 설정합니다.
sudo vi /etc/hosts
192.168.1.11 cent01 master01
192.168.1.12 cent02 node01
Yum 패키지 매니저를 이용하여 Python3, Ansible을 설치합니다.
sudo yum install -y epel-release
sudo yum update -y
sudo yum install -y ansible
sudo yum install -y python3
먼저 SSH Key를 생성합니다.
ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/vagrant/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/vagrant/.ssh/id_rsa.
Your public key has been saved in /home/vagrant/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:0JRjph0/KfCal/Ywj/kSyJ0CsXysP8cvEzCNkqF8B2M vagrant@cent01
The key's randomart image is:
+---[RSA 2048]----+
| .. |
| E .o* |
| . + O.X.+ . |
| o B O.= + |
| . B BS+ . |
| . * @ |
| . = X |
| o O o |
| o *o |
+----[SHA256]-----+
그 다음에 다른 노드에도 접속이 가능하도록 cent01의 SSH Public Key를 전달합니다.
ssh-copy-id cent01
ssh-copy-id cent02
정상적으로 각 노드에 Public Key가 설정이 되었는지 확인하기 위해서 아래의 파일을 확인하여 cent01의 SSH Public Key와 비교해봅니다.
~/.ssh/known_hosts
세팅은 얼추 끝났으니, Kubespray를 본격적으로 시작해봅시다.
시작하기 위해 GitHub 레포지토리를 클론을 뜹니다.
git clone https://github.com/kubernetes-sigs/kubespray.git
Cloning into 'kubespray'...
remote: Enumerating objects: 55117, done.
remote: Counting objects: 100% (45/45), done.
remote: Compressing objects: 100% (29/29), done.
remote: Total 55117 (delta 14), reused 37 (delta 12), pack-reused 55072
Receiving objects: 100% (55117/55117), 15.92 MiB | 10.34 MiB/s, done.
Resolving deltas: 100% (31108/31108), done.
kubespray에 필요한 패키지가 명시된 requirements.txt를 이용하여 설치합니다.
cd kubespray
sudo pip3 install -r requirements.txt
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead.
Collecting ansible==3.4.0 (from -r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/a9/f3/7e7e3647d58b266768a000b5830c7fca7c02eac4e724e9b23309b735f9b2/ansible-3.4.0.tar.gz (31.9MB)
100% |████████████████████████████████| 31.9MB 44kB/s
Collecting ansible-base==2.10.11 (from -r requirements.txt (line 2))
Downloading https://files.pythonhosted.org/packages/a0/93/9d8c26b2a4e1d2b48802a577ca6ada084f58e576f67917c9e28858bf747b/ansible-base-2.10.11.tar.gz (6.0MB)
100% |████████████████████████████████| 6.0MB 241kB/s
Collecting cryptography==2.8 (from -r requirements.txt (line 3))
Downloading https://files.pythonhosted.org/packages/45/73/d18a8884de8bffdcda475728008b5b13be7fbef40a2acc81a0d5d524175d/cryptography-2.8-cp34-abi3-manylinux1_x86_64.whl (2.3MB)
100% |████████████████████████████████| 2.3MB 627kB/s
Collecting jinja2==2.11.3 (from -r requirements.txt (line 4))
Downloading https://files.pythonhosted.org/packages/7e/c2/1eece8c95ddbc9b1aeb64f5783a9e07a286de42191b7204d67b7496ddf35/Jinja2-2.11.3-py2.py3-none-any.whl (125kB)
100% |████████████████████████████████| 133kB 6.7MB/s
Collecting netaddr==0.7.19 (from -r requirements.txt (line 5))
Downloading https://files.pythonhosted.org/packages/ba/97/ce14451a9fd7bdb5a397abf99b24a1a6bb7a1a440b019bebd2e9a0dbec74/netaddr-0.7.19-py2.py3-none-any.whl (1.6MB)
100% |████████████████████████████████| 1.6MB 877kB/s
Collecting pbr==5.4.4 (from -r requirements.txt (line 6))
Downloading https://files.pythonhosted.org/packages/7a/db/a968fd7beb9fe06901c1841cb25c9ccb666ca1b9a19b114d1bbedf1126fc/pbr-5.4.4-py2.py3-none-any.whl (110kB)
100% |████████████████████████████████| 112kB 7.4MB/s
Collecting jmespath==0.9.5 (from -r requirements.txt (line 7))
Downloading https://files.pythonhosted.org/packages/a3/43/1e939e1fcd87b827fe192d0c9fc25b48c5b3368902bfb913de7754b0dc03/jmespath-0.9.5-py2.py3-none-any.whl
Collecting ruamel.yaml==0.16.10 (from -r requirements.txt (line 8))
Downloading https://files.pythonhosted.org/packages/a6/92/59af3e38227b9cc14520bf1e59516d99ceca53e3b8448094248171e9432b/ruamel.yaml-0.16.10-py2.py3-none-any.whl (111kB)
100% |████████████████████████████████| 112kB 8.5MB/s
Collecting ruamel.yaml.clib==0.2.2 (from -r requirements.txt (line 9))
Downloading https://files.pythonhosted.org/packages/88/ff/ec25dc01ef04232a9e68ff18492e37dfa01f1f58172e702ad4f38536d41b/ruamel.yaml.clib-0.2.2-cp36-cp36m-manylinux1_x86_64.whl (549kB)
100% |████████████████████████████████| 552kB 2.3MB/s
Collecting MarkupSafe==1.1.1 (from -r requirements.txt (line 10))
Downloading https://files.pythonhosted.org/packages/b2/5f/23e0023be6bb885d00ffbefad2942bc51a620328ee910f64abe5a8d18dd1/MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl
Collecting PyYAML (from ansible-base==2.10.11->-r requirements.txt (line 2))
Downloading https://files.pythonhosted.org/packages/7a/5b/bc0b5ab38247bba158504a410112b6c03f153c652734ece1849749e5f518/PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl (640kB)
100% |████████████████████████████████| 645kB 2.1MB/s
Collecting packaging (from ansible-base==2.10.11->-r requirements.txt (line 2))
Downloading https://files.pythonhosted.org/packages/3c/77/e2362b676dc5008d81be423070dd9577fa03be5da2ba1105811900fda546/packaging-21.0-py3-none-any.whl (40kB)
100% |████████████████████████████████| 40kB 10.2MB/s
Collecting cffi!=1.11.3,>=1.8 (from cryptography==2.8->-r requirements.txt (line 3))
Downloading https://files.pythonhosted.org/packages/f2/cd/3f5f059fed635d71047fa9ce507635088f982ab280fc24cde91d9afb9c1c/cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl (401kB)
100% |████████████████████████████████| 409kB 2.9MB/s
Collecting six>=1.4.1 (from cryptography==2.8->-r requirements.txt (line 3))
Downloading https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl
Collecting pyparsing>=2.0.2 (from packaging->ansible-base==2.10.11->-r requirements.txt (line 2))
Downloading https://files.pythonhosted.org/packages/8a/bb/488841f56197b13700afd5658fc279a2025a39e22449b7cf29864669b15d/pyparsing-2.4.7-py2.py3-none-any.whl (67kB)
100% |████████████████████████████████| 71kB 8.5MB/s
Collecting pycparser (from cffi!=1.11.3,>=1.8->cryptography==2.8->-r requirements.txt (line 3))
Downloading https://files.pythonhosted.org/packages/ae/e7/d9c3a176ca4b02024debf82342dab36efadfc5776f9c8db077e8f6e71821/pycparser-2.20-py2.py3-none-any.whl (112kB)
100% |████████████████████████████████| 112kB 9.3MB/s
Installing collected packages: MarkupSafe, jinja2, PyYAML, pycparser, cffi, six, cryptography, pyparsing, packaging, ansible-base, ansible, netaddr, pbr, jmespath, ruamel.yaml.clib, ruamel.yaml
Running setup.py install for ansible-base ... done
Running setup.py install for ansible ... done
Successfully installed MarkupSafe-1.1.1 PyYAML-5.4.1 ansible-3.4.0 ansible-base-2.10.11 cffi-1.14.6 cryptography-2.8 jinja2-2.11.3 jmespath-0.9.5 netaddr-0.7.19 packaging-21.0 pbr-5.4.4 pycparser-2.20 pyparsing-2.4.7 ruamel.yaml-0.16.10 ruamel.yaml.clib-0.2.2 six-1.16.0
Oracle Database나 WebLogic Server를 사용하면 만나는 Inventory라는 디렉토리를 Kubespray에서도 볼 줄 몰랐네요. (물론 두 개는 일절 관련 없습니다ㅋㅋㅋ)
inventory 디렉토리에서 Kubernetes Cluster를 관리합니다.
샘플을 복사하여 사용합니다.
cp -rfp inventory/sample inventory/firstCluster
클러스터를 구성할 노드 리스트를 입력합니다.
서버 리스트와 마스터 노드, 워커 노드, etcd 등을 지정할 수 있습니다.
저는 cent01(master01)과 cent02(node01) 두 개만 있기 때문에 아래와 같이 설정하였습니다.
./inventory/first_cluster/inventory.ini
[all]
master01 ansible_host=192.168.1.11 ip=192.168.1.11
node01 ansible_host=192.168.1.12 ip=192.168.1.12
[kube_control_plane]
master01
[etcd]
master01
[kube_node]
node01
[k8s_cluster:children]
kube_control_plane
kube_node
calico_rr
Master Node(cent01)에서 inventory에 등록한 서버에 접근이 가능한지 테스트를 합니다.
ansible all -i inventory/firstCluster/inventory.ini -m ping
아래와 같이 출력되면 설정이 제대로 되었다는 의미입니다.
node01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
master01 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
위와 같이 Ping이 정상적으로 가는 것을 확인하였다면, Ansible Playbook으로 K8s 클러스터를 구성합니다.
약 설정까지 18분이 소요되었습니다.
ansible-playbook -i inventory/firstcluster/inventory.ini -become --become-user=root cluster.yml
PLAY [localhost] *************************************************************************************************************************************************************************************************************************************************************************************************************
Tuesday 17 August 2021 07:23:48 +0000 (0:00:00.042) 0:00:00.042 ********
TASK [Check 2.9.0 <= Ansible version < 2.11.0] *******************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All assertions passed"
}
Tuesday 17 August 2021 07:23:48 +0000 (0:00:00.041) 0:00:00.084 ********
TASK [Check Ansible version > 2.10.11 when using ansible 2.10] ***************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All assertions passed"
}
Tuesday 17 August 2021 07:23:48 +0000 (0:00:00.040) 0:00:00.125 ********
TASK [Check that python netaddr is installed] ********************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All assertions passed"
}
Tuesday 17 August 2021 07:23:48 +0000 (0:00:00.059) 0:00:00.184 ********
TASK [Check that jinja is not too old (install via pip)] *********************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All assertions passed"
}
PLAY [Add kube-master nodes to kube_control_plane] ***************************************************************************************************************************************************************************************************************************************************************************
Tuesday 17 August 2021 07:23:49 +0000 (0:00:00.057) 0:00:00.241 ********
TASK [add nodes to kube_control_plane group] *********************************************************************************************************************************************************************************************************************************************************************************
changed: [master01]
[WARNING]: Could not match supplied host pattern, ignoring: kube-node
PLAY [Add kube-node nodes to kube_node] **************************************************************************************************************************************************************************************************************************************************************************************
skipping: no hosts matched
[WARNING]: Could not match supplied host pattern, ignoring: k8s-cluster
PLAY [Add k8s-cluster nodes to k8s_cluster] **********************************************************************************************************************************************************************************************************************************************************************************
skipping: no hosts matched
[WARNING]: Could not match supplied host pattern, ignoring: calico-rr
PLAY [Add calico-rr nodes to calico_rr] **************************************************************************************************************************************************************************************************************************************************************************************
skipping: no hosts matched
[WARNING]: Could not match supplied host pattern, ignoring: no-floating
PLAY [Add no-floating nodes to no_floating] **********************************************************************************************************************************************************************************************************************************************************************************
skipping: no hosts matched
[WARNING]: Could not match supplied host pattern, ignoring: bastion
PLAY [bastion[0]] ************************************************************************************************************************************************************************************************************************************************************************************************************
skipping: no hosts matched
...생략...
Tuesday 17 August 2021 07:42:05 +0000 (0:00:00.222) 0:18:16.720 ********
Tuesday 17 August 2021 07:42:05 +0000 (0:00:00.165) 0:18:16.885 ********
Tuesday 17 August 2021 07:42:05 +0000 (0:00:00.117) 0:18:17.002 ********
PLAY RECAP *******************************************************************************************************************************************************************************************************************************************************************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
master01 : ok=571 changed=121 unreachable=0 failed=0 skipped=1145 rescued=0 ignored=1
node01 : ok=367 changed=73 unreachable=0 failed=0 skipped=640 rescued=0 ignored=0
Tuesday 17 August 2021 07:42:05 +0000 (0:00:00.141) 0:18:17.144 ********
===============================================================================
container-engine/docker : ensure docker packages are installed ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 128.05s
download : download_file | Download item ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 81.49s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 46.37s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 45.22s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 43.95s
download : download_file | Download item ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 34.61s
download : download_file | Download item ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 32.58s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 32.30s
kubernetes/kubeadm : Join to cluster --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 30.82s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 30.57s
kubernetes/control-plane : kubeadm | Initialize first master --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 29.75s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 27.84s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 27.47s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 23.20s
download : download_file | Download item ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 20.70s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 19.90s
download : download_file | Download item ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 18.01s
download : download_file | Download item ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 17.19s
download : download_container | Download image if required ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 15.28s
kubernetes-apps/ansible : Kubernetes Apps | Start Resources ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 10.28s
[vagrant@cent01 kubespray]$
[vagrant@cent01 kubespray]$ Connection to 127.0.0.1 closed by remote host.
Connection to 127.0.0.1 closed.