콘텐츠로 이동

Kubespray 배포 분석

Ansible 기반 K8s 배포 자동화: Kubespray를 활용한 프로덕션급 Kubernetes 클러스터 배포 및 내부 동작 분석


Kubespray 소개

1. Kubespray

Kubespray는 Ansible 기반의 Kubernetes 클러스터 배포 자동화 도구이다.

공식 저장소: kubernetes-sigs/kubespray

핵심 특징:

  • 프로덕션급 배포: Best Practice 기반 설정
  • 멀티 플랫폼: AWS, GCP, Azure, On-Premise, Bare-Metal
  • CNI 지원: Calico, Flannel, Cilium, Weave 등
  • HA 구성: Control Plane과 etcd HA 자동 구성
  • 폐쇄망 지원: Air-Gap 환경 배포 가능
  • 라이프사이클 관리: 배포, 업그레이드, 스케일링, 백업/복구

2. 주요 특징

(1) 퍼블릭/폐쇄망 환경 지원

퍼블릭 환경:

# IaC(Terraform) + Kubespray 조합
terraform apply  # 인프라 프로비저닝
ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml
폐쇄망(Air-Gap) 환경: - 오프라인 설치 지원 - 필요한 바이너리/이미지 사전 다운로드 - Private Registry 미러 설정

(2) HA 환경 지원

Control Plane HA: - 여러 Control Plane 노드 구성 - kube-apiserver LoadBalancing (Nginx 또는 외부 LB) - Controller-Manager/Scheduler Leader Election

etcd HA: - 홀수 개(3개 또는 5개) etcd 클러스터 - Raft consensus 기반 HA

Client-Side LB: - Worker 노드에서 API Server로 분산 접속 - Nginx를 이용한 로컬 LoadBalancer

(3) 인증서 자동 갱신

  • kubeadm cert auto renew: 매달 자동 갱신
  • systemd timer를 통한 스케줄링
  • 1년 유효기간 인증서 자동 관리

(4) 클러스터 운영 전반 지원

  • 신규 클러스터 생성 (cluster.yml)
  • 클러스터 업그레이드 (upgrade-cluster.yml)
  • 노드 추가 (scale.yml)
  • 노드 제거 (remove-node.yml)
  • 백업/복구 (etcd snapshot)

3. Release Cycle

Kubespray는 Kubernetes 최신 3개 버전(N, N-1, N-2)을 지원한다.

Kubespray 버전 지원 K8s 버전
2.29.x 1.31 ~ 1.33 (1.34)
2.28.x 1.30 ~ 1.32
2.27.x 1.29 ~ 1.31

운영 환경 버전 추천: - 개발(Dev) 환경: Kubespray 최신 버전 + K8s N-1 - 운영(Prd) 환경: Kubespray 최신-1 버전 + K8s N-2

4. 실습 환경 구성

가상머신 구성:

호스트명 IP 역할 vCPU Memory OS
k8s-ctr 192.168.10.10 Control Plane + Worker 4 4GB Rocky Linux 10.0

특징: Single Node 클러스터 (Control Plane과 Worker 겸용)

네트워크 설정: - Pod CIDR: 10.233.64.0/18 - Service CIDR: 10.233.0.0/18 - CNI: Flannel - Kube Proxy Mode: iptables

컴포넌트 버전: - OS: Rocky Linux 10.0 (Kernel 6.12.0) - Kubernetes: v1.33.3 - Containerd: v2.1.5 - Runc: v1.3.4 - etcd: v3.5.25 - Ansible: v2.17.14 - Python: 3.12.9 - Helm: v3.18.4


Kubespray 아키텍처

1. 전체 실행 흐름

Kubespray는 cluster.yml Playbook을 실행하면 총 15개의 PLAY559개의 TASK가 순차적으로 실행된다.

