7P by GN⁺ 5시간전 | ★ favorite | 댓글 1개
  • 월 $1,432 규모의 프로덕션 인프라월 $233 전용 서버로 옮기면서, 운영체제까지 교체하고도 다운타임 없이 서비스 연속성 유지
  • 30개 MySQL 데이터베이스와 34개 Nginx 가상 호스트, GitLab EE, Neo4J, Supervisor, Gearman을 새 서버에 동일하게 구성한 뒤 실시간 복제와 최종 증분 동기화로 이전 완료
  • 데이터베이스 이전의 핵심은 mydumper·myloader 병렬 처리MySQL replication 조합이었고, MySQL 5.7에서 8.0으로 올리며 발생한 sys 스키마와 권한 문제도 수정
  • 컷오버는 DNS TTL 축소, 기존 서버의 Nginx 리버스 프록시 전환, A 레코드 일괄 변경 순서로 진행돼 DNS 전파 중에도 기존 IP 요청이 새 서버로 전달된 구조
  • 결과적으로 월 $1,199 절감, 연 $14,388 절감, CPU·메모리·스토리지 상향과 0분 다운타임을 함께 달성한 사례

마이그레이션 배경

  • 터키에서 소프트웨어 회사를 운영하는 환경에서 급격한 인플레이션터키 리라 약세로 인해 달러 기준 인프라 비용 부담이 크게 증가한 상황
  • 기존 DigitalOcean 서버 비용은 매달 $1,432였으며, 구성은 192GB RAM, 32 vCPU, 600GB SSD, 1TB 블록 볼륨 2개, 백업 포함 형태
  • 새 대상은 Hetzner AX162-R 전용 서버였으며, AMD EPYC 9454P 48코어 96스레드, 256GB DDR5, 1.92TB NVMe Gen4 RAID1 구성
  • 월 비용은 $233으로 낮아졌고, 월 절감액은 $1,199, 연 절감액은 $14,388 규모
  • 기존 서버의 신뢰성이나 개발자 경험에는 불만이 없었지만, steady-state 워크로드에서는 가격 대비 성능이 더 이상 합리적이지 않은 상태

기존 운영 환경

  • 운영 스택은 단순 테스트 환경이 아니라 실제 프로덕션 환경 구성
    • MySQL 데이터베이스 30개, 총 248GB 데이터 규모
    • 여러 도메인에 걸친 Nginx 가상 호스트 34개 운영
    • GitLab EE 백업 42GB 포함
    • Neo4J Graph DB 30GB 규모 운영
    • Supervisor로 수십 개의 백그라운드 워커 관리
    • Gearman 작업 큐 사용
    • 수십만 사용자를 대상으로 하는 라이브 모바일 앱 운영
  • 기존 서버 운영체제는 CentOS 7이었고 이미 지원 종료 상태
  • 새 서버 운영체제는 AlmaLinux 9.7이며, RHEL 9 호환 배포판이자 CentOS의 자연스러운 후속 선택지
  • 이번 이전은 비용 절감뿐 아니라, 수년간 보안 업데이트를 받지 못한 운영체제에서 벗어나는 계기

