여러분 안녕하세요.
저는 꽤 작은 규모의 Discourse 인스턴스를 운영하고 있습니다(사실 수년째 운영 중이며, 거의 문제가 없었습니다): https://discuss.cubeisland.de/.
전용 VM(데이터 센터 내 자체 하드웨어)에서 표준 launcher 기반 배포 방식을 사용해 왔습니다. 수년간 변경한 유일한 사항은 외부에서 실행되는 공유 PostgreSQL 데이터베이스로 마이그레이션을 진행한 것입니다.
최근에는 자원을 절약하고 인프라의 일부가 더 "탄력적"이 되도록 하기 위해, 궁극적으로 Kubernetes 클러스터로 마이그레이션하기 위한 준비 단계로 전용 VM에서 실행 중인 애플리케이션을 Docker Swarm으로 이전하기 시작했습니다.
오늘은 남은 전용 애플리케이션 VM 중 하나인 이 작은 Discourse 인스턴스를 살펴본 날이었습니다. "이미 Docker에서 실행 중인데, Swarm으로 배포하는 것이 얼마나 어려울까?"라고 생각했습니다. 그리고 제가 읽은 내용으로 보아 실제로 그렇게 될 것 같았습니다. 현재 실행 중인 인스턴스에서 이미지를 가져와 내부 레지스트리에 푸시하고 Swarm에서 실행하면 모든 것이 정상적으로 작동할 것 같아 좋습니다.
launcher 파일, 특히 템플릿과 샘플을 살펴보니, 이러한 배포 환경에서는 Redis를 분리하는 것이 좋은 아이디어일 수 있고, 플러그인을 추가하거나 업데이트할 때 CI 작업을 설정하여 새 이미지를 빌드할 수 있을 것 같다는 생각이 들었습니다. 그래서 discourse_docker를 로컬에 체크아웃하고 기존 app.yml 컨테이너 정의를 클론에 복사한 후, 즉시 배포하지 않고 레지스트리에 푸시할 수 있는 이미지를 빌드하기 위해 ./launcher bootstrap app을 실행해 보았습니다.
놀랍게도, 스크립트는 “production” PostgreSQL 서버에 연결을 시도하며 데이터베이스 마이그레이션을 수행하려 했습니다. 다행히 제 로컬 워크스테이션에서는 해당 서버에 접근 권한이 없었습니다.
여기저기 찾아보니 apparently 이것이 정상적인 동작 방식인 것 같아, 다음과 같은 의문이 들었습니다:
- 아직 데이터베이스가 없는 새 인스턴스의 컨테이너를 어떻게 빌드해야 할까요? 이미지를 빌드하기 전에 production 데이터베이스를 설정해야 하는 건가요?
- db:migrate가 실행되는 시점이 이것뿐이라고 가정하면, 여러 유사한 인스턴스(예: prod와 test)를 가지고 있다면, 새 이미지를 빌드하기 위해 인스턴스 중 하나를 업그레이드해야 하고, 이미지가 동일함에도 불구하고 두 번째 인스턴스에 같은 이미지를 사용할 수 없게 됩니다.
- 이미지 빌드 시스템에서 데이터베이스 서버에 접근할 수 없는 인스턴스에 대한 이미지를 어떻게 빌드해야 할까요(이것은 그리 드문 상황이 아닐 것입니다)?
몇 가지 게시물을 읽은 후(물론 이 게시물도 포함하여), 현재 빌드 프로세스의 이유를 충분히 인지하고 있으며, 표준 풀-스펙 VM에서 Discourse를 배포하는 언급된 99%의 사용자들에게 이것이 가치를 가진다는 점을 이해합니다. 또한 “올인원” 컨테이너 모델에 익숙하며, 이에 반대하지 않습니다. 결국 Docker의 핵심 가치는 소프트웨어 벤더가 사전에 최적화된 구성을 만들어 재현 가능한 런타임 환경으로 번들링할 수 있어, 운영 측면에서 애플리케이션에 특화된 많은 지식이 필요 없게 된다는 사실에서 옵니다. 따라서 제공된 도구를 사용하는 데 완전히 동의합니다. 소프트웨어 벤더 자신보다 더 나은 컨테이너를 다른 사람이 빌드할 것이라고 기대할 이유가 무엇이며, 아무런 이득도 없이 배포를 더 “순수하게”(그것이 무엇을 의미하든…) 만들기 위해 nginx와 Ruby 애플리케이션을 분리하고 싶지 않습니다.
그러나 실행에 거의 근접하지 않은 상태에서 런타임 상태를 변경하는 컨테이너를 보는 것은 이상합니다. 저는 이미 컨테이너에서 여러 애플리케이션을 실행하고 있으며, 일부는 컨테이너 실행을 염두에 두고 있지 않았던 것들을 컨테이너화하기도 했습니다.
제 생각에 Discourse와 유사한 요구사항/문제를 유사한 방식으로 처리하는 애플리케이션의 대표적인 예는 GitLab입니다. GitLab은 이제 완전히 분해된 "있어야 할 방식"의 Kubernetes 배포를 위한 멋진 Helm 차트를 제공하지만, (숫자를 확인하지 않았지만) 추측컨대 소규모~중규모 배포의 유사한 99%는 GitLab의 omnibus Docker 이미지(또는 실질적으로 동일한 OS 패키지)를 사용한다고 봅니다. GitLab에도 유사한 부트스트래핑 프로세스가 있지만, 이는 컨테이너 내부의 chef를 기반으로 하며, 모든 시작 시마다 실행되어 데이터베이스 마이그레이션 및 자산 컴파일과 같은 일반적인 작업을 수행합니다.
네, GitLab의 시작은 이로 인해 몇 분 걸릴 수 있지만, 제가 본 배포(일부는 대기업)에서 이것이 문제가 된 적은 결코 없습니다. 특히 Docker-Swarm과 Kubernetes 및 기타 최신 오케스트레이션 시스템과 같이 롤링 업그레이드를 수행할 수 있는 시스템에서는, 새 인스턴스가 실행 중이고 성공적으로 헬스 체크 및 리디 체크를 통과한 경우에만 구 인스턴스가 종료되므로, 긴 배포 프로세스가 실제로는 문제가 되지 않을 수 있습니다. 하지만 작동할 수도 있고 아닐 수도 있는 고급 롤링 업그레이드 없이도, 많은 상황에서 상당한 다운타임도 감당할 수 있습니다.
그러므로: launcher를 구성하여 이미지 빌드 시 데이터베이스에 의존하는 작업을 건너뛰고, 대신 컨테이너 시작 시 이러한 작업을 수행하도록 하는 것이 가능할까요?
저는 확실히 여기에 시간을 투자할 의향이 있지만, 저녁 시간은 제한적이므로 어떤 조언이라도 매우 환영합니다.
이것이 멍청하거나 심지어 불가능하다고 생각하신다면, 완전히 다른 프로세스에 대해서도 개방적입니다.
피드백 주셔서 감사합니다!