graph TD
    A[Start: cluster.yml] --> B[1. 사전 검증]
    B --> C{Ansible 버전 확인}
    C -->|Pass| D[Inventory 검증]
    C -->|Fail| STOP1[Stop: Update Ansible]
    D --> E{etcd 노드 수<br>홀수인가?}
    E -->|Yes| F[2. Bootstrap]
    E -->|No| STOP2[Stop: Fix etcd count]

    F --> G[Python 설치]
    G --> H[Facts 수집]
    H --> I[3. Container Engine 설치]

    I --> J[Containerd 설치]
    J --> K[Runc 설치]
    K --> L[CNI Plugins 설치]

    L --> M[4. etcd 설치]
    M --> N{etcd_deployment_type}
    N -->|host| O[systemd unit으로 기동]
    N -->|kubeadm| P[Static Pod로 기동]

    O --> Q[5. Kubernetes 노드 설치]
    P --> Q
    Q --> R[kubelet, kubectl 설치]

    R --> S[6. Control Plane 설치]
    S --> T[kubeadm init 실행]

    T --> U[7. CNI 설치]
    U --> V{kube_network_plugin}
    V -->|flannel| W[Flannel 매니페스트 적용]
    V -->|calico| X[Calico 매니페스트 적용]

    W --> Y[8. 애드온 설치]
    X --> Y
    Y --> Z[CoreDNS, Metrics Server, Helm 등]

    Z --> END[Complete: Cluster Ready]
  1. Check Ansible version - Ansible 버전 검증
  2. Inventory setup and validation - 인벤토리 검증
  3. Install bastion ssh config - Bastion 호스트 설정 (미사용 시 skip)
  4. Bootstrap hosts for Ansible - Python 설치, 기본 패키지 설치
  5. Gather facts - Ansible fact 수집
  6. Prepare for etcd install - etcd 설치 전 사전 준비
  7. Add worker nodes to etcd play - Worker + etcd 겸용 노드 지원
  8. Install etcd - etcd 설치 (systemd unit으로 기동)
  9. Install Kubernetes nodes - 모든 노드에 K8s 컴포넌트 설치
  10. Install the control plane - Control Plane 노드 구성
  11. Invoke kubeadm and install a CNI - kubeadm init/join 실행, CNI 설치
  12. Install Calico Route Reflector - Calico BGP 사용 시
  13. Patch Kubernetes for Windows - Windows 노드 사용 시
  14. Install Kubernetes apps - 애드온 설치 (CoreDNS, metrics-server 등)
  15. Apply resolv.conf changes - DNS 설정 최종 정리

2. 디렉터리 구조

graph LR
    A[kubespray/] --> B[playbooks/]
    A --> C[roles/]
    A --> D[inventory/]

    B --> B1[cluster.yml]
    B --> B2[install_etcd.yml]
    B --> B3[scale.yml]
    B --> B4[upgrade-cluster.yml]

    C --> C1[bootstrap_os]
    C --> C2[kubernetes/preinstall]
    C --> C3[container-engine]
    C --> C4[etcd]
    C --> C5[kubernetes/node]
    C --> C6[kubernetes/control-plane]
    C --> C7[network_plugin]
    C --> C8[kubernetes-apps]

    D --> D1[sample/]
    D --> D2[mycluster/]
    D2 --> D2A[inventory.ini]
    D2 --> D2B[group_vars/]
  • playbooks/: 메인 Playbook 파일들
  • cluster.yml: 클러스터 전체 배포
  • upgrade-cluster.yml: 클러스터 업그레이드
  • scale.yml: 노드 추가
  • remove-node.yml: 노드 제거
  • reset.yml: 클러스터 초기화

  • roles/: Ansible Role 디렉터리

  • bootstrap_os: OS 사전 설정
  • container-engine: Containerd, Runc 설치
  • etcd: etcd 설치 및 구성
  • kubernetes/node: kubelet, kubectl 설치
  • kubernetes/control-plane: Control Plane 구성
  • network_plugin: CNI 플러그인 설치
  • kubernetes-apps: 애드온 설치

  • inventory/: 인벤토리 설정

  • sample/: 샘플 인벤토리
  • mycluster/: 사용자 정의 인벤토리

3. Role 의존성

graph TD
    A[cluster.yml] --> B[kubespray_defaults]

    B --> C[bootstrap_os]
    C --> D[network_facts]
    D --> E[kubernetes/preinstall]

    E --> F[container-engine]
    F --> F1[validate-container-engine]
    F --> F2[containerd-common]
    F --> F3[runc]
    F --> F4[crictl]
    F --> F5[nerdctl]
    F --> F6[containerd]

    F6 --> G[download]
    G --> H[etcd]

    H --> I[kubernetes/node]
    I --> J[kubernetes/control-plane]

    J --> K[kubernetes/kubeadm]
    K --> L[kubernetes/node-label]
    K --> M[kubernetes/node-taint]

    M --> N[network_plugin]
    N --> N1[flannel]
    N --> N2[calico]
    N --> N3[cilium]

    N1 --> O[kubernetes-apps]
    N2 --> O
    N3 --> O

    O --> O1[coredns]
    O --> O2[metrics-server]
    O --> O3[helm-apps]
Role 실행 순서:

순서 Role 설명
1 kubespray_defaults 기본 변수 로드
2 bootstrap_os OS 사전 설정 (패키지 업데이트, Python 설치)
3 network_facts 네트워크 정보 수집
4 kubernetes/preinstall K8s 설치 전 준비 (Swap 비활성화, 커널 파라미터)
5 container-engine Containerd, Runc, CNI Plugins 설치
6 download 필요한 바이너리/이미지 다운로드
7 etcd etcd 클러스터 구성
8 kubernetes/node kubelet, kubectl 설치
9 kubernetes/control-plane kubeadm init 실행
10 kubernetes/kubeadm kubeadm join 실행
11 network_plugin CNI 플러그인 설치
12 kubernetes-apps 애드온 설치

Container Engine 설치

1. Containerd 설치 과정

Kubespray는 container-engine Role을 통해 Containerd를 설치한다.