무중단 전략

  • 단순 DNS 변경과 서비스 재시작 방식은 허용하지 않고, 6단계 마이그레이션 절차로 무중단 이전 진행
  • 1단계: 새 서버 전체 스택 설치

    • Nginx를 기존과 동일한 플래그로 소스 컴파일 설치
    • PHP는 Remi repo를 통해 설치하고, 기존 서버의 동일한 .ini 설정 파일 적용
    • MySQL 8.0, Neo4J Graph DB, GitLab EE, Node.js, Supervisor, Gearman 설치 및 기존 동작과 일치하도록 구성
    • DNS 레코드를 건드리기 전, 모든 서비스가 기존 서버와 동일하게 동작하도록 맞춘 상태
    • SSL 인증서는 기존 서버의 /etc/letsencrypt/ 전체 디렉터리를 rsync로 복사해 처리
    • 전체 트래픽이 새 서버로 전환된 뒤 certbot renew --force-renewal로 인증서 일괄 강제 갱신 수행
  • 2단계: 웹 파일 rsync 복제

    • /var/www/html 전체 디렉터리 약 65GB, 150만 개 파일을 SSH 기반 rsync로 복제
    • --checksum 옵션으로 무결성 검증 수행
    • 컷오버 직전에 변경 파일 반영을 위한 최종 증분 동기화 추가 수행
  • 3단계: MySQL 마스터-슬레이브 복제

    • 덤프 후 복원으로 데이터베이스를 내리는 대신 실시간 복제 구성
    • 기존 서버를 마스터, 새 서버를 읽기 전용 슬레이브로 설정
    • 초기 대용량 적재는 mydumper 사용, 이후 덤프 메타데이터에 기록된 정확한 binlog 위치부터 복제 시작
    • 컷오버 시점까지 양쪽 데이터베이스를 실시간 동기 상태로 유지
  • 4단계: DNS TTL 축소

    • DigitalOcean DNS API를 스크립트로 호출해 모든 A/AAAA 레코드 TTL을 3600초에서 300초로 축소
    • MX, TXT 레코드는 변경하지 않음
    • 메일 레코드 TTL 변경 시 전달성 문제를 일으킬 수 있어 제외한 상태
    • 기존 TTL이 전 세계적으로 만료되도록 1시간 대기 후 5분 이내 컷오버 준비 완료
  • 5단계: 기존 서버 Nginx를 리버스 프록시로 전환

    • Python 스크립트가 34개 Nginx 사이트 설정 전반의 server {} 블록을 파싱
    • 기존 설정은 백업하고, 새 서버를 가리키는 프록시 설정으로 대체
    • DNS 전파 중에도 기존 IP로 들어오는 요청은 새 서버로 조용히 전달되는 구조
    • 사용자 입장에서는 중단이 보이지 않는 방식
  • 6단계: DNS 컷오버와 기존 서버 종료

    • Python 스크립트로 DigitalOcean API를 호출해 모든 A 레코드를 새 서버 IP로 수 초 안에 변경
    • 기존 서버는 1주일간 cold standby로 유지 후 종료
    • 서비스는 전체 과정 동안 직접 응답하거나 프록시를 통해 응답하는 형태로 유지돼, 가용성 공백 구간이 없었던 상태

MySQL 마이그레이션

  • 전체 작업 중 가장 복잡한 구간이 MySQL 이전 과정
  • 데이터 덤프

    • 표준 mysqldump 대신 mydumper 사용
    • 새 서버의 48 CPU 코어를 활용한 병렬 export/import로, 단일 스레드 mysqldump 기준 며칠 걸릴 작업을 몇 시간으로 단축
    • 사용한 주요 옵션에는 --threads 32, --compress, --trx-consistency-only, --skip-definer, --chunk-filesize 256 포함
    • 메인 덤프의 metadata 파일에 스냅샷 시점의 binlog 위치 기록
      • File: mysql-bin.000004
      • Position: 21834307
    • 해당 값이 이후 복제 시작 지점으로 사용된 상태
  • 덤프 전송

    • 덤프 완료 후 SSH 기반 rsync로 새 서버에 전송
    • 248GB 압축 청크 전송
    • mydumper--compress 옵션으로 압축된 청크가 네트워크 전송 속도 향상에 기여
  • 데이터 적재

    • myloader 사용
    • 주요 옵션은 --threads 32, --overwrite-tables, --ignore-errors 1062, --skip-definer 구성
  • MySQL 5.7에서 8.0으로의 전환 문제

    • CentOS 7 환경으로 인해 기존 서버는 MySQL 5.7에 머물러 있던 상태
    • 이전 전 mysqlcheck --check-upgrade로 데이터가 MySQL 8.0과 호환되는지 확인했고, 결과는 문제 없음
    • 새 서버에는 최신 MySQL 8.0 Community 설치
    • 프로젝트 전반에서 쿼리 실행 시간이 유의미하게 감소했고, 원문에서는 MySQL 8.0의 개선된 optimizerInnoDB 향상을 이유로 언급
    • 다만 버전 점프로 인한 문제도 발생
      • import 이후 mysql.user 테이블 컬럼 구조가 예상 51개가 아니라 45개 상태
      • 그 결과 mysql.infoschema 누락, 사용자 인증 장애 발생
    • 첫 번째 수정 시도는 아래 명령 사용
      • systemctl stop mysqld
      • mysqld --upgrade=FORCE --user=mysql &
    • 첫 시도는 ERROR: 'sys.innodb_buffer_stats_by_schema' is not VIEW 오류로 실패
    • 원인은 sys 스키마가 뷰가 아닌 일반 테이블로 import된 상태
    • 해결은 DROP DATABASE sys; 실행 후 업그레이드 재실행 방식
    • 이후 정상 완료

