Openstack 기반 Kubernets 구축 with Kubespray

변재한·2023년 7월 26일
0

본 포스팅에서는 오픈스택에 쿠버네티스를 Kubespray라는 오픈소스를 이용하여 구축하는 과정을 다뤄보겠습니다.

졸업과제에 프라이빗 클라우드를 활용한 클라우드 네이티브 환경 구축이 필요하여 진행해보게 되었습니다.

프로그램 버전 등의 이유로 설치 진행 간에 오류가 많아 힘들었어서, 조금 자세히 적어보겠습니다.

환경

먼저, 오픈스택은 devstack을 이용하여 단일 VirtualBox VM에 설치하였고, 사양 및 버전은 다음과 같습니다.

VM 사양
1. CPU - 4core
2. RAM - 16GB
3. Disk - 100GB
3. NIC - 호스트전용 어댑터, 어댑터에브릿지
4. OS - Ubuntu 20.04 server image

Openstack 사양(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

설치 과정

사전 설치 프로그램

  • terraform v1.3.0 설치
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
  • 파이썬 가상환경
    설치 진행 중 버전 호환으로 인한 중지, 에러 등등으로 kubespray의 툴들(requirements.txt)를 다시 설치해야 하는 경우가 많아 가상환경에서 설치 진행을 추천합니다.
sudo apt-get install python3-virtualenv

virtualenv .kubespray

source .kubespray/bin/activate

pip install -U pip

=> 이렇게 하면 CLI 옆에 괄호 안 가상환경 이름이 표시됩니다.

(.kubespray) stack@jae:~/kubespray$
  • Openstack CLI 권한 얻기
    이는 Terraform이 OpenStack을 인증하는 데 사용하는 환경 변수를 설정하는 단계로 오픈스택 대시보드에서 1. 해당 파일을 다운로드 -> 오픈스택이 설치된 vm으로 이동 or 2. 해당 파일을 다운로드 후 메모장으로 열어서 해당 내용 복사하여 vi 편집기로 .sh 확장자 파일을 새로 오픈스택이 설치된 vm에 만들어 인증하는 방법 두 가지 중 편한대로 수행

인증이 완료되면 다음과 같이 openstack CLI 정상 동작

  • SSH Key
    ansible은 ssh 연결을 이용하여 원하는 target node에 명령을 수행하게 하는 오픈소스로 ssh key가 필요합니다.
ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_rsa.kubespray

# 현재 쉘에서 ssh agent 시작
eval $(ssh-agent -s)

# 생성된 키 추가
ssh-add ~/.ssh/id_rsa.kubespray

Kubespray Clone

본격적으로 kubespray 저장소를 clone하여 설치를 진행합니다.
위에서 가상환경을 활성화한 상태에서 진행합니다.

git clone --branch v2.21.0  https://github.com/kubernetes-sigs/kubespray

cd kubespray

pip install -r requirements.txt

Cluster

첫번째로 그냥 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

Terraform

본 포스팅에서는 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 %}'"

Ansible

Ansible ping

다음과 같이 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 멤버 설정

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>

Ansible 변수 설정

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

Ansible을 이용하여 Kubernetes 배포

다음 명령은 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

재설치 시 etcd 관련

설치 진행 중 에러가 발생하여 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에 쿠버네티스를 설치하는 분이 있으면 진행 간에 도움이 되었으면 합니다.

profile
Infra and Devops 엔지니어가 되고 싶어용

1개의 댓글

comment-user-thumbnail
2023년 9월 4일

잘 봤습니다

답글 달기