flowchart TD
    Start[Container Engine Role] --> A[OS 호환성 확인]
    A --> B[커널 모듈 로드]
    B --> B1[modprobe overlay]
    B --> B2[modprobe br_netfilter]

    B1 --> C[Runc 설치]
    B2 --> C
    C --> C1[Download runc binary]
    C1 --> C2[Copy to /usr/local/bin/runc]

    C2 --> D[CNI Plugins 설치]
    D --> D1[Download CNI plugins]
    D1 --> D2[Extract to /opt/cni/bin/]

    D2 --> E[Containerd 설치]
    E --> E1[Download containerd]
    E1 --> E2[Unpack to /usr/local/bin/]
    E2 --> E3[Generate config.toml]
    E3 --> E4[SystemdCgroup 설정]
    E4 --> E5[Registry Mirror 설정]
    E5 --> E6[certs.d 구성]

    E6 --> F[Systemd 서비스 등록]
    F --> F1[Generate containerd.service]
    F1 --> F2[systemctl enable containerd]
    F2 --> F3[systemctl start containerd]

    F3 --> G[도구 설치]
    G --> G1[crictl 설치]
    G --> G2[nerdctl 설치]

    G2 --> End[Container Engine 준비 완료]
설치 단계:

  1. 커널 모듈 로드:
    modprobe overlay      # OverlayFS 지원
    modprobe br_netfilter # 브릿지 네트워크 필터링
    
  2. Runc 설치:
    wget https://github.com/opencontainers/runc/releases/download/v1.3.4/runc.amd64
    install -m 755 runc.amd64 /usr/local/bin/runc
    
  3. CNI Plugins 설치:
    wget https://github.com/containernetworking/plugins/releases/download/v1.6.2/cni-plugins-linux-amd64-v1.6.2.tgz
    mkdir -p /opt/cni/bin
    tar -C /opt/cni/bin -xzf cni-plugins-linux-amd64-v1.6.2.tgz
    
  4. Containerd 설치:
    wget https://github.com/containerd/containerd/releases/download/v2.1.5/containerd-2.1.5-linux-amd64.tar.gz
    tar -C /usr/local -xzf containerd-2.1.5-linux-amd64.tar.gz
    
  5. Config 파일 생성:
    mkdir -p /etc/containerd
    containerd config default > /etc/containerd/config.toml
    

2. Registry 미러 설정

Kubespray는 Containerd의 Registry 미러 기능을 활용하여 Private Registry 사용을 지원한다.

graph TD
    A[Container Image Pull 요청<br>docker.io/flannel/flannel:v0.27.3] --> B{config.toml 확인}

    B --> C[plugins."io.containerd.cri.v1.images".registry<br>config_path: /etc/containerd/certs.d]

    C --> D{/etc/containerd/certs.d/<br>docker.io/hosts.toml 존재?}

    D -->|Yes| E[hosts.toml 읽기]
    E --> F[server = "https://docker.io"<br>host."https://registry-1.docker.io"]

    F --> G{미러 서버 설정?}
    G -->|Yes| H[1순위: mirror.example.com 시도]
    H -->|실패| I[2순위: registry-1.docker.io]
    G -->|No| I

    I --> J[TLS 검증<br>skip_verify: false]
    J --> K{CA 인증서 유효?}
    K -->|Yes| L[Image Pull 성공]
    K -->|No| M[Pull 실패]

    D -->|No| N[기본 동작: Docker Hub 직접 접속]
    N --> I
Registry 미러 설정 예시:

# /etc/containerd/certs.d/docker.io/hosts.toml
server = "https://docker.io"

[host."https://mirror.example.com"]
  capabilities = ["pull", "resolve"]
  skip_verify = false

[host."https://registry-1.docker.io"]
  capabilities = ["pull", "resolve"]
설정 파일 구조:

/etc/containerd/
├── config.toml
└── certs.d/
    ├── docker.io/
    │   ├── hosts.toml
    │   └── ca.crt (선택적)
    ├── gcr.io/
    │   └── hosts.toml
    └── quay.io/
        └── hosts.toml
config.toml 핵심 설정:

[plugins."io.containerd.cri.v1.images".registry]
  config_path = "/etc/containerd/certs.d"

[plugins."io.containerd.cri.v1.images"]
  sandbox_image = "registry.k8s.io/pause:3.10"

3. Systemd Cgroup 설정

Systemd Cgroup 활성화:

# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true
중요성: - kubelet과 containerd가 동일한 cgroup driver 사용 필수 - cgroup v2 사용 시 systemd cgroup 권장 - 리소스 관리 안정성 향상

검증:

# Containerd cgroup driver 확인
crictl info | jq '.config.containerd.runtimes.runc.options.SystemdCgroup'

# Kubelet cgroup driver 확인
kubectl get cm kubelet-config -n kube-system -o yaml | grep cgroupDriver

etcd 설치 및 구성

1. etcd Deployment Type

