서버 프로비저닝 (IaaS + Ansible)
IaaS에서 서버를 생성하고 Ansible로 표준 상태까지 자동 셋업하는 전체 과정입니다. 아래 Phase 1은 Vultr를 예시로 하지만, DigitalOcean / Linode / Hetzner / AWS EC2 등 어떤 IaaS에서도 동일한 흐름이 적용됩니다. 핵심은 "Ubuntu 24.04 LTS 서버 + 운영자 SSH 공개키 + 초기 IP"만 확보하면 Phase 2 이후는 완전히 동일합니다.
사전 요구사항
| 항목 | 필수 여부 | 비고 |
|---|---|---|
| 로컬에 Ansible 2.15+ 설치 | ✅ | pip install ansible 또는 apt install ansible |
| SSH 키 쌍 (운영자용) | ✅ | ssh-keygen -t ed25519 |
| IaaS 계정 + SSH 공개키 등록 | ✅ | 각 IaaS Dashboard의 SSH Keys 메뉴 (Vultr / DigitalOcean / Linode 등 공통) |
| Tailscale 계정 + pre-auth key | ✅ | Admin Console → Settings → Keys → Auth keys |
| ansible-vault 비밀번호 | ✅ | Secret 관리용 |
Phase 1: IaaS 서버 생성 (Vultr 예시)
아래는 Vultr 대시보드 기준 예시입니다. DigitalOcean, Linode, Hetzner, AWS EC2 등에서도 동일한 핵심 4가지만 준비하면 됩니다:
- Ubuntu 24.04 LTS x64 이미지
- 운영자 SSH 공개키 등록
- 역할 기반 hostname (예:
msk-app-01) - 생성된 공인 IP 주소 확보
이후 Phase 2~5는 IaaS와 무관하게 모두 같습니다.
Vultr Dashboard에서 (예시)
- Deploy New Server 클릭
- 설정:
- Server Type: Cloud Compute (또는 High Performance)
- Location: Tokyo/Seoul/Singapore 등 가까운 리전
- Server Image: Ubuntu 24.04 LTS x64
- Server Size: 최소 2GB RAM 이상 권장 (앱에 따라 조정)
- SSH Keys: 사전 등록한 운영자 공개키 선택 (필수)
- Firewall Group: 기본 (Ansible이 UFW로 재구성)
- Hostname: 역할 기반 (예:
msk-npm-01,msk-app-quant)
- Deploy Now
- 생성 완료 후 IP 주소 복사
대부분의 IaaS(Vultr, DigitalOcean, AWS EC2 등)는 User Data(cloud-init)를 지원합니다. 첫 부팅 시 기본 패키지 설치까지 자동화하려면:
#cloud-config
package_update: true
package_upgrade: true
packages:
- curl
- git
단, 복잡한 설정은 Ansible이 담당하므로 cloud-init은 최소만 두는 것이 관리 단순화 측면에서 좋습니다.
Phase 2: Inventory 등록
workspace/_infra/ansible/inventory/hosts.ini에 신규 서버 추가:
# Phase 1: 정적 inventory
[npm_servers]
msk-npm-01 ansible_host=141.164.xx.xx ansible_user=root
[app_servers]
msk-app-quant ansible_host=64.176.xx.xx
[db_servers]
msk-db-01 ansible_host=108.61.xx.xx
[monitoring_servers]
msk-monitor-01 ansible_host=95.179.xx.xx
[all:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_private_key_file=~/.ssh/id_ed25519
Phase 2.5: 계정(Account) 준비
multi-saas-kit은 멀티 계정(tenant) overlay 구조를 따릅니다 (ADR-020). 각 운영자(자사 포함)·고객사는 별도 계정 폴더를 가집니다.
cd workspace/_infra
# 자사 계정 생성 (최초 1회)
cp -r ansible-accounts/_example ansible-accounts/self
cp ansible-accounts/self/inventory/hosts.ini.example ansible-accounts/self/inventory/hosts.ini
cp ansible-accounts/self/vault/secrets.yml.example ansible-accounts/self/vault/secrets.yml
vi ansible-accounts/self/inventory/hosts.ini # 실제 서버 IP 입력
vi ansible-accounts/self/vault/secrets.yml # tailscale_authkey, ssh 공개키 등
ansible-vault encrypt ansible-accounts/self/vault/secrets.yml
# 고객사 관리가 필요하면 동일 절차로 추가
cp -r ansible-accounts/_example ansible-accounts/customer-a
실행은 반드시 scripts/ansible-account.sh <account> <playbook> 형식을 사용합니다.
wrapper가 ANSIBLE_INVENTORY, ANSIBLE_VAULT_PASSWORD_FILE, ANSIBLE_ROLES_PATH를 계정별로 자동 주입하여 타 계정 서버 사고를 방지합니다.
Phase 3: Bootstrap (최초 1회)
대부분의 IaaS는 생성 직후 root만 제공하므로 최초 1회는 root로 접속하여 deploy 유저를 만들고, 이후부터는 deploy로만 접근합니다. (AWS EC2처럼 ubuntu 유저가 기본 제공되는 경우에도 -u ubuntu로 접속 후 동일한 bootstrap 결과를 얻습니다.)
cd workspace/_infra
# 드라이런으로 먼저 확인
scripts/ansible-account.sh self bootstrap \
--limit msk-npm-01 \
--check --diff \
-u root
# 실제 실행
scripts/ansible-account.sh self bootstrap \
--limit msk-npm-01 \
-u root
Bootstrap이 수행하는 작업
| 순서 | 작업 | Role |
|---|---|---|
| 1 | 기본 패키지 업데이트 | common |
| 2 | deploy 유저 생성 + SSH 키 주입 | user |
| 3 | sudo NOPASSWD 설정 | user |
| 4 | PermitRootLogin no | hardening |
| 5 | PasswordAuthentication no (SSH 키 인증만) | hardening |
| 6 | UFW 활성화 (22/80/443만) | hardening |
| 7 | fail2ban 설치 | hardening |
| 8 | unattended-upgrades 활성화 | hardening |
| 9 | Tailscale 설치 + 가입 (pre-auth key) | tailscale |
완료 확인
# deploy 유저로 SSH 접속 가능한가
ssh deploy@{서버IP}
# root 접속은 차단되어야 함
ssh root@{서버IP} # → 거부되어야 정상
# Tailscale 상태
ssh deploy@{서버IP} 'tailscale status'
Phase 4: 표준 셋 업 (site.yml)
Bootstrap 이후에는 deploy 유저로 반복 가능한 표준 셋업을 실행합니다.
cd workspace/_infra
# 드라이런
scripts/ansible-account.sh self site \
--limit msk-npm-01 \
--check --diff
# 실제 실행
scripts/ansible-account.sh self site --limit msk-npm-01
site.yml이 수행하는 작업
| 범주 | 작업 |
|---|---|
| Docker | Docker Engine + Compose v2 설치 + deploy 유저를 docker 그룹에 추가 |
| 관측성 | node_exporter (메트릭) + promtail (로그 → Loki) |
| 역할별 | inventory의 그룹 변수에 따라 npm / laravel_app / postgres / grafana_lgtm role 실행 |
Phase 5: 역할별 배포
각 역할은 별도 playbook으로도 실행 가능합니다.
NPM 서버
scripts/ansible-account.sh self npm --limit npm_servers
수행 내용:
/opt/npm/에 docker-compose.yml 배포data/,letsencrypt/볼륨 권한 설정docker compose up -d실행
App 서버 (Laravel)
scripts/ansible-account.sh self app \
--limit msk-app-quant \
--extra-vars "project=quant.how branch=main"
DB 서버 (PostgreSQL)
scripts/ansible-account.sh self db --limit db_servers
모니터링 서버 (Grafana LGTM)
scripts/ansible-account.sh self monitoring --limit monitoring_servers