Discourse에서 부트스트랩 실패 문제 해결

새로운 “pre-bundling” 프로세스에서 여전히 어려움을 겪고 있습니다. 테스트 인스턴스에서 부트스트랩이 실패하는데 그 이유를 모르겠습니다. 참고로 외부 postgres 데이터베이스가 있는 설정입니다. 컨테이너들은 haproxy 뒤에서 ssl 가속기로 실행됩니다. 여기서는 web_only 컨테이너만 부트스트랩합니다. 현재 빌드 버전(부트스트랩 이전)은 3.5.0.beta8-dev이며, Commits · discourse/discourse · GitHub 입니다.

현재 실패하는 yml 파일은 다음과 같습니다:

# IMPORTANT: SET A SECRET PASSWORD in Postgres for the Discourse User
# TODO: change SOME_SECRET in this template

templates:
  - "templates/web.template.yml"
  ## Uncomment the next line to enable the IPv6 listener
  #- "templates/web.ipv6.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"
  ## Uncomment these two lines if you wish to add Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

## which TCP/IP ports should this container expose?
## If you want Discourse to share a port with another webserver like Apache or nginx,
## see https://meta.discourse.org/t/17247 for details
expose:
  - "80:80"   # http
  - "443:443" # https

# Use 'links' key to link containers together, aka use Docker --link flag.
links:
  - link:
      name: redis
      alias: data

# any extra arguments for Docker?
# docker_args:

params:
  ## Which Git revision should this container use? (default: tests-passed)
  #version: tests-passed

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8
  DISCOURSE_DEFAULT_LOCALE: de

  ## How many concurrent web requests are supported? Depends on memory and CPU cores.
  ## will be set automatically by bootstrap based on detected CPUs, or you can override
  UNICORN_WORKERS: 4

  ## TODO: The domain name this Discourse instance will respond to
  DISCOURSE_HOSTNAME: 'forum2.netzwissen.de'

  ## Uncomment if you want the container to be started with the same
  ## hostname (-h option) as specified above (default "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: List of comma delimited emails that will be made admin and developer
  ## on initial signup example 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'admin@netzwissen.de'

  ## TODO: The SMTP mail server used to validate new accounts and send notifications
  # SMTP ADDRESS, username, and password are required
  # WARNING the char '#' in SMTP password can cause problems!
  DISCOURSE_SMTP_ADDRESS: mail.netzwissen.de
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: discourse@netzwissen.de
  DISCOURSE_SMTP_PASSWORD: [xxxxxxxxxxxxxxxxx}
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (optional, default true)
  #DISCOURSE_SMTP_DOMAIN: discourse.example.com    # (required by some providers)
  DISCOURSE_NOTIFICATION_EMAIL: discourse@netzwissen.de    # (address to send notifications from)

  ## If you added the Lets Encrypt template, uncomment below to get a free SSL certificate
  #LETSENCRYPT_ACCOUNT_EMAIL: me@example.com

## configure connectivity to the databases
  DISCOURSE_DB_SOCKET: ''
  DISCOURSE_DB_USERNAME: [xxxxxxxxxxx]
  DISCOURSE_DB_NAME: [xxxxxxxxxxxxxxx]
  DISCOURSE_DB_HOST: [xxxxxxxxxxxxxxx]
  DISCOURSE_DB_PASSWORD: [xxxxxxxxxxxxxxx]
  ## redis caching on the neighbouring container
  DISCOURSE_REDIS_HOST: redis

  ## The http or https CDN address for this Discourse instance (configured to pull)
  ## see https://meta.discourse.org/t/14857 for details
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

  ## The maxmind geolocation IP account ID and license key for IP address lookups
  ## see https://meta.discourse.org/t/-/173941 for details
  #DISCOURSE_MAXMIND_ACCOUNT_ID: 123456
  #DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456