Kubespray는 두 가지 etcd 배포 방식을 지원한다.

Deployment Type 설명 장점 단점
host systemd unit으로 etcd 실행 etcd 독립 관리, kubeadm과 무관 수동 관리 필요
kubeadm Static Pod로 etcd 실행 kubeadm이 관리 kubeadm에 종속

실습 환경 설정:

# inventory/mycluster/group_vars/all/etcd.yml
etcd_deployment_type: host  # systemd unit으로 실행

2. 인증서 구성

flowchart TD
    Start[etcd 설치 시작] --> A{노드 역할 확인}

    A -->|etcd 그룹| B[etcd 서버 설치]
    A -->|_kubespray_needs_etcd| C[etcd 클라이언트 인증서만]

    B --> B1[User/Group 생성<br>etcd:etcd]
    B1 --> B2[인증서 생성]
    B2 --> B2A[CA 생성<br>/etc/ssl/etcd/ssl/ca.pem]
    B2A --> B2B[Member 인증서<br>member-k8s-ctr.pem]
    B2B --> B2C[Admin 인증서<br>admin-k8s-ctr.pem]
    B2C --> B2D[Node 인증서<br>node-k8s-ctr.pem]

    B2D --> B3[etcd 바이너리 다운로드]
    B3 --> B4[etcd v3.5.25<br>/usr/local/bin/etcd]

    B4 --> B5[설정 파일 생성]
    B5 --> B5A[/etc/etcd.env]
    B5A --> B5B[systemd unit<br>/etc/systemd/system/etcd.service]

    B5B --> B6[etcd 시작]
    B6 --> B6A[systemctl start etcd]
    B6A --> B6B[Health Check]

    C --> C1[클라이언트 인증서 배포]
    C1 --> C1A[node-k8s-ctr.pem<br>node-k8s-ctr-key.pem]

    B6B --> End[etcd 설치 완료]
    C1A --> End
etcd 인증서 목록:

/etc/ssl/etcd/ssl/
├── ca.pem                    # etcd CA
├── ca-key.pem
├── member-k8s-ctr.pem        # etcd Member 인증서
├── member-k8s-ctr-key.pem
├── admin-k8s-ctr.pem         # Admin 인증서
├── admin-k8s-ctr-key.pem
├── node-k8s-ctr.pem          # Node 인증서 (API Server → etcd)
└── node-k8s-ctr-key.pem
인증서 용도:

인증서 용도 사용처
ca.pem etcd CA 모든 etcd 통신 검증
member-*.pem etcd 서버 인증서 etcd 클러스터 내부 통신
admin-*.pem etcd 관리자 인증서 etcdctl 명령어
node-*.pem etcd 클라이언트 인증서 kube-apiserver → etcd

3. Systemd Unit 설정

etcd.service 파일:

# /etc/systemd/system/etcd.service
[Unit]
Description=etcd key-value store
Documentation=https://github.com/etcd-io/etcd
After=network.target

[Service]
User=etcd
Type=notify
EnvironmentFile=/etc/etcd.env
ExecStart=/usr/local/bin/etcd
Restart=always
RestartSec=10s
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
etcd.env 설정:

# /etc/etcd.env
ETCD_NAME=k8s-ctr
ETCD_DATA_DIR=/var/lib/etcd
ETCD_LISTEN_PEER_URLS=https://192.168.10.10:2380
ETCD_LISTEN_CLIENT_URLS=https://192.168.10.10:2379,https://127.0.0.1:2379
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.10.10:2380
ETCD_ADVERTISE_CLIENT_URLS=https://192.168.10.10:2379
ETCD_INITIAL_CLUSTER=k8s-ctr=https://192.168.10.10:2380
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster

# TLS 설정
ETCD_CERT_FILE=/etc/ssl/etcd/ssl/member-k8s-ctr.pem
ETCD_KEY_FILE=/etc/ssl/etcd/ssl/member-k8s-ctr-key.pem
ETCD_TRUSTED_CA_FILE=/etc/ssl/etcd/ssl/ca.pem
ETCD_CLIENT_CERT_AUTH=true
ETCD_PEER_CERT_FILE=/etc/ssl/etcd/ssl/member-k8s-ctr.pem
ETCD_PEER_KEY_FILE=/etc/ssl/etcd/ssl/member-k8s-ctr-key.pem
ETCD_PEER_TRUSTED_CA_FILE=/etc/ssl/etcd/ssl/ca.pem
ETCD_PEER_CLIENT_CERT_AUTH=true
etcd 상태 확인:

# systemd 상태 확인
systemctl status etcd

# etcdctl을 이용한 health check
ETCDCTL_API=3 etcdctl \
  --cacert=/etc/ssl/etcd/ssl/ca.pem \
  --cert=/etc/ssl/etcd/ssl/admin-k8s-ctr.pem \
  --key=/etc/ssl/etcd/ssl/admin-k8s-ctr-key.pem \
  --endpoints=https://192.168.10.10:2379 \
  endpoint health

