모든 시스템 정상 작동 중 8 종 암호화폐 지원 · 모네로 환영 KYC 없음 정책
KernelVPS

마이그레이션

VPS를 다운타임 없이 새 호스트로 마이그레이션하는 방법

서버 이전은 단순한 복사가 아닙니다. 그것은 한동안 두 머신이 동시에 살아 있는 상태에서 이루어지는 통제된 인계 작업이며, 어려움은 전부 그 중첩 구간 안에 있습니다. 첫 TTL 변경부터 예전 디스크를 지우는 순간까지, 모든 요청에 빠짐없이 응답하게 해주는 절차를 소개합니다.

인프라16분 분량 읽기KernelVPS 팀

VPS를 다운타임 없이 새 호스트로 마이그레이션하는 방법

대부분의 마이그레이션은 파일을 복사하는 도중에 실패하지 않습니다. 실패는 DNS를 변경한 뒤의 20분 사이에 일어납니다 — 인터넷의 절반은 여전히 예전 서버와 이야기하고 나머지 절반은 이미 새 서버로 넘어간 상태에서, 두 머신 모두 쓰기를 받아들이고 있는 그 순간입니다. 파일은 멀쩡하게 도착했고 사이트도 잘 열리지만, 주문은 두 개의 데이터베이스에 나뉘어 쌓이고 그 둘은 끝내 하나로 합쳐지지 않습니다. 이를 피하는 일은 전송 속도와는 거의 무관하고, 거의 전적으로 순서에 달려 있습니다: 무엇을 가장 먼저 바꿀지, 무엇을 멈춰 둘지, 그리고 확신이 설 때까지 무엇을 계속 돌려 둘지입니다.

"다운타임 없음"이 실제로 뜻하는 것

정확히 짚고 넘어갈 가치가 있습니다. 이 표현은 서로 매우 다른 두 가지 약속을 가리키며, 그 둘은 들여야 하는 노력의 양도 전혀 다르기 때문입니다. 둘 중 무엇을 얻으려는 것인지 정하는 일이 이 마이그레이션에서 내려야 할 첫 번째 진짜 결정입니다.

다운타임 없음그 어느 순간에도 모든 요청이 둘 중 한 서버로부터 응답을 받습니다. 읽기 위주이거나 상태를 갖지 않는(stateless) 서비스라면 달성할 수 있고, 쓰기가 잠깐 거부되는 대신 읽기는 계속 작동하는 짧은 구간을 받아들일 수 있다면 데이터베이스를 쓰는 대부분의 사이트에서도 달성할 수 있습니다.
데이터 손실 없음예전 서버에 기록된 것 중 새 서버에서 사라지는 것은 하나도 없습니다. 이쪽이 더 지키기 어려운 약속이며, 실제로 중요한 쪽이기도 합니다. 2분짜리 오류 페이지는 그저 불편함이지만, 유실된 주문 하나는 영영 닫히지 않는 고객 문의로 남습니다.
현실에서는 둘 다 아님아무도 중첩 구간을 계획하지 않았을 때 기본적으로 벌어지는 결과입니다: 사이트는 한 번도 다운되지 않지만, 쓰기는 한 시간 동안 조용히 두 머신에 나뉘어 기록됩니다. 이미 해지해버린 서버에만 존재하는 기록을 누군가 찾아 나서기 전까지는, 완벽한 마이그레이션처럼 보입니다.

둘 중 하나를 희생해야 한다면 가용성을 희생하세요. 4분짜리 점검 페이지는 설명할 수 있는 일입니다. 하지만 서로 어긋난 데이터는 고칠 수 없습니다 — 어느 쪽 사본이 맞는지 말해줄 권위 있는 기준이 더 이상 남아 있지 않기 때문입니다.

시작하기 전에, 감내할 수 있는 가장 긴 쓰기 동결 시간을 적어 두세요. 4분, 30초, 0초. 이 숫자 하나가 이후의 모든 것을 결정합니다 — 덤프하고 복원하는 것으로 충분한지, 복제가 필요한지, 아니면 앞단에 프록시까지 두어야 하는지까지 말입니다. 이 숫자를 정하기 전에 도구부터 고르는 것이야말로 마이그레이션이 뜻밖의 사고를 만나게 되는 방식입니다.

복사를 뜨기 전에 인벤토리부터 챙기세요

서버에는 아무도 기록해두지 않은 것들이 쌓여 있기 마련입니다: 장애 대응 중에 급히 추가한 cron 작업, 파트너사 주소를 위한 방화벽 규칙, 서비스 파일에 그대로 붙여넣은 API 키 같은 것들입니다. 복사본은 이런 것들을 옮겨주지 않으며, 이후 2주에 걸쳐 하나씩 발견하게 됩니다. 지금 30분을 들여 인벤토리를 정리해두면 그런 일의 거의 전부를 없앨 수 있습니다.

리스닝 중인 포트

ss -tulpn을 실행해서 리스닝 중인 소켓을 전부 파악하세요. 하나하나가 새 서버에도 반드시 있어야 할 서비스이며, 설명이 안 되는 포트가 있다면 그대로 복제하기 전에 정체를 파악해둘 가치가 있습니다 — 마이그레이션은 2023년부터 계속 돌아가고 있던 무언가를 알아차리기 좋은 기회입니다.

