English {#english}
Execute Step 1 of pulumi-ansible-step1-step2-plan: create Hetzner servers with Pulumi. Prerequisites: Hetzner API token, SSH key; Cloudflare Zone and API token. Set env vars, run pulumi up, then use stack outputs for Ansible. Full details: see Korean section below.
한국어 {#korean}
Runbook: 1단계 — Pulumi로 Hetzner 서버 생성
목적: 기획서 pulumi-ansible-step1-step2-plan 1단계 실행 절차.
Base 경로: /Users/marco/prego-pulumi (또는 prego-pulumi 레포 루트)
사전 확인
- Hetzner Cloud: API 토큰 발급, SSH 키
prego-admin등록 - Cloudflare:
pregoi.comZone 존재, API 토큰 발급 - (선택) R2 버킷을 쓸 경우:
CLOUDFLARE_ACCOUNT_ID확보
1. 환경 변수
cd /Users/marco/prego-pulumicp .env.example .env.local# .env.local 편집:# - HCLOUD_TOKEN_SG=... (또는 HCLOUD_TOKEN=... / 리전별 HCLOUD_TOKEN_US, HCLOUD_TOKEN_EU)# - CLOUDFLARE_API_TOKEN=...# - (선택) CLOUDFLARE_ACCOUNT_ID=...# - PULUMI_CONFIG_PASSPHRASE=... (스택 암호화 사용 시; 새 스택이면 원하는 비밀번호 설정)run-up.sh는 HCLOUD_TOKEN이 없으면 현재 스택에 따라 HCLOUD_TOKEN_SG / HCLOUD_TOKEN_US / HCLOUD_TOKEN_EU를 자동으로 HCLOUD_TOKEN으로 사용합니다.
상용 옵션 (기획 §1.6) — pulumi config set prego-pulumi:<key> <value> 또는 환경변수:
| key | 설명 | 기본값 |
|---|---|---|
serverType | 서버 타입 (상용 기본 cpx31) | cpx31 |
enableBackups | 매일 스냅샷 (비용 +20%) | false |
enableVolumes | App/DB용 볼륨 20~50GB 부착 | false |
volumeSizeGb | 볼륨 크기 (20~50) | 20 |
enablePlacementGroup | Spread 배치 (서로 다른 물리 호스트) | true |
userData | cloud-init 스크립트 (선택) | — |
2. 스택 선택 / 생성
Pulumi Cloud: 조직 opsfork-org, 프로젝트 prego-pulumi, 기본 스택 dev. (app.pulumi.com → Stacks → prego-pulumi → dev)
cd /Users/marco/prego-pulumipulumi stack ls# 스택이 없으면:# PULUMI_CONFIG_PASSPHRASE="원하는비밀번호" pulumi stack init dev# 이미 있으면:pulumi stack select dev # 또는 sg, us, euno stack named 'dev' found 나오면: pulumi login 후 pulumi stack ls로 풀 네임 확인 → pulumi stack select <org>/prego-pulumi/dev 시도. prego-pulumi README §Pulumi Cloud 참고.
3. Preview → Up
./run-up.sh preview # 변경 사항 확인./run-up.sh up # 실제 생성 (Hetzner 과금 리소스 생성)up 완료 후 터미널에 출력되는 server_ip, management_dns 값을 2단계 Ansible 인벤토리에 사용합니다.
4. 결과 확인
- Pulumi 출력:
server_ip,management_dns,ssh_access - SSH 접속 테스트:
ssh root@<server_ip>(또는node-01.pregoi.com) - Cloudflare DNS:
node-01.pregoi.comA 레코드가 서버 IP를 가리키는지 확인
5. 1단계 전체 완료 여부 확인 (체크리스트)
아래를 순서대로 확인하면 1단계(Pulumi) 설정이 모두 마무리된 것으로 볼 수 있습니다.
5.1 Pulumi 상태
cd /Users/marco/prego-pulumi./run-up.sh refresh # 에러 없이 완료되어야 함pulumi stack output # server_ip, management_dns, ssh_access 등 출력 확인| 확인 항목 | 명령/방법 |
|---|---|
| refresh 성공 | ./run-up.sh refresh 종료 코드 0 |
| 스택 리소스 | pulumi stack --show-urns: Server×2(prego-node-01, prego-db-01), Firewall×2(prego-secure-fw, prego-db-fw), DnsRecord, R2Bucket(×2 선택 시). Ref: pulumi-ansible-step1-step2-plan §1, saas-db-separation Phase 1. |
| 출력값 존재 | pulumi stack output server_ip, pulumi stack output app_server_ip, pulumi stack output db_server_ip, pulumi stack output management_dns |
5.2 Hetzner 콘솔
- Hetzner Cloud → 해당 프로젝트 → Servers:
prego-node-01(App),prego-db-01(DB) 존재, Running - Firewalls:
prego-secure-fw(App, SSH 22),prego-db-fw(DB, SSH 22 + 3306 from App only) 존재 - 서버 상세: 이미지 Ubuntu 24.04, 위치(테스트 모드면 hel1), 타입(테스트면 CAX11; 상용은 cx21/cpx31 등)
5.3 Cloudflare
- DNS (Zone
pregoi.com):node-01A 레코드가 Pulumi 출력server_ip와 동일 - (선택) R2: 버킷
prego-usage-raw존재 (accountId 설정했을 때)
5.4 SSH 접속
# server_ip는 pulumi stack output server_ip 로 확인ssh root@<server_ip># 또는ssh root@node-01.pregoi.com- SSH 접속 성공 (Hetzner에 등록한
prego-admin키로 인증) - 접속 후
exit으로 종료
위 체크가 모두 통과하면 1단계 완료. 다음은 2단계(Ansible) 준비로 넘어가면 됩니다.
6. 다음 단계 (2단계 Ansible)
1단계가 완료되면 2단계에서는 아래 순서로 진행합니다. 상세 기획: pulumi-ansible-step1-step2-plan §2.
| 순서 | 작업 | 위치 |
|---|---|---|
| 1 | Pulumi에서 server_ip 확보 | cd /Users/marco/prego-pulumi && pulumi stack output server_ip |
| 2 | Ansible 인벤토리에 해당 IP를 ansible_host로 등록 | /Users/marco/prego-ansible/inventory/ (hosts.yml 등) |
| 3 | SSH 접속 확인 | ssh root@<server_ip> |
| 4 | Ansible Docker role 작성·실행 | Docker CE 설치 |
| 5 | Ansible Frappe role 작성·실행 | Frappe/bench, 테넌트 사이트, API Key 발급 |
현재 prego-ansible 레포는 비어 있으므로, 인벤토리·roles·playbook 구조를 새로 만든 뒤 위 순서대로 구현하면 됩니다.
트러블슈팅
| 현상 | 조치 |
|---|---|
Missing Hetzner Cloud API token | .env.local에 HCLOUD_TOKEN 또는 HCLOUD_TOKEN_SG(sg 스택) 설정 |
incorrect passphrase | 해당 스택 생성 시 사용한 PULUMI_CONFIG_PASSPHRASE와 동일하게 설정 |
no stack selected | pulumi stack select dev (또는 sg/us/eu). Pulumi Cloud면 풀 네임 org/prego-pulumi/dev 등 |
no stack named 'dev' found | pulumi login 후 pulumi stack ls → pulumi stack select <표시된 풀 네임> (예: opsfork-org/prego-pulumi/dev) |
| SSH 키를 찾을 수 없음 | Hetzner 콘솔에서 SSH 키 이름이 prego-admin인지 확인 (__main__.py의 ssh_key_name과 일치) |