Kubernetes 클러스터 배포

1. Node 컴포넌트 설치

kubernetes/node Role은 모든 노드(Control Plane + Worker)에 공통 컴포넌트를 설치한다.

설치 항목: - kubelet (v1.33.3) - kubectl (v1.33.3) - kubeadm (v1.33.3)

kubelet 설정 파일:

# /etc/kubernetes/kubelet-config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
clusterDNS:
  - 10.233.0.10
clusterDomain: cluster.local
containerRuntimeEndpoint: unix:///var/run/containerd/containerd.sock
cpuManagerPolicy: none
maxPods: 110
podCIDR: 10.233.64.0/18
resolvConf: /etc/resolv.conf
rotateCertificates: true
serverTLSBootstrap: true
tlsCertFile: /var/lib/kubelet/pki/kubelet.crt
tlsPrivateKeyFile: /var/lib/kubelet/pki/kubelet.key
kubelet.service:

# /etc/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/

[Service]
ExecStart=/usr/local/bin/kubelet \
  --config=/etc/kubernetes/kubelet-config.yaml \
  --hostname-override=k8s-ctr \
  --kubeconfig=/etc/kubernetes/kubelet.conf \
  --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target

2. Control Plane 구성

kubeadm init 실행:

Kubespray는 kubeadm init을 통해 Control Plane을 구성한다.

kubeadm-config.yaml:

# /etc/kubernetes/kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.10.10
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
  kubeletExtraArgs:
    node-ip: 192.168.10.10
  name: k8s-ctr
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
apiServer:
  certSANs:
    - kubernetes
    - kubernetes.default
    - kubernetes.default.svc
    - kubernetes.default.svc.cluster.local
    - localhost
    - 127.0.0.1
    - 192.168.10.10
  extraArgs:
    enable-admission-plugins: NodeRestriction
    etcd-cafile: /etc/ssl/etcd/ssl/ca.pem
    etcd-certfile: /etc/ssl/etcd/ssl/node-k8s-ctr.pem
    etcd-keyfile: /etc/ssl/etcd/ssl/node-k8s-ctr-key.pem
    etcd-servers: https://192.168.10.10:2379
certificatesDir: /etc/kubernetes/pki
clusterName: cluster.local
controlPlaneEndpoint: localhost:6443
dns: {}
etcd:
  external:
    endpoints:
      - https://192.168.10.10:2379
    caFile: /etc/ssl/etcd/ssl/ca.pem
    certFile: /etc/ssl/etcd/ssl/node-k8s-ctr.pem
    keyFile: /etc/ssl/etcd/ssl/node-k8s-ctr-key.pem
imageRepository: registry.k8s.io
kubernetesVersion: v1.33.3
networking:
  dnsDomain: cluster.local
  podSubnet: 10.233.64.0/18
  serviceSubnet: 10.233.0.0/18
kubeadm init 실행:

kubeadm init --config=/etc/kubernetes/kubeadm-config.yaml --upload-certs
생성되는 Static Pod 매니페스트:

/etc/kubernetes/manifests/
├── kube-apiserver.yaml
├── kube-controller-manager.yaml
└── kube-scheduler.yaml

3. CNI 플러그인 설치

Flannel CNI 설치:

Kubespray는 선택한 CNI 플러그인(Flannel)의 매니페스트를 적용한다.

Flannel 설정:

# inventory/mycluster/group_vars/k8s_cluster/k8s-net-flannel.yml
flannel_backend_type: vxlan
flannel_network_cidr: 10.233.64.0/18
flannel_interface: eth0
Flannel DaemonSet 적용:

kubectl apply -f /etc/kubernetes/flannel.yaml
CNI 특징 네트워크 모드
Flannel 간단한 설정, VXLAN Overlay
Calico NetworkPolicy 지원, BGP Overlay or BGP
Cilium eBPF 기반, 고성능 Overlay or Native Routing
Weave 암호화 지원 Overlay

4. 애드온 설치

kubernetes-apps Role은 다양한 애드온을 설치한다.

# inventory/mycluster/group_vars/k8s_cluster/addons.yml
helm_enabled: true
metrics_server_enabled: true
node_feature_discovery_enabled: true
ingress_nginx_enabled: false
cert_manager_enabled: false
설치되는 애드온:

애드온 설명 설치 여부
CoreDNS 클러스터 DNS 기본 설치
Metrics Server 리소스 메트릭 수집 기본 설치
Node Feature Discovery 노드 하드웨어 정보 자동 라벨링 기본 설치
Helm 패키지 관리자 기본 설치
Ingress NGINX Ingress Controller 선택
Cert Manager 인증서 자동 관리 선택

애드온 확인:

# CoreDNS
kubectl get pods -n kube-system -l k8s-app=kube-dns

# Metrics Server
kubectl get pods -n kube-system -l k8s-app=metrics-server