타이머로 도는 작업

root를 포함한 모든 사용자에 대해 crontab -l을 확인하고, systemctl list-timers도 확인하고, 애플리케이션 내부에 있는 스케줄러도 빠짐없이 확인하세요. 마이그레이션을 거치며 중복으로 살아남는 것 중 단연 가장 흔한 것이 타이머이며, 중복은 누락보다 더 나쁩니다.

디스크에 없는 것들

DNS 레코드, 주소에 걸린 리버스 DNS, 방화벽 규칙, 제3자가 보관하고 있는 API 키, 웹훅 대상, 그리고 지금 쓰는 IP를 어딘가의 허용 목록에 등록해 둔 것들입니다. 이 중 어느 것도 지금 복사하려는 파일시스템 안에는 들어 있지 않습니다.

애플리케이션이 전제하는 것

하드코딩된 절대 경로, 설정 파일에 박힌 호스트명, 데이터베이스 소켓 위치, bind 지시문에 적힌 주소 같은 것들입니다. 이런 것들은 조용히 고장 납니다 — 서비스는 시작되지만, 작동하지는 않습니다.

이 내용은 터미널 스크롤백이 아니라 버전 관리 시스템에 두는 파일에 적어 두세요. 전환 과정에서 세 번은 다시 읽게 될 텐데, 그중 한 번은 머리가 제대로 돌아가지 않는 순간일 것입니다.

나중에는 바꿀 수 없는 조건을 기준으로 목적지를 고르세요

사양은 나중에도 조정할 수 있지만, 몇 가지 속성은 그렇지 않습니다. 그리고 그런 속성이야말로 아직 자유롭게 고를 수 있는 지금, 신중하게 정해둘 가치가 있습니다. 어차피 옮기는 김에, 그동안 어떻게든 피해가며 써왔던 제약을 바로잡을 수 있는 가장 저렴한 순간이 바로 지금입니다.

  • 위치. 사용자까지의 지연 시간과 적용받는 법이 둘 다 여기에 고정되기 때문입니다. /locations 에 각 리전과 왕복 특성이 정리되어 있으니, 지금 떠나려는 곳과는 독립적으로 장애를 겪는 리전을 고르세요.
  • 법적 기반. 지금 옮기려는 이유가 현재 제공업체가 패킷보다 민원을 더 빨리 전달하기 때문이라면 특히 그렇습니다. /offshore-hosting 에는 관할권이 실제로 좌우하는 것과 그렇지 않은 것이 정리되어 있습니다.
  • 결제 신원. 결제를 받기 전에 서류부터 요구하는 호스트는 그 구조상 이미 여러분에 대한 파일을 갖고 있는 셈이기 때문입니다. /no-kyc-vps/pay-with 에 그 대안이 나와 있습니다 — 암호화폐로 충전하는 잔액, 카드 없음, 머신에 이름이 붙지 않는 방식입니다.
  • 여유 자원. 두 번 마이그레이션하는 것은 아무도 계획하지 않는 결말이기 때문입니다. /vps 에 요금제가 정리되어 있고, 지금 쓰는 서버의 사양을 제대로 측정해본 적이 없다면 /guides 에 산정 방법이 나와 있습니다.
  • IPv6와 깨끗한 IPv4. 재사용된 주소는 다른 누군가의 평판을 그대로 물려받은 채로 올 수 있습니다 — 메일 문제로 번지기 전에 미리 확인하세요.

며칠 전에 DNS TTL부터 낮춰두세요

이것은 막판에 서둘러 처리할 수 없는 유일한 준비 단계입니다. 그 효과가 여러분이 통제할 수 없는 시계에 의해 좌우되기 때문입니다. 레코드에 설정된 TTL은 리졸버에게 응답을 얼마나 오래 캐시해둘지 알려줍니다. 이 값이 하루로 설정되어 있다면, 한 시간 전에 조회했던 리졸버는 이후 23시간 동안 여러분이 무엇을 새로 게시하든 상관없이 계속 사용자를 예전 서버로 보냅니다.

  1. 1

    현재 TTL 확인하기

    dig +noall +answer yourdomain.com을 실행하면 남은 캐시 시간이 나오고, dig @ns1.example.net yourdomain.com처럼 권한 네임서버에 직접 질의하면 설정된 값이 나옵니다. 이 값을 적어두세요 — 앞으로 기다려야 할 시간의 길이를 결정합니다.

  2. 2

    300초로 낮추기

    바뀔 예정인 모든 레코드의 TTL을 낮추세요: A, AAAA, 그리고 해당 호스트를 가리키는 MX나 CNAME 전부입니다. 5분이면 전환을 여유 있게 만들 만큼 충분히 짧으면서도, 네임서버에 과부하를 주지 않을 만큼 충분히 깁니다.

  3. 3

    예전 TTL만큼 기다리고, 한 번 더 기다리기

    새로 짧아진 TTL은 예전의 긴 TTL이 만료된 뒤에야 리졸버에 도달합니다. 낮아진 TTL을 실제로 믿을 수 있게 되기까지, 예전 TTL 주기 전체만큼은 — 하루였다면 하루만큼 — 기다리세요. 이 작업을 일찍 시작해도 비용은 전혀 들지 않으면서, 전환 전체에 여유를 만들어줍니다.

