Skip to main content

Ansible

Ansible을 사용하여 Terraform으로 프로비저닝된 OCI 인스턴스에 K3s 클러스터를 설치하고 구성합니다. 멀티 계정 환경에서 마스터와 워커 노드를 자동으로 설정하며, ArgoCD를 통한 GitOps 부트스트랩까지 수행합니다.

아키텍처 개요

배포 흐름

역할(Role) 구조

ansible/
├── roles/
│ ├── common/ # 모든 노드 공통 설정
│ ├── k3s-master/ # K3s 마스터 설치
│ ├── k3s-worker/ # K3s 워커 설치
│ ├── storage-setup/ # MinIO 스토리지 설정
│ └── argocd-bootstrap/ # ArgoCD 부트스트랩
├── playbooks/ # 플레이북 모음
├── group_vars/ # 그룹별 변수
└── inventory/ # 동적 인벤토리

인벤토리 구성

동적 인벤토리

Terraform 출력값을 기반으로 동적 인벤토리를 생성합니다:

#!/usr/bin/env python3
# inventory/terraform_inventory.py

# Terraform 출력값에서 호스트 정보 추출
# 그룹별로 호스트 분류:
# - masters: K3s 마스터 노드
# - workers: 모든 워커 노드
# - workers_0214: 0214 계정 워커
# - workers_0213: 0213 계정 워커

그룹 변수

전역 변수 (group_vars/all.yml)

# K3s 버전 및 설정
k3s_version: "v1.34.3+k3s1"
k3s_install_url: "https://get.k3s.io"

# 네트워크 구성
k3s_cluster_cidr: "10.42.0.0/16"
k3s_service_cidr: "10.43.0.0/16"
k3s_master_private_ip: "10.0.0.241"
k3s_master_url: "https://{{ k3s_master_private_ip }}:6443"

# 공통 패키지
common_packages:
- curl
- wget
- git
- vim
- htop
- iptables
- netfilter-persistent

# 커널 모듈
kernel_modules:
- br_netfilter
- overlay

# sysctl 설정
sysctl_settings:
net.bridge.bridge-nf-call-iptables: 1
net.bridge.bridge-nf-call-ip6tables: 1
net.ipv4.ip_forward: 1

마스터 노드 변수 (group_vars/masters.yml)

k3s_role: server

k3s_server_args:
- "--write-kubeconfig-mode 644"
- "--tls-san {{ ansible_host }}" # 공용 IP
- "--tls-san {{ private_ip }}" # 프라이빗 IP
- "--cluster-cidr {{ k3s_cluster_cidr }}"
- "--service-cidr {{ k3s_service_cidr }}"

--disable traefik이 없으므로 K3s 내장 Traefik이 활성화됩니다.

워커 노드 변수

# group_vars/workers_0214.yml
k3s_role: agent
k3s_connect_via: private # 같은 VCN

# group_vars/workers_0213.yml
k3s_role: agent
k3s_connect_via: private # VCN 피어링을 통한 연결

역할(Role) 상세

Common Role

모든 노드에 공통으로 적용되는 설정을 담당합니다.

주요 작업

# roles/common/tasks/main.yml
- name: Wait for cloud-init to complete
ansible.builtin.wait_for:
path: /var/lib/cloud/instance/boot-finished
timeout: 300

- name: Update apt cache
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600

- name: Install common packages
ansible.builtin.apt:
name: "{{ common_packages }}"
state: present

- name: Load required kernel modules
community.general.modprobe:
name: "{{ item }}"
state: present
loop: "{{ kernel_modules }}"

- name: Configure sysctl settings for K3s
ansible.posix.sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
state: present
sysctl_file: /etc/sysctl.d/99-k3s.conf
reload: yes
loop: "{{ sysctl_settings | dict2items }}"

K3s Master Role

K3s 마스터 노드를 설치하고 구성합니다.

설치 과정

# roles/k3s-master/tasks/main.yml
- name: Download K3s install script
ansible.builtin.get_url:
url: "{{ k3s_install_url }}"
dest: /tmp/k3s-install.sh
mode: '0755'

- name: Install K3s server
ansible.builtin.shell: |
INSTALL_K3S_VERSION="{{ k3s_version }}" /tmp/k3s-install.sh server {{ k3s_server_args | join(' ') }}
args:
creates: /usr/local/bin/k3s

- name: Wait for K3s server to be ready
ansible.builtin.wait_for:
path: "{{ k3s_token_file }}"
state: present
timeout: 120