# Node Feature Discovery
kubectl get pods -n node-feature-discovery

Kubespray 설정 분석

1. Inventory 구조

Inventory 디렉터리 구조:

inventory/mycluster/
├── inventory.ini           # 호스트 정의
└── group_vars/
    ├── all/
    │   ├── all.yml         # 모든 노드 공통 설정
    │   ├── containerd.yml  # Container Runtime 설정
    │   └── etcd.yml        # etcd 설정
    └── k8s_cluster/
        ├── k8s-cluster.yml         # K8s 클러스터 설정
        ├── addons.yml              # 애드온 설정
        ├── k8s-net-flannel.yml     # Flannel CNI 설정
        └── kube_control_plane.yml  # Control Plane 설정
inventory.ini 예시:

[all]
k8s-ctr ansible_host=192.168.10.10 ip=192.168.10.10

[kube_control_plane]
k8s-ctr

[etcd]
k8s-ctr

[kube_node]
k8s-ctr

[k8s_cluster:children]
kube_control_plane
kube_node

2. 주요 변수 설정

k8s-cluster.yml:

# Container Runtime
container_manager: containerd

# CNI 플러그인
kube_network_plugin: flannel

# Kube-Proxy 모드
kube_proxy_mode: iptables

# 네트워크 대역
kube_service_addresses: 10.233.0.0/18
kube_pods_subnet: 10.233.64.0/18

# DNS
enable_nodelocaldns: false
dns_mode: coredns
cluster_name: cluster.local

# 인증서 자동 갱신
auto_renew_certificates: true

# Kubernetes 버전
kube_version: v1.33.3
addons.yml:

helm_enabled: true
metrics_server_enabled: true
node_feature_discovery_enabled: true
ingress_nginx_enabled: false
cert_manager_enabled: false
etcd.yml:

etcd_deployment_type: host
etcd_data_dir: /var/lib/etcd
etcd_events_cluster_enabled: false
containerd.yml:

containerd_use_systemd_cgroup: true
containerd_registries_mirrors:
  - prefix: docker.io
    mirrors:
      - host: https://registry-1.docker.io
        capabilities: ["pull", "resolve"]

3. 변수 우선순위

graph LR
    A[Extra vars<br>-e key=value] -->|최고 우선순위| B[Host vars<br>inventory/host_vars/]
    B --> C[Group vars<br>inventory/group_vars/]
    C --> D[Role vars<br>roles/*/vars/main.yml]
    D --> E[Role defaults<br>roles/*/defaults/main.yml]
변수 우선순위 (높음 → 낮음):

  1. Extra vars (-e key=value): 최고 우선순위
  2. Host vars (inventory/host_vars/<hostname>.yml)
  3. Group vars (inventory/group_vars/<group>.yml)
  4. Role vars (roles/*/vars/main.yml)
  5. Role defaults (roles/*/defaults/main.yml): 최저 우선순위

예시:

# Extra vars로 kube_version 변경
ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml \
  -e kube_version="v1.33.3"

인증서 자동 갱신

1. Kubeadm Auto Renew

Kubespray는 kubeadm cert auto renew 기능을 활성화하여 인증서를 자동으로 갱신한다.

설정:

# inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
auto_renew_certificates: true
자동 갱신 대상 인증서:

인증서 유효기간 갱신 주기
apiserver.crt 1년 매달 자동 갱신
apiserver-kubelet-client.crt 1년 매달 자동 갱신
front-proxy-client.crt 1년 매달 자동 갱신
kubelet-client.crt 1년 자동 갱신 (TLS Bootstrap)

2. Systemd Timer 설정

Kubespray는 systemd timer를 사용하여 매달 인증서를 갱신한다.

k8s-certs-renew.timer:

# /etc/systemd/system/k8s-certs-renew.timer
[Unit]
Description=Renew K8S control plane certificates

[Timer]
OnCalendar=monthly
Persistent=true

[Install]
WantedBy=timers.target
k8s-certs-renew.service:

# /etc/systemd/system/k8s-certs-renew.service
[Unit]
Description=Renew K8S control plane certificates
After=kubelet.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/k8s-certs-renew.sh
Timer 상태 확인:

# Timer 목록 확인
systemctl list-timers --all | grep k8s-certs-renew

# Timer 상태 확인
systemctl status k8s-certs-renew.timer

# 다음 실행 시간 확인
systemctl list-timers k8s-certs-renew.timer

3. 갱신 스크립트 분석

k8s-certs-renew.sh:

#!/bin/bash
# /usr/local/bin/k8s-certs-renew.sh

set -e

# 인증서 갱신
/usr/local/bin/kubeadm certs renew all

# Control Plane Static Pod 재시작
# (kubelet이 자동으로 감지하여 재시작)
find /etc/kubernetes/manifests/ -type f -exec touch {} \;

# Kubelet 재시작 (선택적)
systemctl restart kubelet
수동 갱신:

# 인증서 만료 확인
kubeadm certs check-expiration