일부 리졸버는 여러분의 TTL을 무시하고 자체적인 최소값으로 캐시해버리며, 일부 클라이언트는 프로세스가 살아 있는 내내 캐시를 유지합니다. 교과서적으로 완벽한 전환 이후에도 몇 시간 동안은 예전 주소로 향하는 트래픽이 길게 꼬리를 끈다고 생각해 두세요. 이것은 TTL 작업을 건너뛸 이유가 아니라, 오히려 예전 서버를 그 이후에도 계속 살려둬야 하는 이유입니다.

새 서버는 새로 구축하세요, 예전 서버를 복제하지 마세요

본능적으로는 지금 디스크를 이미지로 떠서 다른 곳에 복원하고 싶어집니다. 이것은 잘못된 선택입니다 — 백업을 복원할 때와 똑같은 이유에서입니다. 블록 단위 복제는 설정 드리프트, 고아 패키지, 누군가 손대다 만 어중간한 서비스, 그리고 예전 침입자가 남겨둔 지속 접근 수단까지 고스란히 그대로 재현합니다. 게다가 예전 배포판 버전에 계속 묶이게 됩니다.

새 머신은 최신 베이스 이미지로 구축하고, 서비스는 스크립트로 설치하고, 데이터만 복사하세요. 진짜 결과물은 그 스크립트입니다 — 다음 마이그레이션을 2주가 아니라 반나절짜리 작업으로 바꿔주는 것도, 장애 이후에 고고학 발굴하듯 뒤지지 않고 재구축할 수 있게 해주는 것도 바로 이 스크립트입니다.

  • 다른 무엇이 손대기 전에 먼저 프로비저닝하고, 업데이트하고, 강화하세요: 키 인증 전용 SSH, 기본적으로 모두 거부하는 방화벽, 무인 보안 업데이트입니다. /guides 에 이 체크리스트를 한 시간 분량으로 풀어낸 글이 있습니다.
  • 런타임과 데이터베이스는 운영 환경과 같은 메이저 버전으로 설치하세요. 마이그레이션은 PostgreSQL을 14에서 17로 함께 업그레이드하기에 나쁜 타이밍입니다 — 한 번에 하나씩만 바꿔서, 문제가 생겼을 때 원인이 정확히 하나만 나오도록 하세요.
  • 파일을 복사하기 전에 동일한 숫자 ID로 사용자와 그룹을 미리 만들어두거나, 복사 후에 소유권을 손으로 바로잡으세요. --numeric-ids 옵션으로 전송하면 숫자는 그대로 유지되며, 그것을 올바른 이름으로 다시 매핑하는 일은 여러분의 몫입니다.
  • 현재 예전 주소를 등록해둔 모든 허용 목록에 새 주소를 추가하세요 — 파트너 API, 관리형 데이터베이스 방화벽, 결제 게이트웨이, 여러분 자신의 모니터링까지 — 둘 다 아직 유효한 지금 해두어야 합니다.

서비스를 설치한 다음, 멈추고 비활성화해두세요. 부팅 시 자동으로 시작되어 새 주소로 응답하는 웹 서버는 스캐너에게 발견되고, 엉뚱한 호스트명으로 색인되며 — 더 나쁘게는 — 일찍 그 주소로 연결한 사람에게 아직 절반만 채워진 사이트 사본을 아무렇지 않게 보여주고 맙니다. 새 서버의 그 무엇도, 여러분이 응답하도록 정하기 전까지는 외부에 공개적으로 응답해서는 안 됩니다.

파일은 두 번에 나눠서 복사하세요

살아 움직이는 파일시스템을 한 번만 전송하는 것은 움직이는 표적을 한 장 찍은 스냅샷일 뿐입니다. 두 번에 나누면 깔끔하게 해결됩니다: 첫 번째는 길게, 살아 있는 시스템을 대상으로 실행하고, 두 번째는 짧게, 동결 구간 동안 실행합니다. 빨라야 하는 것은 오직 두 번째뿐입니다.

