웹과 데이터 컨테이너를 분리하여 빠르게 마이그레이션하기

:warning: 경고: 리눅스 시스템 관리자로 일하는 데 익숙하지 않거나 Docker 컨테이너 사용 경험이 없다면, 멀티 컨테이너 배포로 전환하는 것이 어려울 수 있습니다. 이 곳의 스태프와 자원봉사자들도 적절하게 launcher 스크립트에 의해 완전히 관리되는 스탠드얼론 단일 컨테이너 배포로 되돌아가도록 요청할 것입니다.

멀티 컨테이너 배포로 전환한 후 시스템이 고장 나면, 고장 난 두 부분을 모두 보유하게 될 가능성이 큽니다. 아래 설명을 읽고 이것이 컨테이너 내부에서 실제로 어떻게 작동하는지 설명하는 것이 아니라 마법처럼 느껴진다면, 가장 가까운 기본 스탠드얼론 배포로 달려가세요(걷지 마세요). 그러면 당신 자신에게 도움이 될 것입니다.

단일 컨테이너 배포에서 멀티 컨테이너 배포로 마이그레이션하는 권장 방법은 기본적으로 다음과 같습니다:

  • Discourse 백업
  • 전체를 삭제
  • 멀티 컨테이너 배포로 처음부터 시작
  • 백업 복원

저처럼 복구에 시간이 수 시간 걸리는 큰 사이트를 운영 중이라면, 더 빠른 방법이 있을지 궁금해할 수 있습니다. 더 이상 궁금해하지 마세요! 저는 스탠드얼론 배포에서 웹, 데이터, 레디스 컨테이너 3개로 구성된 배포로 마이그레이션하는 데, 해당 사이트의 ./launcher rebuild app 실행에 일반적으로 걸리는 시간보다 더 짧은 시간이 걸렸습니다. (총 다운타임 12분. 앱 재구축에는 때로는 30분 이상 걸리기도 했습니다.) 제 경험을 바탕으로, 미래에는 Redis를 Postgres와 함께 단일 data 컨테이너에 유지할 것입니다.

이 작업을 수행하면 다른 컨테이너(데이터, 그리고 저처럼 멍청하게 Redis를 분리했다면 Redis도 포함)를 언제 재구축해야 하는지를 알아내는 책임은 당신에게 있습니다. 더 이상 ./launcher rebuild app으로 모든 것에 대한 무료 업그레이드를 받을 수 없습니다. 이 프로세스를 관리할 자원이 없다면 스탠드얼론 배포를 사용하거나 호스팅된 Discourse를 구매하세요.

테스트

이 프로세스를 읽은 후, 멀티 컨테이너에서 단일 컨테이너로 빠르게 마이그레이션하는 방법도 이해하게 되었다면, 이 프로세스를 사용하여 멀티 컨테이너로 마이그레이션하지 마십시오. 만약 이 글을 읽고 나서 그것이 명확하지 않다면, 이 게시물은 충분히 고급 기술(즉, 마법과 구별할 수 없는 수준)이며, 이 프로세스가 중간에 실패하는 경우를 인식하지 못할 수도 있으므로, 나중에야 깨닫게 될 수 있는 고장 난 Discourse를 보유하게 될 수 있습니다. 만약 그런 일이 발생하면, 고장 난 두 부분을 모두 보유하게 됩니다. 고장낸 사람은 그것을 사야 한다는 말처럼 말입니다!

백업

먼저 백업하고, 복원 시 모두 다시 구축하지 않도록 썸네일 백업을 먼저 활성화하세요. 여기서 실수를 하면, 복구하는 가장 쉬우면서 안전하고 빠른 방법이 정상적인 방법으로 전환하는 것이 되는 상황에 쉽게 빠질 수 있습니다. 문제가 발생하면 권장 방법으로 되돌아갈 준비를 하세요.

백업을 다운로드하세요. 아래 명령어는 Discourse 데이터 내에서 파일을 이동하는 것을 포함하며, 실수를 하면 백업을 삭제했을 수도 있습니다. 따라서 다운로드하세요. 그리고 업로드가 백업에 포함되지 않았다면, 그것도 백업하세요. 그것들도 파일을 이동할 위치에 있습니다.

진심으로, 백업하세요.

제가 이 작업을 수행했을 때, 먼저 백업을 하고, 더 이상 진행하기 전에 원격 시스템 백업을 수행했습니다.

새로운 멀티 컨테이너 구성 설정

최소 containers/web_only.yml과 containers/data.yml이 필요하며, Redis를 분리하고 싶다면 containers/redis.yml도 필요합니다. samples/data.yml(선택적으로 samples/redis.yml)을 containers/ 디렉토리로 복사하여 시작하세요.

Redis를 별도로 배포하는 경우, containers/data.yml 파일 상단의 Redis 템플릿을 제거하세요. (하지만 좋은 이유 없이 그렇게 하지 마세요. 그냥 추가적인 작업일 뿐입니다.)

web_only.yml을 만드는 방법은 두 가지가 있습니다.

  1. samples/web_only.yml을 containers/로 복사한 후, 둘 다 containers/app.yml과 비교하여 새로운 containers/data.yml의 params:에 있는 Postgres 구성을 유지하세요.
  • containers/app.yml의 Postgres용 params:를 containers/data.yml로 복사
  • SOME_SECRET을 대체할 고유한 비밀번호 생성
  1. 또는 containers/app.yml을 containers/web_only.yml로 복사하고 samples/web_only.yml과 비교하세요.
  • Postgres 및 Redis 템플릿에 대한 모든 참조 제거
  • Postgres 설정만 있었던 전체 params: 섹션 제거
  • samples/web_only.yml에서 그대로 가져오거나, Redis를 별도의 컨테이너로 배포하는 경우 수정된 links: 섹션 추가 (아래 참조)
  • samples/web_only.yml에서 데이터베이스 섹션을 추가하고 SOME_SECRET을 대체할 고유한 비밀번호 생성
  • 볼륨 정의에서 standalone을 web_only로 변경

Redis를 데이터 컨테이너의 Postgres와 묶는 합리적인 기본값 대신 자체 컨테이너로 분리하는 경우 사용할 links: 섹션은 다음과 같습니다:

# 컨테이너를 함께 연결하기 위해 'links' 키를 사용하세요. 즉, Docker --link 플래그를 사용하는 것입니다.
links:
  - link:
      name: data
      alias: data
  - link:
      name: redis
      alias: redis

Redis와 Postgres 컨테이너를 단일 데이터 컨테이너로 결합하는 경우 redis 링크는 필요하지 않습니다. 이는 수행할 내용을 보여주는 것입니다.

samples/data.yml의 env에 있는 현재 Postgres 설정의 사본이며, 여기서 SOME_SECRET을 변경해야 합니다:

  ## TODO: 데이터베이스 연결 구성
  DISCOURSE_DB_SOCKET: ''
  #DISCOURSE_DB_USERNAME: discourse
  DISCOURSE_DB_PASSWORD: SOME_SECRET
  DISCOURSE_DB_HOST: data
  ## 단일 데이터+레디스 컨테이너를 사용하는 경우, 다음 값은 "data"가 됩니다.
  DISCOURSE_REDIS_HOST: redis

정상적인 배포(멀티사이트가 아닌)의 경우, 다른 행을 수정할 필요가 없습니다. DISCOURSE_DB_SOCKET은 Postgres용 유닉스 도메인 소켓이며, 포트 번호가 아닙니다.

app.yml에서 samples/web_only.yml 대신 복사한 경우 web_only.yml 끝의 볼륨 정의에 필요한 변경 사항의 예는 다음과 같습니다:

@@ -75,10 +80,10 @@
 ## Docker 컨테이너는 무상태(stateless)입니다. 모든 데이터는 /shared에 저장됩니다.
volumes:
   - volume:
-      host: /var/discourse/shared/standalone
+      host: /var/discourse/shared/web_only
       guest: /shared
   - volume:
-      host: /var/discourse/shared/standalone/log/var-log
+      host: /var/discourse/shared/web_only/log/var-log
       guest: /var/log

이제 containers/web_only.yml에서 사용한 것과 동일한 비밀 비밀번호를 containers/data.yml의 SOME_SECRET 대신 설정하세요.

이제 마이그레이션을 준비할 수 있습니다.

지금, 빠른 마이그레이션을 시도하기 전에 최종 백업을 수행하고 다운로드하는 시점입니다. 기억하세요, 여기서 문제가 발생하면 즉시 권장 방법으로 전환해야 합니다. 이것을 아무리 강조해도 부족합니다.

데이터(Postgres)와 Redis 컨테이너 분리:

cd /var/discourse

./launcher stop app
cd  shared
mkdir data
mkdir redis
mv standalone/postgres_* data/
mv standalone/redis_data/ redis/
mv standalone web_only
mkdir -p data/log/var-log
mkdir -p redis/log/var-log

cd ..

./launcher destroy app

./launcher bootstrap data
./launcher bootstrap redis
./launcher start redis
./launcher start data

./launcher bootstrap web_only
./launcher start web_only

Postgres+Redis 통합 데이터 컨테이너:

cd /var/discourse

./launcher stop app
cd  shared
mkdir data
mv standalone/postgres_* data/
mv standalone/redis_data/ data/
mv standalone web_only
mkdir -p data/log/var-log

cd ..

./launcher destroy app

./launcher bootstrap data
./launcher start data

./launcher bootstrap web_only
./launcher start web_only

또한 이전에 외부 nginx를 설정했다면, proxy_pass 경로를 새로운 web_only 소켓 위치와 일치하도록 변경해야 합니다. 예를 들어 http://unix:/var/discourse/shared/standalone/nginx.http.sock:에서 http://unix:/var/discourse/shared/web_only/nginx.http.sock:으로 변경합니다.

저의 경우, 2코어 VM과 4GB RAM, 다운로드를 제외한 600MB 백업이 있는 사이트에서 이 프로세스는 12분의 다운타임으로 이어졌습니다. 결과는 개인차가 있을 수 있습니다.

아직까지 이 중 어느 것도 launcher를 업데이트하지 않는다는 점에 유의하세요. 최신 버전이 아닐 수 있습니다. (예를 들어, 저는 Postgres 12 업데이트가 사용 가능해진 후에, 적용하기 전에 이 작업을 수행했습니다. 이 프로세스는 저를 Postgres 10에 머물게 했습니다. 그리고 제가 다음으로 한 일은 데이터 앱을 재구축하여 launcher를 업데이트하고 Postgres 12 업데이트 프로세스를 성공적으로 거치는 것이었습니다.)

향후 업데이트 시 수행할 작업

이 마이그레이션 후, Redis 또는 데이터를 업데이트해야 하는 경우, 먼저 웹 앱을 중지해야 합니다. 이는 다음과 같을 것입니다:

./launcher stop web_only
./launcher rebuild data # 그리고/또는 redis
./launcher rebuild web_only

data(또는 postgres, 또는 redis) 컨테이너를 재구축하면, 새로운 데이터 컨테이너와 다시 연결하기 위해 새로운 웹 컨테이너를 생성해야 합니다. web_only를 재구축하거나, 재구축이 필요하지 않다고 생각한다면 ./launcher destroy web_only; ./launcher start web_only로 처리할 수 있습니다 (그리고 “missing data container” 또는 유사한 오류가 발생하면, 이것이 수행해야 할 작업입니다).

그러나 Postgres나 Redis 모두 업데이트가 필요하지 않은 경우, 해당 컨테이너를 재구축할 필요가 없으므로 훨씬 빠릅니다. 대부분의 앱 재구축은 단순히 ./launcher rebuild web_only입니다.

또는, 더 적은 다운타임(보고된 바에 따르면 15초에서 2분 사이)을 위해:

./launcher bootstrap web_only
./launcher destroy web_only && ./launcher start web_only

다시 말하지만, 멀티 컨테이너 배포로 전환함으로써, 그것이 적절한 시점을 추적하는 것은 이제 당신의 일입니다. 업데이트에 대한 알림은 관리자 콘솔에서 받게 되지만, 그것들은 web_only 컨테이너에만 적용됩니다. Postgres나 Redis를 업데이트해야 할 시점에 대해 알려주는 것은 없습니다. 이렇게 한다면, 수행하는 모든 버전 업그레이드 전에 Announcements 카테고리를 읽고, 업그레이드하는 모든 새로운 버전의 릴리스 노트를 읽으세요. 즉, 버전 업데이트를 건너뛰는 경우, 업데이트를 건너뛴 버전의 릴리스 노트를 읽지 마세요. (최신 상태를 유지하기 위해 릴리스 노트에 감시(watch)를 설정하거나 피드 리더를 https://meta.discourse.org/tag/release-notes.rss에 구독하는 것을 고려해 보세요.)

web_only 컨테이너 재구축에는 데이터베이스가 실행 중이어야 하므로, 두 개 또는 세 개의 컨테이너를 병렬로 재구축하여 속도를 높일 수 없습니다. 매번 모두 재구축할 계획이라면, 표준 권장 스탠드얼론 배포를 유지하세요. 여러 컨테이너를 다루는 것보다 빠를 것입니다.

백업 검토

업로드를 데이터베이스와 별도로 백업하는 경우, 재해 시 복원을 위해 업로드가 파일 기반 원격 백업 체제로 백업되고 있기를 바랍니다.

원격 백업 구현을 검토하여, 업로드가 /var/discourse/shared/standalone 대신 /var/discourse/shared/web_only에 백업되도록 확인하고, 새로운 멀티 컨테이너 구현에서 백업이 최신 상태를 유지하도록 하세요.

22개의 좋아요

안녕하세요, mcdanlj님! 처음 온 사람입니다. Discourse에는 두 가지 배포 방식이 있는 것 같아요. 하나는 app.yml의 스탠드얼론 모드이고, 다른 하나는 web-only.yml, data.yml, redis.yml을 사용하여 데이터베이스와 Redis 캐시를 분리하는 멀티컨테이너 방식이네요. 그런데 app.yml도 DISCOURSE_DB_HOST와 DISCOURSE_REDIS_HOST 매개변수를 수정하면 Redis와 데이터베이스에 연결할 수 있는 것 같아서, 왜 app.yml을 web-only.yml, data.yml, redis.yml로 분리해야 하는지 궁금합니다.

기존 데이터베이스와 redis(예: rds와 elasticache, 또는 다른 방식으로 직접 생성한 것)가 이미 있다면, 직접 준비할 필요가 없습니다.

각 discourse 인스턴스에는 전용 redis가 필요합니다.

1개의 좋아요

Jay, 친절한 설명 감사합니다! 하지만 여전히 혼란스럽습니다. Falco의 튜토리얼을 살펴보니 web-only.yml, data.yml, redis.yml를 설정할 필요 없이 AWS의 RDS와 ElastiCache를 사용하는 것이 쉬운 것 같았습니다. Falco의 튜토리얼은 app.yml의 매개변수만 수정합니다. 하지만 mcdanlj의 튜토리얼은 다릅니다. 이는 그의 포럼이 너무 크기 때문에 Falco가 제공한 간단한 방법을 사용할 수 없는 것일까요?

RDS를 사용하는 것과 직접 데이터베이스 서버를 운영하는 것은 두 가지가 전혀 다릅니다. 예산이 충분하고 전문 지식이 있다면 RDS가 좋습니다. 아무것도 모른다면 단일 컨테이너 설치 방식이 훌륭합니다. 예산이 적으면서 다운타임을 줄이고 싶다면 두 개의 컨테이너를 사용하는 방식이 좋습니다.

대부분의 경우, 자신에게 가장 합리적인 방법을 선택하는 것이 좋습니다.

2개의 좋아요

정말 감사합니다! 저한테는 단일 컨테이너가 최선의 방법인 것 같아요 :rofl: 말씀해 주시지 않으셨으면 rds와 직접 운영하는 데이터베이스 서버의 차이를 몰랐을 거예요 :joy:

1개의 좋아요

@ShawnLi 2컨테이너 시스템이 복잡하게 느껴진다면, 이는 1컨테이너 기본 설정이 당신에게 좋은 선택임을 의미하는 좋은 신호입니다. 2컨테이너 배포 방식은 업데이트 시 월 1회 정도 몇 분간의 다운타임을 줄여주지만, 더 많은 이해가 필요하며, 새 릴리스마다 공지사항의 세부 사항을 수동으로 따라야 합니다.

그래서 저는 이렇게 시작했습니다:

:grinning:

2개의 좋아요

mcdanlj님 감사합니다! 튜토리얼이 정말 훌륭했고 많은 것을 배웠습니다. 저는 간단한 1컨테이너 기본 설정을 선택하기로 했습니다. 네, 제가 실행한 거예요 :rofl:

2개의 좋아요