AWS 액티브/패시브 DR 배포
Entry, Professional, Enterprise, Enterprise Advanced 플랜에서 사용할 수 있습니다.
시작하기 전에 다음 조건이 갖추어져 있는지 확인하세요.
- 두 리전 모두에서 RDS, S3, OpenSearch 리소스를 관리할 수 있는 IAM 권한이 있는 AWS 계정 접근 권한
- 장애 조치에 사용할 기본 AWS 리전과 보조 AWS 리전 조합 선정
- 정상 동작 중인 기존 Mattermost 기본 배포
- 장애 조치 시 트래픽을 리디렉션할 수 있도록, Mattermost 접속에 사용하는 도메인에 대한 DNS 제어 권한
- 필요한 RDS Aurora PostgreSQL 글로벌 클러스터 권한과 복원 가능한 것으로 검증된 데이터베이스 백업
- 두 리전 모두에서 세분화된 접근 제어(fine-grained access control)를 사용할 수 있는 OpenSearch 2.x
- 기본 리전과 보조 리전 간 네트워크 연결 확인
미션 크리티컬 업무에 Mattermost를 사용하는 Enterprise 고객은 지속적인 가용성과 운영 복원력을 확보해야 합니다. 데이터 센터 장애와 관련된 위험을 완화하려면 견고한 재해 복구 전략이 필수적이며, 이를 통해 예기치 않은 장애 상황에서도 사용자가 Mattermost에 원활하게 접근할 수 있습니다.
이 페이지에서는 AWS에서 Mattermost를 액티브/패시브 재해 복구 구성으로 설정하는 단계와, 한 데이터 센터에서 다른 데이터 센터로 장애 조치하는 방법을 설명합니다.
고가용성과 액티브/액티브 지원을 위해 Kubernetes 환경에서 배포를 안전하게 업그레이드하는 방법은 Kubernetes·고가용성 환경 업그레이드 문서를 참고하세요.
단일 데이터 센터에 구축
첫 단계로 Mattermost를 단일 데이터 센터에 구축합니다. 다음 다이어그램은 기본적인 단일 데이터 센터 아키텍처를 보여 줍니다.

위 다이어그램에는 단일 프록시가 있고 트래픽을 2개 노드로 전달합니다. 또한 단일 writer와 n개 reader로 구성된 데이터베이스, S3 버킷, AWS OpenSearch 서비스를 사용하는 ES/OS가 있습니다.
이 단계에서는 LDAP/SAML, SMTP 같은 다른 세부 사항은 다루지 않습니다.
아래 아키텍처는 리전 전체가 다운되는 상황에 대비한 것입니다. 개별 서버나 서비스 하나가 다운되는 경우는 다루지 않습니다. 예를 들면 다음과 같습니다.
- 앱 노드 하나가 다운되면 모범 사례에 따라 새 노드를 프로비저닝합니다.
- 데이터베이스 복제본 노드가 다운되면 AWS 콘솔에서 새 복제본을 생성합니다. 또는 자동으로 생성되도록 정책을 설정합니다.
데이터베이스 복제
다음 작업은 AWS 글로벌 클러스터를 생성하는 것입니다.
- AWS 콘솔에서 RDS 인스턴스를 선택하고 Actions 메뉴를 펼쳐 Add AWS Region을 선택합니다.
- 보조 리전을 선택하고 나머지 세부 정보를 입력합니다.
보조 클러스터에서 Enable write forwarding 옵션을 선택하여 보조에서 기본으로 쓰기 작업이 전달되도록 하세요. 자세한 내용은 Amazon RDS write forwarding 문서를 참고하세요.
또한 PostgreSQL 버전을 확인해 write forwarding이 허용되는지 검증하세요. 모든 PostgreSQL 버전이 이를 지원하지는 않습니다. 자세한 내용은 Amazon RDS write forwarding 리전 및 버전 지원 현황 문서를 참고하세요.
이제 기본 클러스터가 us-west-1에, 보조 클러스터가 us-east-1에 있는 글로벌 클러스터가 구성되었을 것입니다.