첫 번째 전송은 언제 실행해도 좋습니다 — 며칠 앞서 해도 괜찮습니다. 이 단계가 대부분을 옮깁니다: 업로드 디렉터리, 메일 스풀, 컨테이너 볼륨, 수년간 쌓인 미디어까지입니다. 전환 시점이 되면 이 사본은 이미 낡아 있을 텐데, 바로 그것을 위해 두 번째 전송이 존재합니다.

  • SSH를 통해 rsync -aAXH --numeric-ids --info=progress2를 사용하세요: -a는 일반적인 속성용, -A는 ACL용, -X는 확장 속성용, -H는 하드링크용이며, 서버 안에서 중복 제거를 하는 무언가가 있다면 하드링크가 중요해집니다.
  • 옮겨가서는 안 되는 것은 제외하세요: /proc, /sys, /dev, /run, 임시 디렉터리, 그리고 필요 없는 패키지 캐시와 로그입니다. 커널 인터페이스를 복사해봐야 잘해야 시간 낭비이고, 최악의 경우 전송 자체가 멈춰버립니다.
  • --delete는 두 번째 전송에만 추가하세요. 첫 번째에서는 써도 무해하지만, 두 번째에서는 그사이 원본에서 지워진 파일을 함께 제거해주는데, 이것이 바로 여러분이 없애려는 드리프트 그 자체입니다.
  • 시스템 설정은 통째로가 아니라 선별해서 복사하세요. 필요한 것은 웹 서버 vhost, 서비스 유닛, 애플리케이션 설정이지 — 예전 머신의 파일시스템 테이블이나 네트워크 설정, 머신 ID가 아닙니다.
  • 전송용으로 쓰고 버릴 SSH 키를 새로 만들어, 목적지에 등록하고, 마이그레이션이 끝나면 제거하세요. 2년째 남아 있는 마이그레이션 키는 누가 발급했는지 아무도 기억하지 못하는 자격 증명이 되어버립니다.

두 전송 사이에는 짐작하지 말고 직접 확인하세요. 두 번째 전송을 --dry-run으로 실행하면 무엇이 바뀔지 정확히 출력됩니다: 최근 수백 개 파일 목록 정도면 정상이고, 4만 개짜리 목록이 나온다면 제외 설정이 잘못됐거나 무언가가 이유 없이 타임스탬프를 다시 쓰고 있다는 뜻입니다.

쓰기 손실 없이 데이터베이스 옮기기

동결 시간 예산이 소진되는 지점이 바로 여기이며, 어떤 기법이 옳은지는 전적으로 맨 처음에 적어둔 숫자에 달려 있습니다. 아래 세 가지 선택지는 모두 정답입니다 — 다만 서로 다른 숫자에 대해서만 그렇습니다.

덤프와 복원 — 분 단위 동결쓰기를 멈추고, pg_dump나 mysqldump --single-transaction으로 덤프하고, 전송하고, 복원한 다음, 애플리케이션이 새 호스트를 보도록 바꾸세요. 단순하고, 엔진 버전 간 이식도 가능하며, 수 기가바이트 규모까지는 완전히 충분합니다. 동결 시간은 덤프 더하기 전송 더하기 복원 시간만큼 이어지므로, 실전에서 그 숫자를 처음 알게 되기보다는 미리 사본으로 시간을 재보세요.
복제 — 초 단위 동결새 서버를 며칠 전에 미리 예전 서버의 레플리카로 구성해서 계속 최신 상태로 유지해두세요. 전환 시점이 되면 쓰기를 멈추고, 레플리카가 따라잡을 때까지 기다린 다음, 승격시키고, 애플리케이션이 그쪽을 보도록 바꾸면 됩니다. MySQL과 MariaDB에서는 mysqldump --single-transaction --source-data=2를 쓰면 레플리카가 시작할 binlog 위치가 기록됩니다(예전 버전에서는 --master-data=2). PostgreSQL에서는 pg_basebackup에 스트리밍 복제를 더하거나, 메이저 버전이 다르다면 논리적 복제(logical replication)를 사용하세요.
이중 쓰기(dual-write) — 동결 없음중첩 구간 동안 애플리케이션이 두 데이터베이스 모두에 씁니다. 이 방식은 정말로 동결 시간 0을 달성하지만, 정합성 조정 로직이 잘못되면 두 사본을 모두 망가뜨릴 수 있는 유일한 선택지이기도 합니다. 30초간 쓰기가 거부되는 것이 계약상 문제가 되는 상황이라면 그럴 가치가 있고, 그 외의 경우에는 과합니다.

무엇을 선택하든, 예전 데이터베이스는 새 데이터베이스가 쓰기를 시작하기 전에 반드시 쓰기를 멈춰야 합니다. 직후가 아니라, 그 전입니다. 둘 다 쓰기가 가능한 그 중첩 구간이 바로 스플릿 브레인 구간이며, 이 글 전체를 통틀어 깔끔한 복구 방법이 없는 유일한 실패입니다: 서로 어긋난 두 개의 이력이 남고, 행을 하나하나 손으로 들여다보지 않고는 그것을 합칠 방법이 없습니다.

데이터셋이 크다면 스키마와 데이터를 따로 덤프하세요. 스키마를 먼저 복원해두면 새 호스트에서 구조와 인덱스, 권한을 미리 확인할 수 있고, 그 덕분에 데이터 적재는 동결 구간에 시작해도 제대로 끝나리라는 확신을 가진 채 진행할 수 있는 하나의 긴 작업으로 바뀝니다.

TLS 인증서는 전환 후가 아니라 전에 발급하세요

