주메뉴 바로가기 본문 바로가기

알림

콘솔 이동 시 로그인이 필요합니다.

로그인하시겠습니까?

아니요

닫기

주문 불가 알림

주문권한이 없습니다.

콘솔에 접근할 수 없는 계정입니다.

확인

닫기

알림

신용카드 등록이 필요합니다.

신용카드 등록 페이지로 이동하시겠습니까?

아니요

닫기
C&C Tech
img

kubernetes 를 offline 으로 구축 하여 운영하기

img 정윤재
| 2024.10.12
  • kubernetes
  • offline
  • kubespray

kubespray 로 kubernetes 를 offline 으로 설치 하고 운영하는 방법을 알아본다.

일반적으로 public cloud 를 많이 사용하지만 어쩔 수 없이 망을 분리 하여 사용하기 위해 private cloud 를
검토해야 할 경우가 있습니다.
이런 경우 저희의  구축 및 운영 경험을 기반으로 한 Architeture 와 구축 방법을 공유해 보고자 합니다.
 
  1. 이 글에서 알아 갈 수 있는 것
  • 실무에서 설치,운영되는 Private k8s Architecture (망분리 된 자사 IDC 나 private 환경)
  • 실제 k8s설치 방법 (kubespray 사용, kubespary 버전은 2.24.1, k8s 버전은 1.29.2)
 
  1. 사전 필요 지식
  • 기본 k8s 구성
  • Linux 기본 이해
  • Ansible 기본 사용법
 
  1. Private k8s Archtecture
 

 
  • 이론적으로 k8s cluster 는 control plane 이라고 하는 master node 와 worker node 로 나누지만 실무적으로는 외부와 통신을 주로 담당하는 proxy node 를 두는 것이 좋습니다.
  • 외부 L4 의 역할은 여러 대의 master node, proxy node 에 대한 대표IP 제공(vip), Service 의 loadbalancer type 을 제공 해야 하는 경우 해당 L4 를 통해 서비스를 제공 할 수 있습니다.(metallb 가 없는 경우 직접 external ip 를 제공)
 
  1. K8s provisioning 방법 소개
  • Private k8s 를 설치 하기위해서는 아래와 같은 여러 가지 방법이 있습니다.
    • kubeadm : 단일 클러스터, 온프라미스에서 k8s 를 설치하기 위한 기초적인 방법 (대규모 클러스터에 적합하지 않음)
    • kubespray : ansible 을 이용한 k8s 클러스터 설치, 다양한 옵션제공 및 설정 파일 편집이 직관적임
    • kops : public cloud 환경에서 간단한 설치 및 관리
    • cluster api : operator 기반으로 멀티 k8s 클러스터 환경, 선언적 클러스터 관리가 가능
  • 이 중에 여기에서는 kubespray 를 통한 k8s 설치에 대해 알아 보겠습니다.
Kubespray 를 선택 한 이유는 ansible 기반이기 때문에 직관적이고 설정파일을 직접 수정 할 수 있고 여러가지 기능 추가가 쉽습니다.
Cluster api 는 k8s cluster 를 custom resource 로 관리 하는 진일보한 방식이기는 하지만 addon 확장이 가능은 하나 제한적입니다.
Public cloud 를 사용하지 않는 offline private cloud 환경에서 어떤 hardware 나 software 를 사용해야 할지 모르는 상황에서는 컨트롤이 쉽고 레퍼런스가 더 많은 kubespray 가 낫다고 판단했습니다.


     5. kubespray 를 통한 k8s provisioning

 
  • 실제 설치를 위해서는 위의 architeture 상태로 구성을 해야 합니다.
  • 위의 구성에 대해서 설명을 하자면
    • Bootstrap : ansible 을 실행 하고자 하는 노드 (외부 인터넷이 가능 하거나 인터넷에서 다운 받은 파일을 자유롭게 업로드 할 수 있는 서버 필요)
    • Node 1,2,3,4 … : 실제 k8s 가 설치 될 노드 (실제 k8s 가 구성 될 서버)
    • Image repository : container image 를 pull 받을 수 있는 repository
    • File repository : container runtime 이나 기타 필요한 파일들을 다운 받을 수 있는 구성
