Kubernetes, install / Kubespray

Jeonghak Cho·2025년 4월 13일

Kubernetes

목록 보기
10/20

📗Kubespray 개요

Kubespray는 Ansible 기반의 Kubernetes 클러스터 설치 자동화 도구이다. Kubernetes 공식 프로젝트이며, 프로덕션 수준의 클러스터를 손쉽게 설치하고 관리할 수 있도록 도와줍니다. 온프레미스 환경에서 Kubernetes 클러스터를 설치하고자 할 때 사용한다.

주요 특징

기능설명
Ansible 기반Ansible 플레이북을 활용해 YAML 설정만으로 클러스터 구성 가능
멀티 OS 지원Ubuntu, Debian, CentOS, RHEL, Fedora, Flatcar 등 지원
멀티 클라우드/온프레미스 지원AWS, GCP, Azure, OpenStack, VMware, 베어메탈 등 다양한 환경 지원
플러그인/네트워크 선택 가능Calico, Flannel, Cilium, Canal 등 다양한 CNI 선택 가능
보안 기능 내장TLS 인증서 자동 생성, RBAC 설정 가능
모듈화된 구조컴포넌트 별로 구성 가능 (etcd, container runtime, DNS 등)
Idempotent (멱등성)같은 작업을 여러 번 실행해도 안정적인 상태 유지

활용

  • 클라우드-간 일관된 설치가 필요할 때 (멀티 클라우드 또는 하이브리드 클라우드)
  • 기존 CI/CD 파이프라인에 인프라 구축을 통합하고자 할 때
  • 쿠버네티스의 세부 설정까지 직접 컨트롤하고 싶은 경우

참고

🏳️‍🌈 [궁금한점]

  • CSI 가 무엇인가
  • 인기있는 CSI 드라이버는 어떤 것인가
  • 사용 규모에 따라 어떤 드라이버를 사용할 수 있나

🔗[목차]

설치

노드 준비

VM을 3개 준비한다. IP는 192.168.56.10 (Master), 192.168.56.101 (worker1),, 192.168.56.102 (bastion) 으로 설정했다.

SSH 연결 설정

SSH Key 생성

  • worker2를 bation 으로 활용
  • worker2 접속 후 ssh key 생성
vagrant@worker2:~$ ssh-keygen -t rsa -b 4096 -C "chojeonghak@gmail.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/vagrant/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/vagrant/.ssh/id_rsa
Your public key has been saved in /home/vagrant/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:FJT8a+T+Hb5Db0E4S12NrIv6znMXcb507RDGF3F4/v0 chojeonghak@gmail.com
The key's randomart image is:
+---[RSA 4096]----+
|       oo.   . ++|
|        o.    +.=|
|        ..   oooo|
|       .  o .+=o+|
|        So o.o+*+|
|          = ..+o*|
|         +   .o==|
|        ..o .oooE|
|         o++..++ |
+----[SHA256]-----+

SSH key 복사

ssh-copy-id vagrant@192.168.56.10
ssh-copy-id vagrant@192.168.56.101

KUBE-SPRAY 다운로드

bastion에서 kube-spray 소스를 클론한다.

vagrant@worker2:~$ git clone https://github.com/kubernetes-sigs/kubespray
vagrant@worker2:~$ cd kubespray
vagrant@worker2:~/kubespray$ git checkout release-2.27
Switched to branch 'release-2.27'
Your branch is up to date with 'origin/release-2.27'.

인벤토리 생성

인벤토리에 작업 대상 서버의 속성을 기술한다. master, worker1 과 bation으로 사용할 worker2를 구성했다.

cp -r inventory/sample inventory/mycluster

vi inventory/mycluster/hosts.yml