# 모든 인증서 갱신
kubeadm certs renew all

# 특정 인증서만 갱신
kubeadm certs renew apiserver
kubeadm certs renew apiserver-kubelet-client

# Control Plane 재시작
systemctl restart kubelet
인증서 만료 확인:

# kubeadm으로 확인
kubeadm certs check-expiration

# openssl로 확인
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -dates

HA 환경 지원

1. Control Plane HA

Kubespray는 여러 Control Plane 노드를 구성하여 HA를 지원한다.

HA 구성 예시:

# inventory.ini
[all]
k8s-ctr1 ansible_host=192.168.10.11 ip=192.168.10.11
k8s-ctr2 ansible_host=192.168.10.12 ip=192.168.10.12
k8s-ctr3 ansible_host=192.168.10.13 ip=192.168.10.13
k8s-w1 ansible_host=192.168.10.21 ip=192.168.10.21
k8s-w2 ansible_host=192.168.10.22 ip=192.168.10.22

[kube_control_plane]
k8s-ctr1
k8s-ctr2
k8s-ctr3

[etcd]
k8s-ctr1
k8s-ctr2
k8s-ctr3

[kube_node]
k8s-w1
k8s-w2
HA 특징:

  • kube-apiserver: 모든 Control Plane 노드에서 실행 (Active-Active)
  • kube-controller-manager: Leader Election (Active-Standby)
  • kube-scheduler: Leader Election (Active-Standby)
  • etcd: Raft consensus 기반 HA (홀수 개 권장)

2. etcd HA 클러스터

etcd 클러스터 구성:

노드 수 Quorum 허용 장애 노드 수
1 1 0
3 2 1
5 3 2
7 4 3

권장 사항: - 운영 환경: 3개 또는 5개 etcd 노드 - 개발 환경: 1개 etcd 노드 - 홀수 개: Quorum 달성을 위해 반드시 홀수 개 구성

etcd 클러스터 설정:

# /etc/etcd.env
ETCD_INITIAL_CLUSTER=k8s-ctr1=https://192.168.10.11:2380,k8s-ctr2=https://192.168.10.12:2380,k8s-ctr3=https://192.168.10.13:2380
ETCD_INITIAL_CLUSTER_STATE=new

3. Client-Side LoadBalancing

Kubespray는 Worker 노드에 Nginx 기반 LoadBalancer를 구성하여 API Server에 분산 접속한다.

구성:

Worker Node (k8s-w1)
├── kubelet
│   └── kubeconfig → localhost:6443
└── nginx (localhost:6443)
    └── upstream → k8s-ctr1:6443, k8s-ctr2:6443, k8s-ctr3:6443
nginx.conf:

# /etc/nginx/nginx.conf
stream {
    upstream kube_apiserver {
        server 192.168.10.11:6443 max_fails=3 fail_timeout=10s;
        server 192.168.10.12:6443 max_fails=3 fail_timeout=10s;
        server 192.168.10.13:6443 max_fails=3 fail_timeout=10s;
    }

    server {
        listen 127.0.0.1:6443;
        proxy_pass kube_apiserver;
        proxy_timeout 10s;
        proxy_connect_timeout 1s;
    }
}
kubelet kubeconfig:

# /etc/kubernetes/kubelet.conf
clusters:
- cluster:
    server: https://localhost:6443  # Nginx LoadBalancer
  name: cluster.local
장점: - 외부 LoadBalancer 불필요 - API Server 장애 시 자동 failover - Worker 노드별 독립적인 LB


클러스터 운영

1. 클러스터 업그레이드

upgrade-cluster.yml Playbook 사용:

# Kubernetes 버전 업그레이드
ansible-playbook -i inventory/mycluster/inventory.ini upgrade-cluster.yml \
  -e kube_version=v1.34.0
업그레이드 순서:

순서 대상 설명
1 etcd 필요 시 업그레이드
2 Control Plane 순차 업그레이드
3 Worker 노드 순차 업그레이드
4 CNI 플러그인 필요 시 업그레이드
5 애드온 업그레이드

업그레이드 주의사항:

  • Version Skew Policy 준수: K8s 버전 호환성 확인
  • 백업 필수: etcd snapshot 백업
  • 순차 업그레이드: 한 번에 하나의 마이너 버전씩
  • 테스트: Dev 환경에서 먼저 테스트

2. 노드 스케일링

노드 추가:

# inventory.ini에 새 노드 추가 후 실행
ansible-playbook -i inventory/mycluster/inventory.ini scale.yml \
  --limit=k8s-w3
노드 제거:

# 노드 drain
kubectl drain k8s-w1 --ignore-daemonsets --delete-emptydir-data

# 노드 제거 Playbook
ansible-playbook -i inventory/mycluster/inventory.ini remove-node.yml \
  -e node=k8s-w1

3. 백업 및 복구

etcd 백업:

