커스텀 배포 워크플로우
배포 흐름을 직접 제어하는 방법을 보여드릴게요. 머신을 재시작하지 않거나, 점진적으로 변경을 배포하거나, 앱의 특정 부분만 다른 부분을 건드리지 않고 업데이트하고 싶을 때 유용해요. fly deploy가 지원하는 다양한 타겟팅 옵션을 사용해서 앱의 필요에 맞는 배포 전략을 짤 수 있어요.
출처: 문서
본문
개요
**이 가이드는 머신을 재시작하지 않으려 하거나, 변경 사항을 점진적으로 배포하거나, 앱의 특정 부분만 다른 부분은 건드리지 않고 업데이트하려 할 때 배포 흐름을 제어하는 방법을 보여줍니다.**대부분의 사람들은 fly deploy를 전부 아니면 전무(all-or-nothing) 작업으로 생각해요. 새 이미지를 푸시하면 모든 머신이 재시작되어 그 이미지를 실행하죠. 이 동작은 많은 앱에 적합하지만, 여러분의 앱은 더 세분화된 접근 방식이 필요할 수도 있어요. 아마 오래 실행되는 작업(비디오 인코딩이나 LLM 채팅 세션 같은)을 처리하는 머신을 중단시키고 싶지 않을 수도 있고, 특정 리전에 먼저 점진적으로 변경을 배포하고 싶을 수도 있어요.
fly deploy 명령은 ID, 리전, 프로세스 그룹별로 특정 머신을 타겟팅하는 몇 가지 플래그를 지원하므로, 배포 전략을 앱의 필요에 맞게 조정할 수 있어요.
왜 이것이 필요할까
이런 전략은 진행 중인 활성 작업을 방해하지 않고 코드를 배포하고 싶을 때 유용해요. 예를 들어:
- 처리 도중 중단되면 안 되는 오래 실행되는 작업을 다루고 있을 때
- 유휴 머신을 재사용해야 하는 예측 불가능한 활동 스파이크가 있는 워크로드를 실행할 때
- 배포를 여러 구간으로 나눠 프로덕션에서 더 신중하게 배포하려 할 때
- 중앙 배포 명령에 의존하지 않고 머신 수명 주기를 관리하는 자체 로직을 구축할 때
특히 다음 유형의 앱에 유용해요:
- 미디어를 인코딩하거나, 작업을 처리하거나, 백그라운드 워커를 실행하는 앱
- 작업이 끝나면 깨끗하게 종료되는 앱
- 매번 새 머신을 띄우는 대신 정지된 머신을 재사용하는 것이 유리한 앱
분산(staggered) 및 선택적(selective) 배포
전체 머신을 한 번에 업데이트할 필요는 없어요. Fly는 더 신중한 배포를 위해 머신을 타겟팅하는 여러 방법을 제공해요.
상태별: 정지된 머신
머신이 작업을 마치면 종료되도록 되어 있다면, 정지된 머신만 업데이트할 수 있어요. 오래 실행되는 작업, 백그라운드 워커, 또는 auto_stop_machines를 사용하는 앱에 유용해요.
# 새 이미지를 빌드하고 레지스트리에 푸시하되, 아직 배포하지 않기
fly deploy --build-only --push
# 모든 머신을 나열하고 "stopped" 상태인 것만 필터링한 뒤 ID를 저장하기
fly machines list --json \
| jq -r '.[] | select(.state == "stopped") | .id' \
> stopped-machines.txt
# 정지된 머신에만 새 이미지를 배포하기
fly deploy --image THE_IMAGE \
--only-machines $(cat stopped-machines.txt | paste -sd, -)
모든 머신이 교체될 때까지 이 과정을 반복하세요. 이 방식은 다음 경우에 가장 잘 동작해요:
auto_stop_machines를 사용하고 있을 때- 앱이 완료되면 깨끗하게 종료될 때(
System.exit(0)또는 그에 준하는 것) - 머신이 스스로 수명을 관리하길 원할 때
리전별
영향 범위를 제한하거나 단계적 배포를 하려면 리전별로 머신을 타겟팅하세요:
# 현재 앱 이미지를 "dfw" 리전의 머신에만 배포하기
fly deploy --regions dfw
또는 --only-machines와 결합해 리전 내 특정 ID를 타겟팅할 수 있어요:
# 모든 머신을 나열하고 "dfw" 리전의 것만 필터링한 뒤 ID를 저장하기
fly machines list --json \
| jq -r '.[] | select(.region == "dfw") | .id' \
> dfw-machines.txt
# 그 목록에서 처음 두 머신에만 배포하기
head -n 2 dfw-machines.txt > batch-1.txt
fly deploy --image THE_IMAGE \
--only-machines $(paste -sd, - < batch-1.txt)
# batch 1에 없던 다음 세 머신에 배포하기
head -n 5 dfw-machines.txt | grep -vxFf batch-1.txt > batch-2.txt
fly deploy --image THE_IMAGE \
--only-machines $(paste -sd, - < batch-2.txt)
이후 배포에서 타겟팅하는 머신 수를 늘려 점진적으로 배포를 확장할 수 있어요. 더 나아가려면 이 로직을 스크립트로 만들어 리전별로 적용하거나, 앱의 헬스 체크나 메트릭에 기반해 자동화할 수도 있어요.
프로세스 그룹별
다중 프로세스 앱에서 일부 역할만 업데이트하고 나머지는 그대로 두고 싶을 수 있어요. 예를 들어 zk, supervisor, conductor 프로세스 그룹을 가진 클러스터를 생각해 보세요. 업그레이드 중에 zk 머신이 계속 떠 있어야 한다면, 다른 그룹에만 배포할 수 있어요:
# 새 이미지를 "supervisor"와 "conductor" 프로세스 그룹에만 배포하기
fly deploy --image THE_IMAGE --process-groups supervisor,conductor
이렇게 하면 zk 그룹이 업데이트할 준비가 될 때까지 이전 이미지로 계속 실행될 수 있어요. 이 패턴은 클러스터 환경에서 쿼럼을 유지하거나 다운타임을 최소화하는 데 유용해요.
부분 배포 실패 처리하기
때로는 이미지가 일부 머신에는 깨끗하게 배포됐지만 다른 머신에서는 실패하기도 해요. 다음을 해야 해요:
- 시작 오류나 비정상 상태를 주시하기
- 실패한 업데이트를 개별적으로 재시도하기
- 실패율이 높아지면 배포를 일시 중지하기
결국에는 헬스 체크나 배포 출력에 기반한 자동 롤백을 구현하고 싶을 수도 있어요. 지금은 어떤 머신이 성공했고 어떤 머신이 실패했는지 기록해 두는 것부터 시작하는 게 좋아요.
CI 통합
GitHub Actions나 다른 CI를 사용하고 있다면 이 배포 패턴을 통합할 수 있어요. 예를 들어:
- main에서
fly deploy --build-only --push - 예약된 작업의 일부로 이미지 태그를 사용해 정지된 머신을 업데이트
- 전체 배포가 완료되면 선택적으로 Slack이나 GitHub 댓글로 알림 보내기
이렇게 하면 실행 중인 작업을 방해하지 않고 지속적으로 배포할 수 있어요.
동적 구성 업데이트
모든 변경이 새 이미지를 필요로 하는 것은 아니에요. 볼륨이나 환경 변수에서 구성을 불러오는 앱이라면 다음과 같이 할 수 있어요:
fly secrets set으로 시크릿이나 구성 맵을 업데이트- 유휴 머신을 재시작해 변경 사항 반영
- 활성 머신은 자연스럽게 종료되고 업데이트된 구성으로 재시작하도록 두기
이는 앱이 라이브 리로드를 지원하거나 구성 파일을 감시할 때 특히 유용해요.
주의할 점
모든 머신을 업데이트하는 것을 잊기
스크립트가 특정 정지 머신을 놓치거나, 나중에 다른 머신이 정지하면 그 머신들이 이전 이미지를 계속 실행할 수 있어요. 업데이트 루프가 철저하게 모든 머신을 잡을 만큼 충분히 오래 실행되는지 확인하세요.
오래 살아 있는 머신은 결코 업데이트되지 않음
배포 전략이 정지된 머신만 업데이트하는데 머신이 스스로 종료되지 않는다면, 그 머신들은 절대 업그레이드되지 않아요. 가장 견고한 해결책은 auto_stop_machines를 사용하고 앱이 작업을 마치면 깨끗하게 종료되도록 하는 거예요. 그게 불가능하다면 앱이 고정된 시간 후에 스스로 종료되도록(TTL이라고도 하는 time-to-live 방식) 구성할 수도 있어요. 또는 헬스 체크로 낡았거나 유휴 상태인 머신을 감지하고, 자동화를 사용해 데드라인 후 강제로 정지시킬 수도 있어요.
혼합 이미지 동작
머신이 서로 다른 이미지 버전을 실행 중이라면 앱이 이를 처리해야 해요. 스키마 변경, 프로토콜 불일치, 구성 분기(divergence)는 이에 대비하지 않으면 문제를 일으킬 수 있어요.
배포 시 숨겨진 의존성
머신을 재시작하지 않더라도 일부 변경은 여전히 문제를 일으킬 수 있어요. 환경 변수, 공유 스토리지, 시크릿이 다르게 동작하거나 동기화가 어긋날 수 있어요.
관련 읽을거리
이 가이드의 아이디어를 더 깊이 파고들고 싶다면 다음 Fly.io 문서를 확인하세요:
- Machines 개요: Machine이 어떻게 동작하고 무엇이 다른지 알아보세요.
- fly deploy CLI 참조:
--only-machines,--regions,--process-groups를 포함한 배포 옵션의 전체 목록이에요. - 동적 요청 라우팅:
fly-replay를 사용해 그때그때 머신 간 트래픽을 이동하세요.