all:
  hosts:
    master:
      ansible_host: 192.168.56.10
      ip: 192.168.56.10
      access_ip: 192.168.56.10
      ansible_user: vagrant
      ansible_become: true
    worker1:
      ansible_host: 192.168.56.101
      ip: 192.168.56.101
      access_ip: 192.168.56.101
      ansible_user: vagrant
      ansible_become: true
  children:
    kube_control_plane:
      hosts:
        master:
    kube_node:
      hosts:
        worker1:
    etcd:
      hosts:
        master:
    k8s_cluster:
      children:
        kube_control_plane:
        kube_node:
    calico_rr:
      hosts: {}

Python 설치 (3.10)

ansible 설치를 위해 python을 설치한다. bation에서 계속 진행한다.

sudo add-apt-repository ppa:deadsnakes/ppa -y
sudo apt update
sudo apt install -y python3.10 python3.10-venv python3.10-dev
sudo apt install -y python3-pip
sudo ln -sf /usr/bin/pip3 /usr/bin/pip
python3 --version   # → Python 3.10.x

버전이 3.10.17 이 나와야 한다. 틀릴 경우 이미 설치된 버전이 있다는 것이다. 다음의 방법을 통해 버전을 변경한다.

sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10 1
sudo update-alternatives --config python3

vagrant@worker2:~/kubespray$ python3 --version
Python 3.10.17

참고로 Kubespray 버전별 Python 및 Ansible 호환성은 다음과 같다.

| Kubespray 버전 | 권장 Python 버전 | 권장 Ansible 버전 |
|----------------|------------------|-------------------|
| v2.22.x        | 3.8 이상         | 2.12.x            |
| v2.23.x        | 3.9 이상         | 2.13.x            |
| v2.24.x        | 3.10 이상        | 2.14.x            |
| v2.25.x        | 3.10 이상        | 2.16.x            |

Ansible 설치 ( PIP3 이용 )

vagrant@worker2:~/kubespray$# curl -sS https://bootstrap.pypa.io/get-pip.py | sudo python3
vagrant@worker2:~/kubespray$ pip3 --version
pip 25.0.1 from /usr/local/lib/python3.10/dist-packages/pip (python 3.10)

sudo pip3 install -r requirements.txt

vagrant@worker2:~/kubespray$ ansible --version
ansible [core 2.12.5]
  config file = /home/vagrant/kubespray/ansible.cfg
  configured module search path = ['/home/vagrant/kubespray/library']
  ansible python module location = /usr/local/lib/python3.10/dist-packages/ansible
  ansible collection location = /home/vagrant/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.10.17 (main, Apr  9 2025, 08:54:15) [GCC 9.4.0]
  jinja version = 3.1.2
  libyaml = False

노드 연결 확인

vagrant@worker2:~/kubespray$ ansible all -m ping -i inventory/mycluster/hosts.yml
[WARNING]: Skipping callback plugin 'ara_default', unable to load
master | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
worker1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

CNI 변경

vi inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
  • 변경전
    kube_network_plugin: calico
  • 변경후
    kube_network_plugin: cillium

쿠버네티스 설치

ANSIBLE_NO_LOG=False ansible-playbook -i inventory/mycluster/hosts.yml cluster.yml -b -vvvv

-b는 sudo 권한을 의미, -v는 verbose

-v: 간단한 추가 로그
-vv: SSH 실행 내용, 변경 여부 등
-vvv: 모듈 실행의 STDOUT/STDERR 로그까지 표시 (추천)
-vvvv: 연결 디버그까지 포함 (네트워크 트러블슈팅용)

설치 확인
모든 설치 노드에서 확인

systemctl status kubelet

마스터에서 확인

ps aux | grep kube-apiserver

vagrant@master:~$ which kubectl
/usr/local/bin/kubectl

  • cilium 상태 확인