새 서버의 인증서는 첫 사용자가 도착하는 바로 그 순간에 이미 유효해야 합니다. 그렇지 않다는 것을 뒤늦게 알게 되면 모든 방문자가 브라우저 경고 화면을 만나게 되며, HSTS 헤더를 보내고 있다면 — 보내야 마땅합니다 — 방문자는 그 화면을 그냥 통과할 수조차 없습니다. DNS가 새로운 곳을 가리키기 전에 제대로 작동하는 인증서를 미리 확보해두는 방법은 두 가지입니다.

  • 기존 인증서를 그대로 복사하세요. ACME 상태 디렉터리 전체를 복사하거나, 클라이언트가 보관해둔 곳에서 인증서와 키만 가져와도 됩니다. 유효성은 어느 서버가 그 파일을 들고 있는지와 무관하므로 즉시 유효하며, DNS가 이전되고 나면 갱신도 평소처럼 다시 진행됩니다.
  • DNS-01 챌린지로 새 인증서를 발급하세요. 이 방식은 현재 주소로 보내는 HTTP 요청 대신 TXT 레코드를 통해 도메인 소유권을 증명합니다. 마이그레이션 전에도, 전환 전에도 작동하며, HTTP-01로는 아예 불가능한 와일드카드 인증서에도 사용할 수 있습니다.
  • 전환 전에는 새 서버에서 HTTP-01 검증을 시도하지 마세요. 챌린지는 도메인 이름의 80번 포트로 가져오는데, 도메인은 아직 예전 머신을 가리키고 있으므로 검증은 매번 실패합니다.

DNS를 건드리지 않고도, 명령 하나만 실행하는 동안 호스트명을 새 주소로 직접 resolve해서 확인할 수 있습니다: curl -sI --resolve yourdomain.com:443:198.51.100.10 https://yourdomain.com/ — 실제 주소로 바꿔 넣으세요. 이 한 줄이 전체 마이그레이션 중 가장 가치가 큰 점검입니다. 새 서버의 실제 vhost, 실제 인증서, 실제 애플리케이션 스택을 그대로 돌려보는 것이며, 잘못된 설정을 발견하는 데 아직 아무 비용도 들지 않는 시점에 그것을 찾아낼 수 있는 방법입니다.

서버가 메일을 보낸다면 더 일찍 시작하세요

메일은 마이그레이션에서 며칠 뒤에야 조용히 고장 나고, 엉뚱한 것이 원인으로 지목되는 부분입니다. 새 주소는 발송 평판이 전혀 없으며 어쩌면 다른 누군가의 평판을 물려받았을 수도 있고, 여러분이 게시하는 모든 인증 레코드는 지금 떠나려는 주소에 묶여 있습니다.

  • 새 주소를 확정하기 전에 주요 블랙리스트에 걸려 있지는 않은지 확인하세요. 이력이 있는 재사용 IP라면, 아직 바꾸는 데 비용이 들지 않을 때 바꿔둘 가치가 있습니다.
  • 새 주소의 리버스 DNS 레코드를 메일 호스트명으로 설정하세요. 수신 서버는 정방향 조회와 역방향 조회가 서로 일치하는지 확인하며, PTR이 하나만 빠져 있어도 그것만으로 스팸으로 분류되기에 충분합니다.
  • 전환 전에 새 주소를 SPF에 추가하고, 전환 후에 예전 주소를 제거하세요 — 중첩 구간 동안은 둘 다 등록되어 있어야, 실제로 메일을 보낸 쪽이 어느 서버든 인증이 통과됩니다.
  • 새로 생성하지 말고 DKIM 개인 키를 그대로 복사하세요. 그래야 DNS에 이미 게시된 셀렉터가 계속 검증을 통과합니다. 새로 생성하면 다시 게시해야 하고, 재게시에는 그 나름의 전파 지연이 따라붙습니다.
  • 어느 정도 물량을 보낸다면 새 주소는 천천히 예열하세요. 존재하는 내내 아무것도 보낸 적 없는 서버가 갑자기 만 통의 메일을 쏟아내면, 수신 측 입장에서는 탈취당한 호스트와 구별이 되지 않습니다.

전환

