본 포스팅에서는 오픈스택에 쿠버네티스를 Kubespray라는 오픈소스를 이용하여 구축하는 과정을 다뤄보겠습니다.
졸업과제에 프라이빗 클라우드를 활용한 클라우드 네이티브 환경 구축이 필요하여 진행해보게 되었습니다.
프로그램 버전 등의 이유로 설치 진행 간에 오류가 많아 힘들었어서, 조금 자세히 적어보겠습니다.
먼저, 오픈스택은 devstack을 이용하여 단일 VirtualBox VM에 설치하였고, 사양 및 버전은 다음과 같습니다.
VM 사양
1. CPU - 4core
2. RAM - 16GB
3. Disk - 100GB
3. NIC - 호스트전용 어댑터, 어댑터에브릿지
4. OS - Ubuntu 20.04 server imageOpenstack 사양(devstack)
1. Version - stable/xena기타
1. kubespray - v2.21
2. terraform - v1.3.0(1.5.0버전에서는 kubespray의 tf 구문이 지원되지 않는 부분이 있었음)
3. Bastion Host, kubernetes Master.Node OS - Ubuntu 20.04
4. Bastion Host, kubernetes Node Flavor - CPU 2 Core, RAM: 2GB, Disk 10GB
wget -O- https://apt.releases.hashicorp.com/gpg | \
gpg --dearmor | \
sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform=1.3.0
설치가 완료되면 다음과 같이 확인
(.kubespraylatest) stack@jae:~/kubespray$ terraform version
Terraform v1.3.0
on linux_amd64
Your version of Terraform is out of date! The latest version
is 1.5.3. You can update by downloading from https://www.terraform.io/downloads.html
sudo apt-get install python3-virtualenv
virtualenv .kubespray
source .kubespray/bin/activate
pip install -U pip
=> 이렇게 하면 CLI 옆에 괄호 안 가상환경 이름이 표시됩니다.
(.kubespray) stack@jae:~/kubespray$
인증이 완료되면 다음과 같이 openstack CLI 정상 동작
ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_rsa.kubespray
# 현재 쉘에서 ssh agent 시작
eval $(ssh-agent -s)
# 생성된 키 추가
ssh-add ~/.ssh/id_rsa.kubespray
본격적으로 kubespray 저장소를 clone하여 설치를 진행합니다.
위에서 가상환경을 활성화한 상태에서 진행합니다.
git clone --branch v2.21.0 https://github.com/kubernetes-sigs/kubespray
cd kubespray
pip install -r requirements.txt
첫번째로 그냥 test-cluster로 설치하려면 아래 명령을 이용하면 되고,
cp -LRp contrib/terraform/openstack/sample-inventory inventory/test-cluster
cd inventory/test-cluster
ln -s ../../contrib/terraform/openstack/hosts
ln -s ../../contrib
본 포스팅에서는 https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
에 있는 ubuntu 20.04 cloud img를 openstack glance에 올린 것으로 쿠버네티스 노드를 구성하였습니다.
(.kubespraylatest) stack@jae:~/kubespray/inventory/test-cluster$ pwd
/opt/stack/kubespray/inventory/test-cluster
위 위치로 이동하여 cluster.tfvars를 편집합니다.
아래 설정은 제가 구축하는 데 쓴 것이고, 클러스터 변수 문서의 다양한 변수들을 참고해서 사용할 수 있습니다.
# 아까 생성한 SSH 퍼블릭 키 위치
public_key_path = "~/.ssh/id_rsa.kubespray.pub"
# group vars 폴더의 주소를 명시
group_vars_path="/opt/stack/kubespray/inventory/test-cluster/group_vars"
# Openstack image 이름 명시
image = "ubuntu 20.04 LTS"
# ubuntu 이미지이므로 ubuntu
ssh_user = "ubuntu"
# bastion host 1개 생성
number_of_bastions = 1
# bastion host에 할당할 openstack flavor id 명시
flavor_bastion = "d3"
# standalone etcds
number_of_etcd = 0
# masters
number_of_k8s_masters = 0
number_of_k8s_masters_no_etcd = 0
number_of_k8s_masters_no_floating_ip = 1
number_of_k8s_masters_no_floating_ip_no_etcd = 0
flavor_k8s_master = "d3"
# nodes
number_of_k8s_nodes = 0
number_of_k8s_nodes_no_floating_ip = 2
flavor_k8s_node = "d3"
# GlusterFS
# either 0 or more than one
#number_of_gfs_nodes_no_floating_ip = 0
#gfs_volume_size_in_gb = 150
# Container Linux does not support GlusterFS
#image_gfs = "<image name>"
# May be different from other nodes
#ssh_user_gfs = "ubuntu"
#flavor_gfs_node = "<UUID>"
# 쿠버네티스 노드들이 생성될 network
network_name = "test-cluster-network"
# openstack의 external network
external_net = "5280d3d0-bbca-4a14-93cb-cbfaf6e51cee"
# 쿠버네티스 노드들이 생성될 network의 cidr
subnet_cidr = "10.0.1.0/24"
# openstack의 external network의 이름 명시
floatingip_pool = "public"
bastion_allowed_remote_ips = ["0.0.0.0/0"]
k8s_allowed_remote_ips = ["0.0.0.0/0"]
external_net = ?
아래 명령어를 통해 나온 ID 삽입
노드들의 flavor의 id는 아래 사진과 같이 확인할 수 있습니다
환경에서 언급했던 flavor 명세가 name:ds2G(id:d3)
이후,
# terraform 초기화
terraform -chdir="contrib/terraform/openstack" init
# 실제 리소스 구축
terraform -chdir="contrib/terraform/openstack" apply -var-file=$PWD/cluster.tfvars
# yes 안쳐도 되는 명령
terraform -chdir="contrib/terraform/openstack" apply -var-file=$PWD/cluster.tfvars --auto-approve
# 리소스 삭제하려면 아래 명령어
terraform -chdir="contrib/terraform/openstack" destroy -var-file=$PWD/cluster.tfvars
# yes 안쳐도 되는 명령
terraform -chdir="contrib/terraform/openstack" destroy -var-file=$PWD/cluster.tfvars --auto-approve
성공적으로 리소스들이 생성되면 아래와 같이 bastion host의 floating ip 등 정보들이 출력됩니다.
Apply complete! Resources: 25 added, 0 changed, 0 destroyed.
Outputs:
bastion_fips = tolist([
"172.24.4.112",
])
floating_network_id = "5280d3d0-bbca-4a14-93cb-cbfaf6e51cee"
k8s_master_fips = tolist([])
k8s_node_fips = []
private_subnet_id = "884e753f-d649-4d06-807d-14560bc386ca"
router_id = " 2515d77a-e303-4907-a688-bd326506927a "
인스턴스 생성화면
네트워크 토폴로지 화면
그리고, bastion host를 통해서 ansible host를 통하여 동작할 수 있도록 아래 파일이 생성됩니다.
=> proxyCommand를 위하여 추가 작업을 진행할 필요가 없습니다.
(.kubespraylatest) stack@jae:~/kubespray/inventory/test-cluster/group_vars$ cat no_floating.yml
ansible_ssh_common_args: "-o ProxyCommand='ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -W %h:%p -q ubuntu@172.24.4.232 {% if ansible_ssh_private_key_file is defined %}-i {{ ansible_ssh_private_key_file }}{% endif %}'"
다음과 같이 bastion host의 cloud_init 부팅 과정이 정상적으로 이뤄지면,
다음 ansible command를 실행하여 정상적으로 동작하는지 확인합니다.
fingerprint를 등록하라고 하면 yes를 입력합니다.
간혹, bastion host와 node 수에 맞지 않는 출력 즉 에러1개 성공 3개던, 성공 4개던 에러 4개던 총합이 4개가 안나오고
아무 출력이 나오지 않는 상태일때 yes를 입력해봅니다. 그럼 SUCCESS든 ERROR등 출력이 나오는 경우가 있습니다.
(fingerprint 입력 창이 다른 로그에 묻히는 경우가 있음)
(.kubespraylatest) stack@jae:~/kubespray$ ansible -m ping -i inventory/test-cluster/hosts all
etcd 멤버 등록을 위해 hostvars를 추가,
아래와 같이 etcd 맴버에 master node를 등록하지 않으면 etcd가 member 등록에 실패하여 이후, 수행되는 ansible-playbook 과정 중 에러가 발생합니다.
(.kubespraylatest) stack@jae:~/kubespray/inventory/test-cluster$ pwd
/opt/stack/kubespray/inventory/test-cluster
(.kubespraylatest) stack@jae:~/kubespray/inventory/test-cluster$ mkdir host_vars
(.kubespraylatest) stack@jae:~/kubespray/inventory/test-cluster$ echo "etcd_member_name: etcd1" > host_vars/<master-node-name>
Kubespray에서 지원하는 provider 관련하여 ansible 변수를 설정합니다.
아래 group_vars 폴더 안 yml 파일을 수정합니다.
주석이 있으면 제거하고 value를 삽입합니다.
(.kubespraylatest) stack@jae:~/kubespray/inventory/test-cluster$ ls
cluster.tfvars contrib credentials group_vars hosts host_vars
group_vars/all/all.yml
cloud_provider: external
external_cloud_provider: openstack
group_vars/all/openstack.yml
cinder_csi_enabled: true
다음 명령은 kubespray디렉터리에서 실행했고, 완료하는 데 다소 시간이 걸립니다.
(.kubespraylatest) stack@jae:~/kubespray$ ansible-playbook --become -i inventory/test-cluster/hosts cluster.yml
진행 중에 apt cache error가 발생할 수 있습니다.
TASK [kubernetes/preinstall : Update package management cache (APT)] **************************************************************************************
fatal: [test-cluster-k8s-master-1]: FAILED! => {"changed": false, "msg": "Failed to update apt cache: unknown reason"}
fatal: [test-cluster-k8s-node-1]: FAILED! => {"changed": false, "msg": "Failed to update apt cache: unknown reason"}
fatal: [test-cluster-k8s-node-2]: FAILED! => {"changed": false, "msg": "Failed to update apt cache: unknown reason"}
NO MORE HOSTS LEFT ****************************************************************************************************************************************
PLAY RECAP ************************************************************************************************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test-cluster-bastion-1 : ok=6 changed=0 unreachable=0 failed=0 skipped=20 rescued=0 ignored=0
test-cluster-k8s-master-1 : ok=72 changed=4 unreachable=0 failed=1 skipped=99 rescued=0 ignored=0
test-cluster-k8s-node-1 : ok=56 changed=4 unreachable=0 failed=1 skipped=88 rescued=0 ignored=0
test-cluster-k8s-node-2 : ok=56 changed=4 unreachable=0 failed=1 skipped=88 rescued=0 ignored=0
Wednesday 26 July 2023 10:03:15 +0000 (0:00:31.815) 0:01:07.491 ********
이 경우, master node, worker node에 ssh 접속하여 아래 명령을 실행합니다.
resolve error가 발생할 경우가 있는데 이는 다음 포스트에 명시하겠습니다.
sudo apt update
설치 진행 중 에러가 발생하여 ansible-playbook command 재실행 시 etcd 관련한 node의 설정을 한 번 지워야합니다.
github issue 참고
성공적으로 kubernetes가 구축이 되면 다음과 같이 출력이 됩니다.
proxyCommand를 이용하여 bastion host를 통해 master의 배포 상태를 확인합니다.
bastion host -> kubernetes master node(control plane)
(.kubespraylatest) stack@jae:~/kubespray$ ssh -o ProxyCommand="ssh -W %h:%p ubuntu@172.24.4.232" ubuntu@10.0.1.59 "sudo kubectl get pod -A"
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system calico-kube-controllers-8575b76f66-fbt7s 1/1 Running 16 105m
kube-system calico-node-ks297 1/1 Running 0 106m
kube-system calico-node-v5rp9 1/1 Running 0 106m
kube-system calico-node-z4t7l 1/1 Running 0 106m
kube-system coredns-8474476ff8-bltc9 1/1 Running 0 103m
kube-system coredns-8474476ff8-jmf6v 1/1 Running 0 104m
kube-system csi-cinder-controllerplugin-99c9dd87b-r796j 5/5 Running 0 102m
kube-system csi-cinder-nodeplugin-jg6nv 2/2 Running 0 102m
kube-system csi-cinder-nodeplugin-kwxkv 2/2 Running 0 102m
kube-system dns-autoscaler-7df78bfcfb-zz5dl 1/1 Running 0 104m
kube-system kube-apiserver-test-cluster-k8s-master-nf-1 1/1 Running 0 108m
kube-system kube-controller-manager-test-cluster-k8s-master-nf-1 1/1 Running 1 108m
kube-system kube-proxy-jklmh 1/1 Running 0 107m
kube-system kube-proxy-mb4lt 1/1 Running 0 107m
kube-system kube-proxy-qhrw6 1/1 Running 0 107m
kube-system kube-scheduler-test-cluster-k8s-master-nf-1 1/1 Running 1 108m
kube-system nginx-proxy-test-cluster-k8s-node-nf-1 1/1 Running 0 107m
kube-system nginx-proxy-test-cluster-k8s-node-nf-2 1/1 Running 0 107m
kube-system nodelocaldns-6nqp6 1/1 Running 0 103m
kube-system nodelocaldns-v4qpj 1/1 Running 0 103m
kube-system nodelocaldns-vzxp8 1/1 Running 0 103m
kube-system openstack-cloud-controller-manager-mdsjj 1/1 Running 0 105m
kube-system snapshot-controller-786647474f-52gv5 1/1 Running 0 102m
학부연구생으로 지내며 Openstack을 좀 다뤄보면서 많은 에러 로그를 보고 해결하고 찾고 했어서, 트러블 슈팅에 거부감이 없었어서 겨우 설치를 했던 것 같습니다.
Openstack에 Kubernetes를 구축하는 방법이 많이 없고 있다 하더라도 에러가 발생하여 설치하는 게 힘들었지만... 설치하고 보니 뿌듯합니다.
혹여 다음에 Openstack에 쿠버네티스를 설치하는 분이 있으면 진행 간에 도움이 되었으면 합니다.
잘 봤습니다