vagrant@master:~$ k exec -it cilium-7jvwg -n kube-system -- cilium status
Defaulted container "cilium-agent" out of: cilium-agent, mount-cgroup (init), apply-sysctl-overwrites (init), clean-cilium-state (init), install-cni-binaries (init)
KVStore:                 Ok   etcd: 1/1 connected, leases=1, lock leases=1, has-quorum=true: https://192.168.56.10:2379 - 3.5.19 (Leader)
Kubernetes:              Ok   1.31 (v1.31.7) [linux/amd64]
Kubernetes APIs:         ["EndpointSliceOrEndpoint", "cilium/v2::CiliumClusterwideNetworkPolicy", "cilium/v2::CiliumNetworkPolicy", "cilium/v2alpha1::CiliumCIDRGroup", "core/v1::Namespace", "core/v1::Pods", "core/v1::Service", "networking.k8s.io/v1::NetworkPolicy"]
KubeProxyReplacement:    Partial   [eth0   10.0.2.15 fe80::a00:27ff:fecb:1a1d, eth1   192.168.56.10 fe80::a00:27ff:fec6:2224]
Host firewall:           Disabled
SRv6:                    Disabled
CNI Chaining:            none
CNI Config file:         successfully wrote CNI configuration file to /host/etc/cni/net.d/05-cilium.conflist
Cilium:                  Ok   1.15.9 (v1.15.9-2ea0cf33)
NodeMonitor:             Disabled
Cilium health daemon:    Ok
IPAM:                    IPv4: 4/254 allocated from 10.233.64.0/24,
IPv4 BIG TCP:            Disabled
IPv6 BIG TCP:            Disabled
BandwidthManager:        Disabled
Host Routing:            Legacy
Masquerading:            IPTables [IPv4: Enabled, IPv6: Disabled]
Controller Status:       34/34 healthy
Proxy Status:            OK, ip 10.233.64.84, 0 redirects active on ports 10000-20000, Envoy: embedded
Global Identity Range:   min 256, max 65535
Hubble:                  Disabled
Encryption:              Disabled
Cluster health:          1/2 reachable    (2025-04-13T03:43:12Z)
  Name                   IP               Node          Endpoints
  worker1                192.168.56.101   unreachable   reachable
Modules Health:          Stopped(0) Degraded(0) OK(11)

연결 설정

mkdir -p ~/.kube
sudo cp /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

bastion으로 conf 복사
마스터에서 실행

sudo scp /etc/kubernetes/admin.conf vagrant@192.168.56.101:~/admin.conf
sudo scp /etc/kubernetes/admin.conf vagrant@192.168.56.102:~/admin.conf

베스천에서 실행, kubectl 설치

(필요 시)워크노드와 bastion에 kubectl 설치

curl -LO "https://dl.k8s.io/release/v1.29.0/bin/linux/amd64/kubectl"
chmod +x kubectl

sudo mv kubectl /usr/local/bin/

