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_password | 예 | MariaDB root 비밀번호. bench new-site에서 사용. | -e db_root_password=... 또는 Vault |
| 인벤토리 | ansible_host | 예 | 대상 서버 IP. Pulumi server_ip 또는 기존 노드 host. | inventory/inventory.yml에 기입 |
| 인벤토리 | ansible_user | 예 | SSH 로그인 사용자. 기본 root. | 인벤토리 vars |
| 인벤토리 | ansible_ssh_private_key_file | 예 | 서버 접속용 SSH 비밀키 파일 경로. | 로컬: ~/.ssh/prego-admin 등 실제 경로 |
Ansible용 (CI에서 사용할 GitHub Secrets — 추가 필요)
| Secret 이름 | 필수 | 설명 | 비고 |
|---|---|---|---|
PREGO_SSH_PRIVATE_KEY | 예 | Ansible이 서버에 SSH 접속할 때 쓰는 비밀키 전체 내용(PEM). Hetzner 서버에 주입된 공개키와 쌍. | 워크플로에서 파일로 쓴 뒤 ansible_ssh_private_key_file로 경로 전달. |
PREGO_DB_ROOT_PASSWORD | 예 | MariaDB 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_slug | workflow_dispatch 시 전달. Ansible에는 tenant_id·(파생) canonical_hostname 사용. |
| Secret | HCLOUD_TOKEN_SG | Pulumi up 시 Hetzner API(sg). region별로 us/eu면 HCLOUD_TOKEN_US, HCLOUD_TOKEN_EU 등 필요할 수 있음. |
| Secret | PULUMI_ACCESS_TOKEN | Pulumi Cloud 로그인. |
| Secret | CONTROL_PLANE_API_KEY | resolve-server(기존 노드 조회)·callback(provision-complete / provision-failed) 호출. |
| Secret | CLOUDFLARE_API_TOKEN | tenant-dns 단계(cloudflare-tenant-dns.ts). |
| Secret | CLOUDFLARE_ZONE_ID | tenant-dns 단계. |
| Secret | ZUPLO_ACCOUNT_NAME, ZUPLO_BUCKET_NAME, ZUPLO_API_KEY | zuplo-sync 단계. |
| Variable | CONTROL_PLANE_URL | Control Plane base URL. 기본값 있음. |
| Variable | PREGO_ANSIBLE_REPO | prego-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가 이미 있다”고 가정).
단계 요약
| 단계 | 내용 | 산출물 |
|---|---|---|
| 1 | Frappe/bench 설치 방식 확정 및 role 구현 | roles/frappe_bench 또는 docker 기반 role, playbook 연동 |
| 2 | 변수·시크릿 정리 (db_root_password, SSH) | defaults/Vault, 문서화 |
| 3 | 로컬 수동 검증 | 동일 서버에서 playbook 성공 → artifacts/tenant_api_key.txt 생성 |
| 4 | CI(워크플로) 연동 보완 | 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 기준)
- role 추가:
roles/frappe_bench(또는roles/frappe_docker).- tasks: Docker Compose 적용 또는
docker_container로 Frappe bench 이미지 기동, 볼륨·네트워크 고정. - defaults: 이미지 태그, bench_path(컨테이너 내부 경로), 서비스 이름.
- tasks: Docker Compose 적용 또는
- playbook 수정:
roles/docker다음에frappe_bench실행. 그 다음frappe_site실행. - 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 경로·명령 실행.
- 옵션 1: frappe_site task에서
- 멱등성: 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=... 또는 Vault | GitHub Secret → -e db_root_password=... | API·Vault 권장 |
ansible_ssh_private_key_file | 예 | 인벤토리 또는 env | Secret에서 파일로 쓰고 경로 지정 |
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 사전 확인
- Pulumi에서 server_ip 확보:
cd prego-pulumi && pulumi stack output server_ip - SSH 접속 확인:
ssh -i ~/.ssh/prego-admin root@<server_ip> - 인벤토리:
inventory/inventory.example.yml복사 →inventory/inventory.yml,ansible_host를 server_ip로 설정.
3.2 실행
cd prego-ansibleansible-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-provisionjob에 “Write SSH key” 스텝 추가.- GitHub Secret
PREGO_SSH_PRIVATE_KEY에 비밀키 내용 저장. - Step:
echo "${{ secrets.PREGO_SSH_PRIVATE_KEY }}" > runner_tmp/prego-admin && chmod 600 runner_tmp/prego-admin - 인벤토리에서
ansible_ssh_private_key_file를 해당 경로로 지정(예:$RUNNER_TEMP/prego-admin). 또는ansible-playbook실행 시-e ansible_ssh_private_key_file=$RUNNER_TEMP/prego-admin전달.
- GitHub Secret
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.md | Pulumi 1단계 → Ansible 2단계, §3 Ansible 비범위(Vectorize·테넌트 DNS) |
| provision-tenant-pipeline.md | 수동 프로비저닝 순서, 워크플로 입력 스펙 |
| intelligent-automation-implementation-plan.md | §3.2 Ansible + Zuplo Sync 산출물 |