- name: Wait for K3s API to be available
ansible.builtin.uri:
url: "https://127.0.0.1:6443/healthz"
validate_certs: false
status_code: 200
retries: 30
delay: 5

K3s Worker Role

K3s 워커 노드를 마스터에 조인시킵니다.

조인 과정

# roles/k3s-worker/tasks/main.yml
- name: Get K3s token from master
ansible.builtin.slurp:
src: "{{ k3s_token_file }}"
delegate_to: "{{ groups['masters'][0] }}"
register: k3s_token_raw

- name: Test connectivity to master
ansible.builtin.wait_for:
host: "{{ k3s_master_private_ip }}"
port: 6443
timeout: 30

- name: Install K3s agent
ansible.builtin.shell: |
K3S_URL="{{ k3s_master_url }}" \
K3S_TOKEN="{{ k3s_token }}" \
INSTALL_K3S_VERSION="{{ k3s_version }}" \
/tmp/k3s-install.sh agent

- name: Wait for node to register with master
ansible.builtin.shell: |
kubectl get nodes | grep -q "{{ inventory_hostname }}"
delegate_to: "{{ groups['masters'][0] }}"
retries: 30
delay: 10

Storage Setup Role

워커 노드의 블록 볼륨을 MinIO용으로 설정합니다.

스토리지 구성

# roles/storage-setup/tasks/main.yml
- name: Check if block device exists
ansible.builtin.stat:
path: "{{ storage_block_device }}"
register: block_device

- name: Format disk
community.general.filesystem:
fstype: "{{ storage_filesystem }}"
dev: "{{ storage_block_device }}"
when: disk_fs.stdout != storage_filesystem

- name: Set disk label
ansible.builtin.command: e2label {{ storage_block_device }} {{ minio_label }}
when: disk_label.stdout != minio_label

- name: Mount disk
ansible.posix.mount:
path: "{{ minio_mount_path }}"
src: "LABEL={{ minio_label }}"
fstype: "{{ storage_filesystem }}"
opts: defaults,nofail
state: mounted

ArgoCD Bootstrap Role

ArgoCD를 설치하고 GitOps 애플리케이션을 부트스트랩합니다.

부트스트랩 과정

# roles/argocd-bootstrap/tasks/main.yml
- name: Install Helm if not present
when: helm_version.rc != 0
block:
- name: Download Helm install script
ansible.builtin.get_url:
url: https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
dest: /tmp/get_helm.sh
mode: '0755'
- name: Run Helm install script
ansible.builtin.command: /tmp/get_helm.sh

- name: Create static secrets for bootstrap
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Secret
metadata:
name: minio-root-password
namespace: minio
type: Opaque
stringData:
root-user: "{{ minio_root_user }}"
root-password: "{{ minio_root_password }}"

- name: Install ArgoCD via Helm
kubernetes.core.helm:
name: argocd
chart_ref: argo/argo-cd
chart_version: "{{ argocd_chart_version }}"
release_namespace: "{{ argocd_namespace }}"
values_files:
- "{{ role_path }}/files/bootstrap-values.yaml"

- name: Apply root app-of-apps
kubernetes.core.k8s:
state: present
src: "/tmp/lumie-infra-gitops/{{ item }}"
loop: "{{ app_of_apps_paths }}"

플레이북

전체 클러스터 배포 (site.yml)

# 모든 노드 준비
- name: Prepare all nodes
hosts: all
become: yes
roles:
- common

# 마스터 노드 설치
- name: Install K3s Master
hosts: masters
become: yes
roles:
- k3s-master

# 워커 노드 스토리지 설정
- name: Setup storage partitions on workers
hosts: workers
become: yes
roles:
- storage-setup

# 워커 노드 설치 (순차적)
- name: Install K3s Workers (Account 0214)
hosts: workers_0214
become: yes
serial: 1
roles:
- k3s-worker

- name: Install K3s Workers (Account 0213)
hosts: workers_0213
become: yes
serial: 1
roles:
- k3s-worker

# ArgoCD 부트스트랩
- name: Bootstrap ArgoCD and GitOps
hosts: masters
become: yes
roles:
- argocd-bootstrap

개별 플레이북

마스터만 설치 (k3s-master.yml)

ansible-playbook -i inventory/terraform_inventory.py playbooks/k3s-master.yml

워커만 설치 (k3s-workers.yml)

ansible-playbook -i inventory/terraform_inventory.py playbooks/k3s-workers.yml