MySQL 복제 구성

  • 두 서버 모두 덤프 적재가 끝난 뒤, 새 서버를 기존 서버의 replica로 구성
  • CHANGE MASTER TO 구문에 기존 서버 IP, 복제 사용자, 포트 3306, MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=21834307 지정
  • 이후 START SLAVE; 실행
  • 거의 즉시 error 1062 Duplicate Key로 복제가 중단된 상태
  • 원인은 덤프가 두 번에 나뉘어 수행되면서 그 사이 일부 테이블에 쓰기가 발생했고, import된 덤프와 binlog 재생이 같은 행을 중복 삽입하려 한 상황
  • 해결을 위해 아래 설정 적용
    • SET GLOBAL slave_exec_mode = 'IDEMPOTENT';
    • START SLAVE;
  • IDEMPOTENT 모드는 duplicate key와 missing row 오류를 조용히 건너뛰는 방식
  • 모든 핵심 데이터베이스가 오류 없이 동기화됐고, 몇 분 안에 Seconds_Behind_Master 값이 0으로 감소

컷오버 전 검증

  • DNS 레코드를 건드리기 전에 새 서버에서 모든 서비스가 올바르게 동작하는지 확인 필요
  • 검증 방법은 로컬 머신의 /etc/hosts 파일을 임시 수정해 도메인을 새 서버 IP로 매핑하는 방식
  • 브라우저와 Postman은 새 서버로 요청을 보내고, 외부 사용자는 계속 기존 서버로 접속하는 구조
  • API 엔드포인트, 관리자 패널, 각 서비스 응답 상태 점검
  • 모든 항목 확인 후 실제 컷오버 진행

SUPER 권한 문제

  • 마스터-슬레이브 복제가 완전히 동기화된 뒤, 새 서버에서 read_only = 1인데도 INSERT 문이 성공하는 현상 확인
  • 원인은 모든 PHP 애플리케이션 사용자에게 SUPER 권한이 부여된 상태였기 때문
  • MySQL에서는 SUPER 권한이 read_only를 우회
  • SHOW GRANTS FOR 'some_db_user'@'localhost'; 결과에서 SUPER 권한 포함 상태 확인
  • 24개 애플리케이션 사용자에서 REVOKE SUPER ON *.* FROM 'some_db_user'@'localhost'; 반복 실행
  • 이후 FLUSH PRIVILEGES; 수행
  • 그 다음부터는 read_only = 1이 애플리케이션 사용자 쓰기를 올바르게 차단하면서 복제는 계속 허용하는 상태

DNS 준비

  • 모든 도메인은 DigitalOcean DNS로 관리했고, 네임서버는 GoDaddy에서 연결된 상태
  • TTL 감소 작업은 DigitalOcean API를 대상으로 스크립트화
  • 변경 대상은 A, AAAA 레코드만 한정
  • MX, TXT 레코드는 건드리지 않음
    • Google Workspace 전달성 이슈 가능성 때문에 메일 관련 레코드 TTL 변경 제외
  • 기존 TTL 만료를 위해 1시간 대기 후 컷오버 준비 완료

기존 서버 Nginx의 리버스 프록시 전환

  • 34개 설정 파일을 수작업으로 편집하는 대신 Python 스크립트로 자동 변환 수행
  • 스크립트는 모든 설정 파일의 server {} 블록을 파싱하고, 핵심 content block 식별 후 프록시 설정으로 대체
  • 원본 설정은 .backup 파일로 백업
  • 예시 설정에서는 proxy_pass https://NEW_SERVER_IP;, proxy_set_header Host $host;, proxy_set_header X-Real-IP $remote_addr;, proxy_read_timeout 150; 적용
  • 핵심 옵션은 proxy_ssl_verify off
    • 새 서버의 SSL 인증서는 도메인에 대해 유효하며 IP 주소에 대해서는 유효하지 않기 때문
    • 양 끝단을 모두 제어하는 환경이어서 여기서는 검증 비활성화 허용

