Kubespray
개요
Kubespray는 Ansible을 기반으로 쿠버네티스 클러스터를 구축할 수 있도록 도와주는 툴이다.
앤서블의 방식으로 설정을 진행하며, 앤서블이 그러하듯이 각 노드에 SSH로 접근하여 각종 명령을 수행한다.
큐브스프레이를 처음 알았을 때는 사실 클러스터를 하드웨이로 구축하는 글을 찾다가..[1]
특징
역시 앤서블 기반으로 쿠버네티스를 설치한다는 것이 가장 큰 특징이다.
- 중앙에서 ssh로 접근이 가능한 모든 노드를 관리할 수 있다.
- 여러 태스크를 지정하여 순서대로 필요한 툴을 설치하는 것이 가능하다.
굳이 앤서블의 특징만 강조하는 것 같은데, 그럴 만도 한 게 사실 kubeadm이 하는 동작을 그대로 따라하기도 하고 또 내부적으로 애초에 kubeadm를 사용하고 있다.[2]
이때 kubeadm을 사용할 때 미리 진행해야 하는 여러 작업, 스왑 끄기, ntp 동기화 등 그냥 다 해준다..
그래서 엄밀하게 보면 kubeadm를 앤서블이란 플랫폼으로 추상화시켜서 각종 기능과 자동화를 더 제공해주는 툴이라 보면 된다.
근데 그 자동화의 수준이 굉장히 자유롭고 다양하다는 것이 특장점이라 할 수 있겠다.
전체 디렉토리 구조
먼저 kubespray의 전체 디렉토리는 이렇게 이뤄져 있다.
앤서블에서 기본으로 두는 구조에, 큐브스프레이에서는 쉽게 사용할 수 있도록 몇 가지 플레이북을 상위 디렉토리에 위치시켜 두고 있다.
ansible-playbook -i /inventory/sample --private-key /root/.ssh/id_rsa cluster.yml
그래서 이렇게 해당 플레이북을 실행시키는 방식으로 사용해주면 된다.
인벤토리 구조
앤서블 구조에 익숙하다면 그리 어렵진 않을 것이다.(난 안 익숙해서 어려웠다.)
인벤토리 파일(inventory.ini)에 컨트롤 플레인과 워커 노드를 그룹으로 지정한다.
구체적으로 인벤토리에서 지정하는 그룹은 다음과 같다.[3]
- kube_control_plane - 컨트롤 플레인이 위치할 노드
- kube_node - 워커 노드
- 컨트롤 플레인도 워커노드로 쓰려면 여기에 같이 써준다.
- etcd - Etcd가 위치할 노드
- 즉 컨트롤 플레인과 별도로 배치할 수 있다!
- bastion - 바스티온
- 클러스터에 직접 접속이 불가능하여 바스티온을 경유해야 할 때 설정한다.
- calico_rr - 추가적으로 칼리코 한정 세부 설정을 위한 그룹
etcd를 컨테이너로 띄우는 것을 기본으로 하는 kubeadm(이쪽도 커스텀은 가능)과 다르게 kubespray는 etcd를 systemd에 등록하여 기동하는 것을 기본으로 한다.
그렇기 때문에 etcd를 별도의 그룹으로 지정하며, 클러스터 컨트롤 플레인을 구축할 때 api 서버와 분리된 환경에 etcd를 따로 배치하는 패턴을 간편하게 할 수 있다.
그리고 워커, 마스터 모든 노드를 아우르는 k8s_cluster라는 그룹도 있는데, 이건 직접 명시할 필요가 없다.
이 그룹 네이밍은 현재 버전 기준인데, 이전 버전의 네이밍을 써도 알아서 그룹 네임을 수정해준다.[4]
여기에서 k8s_cluster로 걸어서 모든 노드를 대상으로 삼는 것을 확인할 수 있다.
큐브스프레이에서 사용되는 각종 변수와 설정 값은 inventory 파일이 위치한 디렉토리에 group_vars 하위 디렉토리를 두고 설정한다. (앤서블 기본)
각 그룹 별 커스텀이 필요할 때는 그룹 이름의 디렉토리를 안 속에 만들어서 yaml 파일을 넣어주면 된다.
샘플에는 k8s_cluster 디렉토리가 위치하고 있다.
클러스터의 모든 노드는 이 그룹에 속하므로 여기에 각종 설정을 넣어주는 게 가장 기본적인 사용법이다.
관련한 변수는 문서를 직접 참조하자.[5]
샘플 디렉토리에서는 각 cni나 애드온 별 설정을 구분하기 좋게 따로 파일을 나누어서 넣어둔 것을 확인할 수 있다.
아래는 간단하게 클러스터를 구축하는 설정 파일의 예시이다.
# 컨트롤 플레인에 ip는 api 서버가 서로 통신이 사용할 주소를 말한다.
# etcd를 넣을 노드라면 etcd도 명시해야 한다.
[kube_control_plane]
node1 ansible_host=95.54.0.12 # ip=10.3.0.1 etcd_member_name=etcd1
node2 ansible_host=95.54.0.13 # ip=10.3.0.2 etcd_member_name=etcd2
node3 ansible_host=95.54.0.14 # ip=10.3.0.3 etcd_member_name=etcd3
# etcd 그룹으로 위 컨플을 포함시켰다.
# 그래서 etcd와 컨플은 정확히 같은 노드에 배치된다.
[etcd:children]
kube_control_plane
[kube_node]
node4 ansible_host=95.54.0.15 # ip=10.3.0.4
group_vars 디렉토리의 all에는 모든 노드에 공통적으로 세팅돼야할 설정들이 들어간다.
그리고 클러스터 구축 때 활용되는 설정들은 k8s_cluster에 들어간다.
kube_config_dir: /etc/kubernetes
kube_script_dir: "{{ bin_dir }}/kubernetes-scripts"
kube_manifest_dir: "{{ kube_config_dir }}/manifests"
kube_cert_dir: "{{ kube_config_dir }}/ssl"
kube_token_dir: "{{ kube_config_dir }}/tokens"
kube_api_anonymous_auth: true
# Where the binaries will be downloaded.
local_release_dir: "/tmp/releases"
retry_stagger: 5
kubeadm에서 할 수 있는 설정들이 많이 보이는데, 실제로 kubespray가 내부적으로 kubeadm을 사용하고 있어서 그렇다.
플레이북, 롤 구조
실제 사용하게 되는 플레이북 중 가장 기본이 되는 cluster.yml 파일을 기준으로 세부 구조를 파악해보자.
그렇다! 상위 디렉토리에 있는 cluster.yml은 playbooks 디렉토리 내부에 cluster.yml을 임포트한다.
해당 파일은 이렇게 구성된다.
# 앤서블 버전, 그룹, 인벤토리 세팅 사전 체크
- name: Common tasks for every playbooks
import_playbook: boilerplate.yml
# 팩트 수집
- name: Gather facts
import_playbook: facts.yml
# 클러스터 노드면서 etcd가 설치될 노드에 대한 사전 세팅
- name: Prepare for etcd install
hosts: k8s_cluster:etcd
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
# kubespray_defaults는 모든 설정값이 담긴 롤로, 다른 롤이 수행되기 이전 설정값들을 세팅하는 역할을 한다.
- { role: kubespray_defaults }
- { role: kubernetes/preinstall, tags: preinstall }
- { role: "container-engine", tags: "container-engine", when: deploy_container_engine }
- { role: download, tags: download, when: "not skip_downloads" }
# etcd 설치
- name: Install etcd
vars:
etcd_cluster_setup: true
etcd_events_cluster_setup: "{{ etcd_events_cluster_enabled }}"
import_playbook: install_etcd.yml
# 클러스터 노드 세팅
- name: Install Kubernetes nodes
hosts: k8s_cluster
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
# kubernetes/node 롤은 swapoff, netfilter 등 노드의 사전 세팅
# kubelet, kubeadm 배치 등의 작업 수행
- { role: kubernetes/node, tags: node }
# 컨트롤 플레인 세팅
- name: Install the control plane
hosts: kube_control_plane
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
# kubeadm init할 때 이뤄지는 동작 고대로 함
- { role: kubernetes/control-plane, tags: control-plane }
# 앤서블 호스트에서 접근할 수 있도록 kubeconfig 설정, 혹은 kubectl 배치 작업
- { role: kubernetes/client, tags: client }
- { role: kubernetes-apps/cluster_roles, tags: cluster-roles }
# kubeadm을 통한 노드 조인, cni 배치
- name: Invoke kubeadm and install a CNI
hosts: k8s_cluster
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
- { role: kubernetes/kubeadm, tags: kubeadm}
- { role: kubernetes/node-label, tags: node-label }
- { role: kubernetes/node-taint, tags: node-taint }
- role: kubernetes-apps/gateway_api
when: gateway_api_enabled
tags: gateway_api
delegate_to: "{{ groups['kube_control_plane'][0] }}"
run_once: true
# 노드에 cni 플러그인 세팅 및 cni 프로바이더 설치
# 참고로 network_plugin: cni이라 설정되면 프로바이더는 배치되지 않음
- { role: network_plugin, tags: network }
# 칼리코 한정 세팅
- name: Install Calico Route Reflector
hosts: calico_rr
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
- { role: network_plugin/calico/rr, tags: ['network', 'calico_rr'] }
# 윈도우 한정 세팅
- name: Patch Kubernetes for Windows
hosts: kube_control_plane[0]
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
- { role: win_nodes/kubernetes_patch, tags: ["control-plane", "win_nodes"] }
# kubectl을 통해 배치하는 워크로드, 어플리케이션 배치
# cni 관련 추가 워크로드나 csi 프로바이더, argocd, helm 등등..
- name: Install Kubernetes apps
hosts: kube_control_plane
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
- { role: kubernetes-apps/external_cloud_controller, tags: external-cloud-controller }
- { role: kubernetes-apps/network_plugin, tags: network }
- { role: kubernetes-apps/policy_controller, tags: policy-controller }
- { role: kubernetes-apps/ingress_controller, tags: ingress-controller }
- { role: kubernetes-apps/external_provisioner, tags: external-provisioner }
- { role: kubernetes-apps, tags: apps }
# 클러스터 구축 이후 dns 세팅
- name: Apply resolv.conf changes now that cluster DNS is up
hosts: k8s_cluster
gather_facts: false
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles:
- { role: kubespray_defaults }
- { role: kubernetes/preinstall, when: "dns_mode != 'none' and resolvconf_mode == 'host_resolvconf'", tags: resolvconf, dns_late: true }
길지만 요약하자면 kubeadm으로 클러스터를 구축할 때 하는 일을 거의 완벽하게 따라하며 추가 작업을 곁들여 진행한다.
노드 기본 세팅 -> 마스터 노드 kubeadm init -> 워커 노드 kubeadm join이라는 전체 순서가 완벽하게 똑같다.
또한 플레이북에서는 여러 롤들을 활용해 클러스터 세팅을 진행한다.
이때 중요한 롤 중 하나가 바로 kubespray_defaults
로, 해당 롤은 큐브스프레이의 모든 설정 정보를 담고만 있는 롤이다.
인벤토리에서 어떤 설정을 넣어야 하는지 모르겠다면 이 롤의 내용을 까보면 된다.
여기에 정말 잡다한 설정의 기본값이 담겨 있으며, 인벤토리에서의 설정은 위 설정들을 오버라이드하게 된다.
몇 가지 롤 보기
구체적인 동작을 파악하기 위해 간단하게 몇 가지 롤만 살펴본다.
클러스터를 구축하는데 들어가는 세팅의 태반은 kubespray가 세팅될 때 다 알아서 진행된다.[6]
아래 태스크들은 kubernetes/node에 들어간 태스크들로, 사용자가 일일히 노드에 기본 노드 세팅을 할 필요가 없다.
한편 container_engine 롤은 컨테이너 런타임을 세팅하는 역할을 한다.
그런데 해당 롤 디렉토리엔 tasks 디렉토리가 없다.
대신 meta 디렉토리에서 종속성을 정의하여 여러 컨테이너 런타임이 사용될 때 각 롤을 수행하도록 되어있다.[7]
이러한 방식은 클러스터에 복수의 컨테이너 런타임을 배치하기 용이하다.
network_plugin 롤도 이러한 방식으로 만들어져 있어 다양한 cni를 배치하는 작업을 유연하게 설정할 수 있다.
기본 사용법
kubespray 사용은 그냥 레포를 그대로 다운 받아서 사용하면 된다.[8]
그 중 inventory에 있는 것만 사용자가 수정해주면 된다.
구체적으로 사전에 필요한 사항은 다음과 같다.
- 앤서블이 당연히 설치돼있어야 하며,[9] 이을 구동할 수 있도록 파이썬과 pip(requirements.txt)가 요구된다.
- 타겟 서버에 인터넷에 접근이 가능해야 하나, 에어갭을 위한 세팅도 가능하다.[10]
- 타겟 서버는 패킷 포워딩을 지원해야 한다.
- 이건 노드로서 기능하기 위해 무조건 필요한 거긴 하다.
- 방화벽은 알아서 세워야 하며, 배포 간의 이슈를 피하기 위해서는 방화벽을 내려둘 것이 권장된다.
- 루트 유저로 큐브스프레이를 실행하는 게 아니라면 타겟 서버 세팅 시 적절히 권한 상승이 돼야만 한다.
- ansible_become, -b 메서드를 이용하면 된다고 한다.
kubespray를 이용한 기본 클러스터 구축은 cluster.yml 플레이북을 사용한다.
ansible-playbook -i /inventory/sample -b --become-user=root --private-key /root/.ssh/id_rsa cluster.yml
아래부터는 공통적으로 들어갈 인자는 제외한다.
노드를 추가하거나, 삭제하는 작업은 다음과 같이 설정한다.
# 노드 추가
# 인벤토리에 추가할 노드 먼저 명시
ansible-playbook scale.yml
# 노드 삭제 - 알아서 드레인 등의 작업을 수행
ansible-playbook remove-node.yml -e node=NODE_NAME
# 이후 해당 노드를 인벤토리 파일에서 제거하면 끝.
# 컨트롤 플레인 노드 추가
# 인벤토리에 추가할 노드 먼저 명시
# scale.yml이 아니라 cluster.yml 사용!
ansible-playbook cluster.yml
# HA 세팅 시 - 각 노드 별로 api 서버를 로드밸런싱 해주는 워크로드 재시작
docker ps | grep k8s_nginx-proxy_nginx-proxy | awk '{print $1}' | xargs docker restart
# 클러스터 업그레이드
# 버전 값을 인벤토리 파일에 설정하는 방식이 더 낫다
ansible-playbook upgrade-cluster.yml -e kube_version=1.19.7
노드 추가까지는 kubespray로 간편하게 할 수 있지만 나머지 작업은 kubespray 작업 이후 추가적인 작업을 요구하는 경우가 많다.
개인적인 의견으로는 기존 운영 방식에서 직접 해야 하는 사항을 몇 가지만 자동화시킬 뿐 큐베스프레이를 통해 운영의 편의성을 기대하긴 어렵다고 본다.
오히려 어려워지는 운영 지점까지 생긴다고 생각한다.
- kubespray만으로 설정이 가능한 운영 작업인지 먼저 검토하고, 해당 작업에 대해 kubespray가 얼마나 자동화시켜주는지 고려해야 함
- kubespray만으로 부족해 몇 가지 커스텀 작업을 하게 된다면, 해당 작업이 kubespray의 설정과 겹쳐서 kubespray로 인해 원복될 가능성을 고려해야 함
kubespray가 가져다주는 이점 중 가장 큰 부분은 앤서블에 기반한 멱등성 보장이라고 생각한다.
활용
HA 구성
kubespray는 HA 구성을 매우 쉽게 할 수 있게 되어 있다.
먼저 etcd의 경우 그냥 홀수 개의 노드를 그룹에 넣어주기만 하면 이중화 끝.
어차피 etcd는 RAFT를 사용하며 무조건 구성원은 리더로 트래픽을 넘기기 때문에 딱히 설정이 필요 없는 것이다.
그래도 다음의 설정을 넣어 로드밸런서를 거치게 할 수 있다.
etcd_access_addresses: https://etcd.example.com:2379
etcd_client_url: https://etcd.example.com:2379
etcd_cert_alt_names:
- "etcd.kube-system.svc.{{ dns_domain }}"
- "etcd.kube-system.svc"
- "etcd.kube-system"
- "etcd"
- "etcd.example.com" # This one needs to be added to the default etcd_cert_alt_names
api 서버를 이중화할 때도 그냥 그룹을 작성하기만 하면 되긴 하다.
근데 api 서버로 트래픽을 분산하기 위한 프록시 서버가 필요하다.
kubespray에서는 이를 위해 클러스터 내부에 nginx나 HAproxy를 배치하여 프록시 역할을 수행하게 한다.[11]
유의할 점으로 이 프록시는 클러스터 노드에서 오는 트래픽에 대한 로드밸런싱을 수행한다는 것.
클러스터 내부에서 api 서버의 프록시를 수행한다고 해서 로컬호스트 로드밸런싱이라고도 부른다.
외부 로드밸런서를 배치하고 싶다면 관련한 설정을 추가해서 넣어야 한다.
apiserver_loadbalancer_domain_name: "my-apiserver-lb.example.com"
loadbalancer_apiserver:
address: <VIP>
port: 8383
해당 정보를 미리 세팅해야 하는 게 결국 api 서버의 인증서에 로드밸런서를 SAN으로 추가해야 하기 때문이다.
사용자가 사용하는데 있어서도 해당 프록시를 노출시킨 후 접근해도 되긴 하다.
대규모 운영
많은 노드를 관리하면 설정을 확인하고 태스크를 수행하는데 당연히 시간이 길어지기 마련이다.
이런 운영 케이스에 대해서 몇 가지 고려할 수 있는 전략이 있다.[12]
기본적인 사용에 있어서 중요한 것은 어떤 인벤토리를 사용하는가, 그리고 어떤 태그를 붙이느냐.[13]
비교
비교 대상이 되는 툴들이 있다.[14]
- kops
- Kops는 이를 지원하는 클라우드에서만 사용할 수 있으며 그런 만큼 유연성이 작다.
- kubeadm
- kubeadm은 사실 가장 기본적인 설치 툴이라 비비긴 힘들다.
- 근데 kubeadm은 노드 조인을 할 때 각 노드에 접근해야 하는 번거로움이 있으며, 많은 영역을 자동화해주기는 하나 전체 클러스터를 한번에 구축할 수 있도록 돕지는 않는다.
- 또한 25년 기준 최근에서야 선언적으로 설정 파일을 관리할 수 있도록 양식을 도입하고 있는데, 아직 성숙하지 않았다.
하위 문서
이름 | is-folder | index | noteType | created |
---|---|---|---|---|
kubeadm | - | - | knowledge | 2024-08-05 |
crictl | - | - | knowledge | 2024-08-26 |
Helm | - | - | knowledge | 2024-10-17 |
툴 | false | - | knowledge | 2024-12-28 |
K9s | false | - | knowledge | 2024-12-28 |
kubectl | false | - | knowledge | 2025-02-03 |
kubestr | false | - | knowledge | 2025-02-19 |
KIND | false | - | knowledge | 2025-04-06 |
Kubespray | false | 8 | knowledge | 2025-06-09 |
관련 문서
EXPLAIN - 파생 문서
이름0 | related | 생성 일자 |
---|
기타 문서
Z0-연관 knowledge, Z1-트러블슈팅 Z2-디자인,설계, Z3-임시, Z5-프로젝트,아카이브, Z8,9-미분류,미완이름1 | 코드 | 타입 | 생성 일자 |
---|---|---|---|
에어갭 kubespray 단일 노드 설치 with Vagrant | Z8 | topic | 2025-06-09 21:23 |
참고
https://github.com/kubernetes-sigs/kubespray/blob/master/roles/kubernetes/control-plane/tasks/kubeadm-setup.yml ↩︎
https://github.com/kubernetes-sigs/kubespray/blob/master/docs/ansible/inventory.md ↩︎
https://github.com/kubernetes-sigs/kubespray/blob/master/playbooks/boilerplate.yml ↩︎
https://github.com/kubernetes-sigs/kubespray/blob/master/docs/ansible/vars.md ↩︎
https://github.com/kubernetes-sigs/kubespray/blob/master/roles/kubernetes/node/tasks/main.yml ↩︎
https://github.com/kubernetes-sigs/kubespray/blob/master/roles/container-engine/meta/main.yml ↩︎
https://kubespray.io/#/docs/getting_started/getting-started ↩︎
https://kubespray.io/#/docs/operations/offline-environment ↩︎
https://github.com/kubernetes-sigs/kubespray/blob/master/docs/operations/ha-mode.md#kube-apiserver ↩︎
https://github.com/kubernetes-sigs/kubespray/blob/master/docs/operations/large-deployments.md ↩︎
https://kubespray.io/#/docs/ansible/ansible?id=ansible-tags ↩︎