지금까지의 모든 준비는 이 부분을 짧고, 순서대로, 되돌릴 수 있게 만들기 위한 것이었습니다. 미신처럼 새벽 3시를 고집하지 말고, 실제 트래픽이 가장 적은 시간대에 진행하세요 — 직접 분석 데이터를 확인하세요. 시작하기 전에 롤백 절차를 반드시 적어두세요. 그것이 필요해지는 순간은 하필 그것을 새로 작성하고 싶지 않은 바로 그 순간이기 때문입니다.

  1. 1

    예전 서버의 쓰기를 동결하세요

    점검 모드로 전환하거나, 읽기 전용 데이터베이스 사용자를 쓰거나, 리버스 프록시에서 쓰기 경로에 오류를 반환하게 하세요. 그 내내 읽기는 계속 예전 머신에서 처리됩니다 — 데이터가 이동하는 동안에도 사이트가 계속 떠 있게 해주는 것이 바로 이것입니다.

  2. 2

    예전 서버의 모든 타이머를 비활성화하세요

    crontab을 주석 처리하고, 타이머를 멈추고, 큐 워커를 멈추세요. 이 시점부터 예전 머신은 그 무엇도 처리해서는 안 됩니다. 그렇지 않으면 작업이 두 번 실행됩니다: 청구서도 두 번, 이메일도 두 번, 웹훅 전송도 두 번입니다.

  3. 3

    마지막 차등 전송을 실행하세요

    --delete를 붙인 두 번째 파일 전송을 실행한 다음, 마지막 데이터베이스 덤프 또는 레플리카 따라잡기를 진행하세요. 이번 것은 짧습니다, 길어야 몇 분입니다. 대부분의 용량은 이미 첫 번째 전송에서 옮겨졌기 때문입니다.

  4. 4

    새 서버를 실제 호스트명으로 검증하세요

    위에서 소개한 --resolve 트릭을 사용해서, 데이터베이스를 읽는 페이지 하나, 로그인, 쓰기 경로 하나를 직접 실행해보세요. 행 개수가 원본과 일치하는지 확인하세요. 이 모든 것을 DNS가 바뀌기 전에, 롤백에 여전히 아무 비용도 들지 않는 동안 해두세요.

  5. 5

    DNS를 전환하고 서비스를 시작하세요

    A와 AAAA를 새 주소로 업데이트한 다음, 새 서버에서 애플리케이션과 타이머를 활성화하고 시작하세요. 트래픽은 TTL 한 주기 안에 들어오기 시작해서, 그 이후 한 시간에 걸쳐 계속 옮겨옵니다.

  6. 6

    예전 서버는 계속 읽기를 처리하게 두세요

    최소 24시간은 읽기 전용 상태로 계속 켜 두세요. 캐시가 아직 갱신되지 않은 클라이언트는 여전히 이 서버로 들어오는데, 읽기 전용으로 켜져 있는 예전 서버는 연결 거부 대신 약간 오래된 페이지를 돌려줍니다 — 눈에 띄지 않는 마이그레이션과 눈에 띄는 마이그레이션의 차이가 바로 여기서 갈립니다.

가장 깔끔한 트릭도 바로 이 중첩 구간에 있습니다. DNS를 한 번에 강제로 전환하는 대신, 5단계가 끝난 시점에 예전 서버를 새 서버로 향하는 리버스 프록시로 재구성하세요. 여전히 예전 주소로 연결하는 뒤처진 요청은 모두 투명하게 전달되고, 전환은 더 이상 DNS 전파에 전혀 의존하지 않게 되며, 그쪽으로 향하는 트래픽이 0이 되면 언제든 프록시를 해체하면 됩니다. 로그와 속도 제한이 실제 클라이언트 주소를 계속 볼 수 있도록 X-Forwarded-For를 전달하세요.

처음 48시간

사이트가 열린다고 해서 마이그레이션이 끝난 것은 아닙니다. 예전 머신에 더 이상 아무것도 의존하지 않을 때 비로소 끝납니다. 그리고 그런 의존 관계를 찾아내는 일은 가만히 기다리는 게임이 아니라 능동적으로 해야 하는 작업입니다.

  • 예전 서버의 액세스 로그를 지켜보세요. 그곳에 여전히 들어오는 모든 요청은 아직 옮겨지지 않은 의존 관계입니다 — 파트너 연동에 하드코딩된 주소, 캐시가 갱신되지 않은 모바일 클라이언트, 아무도 관리하지 않는 모니터링 프로브 같은 것들입니다. 그 로그가 곧 할 일 목록입니다.
  • 타이머가 새 호스트에서 실제로 실행되었는지 확인하세요. 활성화되어 있다는 것만으로는 부족합니다 — 예상한 시간에, 예상한 결과물과 함께 실제로 실행되었는지를 확인해야 합니다. 조용히 아무 일도 하지 않는 cron 작업은 제대로 작동하는 cron 작업과 겉모습이 완전히 똑같습니다.
  • 인증서 갱신을 실제로 dry run으로 테스트해보세요. 60일 뒤에야 ACME 클라이언트가 더 이상 챌린지를 받지 못하는 서버를 대상으로 계속 갱신을 시도해왔다는 사실을 알게 되는 것보다는 나을 것입니다.
  • 메일 흐름을 양방향으로, 애플리케이션이 자동으로 보내는 것까지 포함해서 처음부터 끝까지 확인하세요. 비밀번호 재설정 메일이 고전적인 희생양입니다. 사용자가 실제로 필요로 하기 전까지는 아무도 테스트하지 않기 때문입니다.
  • 새 서버를 백업하고 어딘가에 복원해보세요. 검증된 백업이 없는 새 머신은 여러분이 떠나온 곳보다 더 나쁜 처지입니다. /guides 에 이 주장을 완전한 형태로 풀어낸 글이 있습니다.
  • 확신이 서면 DNS TTL을 원래 값으로 되돌리세요. 300초로 영원히 남겨두는 것은 더 이상 아무 이득도 없이 조회 수와 지연 시간에 작지만 영구적인 비용을 계속 치르는 것과 같습니다.

예전 서버 폐기하기