컷오버 절차

  • 컷오버 직전 조건은 복제 지연이 Seconds_Behind_Master: 0 이고 리버스 프록시 준비 완료 상태
  • 실행 순서는 다음과 같음
    • 새 서버에서 STOP SLAVE;
    • 새 서버에서 SET GLOBAL read_only = 0;
    • 새 서버에서 RESET SLAVE ALL;
    • 새 서버에서 supervisorctl start all
    • 기존 서버에서 nginx -t && systemctl reload nginx 실행으로 프록시 활성화
    • 기존 서버에서 supervisorctl stop all
    • 로컬 Mac에서 python3 do_cutover.py 실행해 DNS의 모든 A 레코드를 새 서버 IP로 변경
    • 5분 전파 대기
    • 기존 서버에서 모든 crontab 항목 주석 처리
  • DNS 컷오버 스크립트는 DigitalOcean API를 호출해 모든 A 레코드를 약 10초 안에 변경

컷오버 후 추가 작업

  • 이전 완료 후 다수의 GitLab 프로젝트 웹훅이 여전히 기존 서버 IP를 가리키는 상태 확인
  • GitLab API를 통해 모든 프로젝트를 스캔하고, 웹훅을 일괄 업데이트하는 스크립트 작성 및 적용

최종 결과

  • 월 비용은 $1,432에서 $233으로 감소
  • 연간 절감액은 $14,388
  • 성능 측면에서도 더 강한 서버 확보
    • CPU는 32 vCPU에서 96 logical CPU로 증가
    • RAM은 192GB에서 256GB DDR5로 증가
    • 스토리지는 약 2.6TB 혼합 구성이 2TB NVMe RAID1로 전환
    • 다운타임은 0분
  • 전체 마이그레이션 소요 시간은 대략 24시간
  • 사용자 영향은 없었던 상태

핵심 교훈

  • MySQL replication은 무중단 마이그레이션의 핵심 수단
    • 초기에 설정하고 충분히 따라잡게 한 뒤 컷오버하는 방식
  • MySQL 사용자 권한은 이전 전에 반드시 점검 필요
    • SUPER 권한이 있으면 read_only를 우회해 슬레이브 환경이 실제 읽기 전용이 아니게 되는 문제
  • DNS 업데이트, Nginx 설정 변경, 웹훅 수정은 스크립트화 중요
    • 34개 이상 사이트를 수작업으로 처리하면 시간이 오래 걸리고 오류 가능성이 증가
  • mydumper + myloader 조합은 대용량 데이터셋에서 mysqldump보다 훨씬 빠른 방식
    • 32스레드 병렬 덤프·복원으로 며칠 걸릴 작업을 몇 시간으로 단축
  • steady-state 워크로드에서는 클라우드 제공자가 비쌀 수 있으며, 전용 서버가 더 낮은 비용으로 더 높은 성능을 제공할 수 있는 사례

GitHub 스크립트

  • 마이그레이션에 사용한 Python 스크립트 전부를 GitHub에 공개
  • 포함된 스크립트 목록
    • do_list_domains_ttl.py
      • 모든 DigitalOcean 도메인의 A 레코드, IP, TTL 조회
    • do_ttl_update.py
      • 모든 A/AAAA 레코드 TTL을 300초로 일괄 축소
    • do_to_hetzner_bulk_dns_records_import.py
      • 모든 DNS zone을 DigitalOcean에서 Hetzner DNS로 이전
    • do_cutover_to_new_ip.py
      • 모든 A 레코드를 기존 서버 IP에서 새 서버 IP로 전환
    • nginx_reverse_proxy_update.py
      • 모든 nginx 사이트 설정을 리버스 프록시 설정으로 변환
    • mysql_compare.py
      • 두 MySQL 서버 전반의 모든 테이블 row count 비교
    • final_gitlab_webhook_update.py
      • 모든 GitLab 프로젝트 웹훅을 새 서버 IP로 갱신
    • mydumper
      • mydumper 라이브러리
  • 모든 스크립트는 DRY_RUN = True 모드를 지원해 실제 적용 전 안전한 미리보기 가능