Repository 를 private으로 구성하는 방법은
(https://github.com/kubernetes-sigs/kubespray/tree/master/contrib/offline 를 참고 하시면 됩니다.)
 
  
  • 이제 실제로 kubespray 를 통해 k8s cluster 를 3번에서 설명한 대로 구성해 보겠습니다. (metallb 구성은 여기서는 제외하고 설치 합니다.)
    • Bootstrap 서버에서 root 계정으로 아래의 명령어들을 실행 하여 ssh key 교환을 합니다.
(root 로 진행 하는 이유는 k8s 에서 여러 권한 문제로 서버에서 동작을 안하는 경우를 방지하기 위해서 입니다. (80port 사용등))
shell> ssh-keygen -t rsa -b 2048
shell> ssh-copy-id root@node1
shell> ssh-copy-id root@node2
shell> ssh-copy-id root@node3
shell> ssh-copy-id root@node4

 
  (kubespray 버전과 해당 버전에 같이 설치 되는 사항은 https://github.com/kubernetes-sigs/kubespray 를 참고 하세요)
 
  • shell> cd kubespray
  • shell> pip3 install -r requirements.txt 를 통해 prerequisitions 를 설치 합니다. (사전에 python, pip 는 설치 되어 있어야 합니다.)
  • shell> cp -rpf inventory/sample/ inventory/testcluster 를 통해 sample 로 구성된 클러스터 정보를 설치 할 testcluster 로 복사합니다.
  • 본 문서는 망분리가 되어 있는 offline 설치를 기본으로 하므로 offline 설치에 대한 개략적인 설명을 하겠습니다.
    • shell> cd contrib/offline
    • shell >  ./generate_list.sh  명령을 통해 k8s 설치 되는데 필요한 파일과 container image 리스트를 얻을 수 있습니다.
위의 ~/kubespray/contrib/offline/temp 경로에 files.list , images.list 라는 파일, image 리스트가 담긴 파일이 생성 됩니다.
해당 file과 image 리스트를 다운받아서 사내 웹서버 또는 사내 repository 에서 k8s 가 설치 될 서버가 http 로 다운 받을 수 있는 환경을 구성 해주면 됩니다.
다만 그런 구성이 힘들 경우 아래의 스크립트를 추가 실행 시켜서 bootstrap 서버에 임시로 image repository, file repository 를 구성할 수 있습니다.
  • shell> ./manage-offline-files.sh 를 통해 k8s 를 위해 설치될 파일들을 다운로드 받고 file repository (8080 포트) 를 기동시킵니다.
  • shell> ./manage-offline-container-images.sh create 
  • shell> ./manage-offline-container-images.sh register 를 통해 설치될 image 들을 다운로드 받고 image repository(5000 포트) 를 기동시킵니다.
  • shell> vi ~/kubespray/inventory/testcluster/group_vars/all/offline.yml 에서
## Global Offline settings 부분을 아래와 같이 수정해 줍니다.
registry_host: "[bootstrap서버IP:5000]"
files_repo: "[bootstrap서버IP:8080]"
#아래는 OS 설정에 맞게 처리
ubuntu_repo: "[bootstrap서버IP:8080]"
#그 아래는 필요한 부분에 대해서 주석 해제 해주면 됩니다. (위의 global 변수 설정을 가져오므로 주석 해제만으로 처리됩니다.)
 
  • shell> vi ~/kubespray/inventory/testcluster/group_vars/all/containerd.yml
containerd_registries_mirrors:
 - prefix: [bootstrap서버IP:5000]
   mirrors:
    - host: http://[image[bootstrap서버IP:5000]
      capabilities: ["pull", "resolve"]
      skip_verify: true #https 가 아닌 http 를 사용하기 위해
 
  • shell> vi ~/kubespray/roles/container-engine/containerd/templates/hosts.toml.j2 부분을
server = "https://{{ item.prefix }}" 에서
server = "http://{{ item.prefix }}" 로 변경 해줘야 합니다. (kubespray 2.24.1 기준)
 
  • shell> vi ~/kubespray/inventory/testcluster/group_vars/all/offline.yml 의
kube_image_repo: "{{ registry_host }}"
gcr_image_repo: "{{ registry_host }}"
github_image_repo: "{{ registry_host }}"
docker_image_repo: "{{ registry_host }}"
quay_image_repo: "{{ registry_host }}"

kube_image_repo: "{{ registry_host }}/registry.k8s.io"
gcr_image_repo: "{{ registry_host }}/gcr.io"
github_image_repo: "{{ registry_host }}/ghcr.io"
docker_image_repo: "{{ registry_host }}/docker.io"
quay_image_repo: "{{ registry_host }}/quay.io"
로 변경 해줍니다.
 
 
  • k8s 클러스터를 구성 하고자 하는 모습은 아래 그림과 같습니다.
 

 
  • shell> vi inventory/testcluster/inventory.ini 를 통해 k8s 클러스터가 설치 될 서버들에 대한 정보를 기술 합니다. (etcd 는 모든 master node 에 기동 되도록 구성합니다.)
 
[all]
master1 ansible_host=[master1아이피] ip=[master1아이피] etcd_member_name=etcd1
master2 ansible_host=[master2아이피] ip=[master2아이피] etcd_member_name=etcd2
master3 ansible_host=[master3아이피] ip=[master3아이피] etcd_member_name=etcd3
proxy ansible_host=[proxy아이피] ip=[proxy아이피]
worker1 ansible_host=[worker1아이피] ip=[worker1아이피]
worker2 ansible_host=[worker2아이피] ip=[worker2아이피]
 
 
[kube_control_plane]
master1
master2
master3
 
[etcd]
master1
master2
master3
 
[kube_node]
master1
master2
master3
proxy
worker1
worker2
 
[proxy-node]
proxy
 
[worker-node]
worker1
worker2
 
 
[kube_control_plane:vars]
node_labels={"node-role.kubernetes.io/master" : "", "master" : "true", "node-role.kubernetes.io/control-plane" : "", "control-plane" : "true"}
 
[proxy-node:vars]
node_labels={"node-role.kubernetes.io/proxy" : "", "proxy" : "true"}
 
[worker-node:vars]
node_labels={"node-role.kubernetes.io/worker" : "", "worker" : "true"}
 
[calico_rr]
 
[k8s_cluster:children]
kube_control_plane
kube_node
calico_rr
 
  • shell> vi inventory/testcluster/group_vars/k8s_cluster/addons.yml 에서 주석 처리 되어 있는 nginx 설정을 아래와 같이 변경 합니다.
 
ingress_nginx_enabled: true
ingress_publish_status_address: ""
ingress_nginx_nodeselector:
  node-role.kubernetes.io/proxy : ""
ingress_nginx_configmap:
  proxy-read-timeout : "300"
  proxy-send-timeout : "300"
  worker-shutdown-timeout : "60m"
  proxy-body-size : "0"
 
 
  • shell> ansible all -m ping -i inventory/testcluster/inventory.ini 를 통해 설치를 진행할 노드와의 연결이 정상인지 확인 해 봅니다.
 
  • Shell> ansible-playbook --forks 50 -i inventory/testcluster/inventory.ini cluster.yml -b --become-user root -e ansible_ssh_timeout=50 -vvv | tee  kubespray_install_yyyymmdd.log 를 통해 설치를 진행 합니다.
 
  • Master node 에서 shell> kubectl get node 로 정상적으로 node 들이 Ready 상태인지 확인 합니다.

 
  • 클러스터에서 특정 node 를 제거하는 명령어는 다음과 같습니다.
shell> ansible-playbook -i inventory/testcluster/inventory.ini --become --become-user=root remove-node.yml -e node=[삭제노드host명] -v | tee kubespray_remove_yyyymmdd.log
 
 
  • 클러스터에서 특정 node 를 추가하는 명령어는 다음과 같습니다.
shell> ansible-playbook -i inventory/testcluster/inventory.ini --become --become-user=root scale.yml -l [추가노드host명] -v | tee kubespray_add_20241010.txt
 
 
 
  • K8S 클러스터 전체를 제거 하는 명령어는 아래와 같습니다.
shell> ansible-playbook --forks 50 -i inventory/testcluster/inventory.ini reset.yml --become --become-user=root -e ansible_ssh_timeout=50 -v | tee kubespray_reset_yyyymmdd.txt
 
  • K8S 클러스터에 대한 개별 노드에 대해 upgrade 를 진행 하기 위해서는
  • wget 으로 contrib/offline/offline-files/dl.k8s.io/release/v[업그레이드 타겟버전]/bin/linux/amd64 경로에
kubelet
kubectl
kubeadm
파일을 가져다 놓습니다.
그 다음
roles/kubespray-defaults/defaults/main/checksums.yml 파일에서 checksum 내용을 타겟 버전으로 kubelet, kubeadm, kubectl 을 추가 합니다.
(업그레이드 하려는 버전의 kubespray 가 있다면 가져오면 됩니다.)
 
  • image repository 에 upgrade 하려는 버전의 아래의 이미지들을 push 합니다.
registry.k8s.io/kube-apiserver
registry.k8s.io/kube-controller-manager
registry.k8s.io/kube-proxy
registry.k8s.io/kube-scheduler
 
  • roles/network_plugin/meta/main.yml 에서
  - role: network_plugin/multus
    when: kube_network_plugin_multus
    tags:
      - multus
주석 처리
 
  • roles/kubernetes-apps/network_plugin/meta/main.yml 에서
  - role: network_plugin/multus
    when: kube_network_plugin_multus
    tags:
      - multus
 
을  주석 처리로 변경 해 줍니다.
 
그 다음 업그레이드 명령을 수행하면 됩니다.
shell> ansible-playbook -i inventory/baremetal/inventory.ini upgrade-cluster.yml --become --become-user=root -e kube_version=v[타겟버전] --limit [타겟노드] | tee kubespray_upgrade_yyyymmdd.txt
 

 
 
위와 같이 kubespray 로 kubernetes 를 구성, 삭제, 추가, 업그레이드 하는 방법을 살펴 보았습니다. 
위의 내용을 따라 하신 다면 ansible 에 대한 이해가 크게 없으셔도 충분히 따라서 구축 및 운영에 도움이 되실 거라고 생각합니다.
이 글로 private cloud 의 offline 설치에 좀 더 자신감을 가지실 수 있었으면 합니다.

상세 내용을 실제 코드 상에서 확인 하고 싶으시다면
https://github.com/YunchaeJung/kubespray/tree/main/2.24.1
를 참고 하세요
img
정윤재 | Cloud Architect team

C&C 에서 private cloud 를 운영하고 있습니다.