S3 버킷 복제
- 보조 리전에 새 S3 버킷을 생성합니다.
- 원래 버킷으로 돌아가 Properties 탭에서 Bucket versioning을 활성화합니다.
- Management 탭으로 이동해 Replication Rules까지 스크롤한 뒤 새 복제 규칙을 생성합니다.
- 규칙에서 소스 버킷을 선택한 다음 Apply to all objects in the bucket을 선택해 버킷의 모든 객체를 복제합니다.
- 대상 버킷을 선택합니다.
- IAM 역할은 Create new role을 선택합니다.
복제본 버킷과 소스 버킷이 서로 동기화 상태를 유지하도록 버킷에 Replica modification sync 옵션을 선택하세요.
- Save를 선택합니다.
- 기존 객체를 보조 버킷으로 복제하는 작업을 시작할지 묻는 메시지가 표시되면 Yes를 선택합니다.
- 보조 버킷에서도 동일한 단계를 수행합니다.
이제 S3 복제본 버킷과 소스 버킷 사이에 양방향 복제가 동작합니다.
ES/OS 스토리지 복제
- ES/OS 스토리지를 복제하려면 다음 요구 사항에 맞춰 AWS OpenSearch용 CCR(교차 클러스터 복제)을 설정합니다.
- Elasticsearch 7.10 또는 OpenSearch 2.x
- 세분화된 접근 제어 활성화
- 노드 간 암호화 활성화
이미 OpenSearch 2.x를 운영 중이라면 세분화된 접근 제어만 활성화하면 됩니다. 세분화된 접근 제어를 켜면 노드 간 암호화는 자동으로 활성화됩니다.
- 또한 OS 도메인의 Security Configuration 탭에서 설정하는 OS 클러스터 IAM 정책에
CrossClusterGet권한을 추가해야 합니다. AWS 권장에 따라 다음을 사용하되, 필요에 맞게 조정해도 됩니다.{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "es:ESHttp*", "Resource": "arn:aws:es:<region>:<acc_num>:domain/<domain_name>/*" }, { "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "es:ESCrossClusterGet", "Resource": "arn:aws:es:<region>:<acc_num>:domain/<domain_name>" } ] }
요약하면 다음과 같습니다.
- OpenSearch 2.x를 사용합니다.
- 세분화된 접근 제어를 활성화합니다.
- 마스터 사용자를 생성하고 서버 자격 증명을 기록해 둡니다.
- 위와 같이 IAM 정책을 설정합니다.
- 보조 리전에 새 OS 클러스터를 생성합니다. 이 클러스터에도 동일한 단계를 다시 수행합니다.
주의
이 단계에서는 기본 리전의 모든 인덱스에 데이터가 채워져 있는지 확인하세요. 아직 하지 않았다면 대량 인덱싱을 실행하세요.
- 기본 리전에서 보조 리전으로 복제를 시작합니다.
- 먼저 보조에서 기본으로 연결을 생성합니다. OS의 복제는 "풀(pull)" 모델로 동작하므로 보조 사이트가 기본 사이트에서 데이터를 가져옵니다.
- Amazon OpenSearch Service 콘솔에서 보조 도메인을 선택하고 Connections 탭으로 이동한 뒤 Request를 선택합니다.
- Connection alias에 연결 이름을 입력합니다.
- connect to a domain in another AWS account or region을 선택하고 기본 도메인의 ARN을 입력합니다.
- Request를 선택해 기본 도메인에 권한 요청을 보냅니다.
- 기본 도메인을 열어 Connections 탭에서 들어온 요청을 확인하고 수락합니다.
- 이제 인덱스에 대한 복제 규칙을 설정합니다.
- 보조 리전의 앱 노드에 SSH로 접속해
posts*인덱스에 대한 자동 추종(auto-follow) 규칙을 설정합니다. 이 인덱스는 일 단위 명명 규칙과 월 단위 집계를 사용하기 때문입니다. - 나머지 인덱스는 각각 복제합니다.
*로 규칙을 설정해 전부 복제할 수도 있지만, 그러면 원하지 않는 숨김 인덱스와 시스템 인덱스까지 포함됩니다. posts*인덱스에 대한 자동 추종을 설정합니다.curl -XPOST -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/_autofollow?pretty' -d ' { "leader_alias" : "<LEADER_ALIAS>", "name": "autofollow-rule", "pattern": "posts*", "use_roles":{ "leader_cluster_role": "all_access", "follower_cluster_role": "all_access" } }'- 자동 추종 규칙의 상태를 확인합니다.
curl -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/autofollow_stats?pretty' { "num_success_start_replication" : 2, "num_failed_start_replication" : 0, "num_failed_leader_calls" : 0, "failed_indices" : [ ], "autofollow_stats" : [ { "name" : "autofollow-rule", "pattern" : "posts*", "num_success_start_replication" : 2, "num_failed_start_replication" : 0, "num_failed_leader_calls" : 0, "failed_indices" : [ ], "last_execution_time" : 1737699113927 } ] } - 다음으로 나머지 인덱스에 대한 복제를 설정합니다.
curl -XPUT -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/channels/_start?pretty' -d ' { "leader_alias": "<LEADER_ALIAS>", "leader_index": "channels", "use_roles":{ "leader_cluster_role": "all_access", "follower_cluster_role": "all_access" } }' curl -XPUT -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/users/_start?pretty' -d ' { "leader_alias": "<LEADER_ALIAS>", "leader_index": "users", "use_roles":{ "leader_cluster_role": "all_access", "follower_cluster_role": "all_access" } }' curl -XPUT -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/files/_start?pretty' -d ' { "leader_alias": "<LEADER_ALIAS>", "leader_index": "files", "use_roles":{ "leader_cluster_role": "all_access", "follower_cluster_role": "all_access" } }' - 복제 규칙의 상태를 확인합니다.
curl -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/channels/_status?pretty' curl -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/files/_status?pretty' curl -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/users/_status?pretty' curl -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/posts_<DATE>/_status?pretty' Sample output: { "status" : "SYNCING", "reason" : "User initiated", "leader_alias" : "<LEADER_ALIAS>", "leader_index" : "<INDEX>", "follower_index" : "<INDEX>", "syncing_details" : { "leader_checkpoint" : 16, "follower_checkpoint" : 16, "seq_no" : 17 } } - 인덱스를 확인합니다. 기본 도메인의 모든 인덱스가 보조 도메인에서도 보여야 합니다.
curl -s -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_cat/indices?pretty'
- 보조 리전의 앱 노드에 SSH로 접속해
작업 서버 복제
보조 리전에서 작업 스케줄러가 계속 실행되면 작업을 가져와 실행하기 시작합니다. 다음 단계를 따라 올바르게 관리하세요. 자세한 내용은 RunScheduler 구성 설정 문서를 참고하세요.
- 사전 조건: 보조 리전을 활성화하기 전에 해당 리전의 모든 노드에서
JobSettings.RunScheduler를false로 설정합니다. - 장애 조치 시: 새 기본 리전의 모든 노드에서
JobSettings.RunScheduler를true로 설정합니다. - 직후: 새 보조 리전의 모든 노드에서
JobSettings.RunScheduler를false로 설정합니다. - 검증: 작업이 활성 리전에서만 실행되는지 확인합니다. 테스트 작업(예: 인덱스 재구축 트리거)을 실행하고 작업 로그를 확인해 보조가 아닌 새 기본 리전에서 실행되는지 확인하세요.
보조 리전 테스트
위 단계를 마치면 완전히 동작하는 보조 리전이 준비됩니다. 기본 리전과 동일한 노드 및 프록시 서버 구성을 그대로 복제할 수 있습니다. 보조 리전의 앱 노드는 처음에는 기동되지 않습니다. Mattermost가 write forwarding에서 허용되지 않는 일부 DDL 문을 실행하려 하기 때문에 연결을 시도하며 루프에 갇히게 됩니다. 리전을 장애 조치하고 나면 정상 동작하기 시작합니다. 기본 리전은 계속 읽기가 가능하며, 주기적인 쓰기는 보조 리전(이제 기본이 된)으로 전달됩니다.
두 리전의 클러스터가 동일한 데이터베이스를 공유하려면 각 클러스터의 ClusterNames가 서로 달라야 합니다.
RDS를 보조로 장애 조치
장애 조치를 수행하려면 RDS 글로벌 클러스터로 이동해 Actions에서 Switchover or Failover global database를 선택한 다음, 데이터 손실 없이 전환하려면 switchover를 선택합니다(완료까지 더 오래 걸립니다). 또는 데이터 손실을 감수하고 더 빠르게 전환하려면 failover를 선택할 수 있습니다. 어차피 리전 전체를 사용할 수 없는 상황이라면 failover가 switchover보다 나쁠 것이 없습니다.
이 작업이 끝나면 연결을 시도하며 멈춰 있던 앱 노드가 진행되어 모든 기능이 정상 동작해야 합니다. 읽기·쓰기와 이미지 업로드가 가능하고 모든 것이 복제됩니다. OpenSearch 데이터만 예외입니다.
ES/OS를 보조로 장애 조치
ES/OS는 단일 인덱스에 대해 다중 writer를 허용하지 않습니다. 한 번에 하나의 인덱스에만 쓸 수 있습니다. 따라서 복제 방향을 반대로 돌려 보조에서 기본으로 복제하도록 수동 작업을 수행해야 합니다.
설명을 단순하게 하기 위해 site1을 기본, site2를 보조라고 하겠습니다. 즉 site1의 OS가 리더 도메인이고 site2가 팔로워입니다. 팔로워는 리더에서 데이터를 가져옵니다. 이제 site2가 리더가 되고 site1이 팔로워가 되도록 방향을 전환합니다.
- AWS 콘솔에서
site1>site2규칙을 제거합니다. 이렇게 하면 복제가 자동으로 일시 중지되지만site2의 인덱스는 여전히 읽기 전용입니다. 이를 위해 복제 규칙을 제거하세요. - 자동 추종 규칙을 제거합니다.
curl -XDELETE -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/_autofollow?pretty' -d ' { "leader_alias" : "<LEADER_ALIAS>", "name": "autofollow-rule" }' - 앞에서 설명한 대로 자동 추종 규칙의 상태를 확인합니다.
- 복제 규칙을 제거합니다.
curl -XPOST -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/channels/_stop?pretty' -d '{}' curl -XPOST -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/files/_stop?pretty' -d '{}' curl -XPOST -H 'Content-Type: application/json' -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_plugins/_replication/users/_stop?pretty' -d '{}' - 앞에서 설명한 대로 복제 규칙의 상태를 확인합니다.
- 이제 인덱스에 쓰기가 가능해집니다.
- AWS 콘솔에서
site2>site1규칙을 추가합니다. site1에서 모든 인덱스를 팔로워로 만듭니다. 먼저 모든 인덱스를 삭제해야 합니다.curl -XDELETE -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/posts*?pretty' curl -XDELETE -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/channels?pretty' curl -XDELETE -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/files?pretty' curl -XDELETE -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/users?pretty'- 인덱스를 새로 고칩니다.
curl -XPOST -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_refresh?pretty' - 모두 삭제되었는지 확인합니다.
curl -s -u '<USERNAME>:<PASSWORD>' 'https://<HOSTNAME>/_cat/indices?pretty' - 자동 추종 규칙과 복제 규칙을 추가합니다. 앞과 동일한 단계를 따르세요.
- 인덱스를 다시 나열해 복제가 시작되었고 인덱스를 사용할 수 있는지 확인합니다.
S3 버킷이 양방향으로 자동 복제되도록 하기 위해 따로 해야 할 일은 없습니다.
엔드투엔드 테스트
장애 조치가 완료되고 ES/OS 복제 방향이 전환되면 새 사이트를 정상적으로 사용할 수 있습니다.
최종 아키텍처는 다음과 같습니다.

장애 조치 시 DNS를 사용하면 PRIMARY와 SECONDARY 사이를 쉽게 전환할 수 있습니다.
DNS를 전환하더라도 웹소켓은 여전히 기존 데이터 센터를 가리킵니다. 해당 연결을 새 데이터 센터로 옮기려면 앱 노드를 하나씩 순차적으로 재시작해야 합니다. 모든 노드가 다운된 상태라면 별도 조치가 필요 없으며 클라이언트가 자동으로 새 데이터 센터에 다시 연결합니다.
S3 버킷은 양방향으로 복제되고, 데이터베이스와 ES/OS는 단방향으로 복제됩니다.
기본 데이터 센터로 복원
재해 상황이 해소되어 정상 운영으로 복귀할 준비가 되면, 위 장애 조치 단계를 역순으로 수행해 트래픽을 원래의 기본 데이터 센터로 되돌립니다.
- RDS 콘솔의 Switchover or Failover global database 옵션을 사용해 원래 기본 리전으로 RDS switchover를 수행합니다.
- ES/OS를 보조로 장애 조치 섹션과 동일한 단계를
site1과site2의 역할만 바꿔 수행하여 ES/OS 복제 방향을 되돌립니다. - DNS를 갱신해 트래픽을 원래의 기본 데이터 센터로 다시 보냅니다.
- 원래 기본 노드에서
JobSettings.RunScheduler를 다시 활성화하고 보조 노드에서는 비활성화합니다. - 앱 노드를 하나씩 순차적으로 재시작해 웹소켓 연결을 기본 데이터 센터로 되돌립니다.