Hacker News 의견들
  • 몇 달 전에 서버 두 대를 Linode와 DO에서 Hetzner로 옮겼는데, 비용을 비슷하게 크게 절감했음. 더 인상적이었던 점은 수십 개 사이트가 서로 다른 언어, 오래된 라이브러리, MySQL과 Redis까지 뒤엉킨 난장판 스택이었다는 점임. 그런데 Claude Code가 이걸 전부 옮겨줬고, 없는 라이브러리는 일부 코드를 다시 써가며 처리했음. 이제는 이런 복잡한 마이그레이션이 훨씬 쉬워져서, 앞으로는 사업자 간 이동성이 더 커질 것 같음

    • 내 생각엔 사람들이 돈을 낸 건 마법 같은 컴퓨트가 아니라 10년치 붙여놓은 glue 코드를 안 건드리기 위해서였음. 그런데 에이전트가 그 glue를 먹어치우기 시작하면, 기존 사업자의 moat는 빠르게 얇아질 것 같음
    • 솔직히 이건 Claude 광고 안에 Hetzner 광고가 또 들어간 느낌임. 대체 어디까지 중첩되는지 궁금해짐
    • 모든 이야기를 꼭 AI 얘기로 가져갈 필요는 없다고 느낌
    • 나도 Linode를 앞으로 몇 달 안에 떠날 예정임. 10년 넘게 썼고 고객도 많이 소개했는데, 가격을 계속 올려서 이제는 Hetzner 같은 곳에서 더 싸게 메모리 8배, 전용 NVMe, 전용 CPU를 받을 수 있음. 가상 서버의 쉬운 이전성 같은 장점은 조금 잃지만, 장애가 나더라도 Hetzner 지원은 늘 빠르고 유능했음
    • 나도 Claude를 점점 더 DevOps에 쓰는 중임. 내가 가진 베어메탈 위에 Proxmox로 VM을 돌리는데, Claude가 여러 머신에 걸친 새 네트워크를 엄청 빠르게 최적화하고 구성해줘서 거의 동료나 잘 받는 sysadmin처럼 느껴짐
  • 나는 AWS에서 Hetzner로 옮길 계획을 세우는 중임. Amazon은 경쟁사보다 때로는 20배 비싼 가격을 매기고, 좀 괜찮은 가격을 받으려면 장기 약정을 강요하며, 데이터 이전도 아주 비싸게 만들어둔 점이 너무 고객 적대적이라고 느낌. egress 요금으로 사람을 가둔다고 생각하겠지만, 사실은 한 부분만 경쟁사로 옮겨도 전체를 다 옮기게 만드는 압박으로 작동함. 그래도 나는 Amazon 전용 서비스 위에 플랫폼을 쌓지 않았기 때문에 이전이 조금은 쉬워진 편임

    • 이 부분은 예전엔 맞았지만, 2024년 1월에 GCP가 egress 비용 면제 정책을 내면서 분위기가 바뀌었고, AWS도 몇 달 뒤 비슷한 정책을 맞춰냈음. 남으라고 설득하려는 건 아니고, 기술적으로는 waiver 요청이 가능하다는 점만 말하고 싶음. 실제로 어떤 범위까지 되는지는 나도 확실치 않고, AWS 문구를 보면 EU Data Act 영향도 있어 보였음
  • 이런 글을 볼 때마다, 다들 이중화나 로드밸런서 같은 얘기는 잘 안 해서 의아함. 서버 한 대가 죽으면 여러 서비스가 같이 내려갈 수 있는데, 정말 이걸 괜찮다고 보는지 궁금함. 돈은 아꼈을지 몰라도 유지보수 시간과 미래의 골칫거리를 더 쓰게 될 수도 있음

    • 이건 서비스 성격과 얼마나 중요한지에 따라 다르다고 봄. 서버 한 대가 10년 동안 굴러가며 그 기간에 1주~1개월 정도 다운되는 수준이면 충분히 받아들일 수 있는 경우가 많음. 소규모 비즈니스, 취미 사이트, 포럼, 블로그처럼 웹사이트가 핵심 업무가 아닌 곳은 짧은 다운타임이 큰 문제가 아닐 수 있음. 사실 이런 저트래픽 사이트의 긴 꼬리가 웹의 다수일 수도 있음. 모든 게 고가용성일 필요는 없고, 원하면 이런 사업자도 로드밸런서 같은 기능은 제공함
    • 이런 글이 인기 있는 이유는 종종 요구사항과 해법의 불일치가 드러나기 때문이라고 봄. 취미 프로젝트나 작은 비즈니스에 엔터프라이즈급 아키텍처를 얹어 과설계한 경우라면, 가끔 하루쯤 다운돼도 괜찮아서 클라우드식 풀세팅이 꼭 필요하지 않을 수 있음. 다만 이번 글은 무중단 마이그레이션을 강조하면서, 정작 도착한 구조는 장애 허용성이 높지 않아 보인다는 점이 좀 묘했음. Hetzner 쪽에 약간만 구조를 더 얹어도 충분히 개선 가능했을 것 같음
    • 많은 워크로드에는 그런 수준의 대비가 필요 없다고 봄. 그리고 단순함의 신뢰성을 과소평가하면 안 됨. 나는 오랫동안 Linux sysadmin으로 일했는데, 복잡한 시스템에서 보는 다운타임이 단순한 시스템보다 훨씬 많았음. 이론과 현실 사이 어딘가에서, 대부분의 경우 결국 단순한 쪽이 더 잘 버틴다는 인상을 받았음
    • 공정하게 말하면, 원래도 DigitalOcean의 단일 VM을 쓰고 있었으니 클라우드 사업자의 장점을 크게 누리던 상황은 아니었다고 봄. 보통 이런 글은 클라우드에 잘못된 이유로 올라갔다가 물리적인 쪽으로 가는 게 맞는 경우와, 반대로 그렇게 옮기면 재앙이 되는 경우로 나뉘는데, 이번 건은 전자에 가까워 보임. DO에서 잘 돌던 구성이었다면 Hetzner에서도 적절한 DR 정책만 넣으면 충분히 괜찮을 듯함
    • 아마 이 결정은 실제로 오랫동안 유지보수 지옥이나 미래의 골칫거리를 별로 겪어보지 않았던 경험 위에서 나온 것일 수도 있음
  • 우리는 lithus.eu에서 여러 클라우드에서 Hetzner로 고객을 자주 옮겨봤음. 보통은 멀티서버, 때로는 멀티 AZ로 구성하고, Kubernetes로 워크로드를 분산해서 HA를 제공함. 단일 노드라면 Kubernetes가 과할 수 있지만, 노드가 여러 개면 훨씬 말이 됨. 백업은 Velero와 애플리케이션 레벨 백업을 함께 쓰고, 예를 들어 Postgres는 WAL 백업으로 PITR까지 가져감. 상태 데이터는 최소 두 노드에 두어 HA를 보장함. 성능 면에서도 베어메탈이 대체로 더 좋고, AWS 대비 응답 시간이 반으로 줄어드는 경우가 많았음. 이유는 가상화 자체보다도 NVMe, 낮은 네트워크 지연, 적은 cache contention 같은 주변 요소 덕분이라고 봄. 관련 내용은 예전에 쓴 HN 글에도 더 적어뒀음

    • 나도 몇 년 전에 직접 측정해봤는데, 그 뒤로는 가상 서버를 다시 보지 않게 됐음. CPU 시간은 RAM처럼 예약되는 게 아니라서, 실제 하드웨어 대비 성능이 정말 별로였음. 측정 글도 참고할 만했음
    • k8s 배포는 옮겨 다니기가 정말 좋다고 느낌. 여러 클라우드의 관리형 서비스들에 비해 벤더 종속이 적음. 내 스택도 k8s, hosted Postgres, s3류 스토리지 정도라서, Postgres는 언제든 직접 호스팅할 수 있고 결국 핵심은 k8s와 s3 정도만 남음. Hetzner에도 s3 비슷한 게 있는 것 같긴 한데, 아직 안 봤고 100TB 옮기기는 꽤 큰 작업일 것 같음
    • 참고로 HA는 high availability를 뜻함
    • 글은 합리적이었는데 마지막에 이메일 달아둔 건 좀 홍보 문구처럼 보여서 아쉬웠음
  • 이 글은 읽기가 꽤 힘들었음. Claude가 마이그레이션을 하고, 그다음 Claude가 쓴 보고서를 읽는 느낌이었음. LLM 덕분에 이렇게 절약했다면 그건 멋진 일인데, 글로 공개할 거면 최소한 퇴고해서 중복과 LLM식 서술은 정리했으면 좋겠음

    • 원문을 안 읽는 사람이 많다는 건 알지만, 이번 글은 정말 고통스러운 수준으로 읽기 힘들었음
  • Hetzner는 조심해야 한다고 느낌. 예전엔 정말 좋아했지만 최근에 옮겨 나왔음. 우리 CI/CD 파이프라인에 쓰던 VM 약 30대를, 36달러 청구 분쟁 하나로 전부 내려버렸음. 은행 기록까지 포함해 전액 지급 증빙을 냈는데도 보려 하지 않았고, 긴급하게 연락하는 중에도 결국 접근을 모두 차단했음. 지금은 Scaleway로 옮겼음

    • 고객 서비스가 의외로 적대적이라고 느낌. 그래도 나는 중요하지 않은 용도에는 아직 사용 중임
    • Hetzner의 청구 처리는 꽤 자동화되어 있지만, 보통 카드 결제가 실패해도 한 달 정도는 납부 유예를 주는 편이었음
  • 몇 달 전 작은 SaaS 사이드 프로젝트용으로 AWS 대안을 찾다가, 비용 절감과 EU 클라우드 지원 차원에서 처음엔 Hetzner를 진지하게 봤음. 직접 해야 할 일이 많아도 감수할 생각이었는데, 결정적으로 IP 평판이 발목을 잡았음. 회사에서 쓰는 관리형 AWS 방화벽 규칙 중 하나가 Hetzner IP를 많이, 어쩌면 전부 막고 있었고, 내 업무용 노트북에서도 Hetzner IP에 호스팅된 사이트가 IT 정책 때문에 열리지 않았음. Cloudflare 같은 걸 쓰면 덜할 수는 있겠지만, DDoS 보호가 약하다는 얘기도 봤음. 결국 나는 EU 리전의 DO App Platform을 골랐고, 관리형 DB 옵션도 큰 장점이었음

    • 경쟁사를 이런 식으로 막아버린다면 Amazon 입장에선 참 편리한 방식이겠다는 생각이 듦
    • 어떤 방화벽 규칙을 말하는지는 모르겠지만, DO가 Hetzner보다 더 신뢰된다는 건 꽤 의외였음. 내가 스크래퍼나 해커를 볼 때는 DO ASN도 자주 보여서, 그쪽도 언젠가는 막힐 수 있다고 느낌
    • 내 경험상 DO IP가 더 심각했음. 나도 바로 그 이유로 DO에서 옮겼음
    • 나는 예전에 Tor 관련 스레드에 이 이슈를 쓴 적이 있음. Hetzner가 Tor 친화적이라서 IP 평판에 영향이 있을 수 있다고 추정했는데, 당시엔 평판 문제가 없다는 답도 있었음. 그런데 Tor Project 자료를 보니 Hetzner가 Tor 네트워크의 약 7%를 차지하는 듯해서, 이야기가 그만큼 단순하진 않아 보였음
    • 아이러니하게도 나는 AWS와 Azure 차단만으로 봇 문제의 99%를 해결했음. 실제 사용자 피해는 0이었고, 그래서 아예 이 차단 기능만 서비스로 팔아볼까 생각 중임
  • 이런 마이그레이션 경험을 공유한 점은 꽤 유익하고 고맙다고 느낌. 나는 DO와 Hetzner 비교를, DoorDash나 UberEats를 켜는 것과 직접 저녁을 만드는 것 사이의 트레이드오프처럼 봄. 비용 비율도 비슷한 느낌임. 나는 3대 클라우드와 온프렘을 다루지만, 자잘한 작업이나 PoC 테스트에는 여전히 DigitalOcean 콘솔로 감. 버튼 몇 번으로 서버나 버킷이 준비되고, sane default가 있고, 백업도 체크박스 하나로 붙는 식의 편의성은 시간값을 생각하면 분명 의미가 있음

    • 무슨 뜻인지는 완전히 확신 못 하겠지만, Hetzner Console도 비슷하게 동작한다고 느낌
    • 이 글에서 흥미로운 건 두 가지였음. 하나는 무중단 이전 절차 자체이고, 이건 범용적으로 참고할 만함. 다른 하나는 클라우드 인스턴스를 베어메탈로 바꾼 결정인데, 비용 절감과 함께 빠른 장애 전환과 백업 손실도 가격에 포함되어 있다고 봐야 함. 내가 한다면 200달러 정도 더 써서 hot spare를 하나 두고 며칠마다 주/대기를 바꿔가며 둘 다 정상 동작하는지 검증했을 것 같음. 비교적 적은 비용으로 치명적 장애 위험을 크게 줄일 수 있음
    • 방금 설명한 건 사실 Hetzner Cloud가 이미 여러 해 동안 제공해온 경험과 거의 같음. 게다가 Hetzner Cloud API도 있어서, 버튼 클릭조차 없이 IaC로 전부 구성할 수 있음
    • 내 경우엔 Hetzner 서버 위에 Coolify를 올려서 거의 원클릭 서비스 같은 경험을 얻고 있음
    • 이 상황을 보면서 떠오른 건 그냥 이 xkcd였음
  • DB 백업을 어떻게 하는지 궁금했음. replica나 standby가 있는지, 아니면 그냥 시간 단위 백업 정도인지 알고 싶었음. 이런 단일 서버 구성에서는 SSD 같은 하드웨어 장애가 나면 앱이 바로 멈출 수 있고, 특히 SSD가 죽으면 다시 세팅하는 동안 몇 시간이나 며칠 다운될 수도 있다고 생각했음

    • Hetzner는 보통 하드웨어 서버를 2x 1TB SSD로 광고하고, 순용량 1TB를 위해 SW RAID1 구성을 강하게 권장함. 이미지 설치기도 기본이 그 방향임. 몇 년 뒤 첫 SSD가 죽더라도 모니터링이 잡아준다면 새 박스로 옮기거나, 중간 대안/replica를 쓰거나, 다른 디스크로 버티며 핫스왑을 받을 수 있음. 물론 물리 서버로 가면 클라우드의 이중화 일부를 잃게 되니, 절감액과 함께 위험 모델에 넣어 계산해야 함. 그리고 최소한 원격 저장소로 일일 백업조차 없으면 그건 무모하다고 봄. 이건 클라우드에서도 마찬가지이되, 설정은 더 쉬울 뿐임
    • 그렇게 오래 다운돼도 아무도 크게 신경 안 쓸 수도 있음. 예를 들어 내 HOA 모바일 앱이 일주일 내려가 있어도 나는 별로 상관없음. 모든 것에 상시 가동이 필요한 건 아님
    • 나도 같은 걱정을 했음. 이 글은 작성자가 충분히 고민하지 않고 공격적인 비용 절감만 본 느낌이었음. DigitalOcean VM은 아마 라이브 마이그레이션과 스냅샷을 지원했을 텐데, Hetzner에서도 그건 cloud 상품에서나 가능함. Hetzner 베어메탈에서는 디스크나 부품이 죽으면 그냥 죽는 것이고, 디스크 교체는 해주더라도 복구는 사용자가 처음부터 해야 함. Hetzner도 이 점을 여러 곳에서 분명히 밝히고 있음
    • 내가 해본 것 중 가장 쉬웠던 건 MongoDB 쪽이었고, replication, sharding, failover가 매우 간단했음. 최근엔 PostgreSQL에서도 pg_auto_failover로 monitor 1대, primary 1대, replica 1대로 구성했는데, 설정과 함정을 좀 익히고 나니 이것도 꽤 쉬웠음. 내 경험상 무중단 이전도 가능했음
    • 그들이 그런 트레이드오프를 받아들이겠다고 판단했다면, 그게 틀렸다고 단정할 수는 없다고 봄. 모든 앱이 24/7 가용성을 필요로 하진 않고, 대다수 웹사이트는 몇 시간 정도의 다운타임이 있어도 큰 타격이 없음. 비용 절감이 위험보다 크다면 충분히 합리적인 비즈니스 판단일 수 있음. 오히려 궁금한 건 그들이 어떤 백업·복구 전략을 갖고 있는지, 그리고 Hetzner로 옮기며 무엇이 바뀌었는지임
  • 헤더에 들어간 밈 이미지는 내가 만든 것이었음. 이 글에 실었던 건데, 이렇게 두 번이나 쓰인 걸 보니 반가웠음