Kubeconfig 가져오기 (fetch-kubeconfig.yml)

ansible-playbook -i inventory/terraform_inventory.py playbooks/fetch-kubeconfig.yml

클러스터 리셋 (k3s-reset.yml)

ansible-playbook -i inventory/terraform_inventory.py playbooks/k3s-reset.yml

배포 과정

1. 사전 준비

# Ansible 의존성 설치
cd provision/ansible
ansible-galaxy install -r requirements.yml

# 인벤토리 테스트
./inventory/terraform_inventory.py --list | jq .

# 연결 테스트
ansible all -i inventory/terraform_inventory.py -m ping

2. 시크릿 설정

MinIO 루트 자격 증명을 환경 변수로 설정합니다:

export MINIO_ROOT_USER="admin"
export MINIO_ROOT_PASSWORD="your-secure-password"

또는 ansible-vault를 사용하여 암호화된 변수 파일을 생성합니다:

ansible-vault create group_vars/all/vault.yml

3. 전체 클러스터 배포

# 전체 배포 (마스터 + 워커 + ArgoCD)
ansible-playbook -i inventory/terraform_inventory.py playbooks/site.yml

# 특정 태그만 실행
ansible-playbook -i inventory/terraform_inventory.py playbooks/site.yml --tags "master,workers"

4. Kubeconfig 설정

# Kubeconfig 가져오기
ansible-playbook -i inventory/terraform_inventory.py playbooks/fetch-kubeconfig.yml

# 환경 변수 설정
export KUBECONFIG=provision/ansible/kubeconfig/config

# 클러스터 확인
kubectl get nodes
kubectl get pods -A

문제 해결

연결 문제

# SSH 연결 테스트
ansible all -i inventory/terraform_inventory.py -m ping

# 특정 호스트 연결 테스트
ansible masters -i inventory/terraform_inventory.py -m ping

# 인벤토리 확인
./inventory/terraform_inventory.py --host k3s-master

K3s 설치 문제

# 마스터 노드 상태 확인
ansible masters -i inventory/terraform_inventory.py -a "systemctl status k3s"

# 워커 노드 상태 확인
ansible workers -i inventory/terraform_inventory.py -a "systemctl status k3s-agent"

# 로그 확인
ansible masters -i inventory/terraform_inventory.py -a "journalctl -u k3s -n 50"

VCN 피어링 문제

# 0213 계정 워커에서 마스터 연결 테스트
ansible workers_0213 -i inventory/terraform_inventory.py -a "telnet 10.0.0.241 6443"

# 라우팅 확인
ansible workers_0213 -i inventory/terraform_inventory.py -a "ip route"

ArgoCD 부트스트랩 문제

# ArgoCD 파드 상태 확인
kubectl get pods -n argocd

# ArgoCD 애플리케이션 확인
kubectl get applications -n argocd

# ArgoCD 로그 확인
kubectl logs -n argocd deployment/argocd-server

모범 사례

1. 멱등성 보장

모든 작업은 여러 번 실행해도 같은 결과를 보장합니다:

- name: Install K3s server
ansible.builtin.shell: |
INSTALL_K3S_VERSION="{{ k3s_version }}" /tmp/k3s-install.sh server
args:
creates: /usr/local/bin/k3s # 이미 설치된 경우 스킵

2. 오류 처리

- name: Wait for node to register
ansible.builtin.shell: kubectl get nodes | grep -q "{{ inventory_hostname }}"
delegate_to: "{{ groups['masters'][0] }}"
retries: 30
delay: 10
until: node_registered.rc == 0

3. 순차 배포

워커 노드는 순차적으로 설치하여 경합 상태를 방지합니다:

- name: Install K3s Workers
hosts: workers
become: yes
serial: 1 # 한 번에 하나씩
roles:
- k3s-worker

4. 태그 활용

# 특정 단계만 실행
ansible-playbook playbooks/site.yml --tags "common,master"
ansible-playbook playbooks/site.yml --tags "workers_0214"
ansible-playbook playbooks/site.yml --tags "argocd"

모니터링 및 로깅

Ansible 실행 로그

# 상세 로그로 실행
ansible-playbook -vvv playbooks/site.yml

# 로그 파일로 저장
ansible-playbook playbooks/site.yml | tee ansible-deploy.log

성능 프로파일링

ansible.cfg에서 성능 프로파일링을 활성화합니다:

[defaults]
callbacks_enabled = profile_tasks

관련 문서