# Snapshot 생성
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot.db \
  --cacert=/etc/ssl/etcd/ssl/ca.pem \
  --cert=/etc/ssl/etcd/ssl/admin-k8s-ctr.pem \
  --key=/etc/ssl/etcd/ssl/admin-k8s-ctr-key.pem \
  --endpoints=https://192.168.10.10:2379

# Snapshot 검증
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot.db
etcd 복구:

# etcd 중지
systemctl stop etcd

# 데이터 디렉터리 백업
mv /var/lib/etcd /var/lib/etcd.old

# Snapshot 복구
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db \
  --data-dir=/var/lib/etcd

# 권한 설정
chown -R etcd:etcd /var/lib/etcd

# etcd 재시작
systemctl start etcd
자동 백업 스크립트:

#!/bin/bash
# /usr/local/bin/etcd-backup.sh

BACKUP_DIR="/backup/etcd"
DATE=$(date +%Y%m%d-%H%M%S)
SNAPSHOT="$BACKUP_DIR/etcd-snapshot-$DATE.db"

# Snapshot 생성
ETCDCTL_API=3 etcdctl snapshot save "$SNAPSHOT" \
  --cacert=/etc/ssl/etcd/ssl/ca.pem \
  --cert=/etc/ssl/etcd/ssl/admin-k8s-ctr.pem \
  --key=/etc/ssl/etcd/ssl/admin-k8s-ctr-key.pem \
  --endpoints=https://192.168.10.10:2379

# 7일 이상 된 백업 삭제
find "$BACKUP_DIR" -name "etcd-snapshot-*.db" -mtime +7 -delete

핵심 개념 정리

1. Kubespray vs Kubeadm

항목 Kubespray Kubeadm
도구 Ansible Playbook CLI 도구
자동화 수준 전체 자동화 부분 자동화
사전 준비 Ansible이 자동 수행 수동 설정 필요
멀티 노드 배포 자동 수동 (각 노드 접속)
HA 구성 자동 수동 설정 필요
폐쇄망 지원 공식 지원 수동 구성
업그레이드 Playbook 실행 각 노드에서 수동 실행
인증서 관리 자동 갱신 설정 수동 갱신
설정 관리 Inventory 기반 각 노드별 설정 파일

Kubespray 장점:

  • 프로덕션급 클러스터 빠른 배포: 자동화된 배포 프로세스
  • Best Practice 자동 적용: 검증된 설정 기본 제공
  • 멀티 노드 동시 배포: 병렬 처리로 빠른 구축
  • IaC (Infrastructure as Code): Git 기반 설정 관리
  • 일관된 설정 관리: Ansible Inventory 기반

Kubeadm 장점:

  • 간단한 사용법: 최소한의 명령으로 클러스터 구축
  • 공식 도구: Kubernetes 프로젝트 공식 지원
  • 작은 클러스터에 적합: 간단한 환경에서 효율적

2. Ansible Role 기반 구조

Kubespray는 Ansible Role을 활용하여 모듈화된 구조를 제공한다.

Role 기반 구조의 장점:

  1. 재사용성: Role을 다른 Playbook에서 재사용
  2. 모듈화: 각 Role이 독립적인 기능 수행
  3. 유지보수성: Role별로 코드 관리
  4. 테스트 용이성: Role 단위 테스트 가능

Role 구조 예시:

roles/container-engine/
├── defaults/
│   └── main.yml        # 기본 변수
├── tasks/
│   ├── main.yml        # 메인 Task
│   ├── containerd.yml  # Containerd 설치
│   ├── runc.yml        # Runc 설치
│   └── cni.yml         # CNI Plugins 설치
├── templates/
│   ├── config.toml.j2  # Containerd config
│   └── containerd.service.j2
├── handlers/
│   └── main.yml        # Handler (재시작 등)
└── vars/
    └── main.yml        # Role 변수

3. 퍼블릭 vs 폐쇄망 배포

퍼블릭 환경 배포:

# 인터넷 연결된 환경
ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml
폐쇄망(Air-Gap) 환경 배포:

  1. 바이너리 사전 다운로드:
    ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml \
      --tags download --skip-tags upload,upgrade
    
  2. 이미지 사전 다운로드:
    # 이미지 목록 생성
    ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml \
      --tags download --skip-tags upload,upgrade \
      -e download_container=true
    
  3. Private Registry 구성:
    # group_vars/all/containerd.yml
    containerd_registries_mirrors:
      - prefix: docker.io
        mirrors:
          - host: https://registry.internal.com
            capabilities: ["pull", "resolve"]
    
  4. 오프라인 배포 실행:
    ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml \
      -e download_run_once=false \
      -e download_localhost=true
    
    폐쇄망 배포 요구사항:
  5. Private Registry (Harbor, Nexus 등)
  6. 바이너리 저장소 (HTTP 서버)
  7. Ansible Control Node (폐쇄망 내부)
  8. 사전 다운로드된 파일 목록


작성일: 2026-01-28 스터디: K8s-Deploy Week 4