volumes:
  - volume:
      host: /mnt/data/discourse/shared/web-only
      guest: /shared
  - volume:
      host: /mnt/data/discourse/shared/web-only/log/var-log
      guest: /var/log

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-shared-edits.git
# some plugins are removed, as they are now bundled with core
# https://meta.discourse.org/t/bundling-more-popular-plugins-with-discourse-core/373574
## = now bundled
##          - git clone https://github.com/discourse/discourse-chat-integration.git
##          - git clone https://github.com/discourse/discourse-openid-connect.git
##          - git clone https://github.com/discourse/discourse-calendar.git
##          - git clone https://github.com/angusmcleod/discourse-events.git
##          - git clone https://github.com/discourse/discourse-data-explorer.git
##          - git clone https://github.com/discourse/discourse-reactions.git
##          - git clone https://github.com/discourse/discourse-chat.git
##          - git clone https://github.com/discourse/discourse-ai.git
##          - git clone https://github.com/discourse/discourse-topic-voting.git
##          - git clone https://github.com/discourse/discourse-post-voting.git
##          - git clone https://github.com/discourse/discourse-user-notes.git
##          - git clone https://github.com/discourse/discourse-solved.git
          - git clone https://github.com/discourse/discourse-docs-card-filter.git
          - git clone https://github.com/discourse/discourse-doc-categories.git
##          - git clone https://github.com/discourse/discourse-assign.git
##          - git clone https://github.com/discourse/discourse-templates.git
          - git clone https://github.com/discourse/discourse-saved-searches.git
          - git clone https://github.com/discourse/discourse-tooltips.git
          - git clone https://github.com/discourse/discourse-category-experts.git
          - git clone https://github.com/discourse/discourse-activity-pub.git
          - git clone https://github.com/discourse/discourse-follow.git
          - git clone https://github.com/nathan-nz/discourse-wikified-posts.git
          - git clone https://github.com/discourse/discourse-whos-online.git
          - git clone https://github.com/merefield/discourse-workflow.git

## Remember, this is YAML syntax - you can only have one block with a name
run:
  - exec: echo "Beginning of custom commands"

  ## If you want to configure password login for root, uncomment and change:
  ## Use only one of the following lines:
  #- exec: /usr/sbin/usermod -p 'PASSWORD_HASH' root
  - exec: /usr/sbin/usermod -p "$(mkpasswd -m sha-256 'xxxxxxxxxxxxxxx')" root

