클러스터 생성 및 설정 (Kubespray)
이번 데모에서는 한 물리 서버에, 가상 머신 4대를 사용하여 쿠버네티스 클러스터를 생성할 예정이다.
💡 현재 VMWare Workstation에서 실습 진행
- Control Node (Ubuntu 22.04): 192.168.1.90
- Master Node (CentOS 7): 192.168.1.150
- Worker Node 1 (CentOS 7): 192.168.1.160
- Worker Node 2 (CentOS 7): 192.168.1.170
Kubespray를 통해 클러스터 생성
Kubespray는 쿠버네티스 클러스터를 배포하고 관리하기 위한 오픈 소스 도구이다. Ansible을 기반으로 하며, 클러스터 설정, 노드 배치, 네트워킹, 보안 설정 등을 자동화 한다. 이를 통해 사용자는 일관된 방식으로 쿠버네티스 클러스터를 배포하고 관리할 수 있으며, 다양한 환경에서 유연하게 사용할 수 있다. 간단하게 생각하면 Kubespray는 K8s를 설치 할 수 있는 Ansible 묶음이다. 중요한 키 포인트들은:
- AWS, GCE, Azure, OpenStack 또는 Baremetal등에서 쉽게 배포 할 수 있다
- 고가용성 클러스터를 생성 할 수 있다
- 네트워크 플러그인의 선택 가능 하다
- 대부분의 인기 있는 리눅스 배포판을 지원 한다
- 지속적인 통합 테스트를 지원 한다
기존에는 Kargo라는 이름이었다. 더 많은 정보는 Kubespray 깃 허브 페이지를 참고 할 수 있다.
Requirements & Prerequisites
- 최소 쿠버네티스 설치 버전은 v1.24
- Python3.9+, Ansible v2.11+, Jinja 2.11+ 그리고 python-netaddr이 Ansible 명령어를 실행 할 노드에 설치 되어 있어야 된다
- 도커 이미지를 가져오기 위해 대상 서버는 인터넷에 액세스해야 한다. (오프라인 환경은 여기 참조)
- 대상 서버들은 IPv4 Forwarding을 허용하도록 설정되어 있어야 한다
- 방화벽은 관리되지 않으므로, 배포 전에 방화벽을 비활성화 하도록 해야 한다.
- kubespray를 root 사용자 계정이 아닌 다른 사용자 계정에서 실행하는 경우, 올바른 권한 상승 방법을 대상 서버에 구성해야 한다. 그런 다음
ansible_become
플래그 또는 명령 매개변수--become
또는-b
를 지정해야 합니다. - Master & Worker Nodes 최소 사양 1500MB RAM, 2CPU, 20GB 디스크 공간
- Ansible Node (Control Node) 최소 사양 1024MB RAM, 1CPU, 20GB 디스크 공간
- 모든 노드 들은 인터넷 통신이 가능 해야 된다
- 각 노드의 계정 들은 관리자 권한(sudo) 명령어를 사용 할 수 있어야 된다
💡중요 포인트들!
Ansible은 오픈 소스 IT 자동화 도구로, 서버 설정, 배포, 관리 작업을 간편하게 자동화하는 데 사용 된다. 파이썬으로 작성 되었으며, SSH를 통해 에이전트 없이 호스트를 제어 한다.
Jinja는 파이썬 기반의 템플릿 엔진으로, 동적으로 데이터를 조작하여 텍스트를 생성하는 데 사용 된다. Jinja는 Ansible과 함께 사용되며, 템플릿 파일과 변수를 결합하여 구성 파일을 생성하거나 동적으로 콘텐츠를 생성하는 데 유용 하다.
Ansible과 Jinja를 Control 노드에 설치 하겠다. 이 노드는 클러스터를 배포하는 역할 만 수행하고 실제 클러스터에는 구성 되지 않는다.
그리고 진행 하기 전, selinux 상태도 확인 해야 한다.
# 파일 안에 selinux=enforcing값을 selinux=disabled로 변경
vi /etc/selinux/config
.
.
selinux=disabled
Kubespray 실행 하기
Control 노드 에서 작업
전체 패키지 업데이트 및 파이썬 그리고 pip을 설치 한다
sudo apt update
# 깃을 사용 하여 kubespray 코드를 가져와야 한다
sudo apt install git python3 python3-pip -y
파이썬 버전과 pip 버전을 확인 한다
python3 -V
python 3.10.6
pip -V
pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)
pip을 통해 Ansible 과 Jinja 패키지를 설치 할 수 있다. pip을 통해 설치하는 것이 권장되는 이유는 pip가 파이썬의 패키지 설치 도구이며, Ansible과 Jinja 모두 파이썬 기반 도구이기 때문이다
git clone
명령어를 통해 kubespray 깃 허브 소스 코드를 내려 받는다
git clone https://github.com/kubernetes-incubator/kubespray.git
kubespray의 깃 허브 소스 코드를 내려 받으면 이미 필요한 요소들을 쉽게 설치 할 수 있는 requirements.txt
파일이 존재 한다
# kubespray 디렉터로 이동
cd kubespray
# 파일 안에 있는 모든 항목들을 pip을 사용 하여 설치 한다
pip install -r requirements.txt
참고로 requirements.txt 파일 안에 존재하는 항목들은
설치가 무사히 완료 된 후 아래 명렁어를 사용 했을때 ansible
버전을 확인 할 수 있다
ansible --version
ansible [core 2.12.5]
config file = /home/ansible/kubespray/ansible.cfg
configured module search path = ['/home/ansible/kubespray/library']
ansible python module location = /home/ansible/.local/lib/python3.10/site-packages/ansible
ansible collection location = /home/ansible/.ansible/collections:/usr/share/ansible/collections
executable location = /home/ansible/.local/bin/ansible
python version = 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0]
jinja version = 3.1.2
libyaml = True
-bash: ansible: command not found?
만약에 설치가 완료 되었지만 ansible 명령어를 찾을 수 없다고 나온다면, Ansible이 설치된 디렉터리가 PATH 환경 변수에 포함되지 않았다는 거다.
Ansible 설치 경로는 여기서 확인
ls ~/.local/bin/
__pycache__ ansible-config ansible-console ansible-galaxy ansible-playbook ansible-test jp.py pbr
ansible ansible-connection ansible-doc ansible-inventory ansible-pull ansible-vault netaddr
pip을 사용하여 Ansible을 설치하면 기본적으로 ~/.local/bin 디렉토리에 설치 된다. Python packaging의 일반적인 관례로, 사용자 별로 패키지를 격리하고 개별적으로 관리하기 위해 사용자의 로컬 디렉토리에 설치되는 것이다
Ansible의 설치 경로를 ~/.bashrc
파일에 추가 해주면 해결 된다
~/.bashrc는 Bash Shell 환경을 자신의 선호에 맞게 구성할 수 있는 파일
vi ~/.bashrc
# 마지막 줄에 추가
export PATH=$PATH:/home/ansible/.local/bin
# 저장 후 나가기
:wq
# bashrc파일의 변경 내용을 업데이트
source ~/.bashrc
ansible이 정상적으로 작동 하는지 확인 후 호스트 파일을 만들기 위해 아래 명령어들을 실행 한다
# inventory/sample 디렉토리의 내용을 inventory/mycluster 디렉토리로 복사한다
# -rfp 옵션을 사용하여 재귀적으로 모든 하위 디렉터리 포함 복사하여 원본 파일의 속성들도 보존 한다
cp -rfp inventory/sample inventory/mycluster
# IPS라는 배열 변수를 선언하고, IP 주소 목록을 할당한다
declare -a IPS=(192.168.1.150 192.168.1.160 192.168.1.170)
# inventory.py라는 파이썬 스크립트를 실행한다
# 스크립트는 CONFIG_FILE 환경 변수가 설정되어야 하므로, hosts.yaml로 설정 한다
CONFIG_FILE=inventory/mycluster/hosts.yml python3 contrib/inventory_builder/inventory.py ${IPS[@]}
# inventory 디렉토리의 주어진 IP 주소와 디렉토리 구조를 사용하여 인벤토리 파일(hosts.yaml)을 생성하는 설정 프로세스
설정 완료 후 hosts.yaml
파일안에 내용을 아래와 같이 수정 한다
vi inventory/mycluster/hosts.yml
all:
hosts:
node1:
ansible_host: 192.168.1.150 # 작업을 실행하기 위해 대상 노드에 연결할 때 사용하는 IP 주소 또는 호스트 이름을 지정하는 필드
ip: 192.168.1.150
access_ip: 192.168.1.150
node2:
ansible_host: 192.168.1.160
ip: 192.168.1.160
access_ip: 192.168.1.160
node3:
ansible_host: 192.168.1.170
ip: 192.168.1.170
access_ip: 192.168.1.170
children:
kube_control_plane: # 마스터 노드 지정 하는 곳
hosts:
node1:
kube_node: # 워커 노드 지정 하는 곳
hosts:
node2:
node3:
etcd: # etcd 노드 지정 하는 곳
hosts:
node1:
k8s_cluster:
children:
kube_control_plane:
kube_node:
calico_rr:
hosts: {}
그 외 쿠버네티스 클러스터 관련 검토 및 수정 할 수 있는 설정 파일은:
vi inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
# 파일 내용이 너무 길어서 중요한 요소들만 지정 하였다
# 20번째 줄
kube_version: v1.26.5
# 70번째 줄
kube_network_plugin: calico
# 76번째 줄
kube_service_addresses: 10.233.0.0/18
# 81번째 줄
kube_pods_subnet: 10.233.64.0/18
# 160번째 줄
cluster_name: cluster.local
# 229번째 줄
container_manager: containerd
마지막으로 추가적인 클러스터 요소들을 클러스터 설치 시 같이 활성화 시킬 수 있게 설정 할 수 있는 파일:
vi inventory/mycluster/group_vars/k8s_cluster/addons.yml
# 파일 내용이 너무 길어서 중요한 요소들만 지정 하였다
# 4번째 줄
dashboard_enabled: false
# 7번째 줄
helm_enabled: false
# 10번째 줄
registry_enabled: false
# 16번째 줄
metrics_server_enabled: false
# 100번째 줄
ingress_nginx_enabled: false
# 177번째 줄
metallb_enabled: false
# 246번째 줄
argocd_enabled: false
만약에 Control 노드에서 root 유저로 지금 까지 진행 하였다면 아래 호스트 노드들에서의 작업이 불필요하다
호스트 노드들에서 작업
현재 까지의 Control노드의 설정들은 'ansible'유저 이름로 진행 되었다. 그렇기 때문에 Ansible 명령어를 실행 하려면 호스트 노드들도 동일한 이름의 유저가 존재 해야 한다. 각각 호스트 노드에 먼저 새로운 'ansible' 유저 생성 후 sudoers.d
파일에 등록 시켜 줘야 한다.
# 모든 호스트노드에서 동일하게 설정
useradd ansible
passwd ansible
New Password:
# root 사용자를 위해 sudoers파일에 ansible 사용자가 비밀번호를 입력 하지 않고도 root 권한으로 모든 명령어를 실행할 수 있게 해 준다
echo "ansible ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/root
Control노드에서 작업
이제 Control 노드가 호스트 노드들 (마스터 와 워커 노드)의 설정들을 자유롭게 할 수 있게 접근권한을 부여 하는 설정을 해야 한다
첫째로 Control노드에서 SSH 접속을 위해 SSH 키를 발행 한다
ssh-keygen
SSH키를 발급 받은 후 그 Public키를 모든 호스트 노드들에게 전달 해야된다.
# non-root 유저(ansible 유저)로 진행 하였을 경우
ssh-copy-id ansible@192.168.1.150
ssh-copy-id ansible@192.168.1.160
ssh-copy-id ansible@192.168.1.170
# root 유저로 진행 하였을 경우
ssh-copy-id root@192.168.1.150
ssh-copy-id root@192.168.1.160
ssh-copy-id root@192.168.1.170
마지막으로 Kubespray 실행 하기 전에 Firewall을 비활성화 그리고 IPv4 포워딩을 활성화 해주는 작업을 진행 한다.
쿠버네티스는 클러스터의 구성요소간 통신에 다양한 네트워크 포트를 사용 한다. 방화벽을 사용하지 않도록 설정하면 클러스터 노드 간의 원활한 통신을 위해 필요한 포트가 열려 있고 차단되지 않도록 할 수 있다. 그리고 IPv4 Forwarding을 사용 하면 쿠버네티스 클러스터에서는 노드, 포드 및 서비스간 서로 다른 네트워크 인터페이스 또는 서브넷 간에 네트워크 트래픽을 라우팅할 수 있다.
# Kubespray 디렉토리로 이동
cd kubespray
# ansible 명령어를 통해 모든 호스트들의 firewalld 서비스 중단
ansible all -i inventory/mycluster/hosts.yml -m shell -a "sudo systemctl stop firewalld && sudo systemctl disable firewalld"
# IPv4 포트 forwarding 기능 활성화
ansible all -i inventory/mycluster/hosts.yml -m shell -a "echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf"
# Swap memory off 설정
ansible all -i inventory/mycluster/hosts.yml -m shell -a "sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab && sudo swapoff -a"
모든 준비 단계들과 요소들이 끝났다. 이제 Kubespray를 통해 Kubernetes 클러스터를 생성 하면 된다
ansible-playbook -i inventory/mycluster/hosts.yml --become --become-user=root cluster.yml
이 한 명령어로 쿠버네티스 클러스터가 생성 된다 (네트워크 속도와 하드웨어 장비의 리소스의 따라 20 ~ 40 분 사이 시간 소요)
모든 설정들이 완료 되면 이런 화면이 보일 것이다
마스터 노드에서 확인
Worker노드들의 경우 기본적으로 특정 역할이 할당되지 않으므로 "<none>"으로 표시 된다. "Ready" 상태인 한, Worker 노드들은 올바르게 동작 한다.
추가로 <none> Label을 수동으로 바꿀 수 있는 명령어가 있다kubectl label node <노드 이름> node-role.kubernetes.io/worker=worker
변경 후: