하나에서 세 개로 나눈 Terraform
한 main.tf에 쌓인 서버, 복구와 백업 설정을 배포 단위가 다른 세 작업 디렉터리로 다시 작성한 과정
남아 있는 최초의 terraform/main.tf에는 Compute Engine VM과 방화벽이 있었다. VM을
띄우고 Minecraft 접속 포트를 여는 데 필요한 만큼만 Terraform에 적은 구성이었다.
서버를 운영하는 동안 해야 할 일이 늘었다. 고정 IP가 필요했고, 월드는 VM 밖에
백업해야 했다. 선점된 VM을 다시 켜는 함수와 Discord 봇 배포도 같은 파일로 들어왔다.
처음에는 서버 한 대를 만들던 terraform plan이 나중에는 백업과 복구 자동화까지 함께
포함했다.
flowchart LR FIRST["첫 저장소<br/>VM과 방화벽"] --> GROWN["커진 main.tf<br/>서버, 백업과 복구 자동화"] GROWN --> NEW["새 저장소<br/>서버 구성 재작성"] NEW --> SPLIT["세 작업 디렉터리<br/>서버, 선점 복구, 백업 정리"]
VM과 방화벽으로 시작한 main.tf
첫 HCL에서 확인되는 관리 대상은 두 종류다.
terraform/main.tf
├── google_compute_firewall
└── google_compute_instance
방화벽은 Minecraft 접속 포트를 열었고, VM은 Ubuntu 22.04와 30GB 표준 영구 디스크로 시작했다. 이후 작은 머신 유형은 더 큰 값으로 바뀌었고, VM에는 구형 선점형 설정이 들어갔다.
이 범위에서는 한 파일이 읽기 편했다. VM 이름, network tag와 방화벽을 같은 plan에서 검토할 수 있었기 때문이다. 서버와 함께 바뀌는 리소스만 있을 때는 작업 디렉터리를 더 나눌 이유가 크지 않았다.
추가된 운영 리소스
Minecraft 프로세스 바깥의 운영 요구가 생길 때마다 Google Cloud 리소스와 배포 파일이 따라왔다.
| 운영 중 필요해진 일 | Terraform에 들어온 대상 | plan에서 함께 보게 된 변경 |
|---|---|---|
| 접속 주소 유지 | 고정 외부 IP | VM network interface와 IP 연결 |
| 관리 경로 분리 | 게임, RCON, SSH, Dynmap 방화벽 | 접속 포트와 허용 CIDR |
| 월드 보관 | 백업 버킷과 IAM | 버킷 보존 설정과 VM 권한 |
| 선점 뒤 재시작 | Scheduler, Pub/Sub, Cloud Functions, Cloud Run 실험 | 함수, 메시지 경로와 IAM |
| Discord 운영 | 봇 ZIP과 VM metadata | 인프라 변경과 애플리케이션 파일 배포 |
선점 복구를 추가하면서 VM 바깥의 리소스가 늘었다. 종료된 VM은 자기 자신을 다시 시작할 수 없다. VM 바깥에서 상태를 보고 시작 요청을 보내는 Google Cloud 서비스가 필요했다. 여러 방식을 시험한 HCL이 한 파일에 남으면서, 선언은 있지만 호출 경로가 완성되지 않은 리소스도 생겼다. 마지막 HCL 전체를 한 시점의 운영 구성으로 볼 수 없는 이유다.
metadata의 용도도 넓어졌다. 시작 스크립트, 종료 스크립트, systemd unit, Minecraft
설정과 Discord 봇 ZIP이 VM resource 안에 모였다. terraform apply가 VM 생성과
서버 안에서 실행할 파일 배포를 함께 맡았다.
새 저장소에서 다시 쓴 서버 구성
현재 저장소는 앞선 저장소의 Git 이력을 이어받지 않았다. 공통 커밋이 없으며 첫 파일도
기존 HCL을 그대로 복사한 형태가 아니다. 새 저장소의 최초 main.tf에서 확인한 resource
선언은 다음 다섯 개다.
resource "google_compute_address" "minecraft_static_ip" {}
resource "google_storage_bucket" "backup_bucket" {}
resource "google_compute_network" "minecraft_network" {}
resource "google_compute_firewall" "minecraft_firewall" {}
resource "google_compute_instance" "minecraft_server" {}
위 코드는 resource 선언만 남긴 발췌다. 실제 속성과 식별자는 공개하지 않았다.
한 개의 Terraform으로 관리하던 저장소를 참고해 리소스 이름과 파일 구성을 새로
작성했다. 첫 버전은 저장소 최상위의 main.tf, variables.tf, outputs.tf로 시작했다.
새 저장소를 만들었다고 곧바로
세 작업 디렉터리가 생긴 것은 아니었다.
저장소를 새로 만든 명령과 당시 판단을 설명한 문서는 남아 있지 않다. 확인할 수 있는 범위는 두 저장소의 Git과 파일 내용, 그리고 서버, 복구, 백업 정리를 따로 구성하려 했다는 현재의 기억까지다.
세 번으로 나뉜 plan과 apply
서버 파일은 먼저 server-terraform으로 옮겨졌다. Git은 이 변경을 내용 수정 없는 파일
이동으로 기록한다. 같은 변경에 선점 복구용 preempted-terraform이 추가됐고, 이후 백업
정리 디렉터리가 들어왔다. 이름을 한 번 더 고친 결과가 현재의 세 디렉터리다.
| 작업 디렉터리 | plan에서 검토한 대상 | apply한 서비스 |
|---|---|---|
start-minecraft-server | 고정 IP, 방화벽, VM, 백업 버킷 | Minecraft 서버 |
restart-preempted-instance | 로그 지표, Monitoring, Pub/Sub, 함수와 IAM | 선점 복구 |
bucket-backup-cleanup | Scheduler, Pub/Sub, 함수와 IAM | 오래된 백업 정리 |
flowchart TB
subgraph BEFORE["한 작업 디렉터리"]
ONE_PLAN["한 번의 plan"] --> ONE_APPLY["서버와 외부 자동화 apply"]
end
subgraph AFTER["세 작업 디렉터리"]
SERVER_PLAN["서버 plan"] --> SERVER_APPLY["서버 apply"]
RESTART_PLAN["선점 복구 plan"] --> RESTART_APPLY["복구 함수 apply"]
CLEANUP_PLAN["백업 정리 plan"] --> CLEANUP_APPLY["정리 함수 apply"]
end
나눈 이유는 배포할 서비스와 검토할 Terraform의 범위를 맞추기 위해서였다. VM 사양을 바꿀 때 복구 함수와 백업 정리 설정까지 읽을 필요가 없었다. 복구 함수만 수정할 때도 방화벽과 VM 변경을 다시 확인하고 싶지 않았다.
당시 state 충돌이나 장애 격리를 직접적인 목적으로 삼았다는 기록과 기억은 없다. 디렉터리를 나눈 뒤 각 위치에 local state가 생겼다는 사실과, 왜 나눴는지에 대한 회고는 구분해야 한다.
분리 뒤 드러난 운영 문제
파일을 세 곳으로 나누자 plan은 짧아졌다. 서비스 사이에 전달할 값과 원격 리소스의 소유 관계는 따로 정리해야 했다.
| 남은 문제 | 실제 코드와 state에서 확인한 모습 | 운영자가 해야 했던 확인 |
|---|---|---|
| 입력값 중복 | 프로젝트, zone, 인스턴스와 버킷 이름을 여러 변수에 다시 입력 | 세 디렉터리가 같은 대상을 가리키는지 비교 |
| output 미사용 | 서버의 인스턴스와 버킷 output을 다른 구성이 읽지 않음 | 값이 바뀌면 다른 입력 파일도 수정 |
| 배포 승인 생략 | 두 Windows 배치 파일이 ZIP 생성 뒤 apply -auto-approve 실행 | 적용 전에 별도 plan을 읽으려면 수동 절차 추가 |
디렉터리를 나눈 뒤에도 세 state가 같은 대상을 함께 관리한 자국이 남았다. 중복된 프로젝트 API와 백업 보존 설정은 24편에서 세 state를 나란히 놓고 확인할 수 있다.
세 디렉터리는 서버, 선점 복구와 백업 정리의 plan을 따로 만들었다. 배포 단위를 나눈다는 목적은 그것으로 이뤘다. 다만 인스턴스와 버킷 이름은 여전히 운영자가 손으로 맞춰야 했고, 프로젝트 API는 두 state에 중복됐다.
세 루트가 실제로 실행한 ZIP 생성, plan과 apply 명령은 21편에 남아 있다.
참고
Comments
아직 댓글이 없습니다. 첫 댓글을 남겨주세요.
검토 대기 중