Skip to content

English {#english}

Ansible Stepwise Implementation Plan

Purpose: Stepwise implementation order and deliverables so prego-ansible runs end-to-end locally and in CI.
References: pulumi-ansible-step1-step2-plan, provision-tenant-pipeline; for DB-separate setup, saas-db-separation-and-scaling-plan §5 (Ansible).

Status: §1–2, §4–5 code/docs done. §3 (local manual verification) requires real server and inventory. Execution order: ansible-implementation-sequence.


Prep: variables and secrets

Ansible (local): tenant_id, canonical_hostname (optional), db_root_password, ansible_host, ansible_user, ansible_ssh_private_key_file. CI: PREGO_SSH_PRIVATE_KEY, PREGO_DB_ROOT_PASSWORD. Provisioning workflow: job_id, tenant_id, region, target_server_id, create_new_server, subdomain_slug; HCLOUD_TOKEN_, PULUMI_ACCESS_TOKEN, CONTROL_PLANE_API_KEY, CLOUDFLARE_, ZUPLO_*, CONTROL_PLANE_URL, PREGO_ANSIBLE_REPO. Checklist: local SSH key + Hetzner; db_root_password; CI Secrets.


Assumptions and step summary

  • Pulumi has already provisioned server (server_ip). prego-ansible has playbook, roles/docker, roles/frappe_site; no Frappe/bench install role (frappe_site assumes bench exists).
  • Steps: (1) Decide Frappe/bench install method, implement role (frappe_bench or Docker-based). (2) Variables/secrets (defaults, Vault, docs). (3) Local verification (playbook → artifacts/tenant_api_key.txt). (4) CI: SSH key write, db_root_password, Ansible version. (5) README, provision-tenant-pipeline runbook.

§1–§5 (summary)

§1: Option A (Docker) recommended: frappe_bench role, playbook order docker → frappe_bench → frappe_site; frappe_site uses docker exec for bench. Option B: native install role. §2: Required vars table; Vault/CI secrets; group_vars example. §3: Pre-check (server_ip, SSH, inventory); run command; verify Docker, bench, new-site, API key, artifact, zuplo_sync. §4: Write SSH key from Secret; db_root_password from Secret; optional Ansible version pin. §5: README, provision-tenant-pipeline.

Full tables (prep, §1.1–§1.3, §2.1–§2.3, §3–§5) and exact wording are in the Korean section below.


한국어 {#korean}

Ansible 단계별 구현 방안

목적: prego-ansible을 로컬·CI에서 완결되게 동작시키기 위한 단계별 구현 순서와 산출물.
참조: pulumi-ansible-step1-step2-plan.md, provision-tenant-pipeline.md. DB 분리형 구성saas-db-separation-and-scaling-plan.md §5(Ansible) 반영.

구현 상태: §12·§45 코드·문서 반영 완료. §3(로컬 수동 검증)은 실제 서버·인벤토리로 실행 후 확인. 실행 순서는 ansible-implementation-sequence.md 참고.


구현 전 준비: 변수·Secret 목록

구현을 시작하기 전에 아래를 준비해야 한다. 로컬만 쓸 항목과 CI(GitHub Actions)용을 구분했다.

Ansible용 (로컬 실행 시)

구분이름필수설명준비 방법
변수tenant_id테넌트 ID(UUID 등). site_name·canonical_hostname 계산에 사용.실행 시 -e tenant_id=...
변수canonical_hostname선택예: tenant-a1b2c3d4.pregoi.com. 미전달 시 tenant_id 앞 8자로 생성.-e canonical_hostname=... 또는 생략
변수db_root_passwordMariaDB root 비밀번호. bench new-site에서 사용.-e db_root_password=... 또는 Vault
인벤토리ansible_host대상 서버 IP. Pulumi server_ip 또는 기존 노드 host.inventory/inventory.yml에 기입
인벤토리ansible_userSSH 로그인 사용자. 기본 root.인벤토리 vars
인벤토리ansible_ssh_private_key_file서버 접속용 SSH 비밀키 파일 경로.로컬: ~/.ssh/prego-admin 등 실제 경로

Ansible용 (CI에서 사용할 GitHub Secrets — 추가 필요)

Secret 이름필수설명비고
PREGO_SSH_PRIVATE_KEYAnsible이 서버에 SSH 접속할 때 쓰는 비밀키 전체 내용(PEM). Hetzner 서버에 주입된 공개키와 쌍.워크플로에서 파일로 쓴 뒤 ansible_ssh_private_key_file로 경로 전달.
PREGO_DB_ROOT_PASSWORDMariaDB root 비밀번호. bench new-site --db-root-password에 전달.워크플로에서 -e db_root_password=${{ secrets.PREGO_DB_ROOT_PASSWORD }} 로 전달.

프로비저닝 워크플로 전체용 (이미 사용 중인 것 + 참고)

구분이름용도
워크플로 입력job_id, tenant_id, region, target_server_id, create_new_server, subdomain_slugworkflow_dispatch 시 전달. Ansible에는 tenant_id·(파생) canonical_hostname 사용.
SecretHCLOUD_TOKEN_SGPulumi up 시 Hetzner API(sg). region별로 us/eu면 HCLOUD_TOKEN_US, HCLOUD_TOKEN_EU 등 필요할 수 있음.
SecretPULUMI_ACCESS_TOKENPulumi Cloud 로그인.
SecretCONTROL_PLANE_API_KEYresolve-server(기존 노드 조회)·callback(provision-complete / provision-failed) 호출.
SecretCLOUDFLARE_API_TOKENtenant-dns 단계(cloudflare-tenant-dns.ts).
SecretCLOUDFLARE_ZONE_IDtenant-dns 단계.
SecretZUPLO_ACCOUNT_NAME, ZUPLO_BUCKET_NAME, ZUPLO_API_KEYzuplo-sync 단계.
VariableCONTROL_PLANE_URLControl Plane base URL. 기본값 있음.
VariablePREGO_ANSIBLE_REPOprego-ansible 체크아웃 시 repository. 선택.

준비 체크리스트

  • 로컬: SSH 키 쌍(prego-admin) 생성 후 공개키를 Hetzner에 등록·서버에 주입됨. 비밀키 경로를 인벤토리에 반영.
  • 로컬: db_root_password 값을 정해 두고, playbook 실행 시 -e 또는 Vault로 전달 가능한지 확인.
  • CI: GitHub 리포지토리 Settings → Secrets and variables → Actions에 PREGO_SSH_PRIVATE_KEY, PREGO_DB_ROOT_PASSWORD 추가.
  • CI: (이미 있다면) HCLOUD_TOKEN_*, PULUMI_ACCESS_TOKEN, CONTROL_PLANE_API_KEY, CLOUDFLARE_*, ZUPLO_* 등 워크플로에서 쓰는 나머지 Secret·Variable 확인.

전제

  • Pulumi로 서버(server_ip)는 이미 프로비저닝되어 있음.
  • prego-ansible 레포에는 playbook.yml, roles/docker, roles/frappe_site가 있으나, Frappe/bench 설치를 담당하는 role은 없음(frappe_site는 “bench가 이미 있다”고 가정).

단계 요약

단계내용산출물
1Frappe/bench 설치 방식 확정 및 role 구현roles/frappe_bench 또는 docker 기반 role, playbook 연동
2변수·시크릿 정리 (db_root_password, SSH)defaults/Vault, 문서화
3로컬 수동 검증동일 서버에서 playbook 성공 → artifacts/tenant_api_key.txt 생성
4CI(워크플로) 연동 보완SSH 키 주입, db_root_password 전달, 필요 시 Ansible 버전 고정
5문서·Runbook 정리README, provision-tenant-pipeline 보완

1단계: Frappe/bench 설치 방식 확정 및 role 구현

1.1 방식 선택

방식설명구현 시 할 일
A. Docker 기반frappe/bench 등 이미지로 컨테이너 실행, 그 안에서 bench 명령 실행새 role: Docker Compose(또는 docker_container)로 Frappe bench 컨테이너 기동. frappe_site는 해당 컨테이너에 docker exec로 bench new-site·add-api-key 실행하거나, Ansible이 컨테이너 내부를 대상으로 하는 방식(connection: docker 등) 적용.
B. 네이티브 설치서버에 Python/Node·bench 설치(install.py 또는 frappe_docker 스크립트)새 role: 의존성 설치 → bench init(또는 공식 설치 스크립트) → bench_path·bench_user를 frappe_site와 동일하게 맞춤.

권장: 기획서(pulumi-ansible-step1-step2-plan §1.6)에서 Docker·볼륨 전략을 쓰고 있으므로 **A(Docker 기반)**가 운영·백업과 맞기 쉬움. B는 서버 직접 관리 부담이 큼.

1.2 구현 순서 (방식 A 기준)

  1. role 추가: roles/frappe_bench (또는 roles/frappe_docker).
    • tasks: Docker Compose 적용 또는 docker_container로 Frappe bench 이미지 기동, 볼륨·네트워크 고정.
    • defaults: 이미지 태그, bench_path(컨테이너 내부 경로), 서비스 이름.
  2. playbook 수정: roles/docker 다음에 frappe_bench 실행. 그 다음 frappe_site 실행.
  3. frappe_site 연동:
    • 옵션 1: frappe_site task에서 docker exec로 bench 명령 실행 (become, command 모듈, container_id 또는 name으로 exec).
    • 옵션 2: Ansible connection을 docker로 바꾼 호스트 그룹을 두고, 해당 “호스트”가 컨테이너가 되도록 해 frappe_site가 기존처럼 command로 bench 실행. (구현 복잡도 높음)
    • 권장: 옵션 1. frappe_site에 frappe_container_name(또는 id) 변수를 두고, docker exec {{ frappe_container_name }} ... 형태로 bench 경로·명령 실행.
  4. 멱등성: bench new-site는 기존처럼 creates:로 사이트 디렉터리 지정. 컨테이너 재시작 시에도 사이트 디렉터리가 볼륨에 있으면 스킵.

1.3 산출물

  • roles/frappe_bench/ (tasks, defaults, templates 필요 시).
  • playbook.yml에 frappe_bench role 추가 및 frappe_site에 container 변수 전달.
  • roles/frappe_site/tasks/main.yml: bench 명령을 컨테이너 기준으로 실행하도록 수정(방식 A인 경우).

2단계: 변수·시크릿 정리

2.1 필수 변수

변수필수로컬CI비고
tenant_id-e tenant_id=...워크플로 입력
canonical_hostname선택미전달 시 tenant_id 앞 8자로 생성워크플로에서 계산해 전달
db_root_password예(bench new-site 시)-e db_root_password=... 또는 VaultGitHub Secret → -e db_root_password=...API·Vault 권장
ansible_ssh_private_key_file인벤토리 또는 envSecret에서 파일로 쓰고 경로 지정

2.2 시크릿 관리

  • 로컬: ansible-vault로 변수 파일 암호화하거나, playbook 실행 시 -e db_root_password=...만 전달(히스토리 노출 주의).
  • CI: GitHub Secrets PREGO_DB_ROOT_PASSWORD, PREGO_SSH_PRIVATE_KEY 등 정의 후 워크플로에서만 사용.

2.3 산출물

  • group_vars 또는 vars 예시 파일(비밀값 제외), README에 변수 표 정리.
  • (선택) inventory/group_vars/prego_nodes.yml.example에 db_root_password 제외한 예시.

3단계: 로컬 수동 검증

3.1 사전 확인

  1. Pulumi에서 server_ip 확보: cd prego-pulumi && pulumi stack output server_ip
  2. SSH 접속 확인: ssh -i ~/.ssh/prego-admin root@<server_ip>
  3. 인벤토리: inventory/inventory.example.yml 복사 → inventory/inventory.yml, ansible_host를 server_ip로 설정.

3.2 실행

Terminal window
cd prego-ansible
ansible-playbook -i inventory/inventory.yml playbook.yml \
-e tenant_id=<TENANT_ID> \
-e db_root_password=<DB_ROOT_PASSWORD>

3.3 검증 포인트

  • Docker 설치 성공(해당 role까지 실행 시).
  • Frappe bench 기동(방식 A면 컨테이너 실행) 성공.
  • bench new-site로 사이트 생성 성공.
  • add-api-key로 API 키 생성 성공.
  • artifacts/tenant_api_key.txt에 키 한 줄 기록됨.
  • Prego 레포에서 npx tsx infra/zuplo_sync.ts <tenant_id> --api-key-file artifacts/tenant_api_key.txt 실행 시 Zuplo 등록 성공.

4단계: CI(워크플로) 연동 보완

4.1 SSH 키 주입

  • 현상: 워크플로 인벤토리에 ansible_ssh_private_key_file: ~/.ssh/prego-admin 이 있으나 runner에는 해당 파일 없음.
  • 조치: ansible-provision job에 “Write SSH key” 스텝 추가.
    1. GitHub Secret PREGO_SSH_PRIVATE_KEY에 비밀키 내용 저장.
    2. Step: echo "${{ secrets.PREGO_SSH_PRIVATE_KEY }}" > runner_tmp/prego-admin && chmod 600 runner_tmp/prego-admin
    3. 인벤토리에서 ansible_ssh_private_key_file를 해당 경로로 지정(예: $RUNNER_TEMP/prego-admin). 또는 ansible-playbook 실행 시 -e ansible_ssh_private_key_file=$RUNNER_TEMP/prego-admin 전달.

4.2 db_root_password 전달

  • 워크플로 “Run Ansible playbook” 단계에 -e db_root_password=${{ secrets.PREGO_DB_ROOT_PASSWORD }} 추가.
  • (선택) MariaDB가 컨테이너 내부라면 해당 컨테이너의 root 비밀번호와 동일한 값으로 통일.

4.3 Ansible 버전

  • runner에 Ansible 설치: pip install ansible 또는 apt-get install -y ansible 또는 actions/setup-python + pip install ansible. 필요 시 ansible-core 버전 고정.

4.4 산출물

  • .github/workflows/provision-tenant.yml 수정: SSH 키 파일 생성, db_root_password 전달, Ansible 설치(필요 시).

5단계: 문서·Runbook 정리

5.1 prego-ansible README

  • One-off/수동 실행 절차(인벤토리 복사, 변수, 실행 명령).
  • Pipeline에서의 역할(입력: server_ip·tenant_id, 출력: artifacts/tenant_api_key.txt).
  • 필수 변수 표, Frappe 설치 방식(Docker/네이티브) 요약.

5.2 Prego Runbook

  • docs/runbook/provision-tenant-pipeline.md: Ansible 단계에서 필요한 Secret(SSH, db_root_password) 명시, 실패 시 확인 항목(SSH 접근, bench 로그 등).

5.3 산출물

  • prego-ansible/README.md 보완.
  • Prego docs/runbook/provision-tenant-pipeline.md 보완.

체크리스트 (완료 기준)

  • 1단계: Frappe/bench 설치 role 추가·playbook·frappe_site 연동 완료. roles/frappe_bench(Docker), frappe_site(docker exec), playbook 순서·변수 연동 구현됨. 로컬 한 서버에서 Docker → bench → new-site → API key까지 playbook 한 번에 성공 여부는 환경에서 수동 검증.
  • 2단계: db_root_password·SSH 경로 문서화, (선택) Vault/예시 vars. README·Runbook·github-secrets.md·group_vars 예시 반영.
  • 3단계: 로컬에서 Pulumi server_ip 기준으로 playbook 수동 실행 후 artifacts 생성·Zuplo sync 수동 검증. (실제 서버·인벤토리 필요)
  • 4단계: 워크플로에서 SSH 키·db_root_password·requirements.yml 컬렉션 설치 반영. workflow_dispatch로 end-to-end 성공 여부는 환경에서 수동 검증.
  • 5단계: README·Runbook·IMPLEMENTATION_INDEX·ansible-implementation-sequence(현재 상태) 갱신 완료.

참조

문서내용
pulumi-ansible-step1-step2-plan.mdPulumi 1단계 → Ansible 2단계, §3 Ansible 비범위(Vectorize·테넌트 DNS)
provision-tenant-pipeline.md수동 프로비저닝 순서, 워크플로 입력 스펙
intelligent-automation-implementation-plan.md§3.2 Ansible + Zuplo Sync 산출물
Help