마지막 단계는 흔히 건너뛰게 되는 단계이면서, 유일하게 프라이버시에 결과를 남기는 단계이기도 합니다. 예전 디스크에는 여러분의 키, 데이터베이스, 고객 데이터, 로그가 담겨 있는데, 서비스를 해지한다고 해서 그중 무엇도 지워지지는 않습니다 — 그저 볼륨을 풀(pool)로 반환할 뿐이며, 다음 사용자는 제공업체의 삭제 정책이 남겨둔 것을 그대로 물려받게 됩니다.

  • 무엇이든 손대기 전에 예전 액세스 로그가 잠잠해질 때까지 기다리세요. 결제 제공업체가 여전히 예전 주소로 웹훅을 보내고 있는 상태에서 서비스를 해지하면, 마이그레이션이 일주일 뒤에 장애로 되돌아옵니다.
  • 단순히 삭제하지 말고 교체하세요: 예전 서버가 갖고 있던 모든 자격 증명 — API 키, 데이터베이스 비밀번호, 배포 키, 임시 마이그레이션 키까지입니다. 더 이상 통제할 수 없는 머신 위에 있었던 것은 무엇이든 탈취당했다고 가정하세요. 결국에는 실제로 그렇게 되기 때문입니다.
  • 볼륨을 반환하기 전에 데이터를 덮어쓰세요. 민감한 디렉터리는 복구 불가능하게 지우거나, 빈 공간을 커다란 무작위 파일 하나로 채운 다음 지우세요. 가상화된 디스크에서는 완벽하지 않지만, 아무것도 안 하는 것보다는 훨씬 낫습니다.
  • 참고할 일이 있을 만한 것들 — 로그, 설정, 실제로 무엇을 했는지 기록된 셸 히스토리 — 은 마지막으로 아카이브를 하나 만들어, 두 서버 중 어디도 아닌 곳에 암호화해서 보관하세요.
  • 새 서버가 결제 주기 하나를 온전히 넘기고 백업-복원 테스트까지 완전히 통과한 뒤에야 예전 서비스를 해지하세요. 그 한 달의 중첩 구간이 이 과정 전체에서 가장 저렴한 보험입니다.

그대로 따라 할 수 있는 일정표

여기서 다루는 것 중 그 자체로 어려운 일은 하나도 없습니다. 마이그레이션이 잘못되는 이유는 이 단계들이 하룻저녁으로 압축되어, TTL은 아직 만료되지 않았고, 인증서는 아직 테스트되지 않았고, 롤백은 아직 적어두지 않은 상태로 진행되기 때문입니다. 일주일에 걸쳐 나누면, 하루에 20분씩만 일하면 됩니다.

D-7일예전 서버의 인벤토리를 정리하세요. 새 서버를 프로비저닝하고 강화하세요. 서비스를 설치하고 설정한 다음, 멈추고 비활성화하세요. 제3자 허용 목록에 새 주소를 추가하세요.
D-3일DNS TTL을 300초로 낮추세요. 첫 번째 파일 전송을 시작하세요. 동결 시간 예산이 빠듯하다면 복제를 구성하세요. 리버스 DNS 레코드를 설정하고 새 주소를 SPF에 추가하세요.
D-1일TLS 인증서를 복사하거나 새로 발급하세요. --resolve 트릭으로 새 서버를 처음부터 끝까지 검증하세요. 동결 시간을 짐작이 아니라 실측값으로 알기 위해, 사본을 대상으로 전체 덤프와 복원 시간을 재보세요. 롤백 절차를 적어두세요.
D-DAY쓰기를 동결하세요. 예전 타이머를 비활성화하세요. 마지막 파일 전송과 마지막 데이터베이스 동기화를 실행하세요. 검증하세요. DNS를 전환하세요. 새 호스트에서 서비스를 시작하세요. 예전 서버는 계속 읽기를 처리하게 두세요.
D+1일예전 액세스 로그를 살펴 뒤처진 요청이 없는지 점검하세요. 타이머가 실행됐는지 확인하세요. 메일을 양방향으로 테스트하세요. 새 서버를 백업하고 복원해보세요.
D+30일예전 서버가 갖고 있던 모든 자격 증명을 교체하세요. 데이터를 지우세요. 서비스를 해지하세요. DNS TTL을 원래대로 되돌리세요.

마이그레이션은 실제로 어떻게 잘못되는가

복사 과정에서가 아닙니다. 애초에 디스크에 없었던 것들, 그리고 두 번 실행된 것들을 통해서입니다.

  • 두 서버가 동시에 쓰는 상황 — 스플릿 브레인 구간이며, 여기서 유일하게 깔끔한 해결책이 없는 실패입니다. 이것을 막는 것은 도구가 아니라 순서입니다: 예전 것을 멈추고, 그다음 새것을 시작하세요.
  • 타이머가 두 머신 모두에서 도는 것. 고객이 모든 것을 두 번씩 받게 되는 원인입니다. 마지막 동기화 이후가 아니라 그 전에 예전 타이머를 비활성화하세요.
  • 한 번도 낮추지 않은 TTL. 5분이면 끝날 전환을 아무도 대응 인력을 배치하지 않은 하루짜리 꼬리로 늘려버립니다.
  • 머신 사이에 숫자 ID가 서로 달라 파일 소유권이 잘못 매겨지는 것. 그러면 애플리케이션은 시작은 되지만 자신의 업로드 디렉터리에 쓰지 못합니다.
  • 전환 후에 처리하려고 미뤄둔 인증서가, 방문자에게 더 진행할 방법을 남겨주지 않는 HSTS 헤더와 맞부딪히는 것입니다.
  • 여러분이 통제하지 못하는 어딘가에 하드코딩된 주소 — 파트너 연동, 방화벽 규칙, 존재하는지조차 잊고 있던 서브도메인의 DNS 레코드 같은 것들입니다.
  • 이전 당일에 예전 서버를 해지해버리는 것. 통계적으로 롤백이 가장 필요할 가능성이 높은 바로 그 순간에, 롤백 경로 자체를 없애버리는 셈입니다.
