이 런처는 도커 컴포즈(docker compose)가 등장하기 전에 만들어졌다고 생각합니다:
Docker compose에는 필요한 기능이 없습니다. Discourse의 Dockerfile 템플릿 구성은 유연한 Docker 결과를 허용합니다. 반면 compose에서는 고정된 Dockerfile 세트만 사용할 수 있어 여러 컨테이너가 생성될 수 있습니다.
제 Discourse 설정에서는 UNIX 소켓을 사용하여 Discourse와 nginx를 단일 컨테이너로 실행합니다. PostgreSQL과 Redis는 호스트의 서비스로 실행됩니다. 이는 기본 설정에서 상당히 벗어난 방식이지만, 추가 설정 없이도 가능합니다.
compose를 사용하면 부분적으로 구현할 수 있습니다. 예를 들어, 설계가 다소 엉성한 profile 기능을 사용할 수 있습니다. 하지만 그렇게 하더라도 여전히 복잡합니다. 아니면 각 변형별로 다른 compose 파일을 제공해야 합니다.
문제를 단순히 옮기는 것뿐입니다.
Discourse에 대한 깔끔한 compose 설정은 다음과 같은 서비스를 개별 컨테이너로 구성하는 것입니다:
- Discourse
- nginx
- PostgreSQL
- Redis
Discourse와 nginx는 볼륨을 공유해야 하지만, 큰 문제는 아닙니다.
PostgreSQL과 Redis는… 이러한 서비스는 다른 곳에 호스팅하는 것이 더 나을 수 있으며, Discourse 전용 컨테이너로 실행하고 싶지 않을 수 있습니다. 그런데 이제 docker compose가 문제가 됩니다. docker compose up -d를 실행하면 원치 않는 PostgreSQL이 시작됩니다. 그래서 기본 Discourse 설정과 postgresql 컨테이너를 시작하려면 docker compose --profile postgresql up -d를 사용해야 합니다. “완전한” 자체 포함 Discourse 컨테이너 설정을 위해선 docker compose --profile postgresql --profile redis up -d를 사용해야 합니다. --profile ... 인수를 누르면 더 많은 문제가 발생하므로 주의해야 합니다.
따라서 더 나은 UX를 위해 원하는 docker compose 명령을 생성하도록 launcher를 만들어야 합니다. 이제 우리는 거의 처음 위치로 돌아온 셈입니다. 다만, nginx 컨테이너에 대한 수정은 아직 불가능합니다. 그래서 nginx-http 컨테이너와 nginx-unix 컨테이너가 필요하며, 이들은 상호 배타적이어야 하나요? …
확실히 플러그인 관리가 더 좋아질 수는 있지만, docker compose로 이렇게 하려면 지옥이 될 것입니다.
자, 요약하자면. 제대로 된 Docker 이미지는 제공되지 않습니다.
Docker가 무엇이며 어떻게 작동하는지에 대한 믿기 힘든 수준의 잘못된 지식에 관해서는: What is Docker? | Docker Docs
작업 중에 컨테이너를 공유할 수 있으며, 공유하는 모든 사람이 동일한 방식으로 작동하는 동일한 컨테이너를 받게 된다는 것을 보장할 수 있습니다.
또한 - 사랑받는 "launcher"를 사용하여, 소비하고 배포할 Docker 이미지가 없는데 어떻게 k8s 클러스터에서 Discourse를 실행할 수 있겠습니까?
아, 그렇군요…
이 스크립트는 root로 실행되어야 합니다. 먼저 sudo를 사용하거나 root로 로그인하십시오.
아니요, 감사합니다. 인터넷에서 가져온 랜덤 스크립트를 실행하는 것을 좋아하지 않습니다. 저는 안전하게 격리되어 실행할 수 있는 멋진 Docker 이미지만 있으면 됩니다 ![]()
저는 공개된 이미지를 사용하여 Docker Compose로 Discourse를 프로덕션 환경에 성공적으로 배포했으며, 고객들도 마찬가지입니다.
하지만, 그렇습니다. 다소 지저분하고 상당한 수준의 맞춤형 작업이 필요합니다.
특정한 관점, 특정 아키텍처 또는 기타 특별한 요구 사항이 있어 반드시 다른 방법을 사용해야 하는 경우가 아니라면, 표준 설치 방식과 CDCK 런처를 사용하는 것이 훨씬 쉽습니다.
비마법사(Non-wizard) 방식, 즉 손을 잡아 주는 방식을 사용하지 않는 것은 “의견이 분명한, 특정의, 또는 특별한” 것이 아닙니다 ![]()
어쨌든 - 핵심은 discourse의 원래 도커 이미지를 사용하는 것입니다. 그 정도면 간단합니다.
저는 설정을 조금 만져보기 위해 공식 가이드와 "launcher"를 사용해 보았지만 실패했습니다(유저가 루트인지 확인하는 꽤 멍청한 체크는 제외하고, 이는 문제를 초래하기 위한 것입니다).
그 후 저는 bitnami/discourse - Docker Image 의 bitnami 이미지(그리고 그들의 권장 compose 파일)로 전환했고, docker compose up 한 번(그리고 좋은 징조가 아닌 SQL 오류 다수[동일한 주의사항] 및 ruby 경고[동일한 주의사항]) 후 discourse의 실행 중인 인스턴스를 얻었습니다:
순수하게 복잡하고 “비표준적인 마법”…
그러니 다시 한번 - 왜 정규적인 이미지가 없을까요?
소스와 저장소를 파고들다 보니 base 이미지가 사용되고 있음을 발견했습니다(discourse/base - Docker Image) 하지만 그 버전 관리/태깅이 놀라웠습니다(discourse/base - Docker Image)… 합리적인 버전이 없나 싶었습니다? 그리고 실제로, 메인 저장소를 보면 릴리스가 없는 것 같았지만 어쨌든 적절히 태그된 버전은 있습니다(Tags · discourse/discourse · GitHub).
이제 궁금한 점 - 왜 메인 도커 허브에 일치하는 이미지가 없을까요?
그러니 네 - 것들이 어떻게 조직되어 있는지 살펴본 후 저는 동의합니다:
![]()
반면에 (또는: “물건이 되어야 할 방식”), 예제 프로젝트(범위는 작지만 논리는 성립): GitHub - miniflux/v2: Minimalist and opinionated feed reader · GitHub.
합리적인 릴리스가 있습니다: Releases · miniflux/v2 · GitHub
그리고 올바르게 태그된 대응하는 이미지가 있습니다: miniflux/miniflux - Docker Image
그리고 업그레이드는 단순히 버전 x에서 y로 전환하는 것입니다(또는 latest 태그를 사용하여 간단한 stop/pull/start가 업데이트된 버전을 제공합니다(이는 필요한 모든 마이그레이션을 자동으로 실행할 것입니다)
(오, 그리고 이미지는 약 70배 작지만 그것은 또 다른 이야기입니다)
잘하셨습니다!
질문이 두 개 있습니다… SQL 오류와 ruby 경고가 무엇인가요? 저는 그것에 익숙하지 않습니다. 하지만 아마도 docker와 같은 것을 완전히 잘못된 방식으로 사용했기 때문일 것입니다 ![]()
다음과 같은 작업을 수행하면 됩니다:
./launcher bootstrap myimage
# 해당 이미지를 원하는 위치에 푸시하는 명령어
./launcher start-cmd
이렇게 하면 이미지를 실행하는 데 필요한 ENV 변수를 설정할 수 있습니다.
실제로 그렇게 어렵지 않습니다. GitHub Action에 통합하여 이미지를 빌드하고 docker 저장소 같은 곳에 푸시하도록 설정할 수도 있습니다. docker_compose의 커밋을 살펴보면, 부트스트랩이 필요 없는 이미지를 생성하거나, 적어도 필요한 작업(데이터베이스 마이그레이션, 자산 사전 컴파일 및 s3 푸시 등)을 수행하는 것을 더 쉽게 만들기 위한 움직임이 있는 것으로 보입니다. 저는 k8s나 AWS 이미지 런처 도구(이름을 정확히 기억은 못 합니다)를 사용하고자 하는 고객들을 위해 이 작업을 수행해 본 적이 있습니다.
몇 번 정도는 이러한 사전 빌드된 이미지를 서비스로 제공해볼까 생각했지만, 이를 위해 돈을 지불하고자 하는 사람을 찾지 못했습니다.
그러나 여러 작은 조각들이 있습니다. 제 판단에 따르면 CDCK는 launcher를 사용하여 이미지를 빌드하지만, 실행과 관리는 다른 도구를 사용하여 수행합니다. 이는 여러분이 원하는 방식과 동일합니다. 그리고 그들이 시작했을 당시에는 docker-compose가 이를 수행하는 적절한 방법이 아니었으며, docker-compose가 적절한 방법이 되었을 때는 이미 launcher가 작동하도록 만들어졌기 때문에, 모든 사람을 launcher에서 다른 것으로 마이그레이션하는 방법을 찾는 것은 현실적인 옵션이 아니었습니다.
bitnami 이미지가 여러분에게 적합하다면 그것을 사용하세요. 그렇지 않다면, 그것들을 사용하는 사람에게 도움을 받아야 합니다. 여기서는 그런 사람이 거의 없으니 말이죠.
음… NodeBB를 찾게 되었는데, 배포 측면에서 NodeBB가 사용자 친화적이어서 그런지 훨씬 덜 적대적으로 느껴져서 이미 해당 파일과 전체 설정을 삭제했습니다. (가이드: Docker - NodeBB Documentation; nodebb, postgres, redis 3개 서비스로 구성된 간단한 docker-compose 파일: NodeBB/docker-compose-pgsql.yml at master · NodeBB/NodeBB · GitHub; 그리고 잘 태그된 이미지: Package nodebb · GitHub)
하지만 이미지는 확보했고, 관련 오류는 다음과 같습니다:
- sql 스키마 문제인 것 같습니다:
postgresql-1 | 2025-07-06 17:15:40.518 GMT [155] ERROR: relation "translation_overrides" does not exist at character 523
postgresql-1 | 2025-07-06 17:15:40.518 GMT [155] STATEMENT: SELECT a.attname, format_type(a.atttypid, a.atttypmod),
postgresql-1 | pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
postgresql-1 | c.collname, col_description(a.attrelid, a.attnum) AS comment,
postgresql-1 | attidentity AS identity,
postgresql-1 | attgenerated as attgenerated
postgresql-1 | FROM pg_attribute a
postgresql-1 | LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
postgresql-1 | LEFT JOIN pg_type t ON a.atttypid = t.oid
postgresql-1 | LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
postgresql-1 | WHERE a.attrelid = '"translation_overrides"'::regclass
postgresql-1 | AND a.attnum > 0 AND NOT a.attisdropped
postgresql-1 | ORDER BY a.attnum
postgresql-1 |
postgresql-1 | 2025-07-06 17:15:40.616 GMT [156] ERROR: relation "translation_overrides" does not exist at character 523
postgresql-1 | 2025-07-06 17:15:40.616 GMT [156] STATEMENT: SELECT a.attname, format_type(a.atttypid, a.atttypmod),
postgresql-1 | pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
postgresql-1 | c.collname, col_description(a.attrelid, a.attnum) AS comment,
postgresql-1 | attidentity AS identity,
postgresql-1 | attgenerated as attgenerated
postgresql-1 | FROM pg_attribute a
postgresql-1 | LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
postgresql-1 | LEFT JOIN pg_type t ON a.atttypid = t.oid
postgresql-1 | LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
postgresql-1 | WHERE a.attrelid = '"translation_overrides"'::regclass
postgresql-1 | AND a.attnum > 0 AND NOT a.attisdropped
postgresql-1 | ORDER BY a.attnum
- ruby 경고 (discourse 컨테이너와 sidekiq 컨테이너 모두에서 발생하는데, 동일한 이미지를 사용하므로 어느 정도 이해가 갑니다 :D):
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:5: warning: already initialized constant DiscourseAutomation::Scripts::ADD_USER_TO_GROUP_THROUGH_CUSTOM_FIELD
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:5: warning: previous definition of ADD_USER_TO_GROUP_THROUGH_CUSTOM_FIELD was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:6: warning: already initialized constant DiscourseAutomation::Scripts::APPEND_LAST_CHECKED_BY
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:6: warning: previous definition of APPEND_LAST_CHECKED_BY was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:7: warning: already initialized constant DiscourseAutomation::Scripts::APPEND_LAST_EDITED_BY
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:7: warning: previous definition of APPEND_LAST_EDITED_BY was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:8: warning: already initialized constant DiscourseAutomation::Scripts::AUTO_RESPONDER
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:8: warning: previous definition of AUTO_RESPONDER was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:9: warning: already initialized constant DiscourseAutomation::Scripts::AUTO_TAG_TOPIC
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:9: warning: previous definition of AUTO_TAG_TOPIC was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:10: warning: already initialized constant DiscourseAutomation::Scripts::BANNER_TOPIC
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:10: warning: previous definition of BANNER_TOPIC was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:11: warning: already initialized constant DiscourseAutomation::Scripts::CLOSE_TOPIC
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:11: warning: previous definition of CLOSE_TOPIC was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:12: warning: already initialized constant DiscourseAutomation::Scripts::FLAG_POST_ON_WORDS
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:12: warning: previous definition of FLAG_POST_ON_WORDS was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:13: warning: already initialized constant DiscourseAutomation::Scripts::GIFT_EXCHANGE
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:13: warning: previous definition of GIFT_EXCHANGE was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:14: warning: already initialized constant DiscourseAutomation::Scripts::GROUP_CATEGORY_NOTIFICATION_DEFAULT
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:14: warning: previous definition of GROUP_CATEGORY_NOTIFICATION_DEFAULT was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:15: warning: already initialized constant DiscourseAutomation::Scripts::PIN_TOPIC
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:15: warning: previous definition of PIN_TOPIC was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:16: warning: already initialized constant DiscourseAutomation::Scripts::POST
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:16: warning: previous definition of POST was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:17: warning: already initialized constant DiscourseAutomation::Scripts::SEND_PMS
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:17: warning: previous definition of SEND_PMS was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:18: warning: already initialized constant DiscourseAutomation::Scripts::SUSPEND_USER_BY_EMAIL
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:18: warning: previous definition of SUSPEND_USER_BY_EMAIL was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:19: warning: already initialized constant DiscourseAutomation::Scripts::TOPIC
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:19: warning: previous definition of TOPIC was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:20: warning: already initialized constant DiscourseAutomation::Scripts::TOPIC_REQUIRED_WORDS
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:20: warning: previous definition of TOPIC_REQUIRED_WORDS was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:21: warning: already initialized constant DiscourseAutomation::Scripts::USER_GLOBAL_NOTICE
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:21: warning: previous definition of USER_GLOBAL_NOTICE was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:22: warning: already initialized constant DiscourseAutomation::Scripts::USER_GROUP_MEMBERSHIP_THROUGH_BADGE
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:22: warning: previous definition of USER_GROUP_MEMBERSHIP_THROUGH_BADGE was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:23: warning: already initialized constant DiscourseAutomation::Scripts::ZAPIER_WEBHOOK
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/scripts.rb:23: warning: previous definition of ZAPIER_WEBHOOK was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:5: warning: already initialized constant DiscourseAutomation::Triggers::AFTER_POST_COOK
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:5: warning: previous definition of AFTER_POST_COOK was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:6: warning: already initialized constant DiscourseAutomation::Triggers::API_CALL
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:6: warning: previous definition of API_CALL was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:7: warning: already initialized constant DiscourseAutomation::Triggers::CATEGORY_CREATED_EDITED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:7: warning: previous definition of CATEGORY_CREATED_EDITED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:8: warning: already initialized constant DiscourseAutomation::Triggers::PM_CREATED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:8: warning: previous definition of PM_CREATED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:9: warning: already initialized constant DiscourseAutomation::Triggers::TOPIC_TAGS_CHANGED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:9: warning: previous definition of TOPIC_TAGS_CHANGED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:10: warning: already initialized constant DiscourseAutomation::Triggers::POINT_IN_TIME
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:10: warning: previous definition of POINT_IN_TIME was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:11: warning: already initialized constant DiscourseAutomation::Triggers::POST_CREATED_EDITED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:11: warning: previous definition of POST_CREATED_EDITED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:12: warning: already initialized constant DiscourseAutomation::Triggers::RECURRING
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:12: warning: previous definition of RECURRING was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:13: warning: already initialized constant DiscourseAutomation::Triggers::STALLED_TOPIC
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:13: warning: previous definition of STALLED_TOPIC was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:14: warning: already initialized constant DiscourseAutomation::Triggers::STALLED_WIKI
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:14: warning: previous definition of STALLED_WIKI was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:15: warning: already initialized constant DiscourseAutomation::Triggers::TOPIC
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:15: warning: previous definition of TOPIC was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:16: warning: already initialized constant DiscourseAutomation::Triggers::USER_ADDED_TO_GROUP
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:16: warning: previous definition of USER_ADDED_TO_GROUP was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:17: warning: already initialized constant DiscourseAutomation::Triggers::USER_BADGE_GRANTED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:17: warning: previous definition of USER_BADGE_GRANTED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:18: warning: already initialized constant DiscourseAutomation::Triggers::USER_FIRST_LOGGED_IN
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:18: warning: previous definition of USER_FIRST_LOGGED_IN was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:19: warning: already initialized constant DiscourseAutomation::Triggers::USER_PROMOTED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:19: warning: previous definition of USER_PROMOTED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:20: warning: already initialized constant DiscourseAutomation::Triggers::USER_REMOVED_FROM_GROUP
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:20: warning: previous definition of USER_REMOVED_FROM_GROUP was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:21: warning: already initialized constant DiscourseAutomation::Triggers::USER_UPDATED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers.rb:21: warning: previous definition of USER_UPDATED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/recurring.rb:6: warning: already initialized constant DiscourseAutomation::Triggers::Recurring::RECURRENCE_CHOICES
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/recurring.rb:6: warning: previous definition of RECURRENCE_CHOICES was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/stalled_wiki.rb:6: warning: already initialized constant DiscourseAutomation::Triggers::StalledWiki::DURATION_CHOICES
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/stalled_wiki.rb:6: warning: previous definition of DURATION_CHOICES was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/topic_tags_changed.rb:7: warning: already initialized constant DiscourseAutomation::Triggers::TopicTagsChanged::TriggerOn::TAGS_ADDED_OR_REMOVED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/topic_tags_changed.rb:7: warning: previous definition of TAGS_ADDED_OR_REMOVED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/topic_tags_changed.rb:8: warning: already initialized constant DiscourseAutomation::Triggers::TopicTagsChanged::TriggerOn::TAGS_ADDED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/topic_tags_changed.rb:8: warning: previous definition of TAGS_ADDED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/topic_tags_changed.rb:9: warning: already initialized constant DiscourseAutomation::Triggers::TopicTagsChanged::TriggerOn::TAGS_REMOVED
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/topic_tags_changed.rb:9: warning: previous definition of TAGS_REMOVED was here
sidekiq-1 | /opt/bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/topic_tags_changed.rb:11: warning: already initialized constant DiscourseAutomation::Triggers::TopicTagsChanged::TriggerOn::MODES
sidekiq-1 | /bitnami/discourse/plugins/automation/lib/discourse_automation/triggers/topic_tags_changed.rb:11: warning: previous definition of MODES was here
sidekiq-1 | 2025-07-06T17:15:52.699Z pid=1 tid=4ox INFO: Booted Rails 7.2.2.1 application in production environment
정말 좋은 지적입니다. 이 스크립트가 루트 권한 없이 실행될 수 없는 데에는 정말 그럴 만한 이유가 없습니다.
실제로 루트 권한이 필요한 것은 설정 스크립트뿐이며, 인터넷에서 가져온 Docker 설치 스크립트를 실행하도록 제안하는 위험한 부분을 처리하기 위해서입니다. 따라서 이 부분조차도 루트 권한 없이 실행되도록 변경할 수 있습니다.
런처 스크립트는 루트 권한이 필요하지 않으며, /var/discourse에 대한 쓰기 접근 권한과 Docker 컨테이너를 관리할 수 있는 권한만 있으면 됩니다.
음… ![]()
스크립트는 /var/discourse에 대한 접근 권한조차 필요하지 않습니다(왜 필요할까요?!).
이 전체 문제는 다음과 같은 몇 가지 사항에서 비롯됩니다:
- 도커가 무엇인지, 어떻게 작동하는지, 그리고 그것이 무엇을 가능하게 하는지에 대한 막대한 오해
- 도커 = 도커-컴포즈라는 개념을 억지로 결합시키는 것 (아닙니다!)
호스트 환경을 거의 건드리지 않는 완전히 격리된 설정을 가질 수 있습니다…
충분히 조사해 본 결과, 전체 “setup” 스크립트는 매우 비기술적인 사람을 위해 설치를 최대한 단순하게 만들기 위해 작성된 것으로 보입니다. 이 스크립트는 환경을 확인하고, 사용자를 안내하며, 모든 것을 설정합니다. 이는 좋은 점이 될 수 있지만, 의도된 경로에서 아주 작은 차이조차 벗어나려는 시도는 완전히 실패합니다.
가장 기본적인 설정에서는 호스트 디렉토리에 대한 접근 권한조차 필요하지 않을 수 있습니다 - 모든 것이 제한된 환경(이미지를 사용하여 컨테이너를 생성하고, 필요한 모든 스토리지는 도커 볼륨을 통해 처리됩니다 [다른 곳으로 마이그레이션하거나 파일에 접근하려는 경우 문제가 있지만, 여기서는 기본 사항에 대해 이야기하고 있습니다]) 내에 포함됩니다.
또한 DNS가 올바른지 확인하고, 인증서, 리버스 프록시, SMTP 등을 설정하려고 시도합니다 - 다시 말하지만, 이러한 쉬운 설정을 제공하는 것은 완전히 문제없습니다.
하지만!
문제는 그것을 버리는 것이 아니라, 추가로 순수한 도커 이미지를 제공하는 것입니다 (이미 존재하며, 스크립트와 스크립트가 사용하는 템플릿에서 사용됩니다! discourse_docker/templates/postgres.template.yml at main · discourse/discourse_docker · GitHub & discourse_docker/launcher at main · discourse/discourse_docker · GitHub) 그리고
- 적절한 버전 관리: 이미지를 릴리스된 디스커스 버전(3.4.5 등)으로 태그합니다.
- 예상되는 환경 변수(데이터베이스/레디스/등 연결을 제어하는 것)와 호스트에 마운트할 수 있는 가능한 경로/볼륨에 대한 합리적이고 단순한 문서화.
그것뿐입니다…
aforementioned miniflux 가이드를 살펴보세요: Miniflux Installation with Docker - 이미지에 대한 세부 사항(그리고 어떤 저장소가 이를 제공하는지)과 구성할 수 있는 가능한 환경 변수를 제공합니다.
또는 MySQL 도커 이미지: mysql - Official Image | Docker Hub - 동일한 개념입니다 - 구성할 수 있는 것이 무엇인지 설명하는 가이드입니다 (특히 “Environment Variables” 섹션을 참고하세요).
누구도 "mysql 이미지를 사용하려면 mysql 런처를 사용하여 mysql 이미지를 빌드해야 합니다"라고 말하지 않거나, 레디스의 경우에도 마찬가지입니다 - 이 경우 단순히 기존 이미지를 사용하며, 이것이 도커를 사용하는 핵심과 요점입니다. 그런데 디스커스의 경우 갑자기 이것이 “나쁜” 해결책이 되고, 모든 사람이 "자신의 이미지를 직접 빌드해야 합니다!"라고 외칩니다 – 왜!?
[quote=“wojtek, post:198, topic:33205”]
그냥 그게…[/quote]
아니요. 플러그인 때문입니다.
음… 플러그인에 대해 조금 알아봤는데, 다시 한번 말해야겠지만/인용하자면:
![]()
그래서 제가 해본 것 - 플러그인 섹션으로 가서 설명서와 설치 가이드를 찾아 첫 번째 플러그인을 클릭해 봤습니다 (Plugin directory | Discourse - Civilized Discussion → Sign in with Apple | Discourse - Civilized Discussion → Discourse Apple Authentication → Install plugins on a self-hosted site) 그리고… 아, 정말 - 어떤 복잡하고 엉망진창인지.
도대체 왜 플러그인을 사용하려면 새로운 이미지가 필요합니까? Docker에서는 플러그인을 위한 마운트 디렉토리를 지정하고 그곳에 파일을 두면 됩니다…
저는 Ruby 전문가가 아니므로 여기서는 더 이상한 일이 벌어질 수 있지만, 예를 들어 Java 세계에서는 플러그인인 jar 파일을 그냥 넣으면 로드되어 실행됩니다. 그리고 모든 사용자가 동일한 이미지를 사용하죠…
(어수선하다는 말은 아니고, 왜 이런 구조인지 설명하는 거예요)
Ember의 에셋 파이프라인 때문이에요.
그것도 어수선할 거예요. 왜냐하면 그런 의존성들을 외부에 두는 건 원치 않으니까요.
이것 말입니다: GitHub - ember-engines/ember-asset-loader: Asset loading support for Ember applications · GitHub?
그래서 왜 안 되는 걸까요?
플러그인은 온 더 플라이(on the fly)로 처리될 수 있으며, 플러그인을 업그레이드할 때도 이러한 방식이 사용됩니다. 약간의 마법을 부리면 컨테이너를 재빌드하지 않고도 실행 중인 인스턴스에 새 플러그인을 추가할 수도 있습니다. 따라서 컨테이너에 플러그인 볼륨을 마운트하는 것은 가능할 것입니다(다수의 변경 사항이 필요하지만).
제가 보는 주요 문제는 Discourse 업그레이드와 관련이 있습니다. 현재 실행 중인 인스턴스에서 이 작업을 수행할 수 있습니다. 업그레이드는 기본적으로 Discourse를 재빌드하는 작업입니다. Discourse가 사전 빌드된 이미지에서 가져온 것이라면, 해당 파일을 변경할 수 없습니다. 따라서 거의 또는 전혀 다운타임 없이 업그레이드하려면 상당한 작업이 필요할 것입니다.
이 부분은 제가 잘 이해가 되지 않습니다(아마도 Ruby 관련 맥락이 부족한 것 같습니다…).
일반적으로 docker/컨테이너/오케스트레이션에서는 블루-그린(blue-green) 또는 레드-블랙(red-black) 배포를 사용할 수 있습니다. 이는 새로운 버전의 컨테이너를 준비한 후, 준비가 완료되면 트래픽을 전환하는 방식입니다. 그러나 일반적으로 소규모 배포에서는 이것이 문제가 되지 않는 경우가 많습니다. 대부분의 경우 서비스(컨테이너) 시작 시간이 몇 초에 불과하므로, 버전 전환으로 인한 중단 시간은 최소한으로 유지됩니다(가장 큰 문제는 스키마 업그레이드를 실행해야 한다는 점이지만, 이는 이미지를 다시 빌드하든 말든 관계없이 항상 적용됩니다).
네, 하지만 현재는 그렇게 작동하지 않으니, 바로 그 부분이 개선이 필요합니다. Discourse 관리자 인터페이스 내에서 이 작업을 어떻게 수행할 건지, 그리고 블루 컨테이너를 축소하는 동안 그린 컨테이너를 어떻게 시작할 건지(시스템의 리소스는 무한하지 않으므로, 블루를 시작하기 전에 그린의 유니콘 워커 수를 줄여야 합니다)도 고려해야 합니다. 아니면 그냥 그린을 내려놓고, 이제 블루를 올리는 방식으로 진행해도 됩니다.
기술적 관점과 관리자 관점 모두에서 해결하고 다듬어야 할 부분이 많습니다. 관리자 인터페이스에서 클릭 한 번으로 업그레이드할 수 있는 기능은 매우 가치 있는 기능입니다.
플러그인과 커스텀 이미지는 여전히 빌드가 필요하지만, 바닐라 환경에서 Docker Compose를 활용한 구축은 요즘 들어 점점 현실이 되고 있습니다. 호기심이 있으신 분들을 위해 여기에 작은 개념 검증(Proof of Concept) 실험을 해 두었습니다.
물론 이 저장소들은 모두 제 개인 저장소(Discourse™ 공식 저장소가 아님)이므로, 이는 공식적인 것이 아닙니다. 따라서 결과는 개인마다 다를 수 있으며, 공식적인 지원을 기대해서는 안 됩니다
이미 bitnami 등 비공식적인 방식으로 Discourse를 실행하고 있다는 분들이 있다는 언급이 있어, 이 내용을 공유합니다.
시중에서 구할 수 있는 표준 postgres(또는 pgvector) 이미지는 Discourse와 호환되지 않습니다. Discourse는 기본 설정을 변경해야 하며, 슈퍼유저를 통해 연결하지 않고, 로케일을 지원해야 하며, Discourse 관리자가 덤프/복원 과정을 거치지 않아도 postgres 업그레이드를 지원해야 합니다.
음… 이것은 제가 생각하기에 결정적인 차이점이며, 이 "관리자 인터페이스에서 업데이트"라는 개념은 과거 PHP 인터프리터만 있는 “웹 호스팅” 시절, 모든 것이 그 개념을 중심으로 구축되던 때를 상기시킵니다. 그리고 이것이 Discourse의 작동 방식과 관리 기대치에도 그대로 이어졌다고 생각합니다.
글쎄요, 제가 또 알아차린 점은 discourse가 상당히 무겁다는 것입니다(컨테이너가 시작될 때 무서운 수준으로 리소스를 소비하기 시작했거든요). 그러니까 네 - 이것이 문제가 될 수 있습니다.
Ruby 컨텍스트에서(대부분 컴파일되는 언어가 아닌 인터프리터 언어이므로) 그것들이 어떻게 "빌드"되는 건가요?
오프더셸프(시중 제품) 솔루션을 사용해보는 것이 더 나은 것은 아닌가요? postgres 설정도 단순히 커스텀 postgresql.conf 파일을 제공/마운트함으로써 쉽게 변경할 수 있으므로, 설정이 내장된 완전히 커스텀한 이미지가 필요하지는 않지 않나요… 그리고 설령 그것이 필요하다면, discourse는 매번 다시 빌드하는 대신 가져오기(pull)만 하면 되는 그런 사전 빌드된 이미지를 제공할 수 있을 것입니다…
이 “관리자 업그레이드 인터페이스”는 플러그인(“docker manager”라고 함)입니다. 온라인 업데이트를 수행하는 다른 방법이 있다면 이를 포함할 필요가 없습니다.