> 버전 확인
``` bash
vagrant@worker2:~/kubespray$ kubectl version --client
Client Version: v1.29.0
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3

테스트

테스트 용 POD 생성

busybox 테스트

# busybox.yaml
apiVersion: v1
kind: Pod
metadata:
  name: busybox
spec:
  containers:
  - name: busybox
    image: busybox
    command: ["sleep", "3600"]
    imagePullPolicy: IfNotPresent
  restartPolicy: Never
vagrant@master:~$ vi busybox.yml
vagrant@master:~$ k apply -f busybox.yml
pod/busybox created
vagrant@master:~$ k get po
NAME      READY   STATUS    RESTARTS   AGE
busybox   1/1     Running   0          7s

외부 통신 테스트

vagrant@master:~$ kubectl exec -it busybox -- sh
/ # ping google.com
PING google.com (142.250.206.206): 56 data bytes
64 bytes from 142.250.206.206: seq=0 ttl=113 time=33.528 ms
64 bytes from 142.250.206.206: seq=1 ttl=113 time=34.806 ms

추가 POD 생성

vagrant@master:~$ vi busybox2.yml
vagrant@master:~$ k apply -f busybox2.yml
pod/busybox2 created
vagrant@master:~$ k get po
NAME       READY   STATUS    RESTARTS   AGE
busybox    1/1     Running   0          2m30s
busybox2   1/1     Running   0          6s

내부 IP 확인

vagrant@master:~$ k get po -owide
NAME       READY   STATUS    RESTARTS   AGE     IP              NODE      NOMINATED NODE   READINESS GATES
busybox    1/1     Running   0          3m40s   10.233.65.121   worker1   <none>           <none>
busybox2   1/1     Running   0          76s     10.233.65.165   worker1   <none>           <none>

내부 네트워크 연결 테스트 (POD 간 통신)

vagrant@master:~$ k exec -it busybox -- sh
/ # ping 10.233.65.165
PING 10.233.65.165 (10.233.65.165): 56 data bytes
64 bytes from 10.233.65.165: seq=0 ttl=63 time=1.057 ms
64 bytes from 10.233.65.165: seq=1 ttl=63 time=0.099 ms

설치 팁

이미지 사전 다운로드

# Kubernetes Control Plane images
docker pull k8s.gcr.io/kube-apiserver:v1.31.7
docker pull k8s.gcr.io/kube-controller-manager:v1.31.7
docker pull k8s.gcr.io/kube-scheduler:v1.31.7
docker pull k8s.gcr.io/kube-proxy:v1.31.7

# Cilium CNI images
docker pull quay.io/cilium/cilium:v1.15.9
docker pull quay.io/cilium/operator:v1.15.9
docker pull quay.io/cilium/hubble-relay:v1.15.9

# CoreDNS
docker pull registry.k8s.io/coredns/coredns:v1.11.3

# etc
docker pull registry.k8s.io/cpa/cluster-proportional-autoscaler:v1.8.8
docker pull registry.k8s.io/dns/k8s-dns-node-cache:1.22.28
docker pull registry.k8s.io/kube-apiserver:v1.31.7
docker pull registry.k8s.io/kube-controller-manager:v1.31.7
docker pull registry.k8s.io/pause:3.10

이미지 버전 찾기

kubespray 버전마다 의존하는 컴포넌트 이미지의 버전이 상이하다. 버전은 꼼꼼이 확인하는 것이 좋다.

이미지 버전이나 kuby-spray 설치 시 사용하는 속성을 프로젝트 내에서 검색할때 사용한다.

grep -rnw ./ -e "kube-version"

릴리즈 노드 기준으로 설치 버전이 명기되어 있다. 정확하진 않으니 직접 확인해야 한다.

  • 기본 이미지 버전 명기
    inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml 파일에서 확인
kube_version: v1.31.7

CNI 설치 이슈

  • cni 가 설치 과정에서 멈춤 상태에서 진행이 되지 않는 경우가 많다. 이때는 cni를 제외하고 설치한 후 다시 시도하거나 수작업으로 진행한다.
// 연관 이미지를 미리 받아 둔 상태에서 설치가능하다. 
ANSIBLE_NO_LOG=False ansible-playbook -i inventory/mycluster/hosts.yml cluster.yml -b -vvvv  --skip-tags download

// cni가 문제가 될 경우 먼저 cni를 제외한 후 설치한다. 이 후 수작업으로 드라이버를 설치할 수 있다.
ANSIBLE_NO_LOG=False ansible-playbook -i inventory/mycluster/hosts.yml cluster.yml -b -vvvv  --skip-tags cni,download

CNI 선택

요구 사항적합한 CNI주요 특징네트워크 정책 지원
성능 중요, eBPF 활용CiliumeBPF 기반, 고성능, observability, Hubble 지원지원함
안정성, 많은 사례Calico전통적 방식, 널리 사용됨, BGP/Overlay 모두 지원지원함
단순한 실습용Flannel가장 간단함, 빠른 설치, Overlay 네트워크 전용지원 안 함
복잡한 정책 필요Cilium, Calico복잡한 네트워크 정책 및 DNS 기반 정책 가능지원함
자원 적은 환경Flannel리소스 소모 적음, 구성 간단지원 안 함
보안 / L7 정책 필요CiliumL7 레벨 정책(e.g. HTTP 경로 기반 정책)까지 가능고급 지원

cilium 수동 설치

curl -L --remote-name https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz
tar xzvf cilium-linux-amd64.tar.gz
sudo mv cilium /usr/local/bin
vagrant@master:~$ cilium status
    /¯¯\
 /¯¯\__/¯¯\    Cilium:             OK
 \__/¯¯\__/    Operator:           OK
 /¯¯\__/¯¯\    Envoy DaemonSet:    disabled (using embedded mode)
 \__/¯¯\__/    Hubble Relay:       disabled
    \__/       ClusterMesh:        disabled

DaemonSet              cilium                   Desired: 2, Ready: 2/2, Available: 2/2
Deployment             cilium-operator          Desired: 2, Ready: 2/2, Available: 2/2
Containers:            cilium                   Running: 2
                       cilium-operator          Running: 2
                       clustermesh-apiserver
                       hubble-relay
Cluster Pods:          3/3 managed by Cilium
Helm chart version:
Image versions         cilium             quay.io/cilium/cilium:v1.13.0: 2
                       cilium-operator    quay.io/cilium/operator:v1.13.0: 2

콘솔 접속

설치를 진행할 베스천과 쿠버네티스 노드는 환경(OS, Python 버전등)을 통일하는 것이 좋다.
설치 과정에서 노드에 접속한 상태면 kubectl 재시작이 진행되지 않을 수 있다. 콘솔 접속은 설치 후 진행한다.

정상 설치 결과

  • 최신 버전 (release-2.29 )
vagrant@master:~$ k get all -A
NAMESPACE     NAME                                   READY   STATUS    RESTARTS   AGE
kube-system   pod/cilium-7jvwg                       1/1     Running   0          9m41s
kube-system   pod/cilium-operator-6c7fb55565-dzrjx   1/1     Running   0          9m41s
kube-system   pod/cilium-operator-6c7fb55565-t6ldg   1/1     Running   0          9m41s
kube-system   pod/cilium-sqz7c                       1/1     Running   0          9m41s
kube-system   pod/coredns-d665d669-fb8hp             1/1     Running   0          8m49s
kube-system   pod/coredns-d665d669-knq9f             1/1     Running   0          8m45s
kube-system   pod/dns-autoscaler-5cb4578f5f-2nvp2    1/1     Running   0          8m47s
kube-system   pod/kube-apiserver-master              1/1     Running   1          12m
kube-system   pod/kube-controller-manager-master     1/1     Running   2          12m
kube-system   pod/kube-proxy-kfvxs                   1/1     Running   0          10m
kube-system   pod/kube-proxy-tt699                   1/1     Running   0          10m
kube-system   pod/kube-scheduler-master              1/1     Running   1          12m
kube-system   pod/nginx-proxy-worker1                1/1     Running   0          9m54s
kube-system   pod/nodelocaldns-2t7kx                 1/1     Running   0          8m44s
kube-system   pod/nodelocaldns-rrwfl                 1/1     Running   0          8m44s

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.233.0.1   <none>        443/TCP                  12m
kube-system   service/coredns      ClusterIP   10.233.0.3   <none>        53/UDP,53/TCP,9153/TCP   8m48s

NAMESPACE     NAME                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/cilium         2         2         2       2            2           <none>                   9m42s
kube-system   daemonset.apps/kube-proxy     2         2         2       2            2           kubernetes.io/os=linux   12m
kube-system   daemonset.apps/nodelocaldns   2         2         2       2            2           kubernetes.io/os=linux   8m45s

NAMESPACE     NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/cilium-operator   2/2     2            2           9m42s
kube-system   deployment.apps/coredns           2/2     2            2           8m49s
kube-system   deployment.apps/dns-autoscaler    1/1     1            1           8m47s

NAMESPACE     NAME                                         DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/cilium-operator-6c7fb55565   2         2         2       9m42s
kube-system   replicaset.apps/coredns-d665d669             2         2         2       8m49s
kube-system   replicaset.apps/dns-autoscaler-5cb4578f5f    1         1         1       8m47s

0개의 댓글