VPS 마이그레이션은 얼마나 걸리나요?

작업량 자체는 보통 일주일에 걸쳐 나눠진 몇 시간 정도이며, 사용자 눈에 보이는 부분은 몇 분에 불과합니다. 대용량 전송과 TTL 낮추기는 모든 것이 계속 살아 있는 상태에서 며칠 앞서 이루어지고, 전환 자체는 마지막 차등 동기화, DNS 변경, 검증 한 번으로 끝납니다. 데이터가 몇 기가바이트이고 데이터베이스도 크지 않은 사이트라면, 30분짜리 전환에 동결 시간은 한 자릿수 분 단위로 여유 있게 끝낼 수 있습니다.

다운타임을 완전히 없애고 마이그레이션할 수 있나요?

읽기라면 가능합니다 — DNS가 옮겨갈 때까지 예전 서버가 계속 응답하고, 그 후 이를 리버스 프록시로 전환하면 전파 지연으로 인한 꼬리까지도 없앨 수 있습니다. 쓰기는 더 어려운 문제입니다: 짧은 동결이 아무것도 잃지 않는다는 것을 보장하는 단연 가장 단순한 방법이며, 복제를 쓰면 그 동결 시간을 초 단위로 줄일 수 있습니다. 쓰기에서 진짜로 동결 시간을 0으로 만들려면 중첩 구간 동안 애플리케이션이 두 데이터베이스 모두에 써야 하는데, 이는 가능하기는 하지만 대부분의 사이트에는 필요 없는 실패 지점을 하나 더 추가하는 일입니다.

디스크를 복제해야 할까요, 아니면 서버를 새로 구축해야 할까요?

새로 구축하세요. 복제본은 설정 드리프트, 고아 패키지, 과거 침해가 남긴 지속 접근 수단까지 고스란히 옮기며, 예전 배포판 버전에도 계속 묶이게 만듭니다. 스크립트로 설치하고 데이터만 복사하면 깨끗한 머신과 재현 가능한 레시피를 함께 얻을 수 있고, 이것이 바로 다음 재구축을 빠르게 만들어주는 요소이기도 합니다.

IP 주소와 검색 순위는 어떻게 되나요?

주소는 바뀌지만 도메인은 바뀌지 않으며, 링크와 검색 순위, 이력은 모두 도메인을 따라갑니다. URL을 그대로 유지하고, 중첩 구간 동안 예전 서버가 계속 응답하게 해서 어떤 크롤러도 연결 오류를 보지 않게 하면, 이 변화는 검색엔진 입장에서 사실상 눈에 띄지 않습니다. 국가 간 이전은 지연 시간에 민감한 지표를 약간 흔들 수 있으므로, /locations 에서 실제 사용자층과 가까운 리전을 고르세요.

데이터 손실 없이 데이터베이스를 마이그레이션하려면 어떻게 해야 하나요?

목적지에서 쓰기를 시작하기 전에 원본에서 쓰기를 먼저 멈추세요 — 이 순서 하나가 보장의 전부입니다. 작은 데이터셋이라면 동결하고, pg_dump나 mysqldump --single-transaction으로 덤프하고, 복원한 다음 전환하세요. 더 큰 데이터셋이라면 미리 복제해두고 전환 시점에 레플리카를 승격시켜, 따라잡기가 몇 초 만에 끝나게 하세요. 트래픽을 보내기 전에 중요한 테이블의 행 개수를 비교해서 검증하세요.

제 신원을 알리지 않고도 역외 호스트로 옮길 수 있나요?

가능합니다. 암호화폐 잔액으로 결제받는 호스트는 머신에 붙일 카드도, 청구 주소도 없으므로, 서버 뒤에 있는 계정에는 여러분에 대한 정보가 아무것도 남지 않습니다. 마이그레이션 자체는 기술적으로 동일합니다 — 같은 파일 전송, 같은 덤프, 같은 DNS 전환입니다. /offshore-vps 에는 이 모델이 어떻게 작동하는지, /pay-with 에는 결제 쪽이 어떻게 되는지 정리되어 있습니다.

예전 서버는 언제 해지해도 안전한가요?

액세스 로그가 최소 하루 동안 잠잠하고, 그 서버가 갖고 있던 모든 자격 증명을 교체했으며, 새 서버를 백업해서 어딘가에 성공적으로 복원까지 마친 뒤입니다. 작은 VPS 한 달 치 추가 비용은 이 과정에서 가장 저렴한 보험입니다 — 롤백과 장애 사이의 차이를 만들어주는 비용이기 때문입니다.

실전에 적용해 보세요.

월 $3.49부터 해외 서버를 배포하세요 · 8종 암호화폐 · KYC 없음.