## for operation behind haproxy load balancer with local nginx on the container host 
  - replace:
      filename: /etc/nginx/conf.d/discourse.conf
      from: "types {"
      to: |
        set_real_ip_from 127.0.0.1/24;
        set_real_ip_from 10.0.0.0/24;
        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
        proxy_set_header Host $http_host;
        proxy_set_header X-Request-Start “t=${msec}”;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https; # replaced $thescheme;
        proxy_set_header X-Real-IP $remote_addr;
        types {

  ## If you want to authorized additional users, uncomment and change:
  #- exec: ssh-import-id username
  #- exec: ssh-import-id anotherusername

  - exec: echo "End of custom commands"
  - exec: awk -F\# '{print $1;}' ~/.ssh/authorized_keys | awk 'BEGIN { print "Authorized SSH keys for this container:"; } NF>=2 {print $NF;}'

ymll 파일에 rm -rf 블록을 추가해도 마찬가지입니다:

- rm -rf discourse-chat-integration  
- rm -rf discourse-openid-connect         
- rm -rf discourse-calendar         
- rm -rf discourse-events         
- rm -rf discourse-data-explorer         
- rm -rf discourse-reactions         
- rm -rf discourse-chat         
- rm -rf discourse-ai         
- rm -rf discourse-topic-voting         
- rm -rf discourse-post-voting         
- rm -rf discourse-user-notes         
- rm -rf discourse-solved         
- rm -rf discourse-assign         
- rm -rf discourse-templates

부트스트랩은 여전히 다음과 같이 실패합니다.

/usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups.rb
/usr/local/bin/pups --stdin

FAILED
--------------------
Pups::ExecError: cd /var/www/discourse && su discourse -c 'bundle exec rake db:migrate' failed with return #<Process::Status: pid 669 exit 1>
Location of failure: /usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups/exec_command.rb:131:in `spawn'
exec failed with the params {"cd"=>"$home", "tag"=>"migrate", "hook"=>"db_migrate", "cmd"=>["su discourse -c 'bundle exec rake db:migrate'"]}

이것은 “bundle exec rake db:migrate”에서 데이터베이스 마이그레이션 오류로 해석됩니다. 하지만 여기서는 근본 원인이 무엇일까요? discourse2 데이터베이스에는 이전에 이미 설치된 discourse-ai 플러그인에 필요했던 vector 확장이 이미 있기 때문입니다:

postgres=# \c discourse2  
psql (15.12 (Ubuntu 15.12-1.pgdg22.04+1), server 13.20 (Ubuntu 13.20-1.pgdg22.04+1))  
You are now connected to database "discourse2" as user "postgres".  
discourse2=# \dx  
                                   List of installed extensions  
  Name   | Version |   Schema   |                            Description                               
----------+---------+------------+-------------------------------------------------------------------  
hstore   | 1.7     | public     | data type for storing sets of (key, value) pairs  
pg_trgm  | 1.5     | public     | text similarity measurement and index searching based on trigrams  
plpgsql  | 1.0     | pg_catalog | PL/pgSQL procedural language  
unaccent | 1.1     | public     | text search dictionary that removes accents  
vector   | 0.8.0   | public     | vector data type and ivfflat and hnsw access methods  
(5 rows)

나중에 yml 파일에서 “git clone” 줄들이 모두 주석 처리되어 있음에도 불구하고 플러그인 힌트를 확인했습니다:

---
HINT: The plugin 'discourse-openid-connect' is now bundled with Discourse and should not be included in your container configuration.
Remove the line 'git clone https://github.com/discourse/discourse-openid-connect' from your containers/web_only.yml file, then try again.
For more information, see https://meta.discourse.org/t/373574
---

솔직히 지금은 좀 헤매고 있습니다 ::sleepy_face: …

free -h는 무엇을 반환합니까?

root@docker3a:/var/discourse/containers# free -h
총합 사용량 가용량 공유메모리 버퍼/캐시 사용 가능
메모리: 3,8Gi 2,0Gi 1,1Gi 3,8Mi 969Mi 1,8Gi

아마도 4GB의 스와프가 필요할 것입니다.

죄송합니다. 제 실수였는데, 출력이 잘렸습니다.

root@docker3a:~# free -h
총합 사용량 가용 공유 버퍼/캐시 사용 가능
메모리: 3,8Gi 2,0Gi 1,1Gi 3,8Mi 971Mi 1,8Gi
스왑: 974Mi 0B 974Mi

VM에는 이미 4GB의 메모리가 있습니다. 2GB를 추가로 늘리고 ./launcher rebuild web_only^를 다시 실행해 보았지만 동일한 오류가 발생했습니다. 따라서 여기서는 공간 관련 빌드 문제가 아닐 것 같아 보입니다 …

음, 8GB RAM에서 2GB의 스왑이 필요했어요.

8GB RAM로 다시 시도해 보았지만, 동일한 오류가 발생했습니다. 참고로 이것은 Proxmox 호스트(Features - Proxmox Virtual Environment)에서 실행되는 커널 기반 가상 머신(KVM)입니다.

QEMU/KVM 게스트는 게스트 운영체제가 필요할 때 호스트에서 메모리를 요청하지만, 게스트 운영체제가 더 이상 메모리를 필요로 하지 않는다고 해서 호스트로 메모리를 자동으로 반환하지는 않습니다. 호스트가 메모리를 필요로 할 경우, 커널은 프로세스에게 사용하지 않는 RAM을 반환하도록 요청합니다. 이때 QEMU가 일부 메모리를 회수하려고 시도하지만, 게스트 운영체제가 먼저 메모리를 해제해야 하므로 그 여부는 게스트 운영체제에 달려 있습니다.

저는 4GB RAM과 4 CPU 설정으로 메모리 문제를 겪은 적이 없었으며, discourse-ai 플러그인을 사용할 때도 마찬가지였습니다. 부팅 문제는 이 번들링 발표 이후에만 발생하기 시작했습니다…

잠깐, 이 discourse-openid-connect 플러그인이 yml 파일 어딘가에 있나요?

마이그레이션 중 발생하는 문제입니다. 마이그레이션에 실패한 부분이 무엇인지 찾아보기 위해 위로 스크롤해 볼 수 있을까요?

잠깐, 이 discourse-openid-connect 플러그인이 yml 파일 어디에 있나요?

마이그레이션 중 발생하는 문제인데, 마이그레이션에 실패한 부분을 찾도록 위로 스크롤해 볼 수 있나요?

지금까지 discourse-openid-connect를 플러그인 목록에 포함하고 있었습니다. "포스트 번들링 빌드(post-bundling build)"를 위해 제거했습니다. 이제 빌드 yml에는 다음 플러그인만 남아 있습니다:

## non-bundled plugins
- git clone https://github.com/discourse/docker_manager.git\`

  • git clone https://github.com/discourse/discourse-shared-edits.git
  • git clone https://github.com/discourse/discourse-docs-card-filter.git
  • git clone https://github.com/discourse/discourse-doc-categories.git
  • git clone https://github.com/discourse/discourse-saved-searches.git
  • git clone https://github.com/discourse/discourse-tooltips.git
  • git clone https://github.com/discourse/discourse-category-experts.git
  • git clone https://github.com/discourse/discourse-activity-pub.git
  • git clone https://github.com/discourse/discourse-follow.git
  • git clone ``https://github.com/nathan-nz/discourse-wikified-posts.git
  • git clone https://github.com/discourse/discourse-whos-online.git
  • git clone ``https://github.com/merefield/discourse-workflow.git\`

빌드가 ‘bundle exec rake db:migrate’에서 충돌하는 것 같습니다. 하지만 그 위 몇 줄을 보면 다음과 같은 메시지가 보입니다.

Gem::LoadError: can't activate multipart-post-2.4.0, already activated multipart-post-2.4.1 (Gem::LoadError)

…

discourse-wikified-posts is already at latest compatible version discourse-workflow is already at latest compatible version docker_manager is already at latest compatible version I,
[2025-07-28T06:34:13.916393 #1] INFO -- : > cd /var/www/discourse && su discourse -c 'bundle exec rake db:migrate' rake aborted! Gem::LoadError: can't activate multipart-post-2.4.0, already activated multipart-post-2.4.1 (Gem::LoadError) /var/www/discourse/lib/plugin_gem.rb:25:in `load' /var/www/discourse/lib/plugin/instance.rb:861:in `gem' […]

저는 ruby에 대해 잘 모르지만, multipart-post-2.4.0과 multipart-post-2.4.1 사이의 패키지 충돌일까요?

감사합니다!
Thommie

그것이 원인이었고, 내 빌드 두 개가 실패했습니다. CDCK의 플러그인 중 적어도 하나는 이제 업데이트되었을 수 있는 multipart-post의 오래된 버전을 사용하고 있었습니다.

이렇게 쓸모없는 추가 플러그인을 사용하지 않았음에도 불구하고, 이 문제 때문에 제 플러그인 다섯 개를 업데이트하여 해당 지엄의 버전을 되돌려야 했습니다. 이번 업데이트를 위해 이 과정을 처음부터 다시 반복해야 할 것 같습니다.

정말 짜증나고, 이 변경 사항에 대해 전혀 좋아하지 않습니다.

의존성이 다시 업데이트될 때까지 워크플로우를 제거해야 합니다.

이것은 시스템이 설계대로 작동하고 있는 것입니다.

Gemfile과 Gemfile.lock을 사용하여 gem 의존성을 관리하고, dependbot으로 업데이트를 스캔하며, 내부 프로세스를 통해 최신 상태를 유지합니다.

플러그인 디자이너로서 이제 코어에 포함된 gem 의존성에 의존할 수 있습니다.

즉, 플러그인의 plugin.rb에서 multipart-post를 삭제하고, 사용하는 위치에서 단순히 require하면 됩니다.

플러그인 개발자가 신경 쓸 일이 하나 줄어든 것입니다.

유용한 피드백 감사합니다.

@Thomas_Rother 플러그인에서 의존성(그리고 또 다른 하나)을 제거했으니, 빌드를 다시 시도해 보세요.

@merefield @sam :smiley: - 성공!! 로버트의 플러그인 GitHub - merefield/discourse-process-manager: A process management plugin for Discourse that moves work through configurable steps with actions, list filters, charts, swim-lane views, and Kanban boards. · GitHub 의 커밋 6be7a44 덕분에 빌드가 성공적으로 완료되었습니다. 분석과 수정에 감사드립니다!