Terraform 없이 인프라 자동화 구축하기 (Building Infrastructure Automation without Terraform)
Fly.io는 더 이상 Terraform 프로바이더를 제공하지 않아요. 대신 우리 플랫폼에 잘 맞는 도구로 Terraform과 비슷한 경험을 만드는 두 가지 방법을 소개해 드릴게요. 하나는 flyctl + GitHub Actions로 추천하는 방식이고, 다른 하나는 Machines API를 직접 다루는 고급 방식이에요.
출처: 문서
본문
개요 (Overview)
저희는 더 이상 Terraform 프로바이더를 제공하지 않아요. 그건 의도적인 결정이에요. Terraform은 우리 플랫폼의 동작 방식과 잘 맞지 않아요. 이 가이드에서는 실제로 잘 맞는 도구들을 사용해 Terraform과 비슷한 경험을 얻는 방법을 다룹니다.
인프라를 선언적으로 정의하고, 템플릿 변수를 쓰고, 반복 가능한 워크플로우와 단일 진실 공급원(single source of truth)을 사용하는 데 익숙하다면, Fly.io에서도 충분히 그렇게 할 수 있어요. 다만 사고방식을 조금 달리해야 해요: plan/apply 모델에 맞추려고 도구를 구부리기보다, 우리의 실제 프리미티브에 맞춰 만들어진 도구를 사용하는 거죠. 좋은 길을 찾고 있다면 선택지가 있어요.
이 가이드는 Terraform 없이 Fly.io 배포를 자동화하는 두 가지 옵션을 다뤄요.
첫 번째는 flyctl과 GitHub Actions를 사용하는 방식이에요. 대부분의 사용자에게 권장하는 방식이에요: main에 push하면 앱이 배포돼요. 관리할 인프라 상태도, 추적할 VM도 없어요. 코드와 Git만 있으면 돼요.
두 번째는 Machines API를 직접 사용하는 방식이에요. 더 많은 작업이 필요하지만, 각 가상 머신을 완전히 제어할 수 있어요. 리전 간 롤링 배포, 임시 환경, 또는 세밀한 확장 로직처럼 커스텀 오케스트레이션을 한다면 이 방식이 필요해요.
두 접근 방식이 어떻게 동작하는지 보여드리고, 여러분의 설정에 어떤 것이 맞는지 판단하는 데 도움을 드릴게요.
쉬운 방법: flyctl + GitHub Actions (The easy way)
이 경로는 대부분의 Fly.io 앱이 선택하는 방식이고, 우리가 권장하는 방식이에요. 코드를 작성하고 main에 push하면 앱이 배포돼요. 설정이 빠르고, 원할 때까지 VM 라이프사이클 관련 요소를 추상화해 줘요.
요지는 이러해요:
- 앱을 Fly.io에서 실행되게 만든다
- 코드를 GitHub 리포지토리에 push한다
flyctl deploy를 호출하는 GitHub Actions 워크플로우를 연결한다
그게 전부예요. 설정 방법은 다음과 같아요.
1단계: 배포 토큰 생성
fly tokens create deploy --app <app-name>
그 토큰을 비밀번호처럼 취급하세요. 안전한 곳에 복사해 두세요 — GitHub에서 필요할 거예요.
2단계: GitHub 리포지토리에 추가
GitHub에서:
- 리포지토리 > Settings > Secrets and variables > Actions로 이동
FLY_API_TOKEN이라는 새 시크릿 추가- 배포 토큰을 붙여넣기
3단계: 워크플로우 파일 작성
이 내용을 리포지토리의 .github/workflows/fly.yml에 넣으세요:
name: Fly Deploy
on:
push:
branches:
- main # or your default branch
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
이 파일을 push하면, 다음 git push to main이 배포를 시작할 거예요. Actions 탭에서 진행 상황을 볼 수 있어요.
--remote-only 플래그는 flyctl이 Fly.io의 원격 빌더에서 이미지를 빌드하도록 지시해서, CI 환경에 Docker가 필요하지 않게 해줘요.
이제부터 지속적 배포가 적용돼요. main에 push하면 앱이 라이브로 전환돼요.
현실적인 예를 들어 볼게요: Postgres와 Redis로 구동되는 Rails 앱을 iad와 lhr에 배포하고 있다고 해 보죠. 모노레포에 있고, main에 push할 때마다 배포가 트리거되길 원한다고 가정해요. flyctl + GitHub Actions 설정이 지속적 배포를 만들어 줘요. 지원 인프라(데이터베이스, IP 주소, 확장 같은 것)는 명령형(imperatively)으로 처리하게 돼요: fly pg create, fly redis create, fly scale count, fly ips allocate 등등. 플랫폼이 구성한 내용을 계속 추적하므로 매번 다시 선언할 필요가 없어요.
더 어려운 방법: Machines API (The harder way)
terraform apply보다 더 많은 것을 하던 팀이라면 이 경로를 택해요. 카나리아 배포, 임시 환경, 정확히 어느 VM이 어디서 실행되는지 제어하는 것처럼 인프라 자동화에 로직을 얹고 있었다면 Machines API를 살펴보세요. 더 저수준이지만 더 강력해요. Fly.io의 베어메탈 인터페이스라고 생각하세요. plan도, state도, graph도 없고, 그냥 HTTP뿐이에요.
이것으로 할 수 있는 것들:
- 특정 리전에서 새 Machine을 띄우기
- Machine 하나씩 변경사항을 롤아웃하기
- 커스텀 확장 로직 만들기
- 요청 시 환경을 내렸다가 다시 구축하기
이것이 바로 Fly.io 자체 오케스트레이션 도구가 내부적으로 사용하는 방식이에요. 우리처럼 Machine을 띄우고, 서로 이어 붙이고, 리전 간에 오케스트레이션할 수 있어요. 우리가 내부적으로 쓰는 것과 동일한 제어 수단이 모두 주어지므로, 여러분의 설정에 필요한 정확한 워크플로우를 만들 수 있어요.
다루게 될 것 (What you're working with)
Machines API는 REST 인터페이스예요. HTTPS 위에서 JSON으로 통신해요. Fly.io API 토큰으로 인증하며, 이상적으로는 앱이나 조직에 범위가 한정된 배포 토큰을 써요. Authorization 헤더에 Bearer 토큰으로 전달하세요. GitHub Actions로 flyctl을 배포할 때 썼던 것과 같은 종류의 토큰이에요.
각 Fly App은 하나의 네임스페이스예요. 앱 안에 원하는 만큼 많은 Machine(VM)을 만들 수 있어요. 각 Machine은 Docker 이미지를 실행하고, 리전과 리소스 설정, 그리고 생성 → 시작 → 중지 → 파괴의 라이프사이클을 가져요.
사용하는 데 특별한 도구가 필요하지 않아요. curl로 충분해요. fetch, requests, httpie, 또는 Go나 Rust나 Python에서 좋아하는 어떤 HTTP 클라이언트도 괜찮아요. 데이터베이스 생성, 스케일 카운트 설정처럼 flyctl로 스크립트하던 모든 것을 Machines API로도 할 수 있어요. 더 장황하지만, 완전한 제어를 제공하고 더 큰 오케스트레이션 흐름에 인프라 설정을 통합하기 쉬워요.
예시: curl로 Machine 띄우기
export FLY_APP_NAME="your-app-name"
export FLY_API_TOKEN="your-fly-token"
curl -i -X POST \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
"https://api.machines.dev/v1/apps/${FLY_APP_NAME}/machines" \
-d '{
"region": "sjc",
"config": {
"image": "nginx",
"guest": {
"cpu_kind": "shared",
"cpus": 1,
"memory_mb": 256
}
}
}'
응답에는 새 Machine의 ID가 포함돼요. 그런 다음 /machines/{id}에 적절한 메서드로 요청해 시작, 중지, 파괴할 수 있어요.
API를 언제 사용해야 하나 (When to reach for the API)
대부분의 앱은 이 정도까지는 필요 없어요. 하지만 단기간의 브라우저 기반 개발 환경을 띄우거나 임시 멀티플레이어 게임 서버를 실행하는 것처럼 동적인 무언가를 만든다면, 이런 종류의 제어가 필요할 거예요.
우리가 좋아하는 실제 사용 사례 몇 가지:
- "새 머신에서 이 함수 하나 실행하기" 패턴. 이 JS 리포지토리에서 데모하고 있어요. 리전 내에서 새 Machine을 부팅하고, 작업을 실행하고, 내려요. 서버리스처럼 동작하지만 완전한 VM이라 콜드 스타트가 없어요.
- Machines API용 가벼운 Go 클라이언트인
sosedoff/fly-machines는 Machine을 프로그래밍 방식으로 생성, 업데이트, 파괴하는 헬퍼를 제공해요. Terraform 로직을 직접 만든 Go 기반 오케스트레이션으로 대체하고 있다면 좋은 가벼운 예시예요. 더 포괄적인 것이 필요하다면, 공식 fly Go SDK인superfly/fly-go를 확인해 플랫폼과 더 긴밀하게 통합하세요.
Machines API는 어떤 흐름에 여러분을 가두지 않아요. 우리가 프리미티브를 제공할 뿐이에요.
아직도 고민이라면? 여기 비교가 있어요.
| Feature | flyctl + GitHub Actions |
Machines API |
|---|---|---|
| Best for | Standard apps, CI/CD | Custom infra, dynamic environments |
| Setup time | Fast | Slower |
| Complexity | Low | High |
| Control | Abstracted (deploy, scale) |
Full (create, start, destroy) |
| Official support | Fully supported & recommended | Fully supported & documented |
마지막으로 하나 (One last thing)
의존하던 도구가 deprecated 되는 건 정말 속상한 일이라는 걸 알고 있어요. Terraform은 많은 것들을 깔끔하고 선언적으로 느끼게 해줬어요. 하지만 특히 Machines API와 관련해서는, Terraform은 본질적으로 명령형인 라이프사이클을 선언적 모델로 표현하려 했기 때문에 항상 조금 어긋나게 동작하고 있었어요. Machines API는 Terraform의 추상화에 깔끔하게 매핑되지 않았던 세밀한 제어와 유연성을 제공해요. 약간의 노력으로 정확히 필요한 것을 만들 수 있고, 다른 누군가가 앱이 어떤 모습이어야 한다고 생각하는 것에 갇히지 않아도 돼요.
지금 그 도구를 다시 구축하고 있다면, 무엇을 하고 있는지 알려주세요. 도움을 드릴 수도 있고, 적어도 거기서 뭔가 배울 수도 있어요.
관련 자료 (Related Reading)
- flyctl과 GitHub Actions를 사용한 지속적 배포 Fly.io + GitHub Actions로 CI/CD를 연결하는 방법에 대한 안내.
- Fly.io 액세스 토큰 자동화 워크플로우를 위한 토큰 범위, 권한, 모범 사례에 대한 심층 분석.
- Machines API 사용하기 VM/"machine" 수준에서 자동화하기 위한 레퍼런스 가이드 (flyctl의 저수준 대안).
- 앱 구성 (
fly.toml) 앱 설정 파일이 어떻게 동작하는지에 대한 자세한 내용 — 자동화 설정의 일부인 경우가 많아요.