使用 asdf 和 docker-compose 在 macOS 上安装 Discourse 进行开发

注意:本指南针对的是不受支持的开发环境安装。 macOS 的官方支持指南请见 此处(原生)此处(Docker)。请自行承担风险。

本指南的目标是将 PostgreSQL 和 Redis 容器化,但将 Ruby 保留在容器之外。

我曾尝试过 使用 Docker 进行 Discourse 开发 的方案,但在我的机器上速度实在太慢。

接下来我查看了 macOS 上的 Discourse 开发指南。但该脚本首先做的事情就是安装 brewbrew 也许很棒,但我一直使用 MacPorts 很长时间了,并且希望继续成功地抵制安装 brew。此外,该脚本还会全局安装 PostgreSQL 和 Redis 等工具,而我更倾向于能够按项目进行维护。

因此,以下是我使用 asdfdocker-compose 组合后成功的方案。结果是上述两种方法的折中方案:PostgreSQL 和 Redis 通过 docker-compose 在容器中运行,以便将其锁定为 Discourse 在生产环境中使用的官方版本和安装方式。Rails 则直接在宿主机上运行。这种组合对我来说要快得多。效果因人而异(YMMV)。

如果你想跟随操作,需要在机器上安装 asdf 和 Docker。(天哪,asdf 真的非常棒……如果你有兴趣轻松维护多种不同的开发环境,一定要去获取它。它可以替代 renvnvm……似乎除了 jenv 之外的几乎所有工具。)

如果你查看 macOS 安装脚本在做什么,可以将安装内容分为三类:

  • 命令行环境和工具,如 rubyyarn。我们将安装这些工具,并使用 asdf 将其版本锁定到项目目录中。
  • 服务——具体指 PostgreSQL 和 Redis。我们将使用 Docker Compose 安装它们,同样是为了将版本锁定为本项目所需,并拥有一个可以轻松启动和停止的开发环境。
  • 其他——主要是图像处理库(如 ImageMagick)和优化工具。这些可以使用 brewport 或直接源码安装。

我们还需要对开发环境进行轻微的重配置,以便连接到由 docker-compose 运行的 PostgreSQL 服务器。

Discourse 源代码

以下所有步骤都应在你的 Discourse 源代码目录中执行:

git clone https://github.com/discourse/discourse.git && cd discourse

这很重要,因为 asdf 将在此处保存其 .tool-versions 配置文件,而我们也将在此处创建用于 Docker 的 docker-compose.yml 文件。

asdf

我们需要使用 asdf 安装三样东西:rubyyarnpostgres。令人高兴的是,asdf 使得一次性安装所有组件并将版本锁定到项目目录变得非常容易。首先,创建包含以下内容的 .tool-versions 文件:

yarn 1.22.2
ruby 2.6.5
postgres 10.12

接下来只需运行 asdf install

现在你应该能够执行脚本中以及后续说明中包含的 Ruby 库安装步骤:

gem update --system
gem install bundler
gem install rails
gem install mailcatcher
gem install pg -- --with-pg-config=$HOME/.asdf/installs/postgres/10.12/bin/pg_config
bundle install

你可能需要根据 asdf 的安装位置调整 pg_config 的路径。

docker-compose.yml

接下来,我们需要创建配置为启动 Redis 和 PostgreSQL 的 docker-compose.yml 文件。我的文件内容如下:

version: "3"
networks:
  discourse:
    driver: bridge
services:
  data:
    image: "geoffreychallen/discourse_data:latest"
    command: /sbin/boot
    ports:
      - "5432:5432"
      - "6379:6379"
    volumes:
      - "data_shared:/shared/"
      - "data_logs:/var/log/"
    networks:
      - discourse
volumes:
  data_shared:
    driver: local
  data_logs:
    driver: local

感谢 @pfaffman 建议使用标准的 Discourse 数据容器。geoffreychallen/discourse_data:latest 基于 Discourse Docker 构建。我使用了示例 data.yml 文件,但做了两处修改。首先,我将 discourse 用户的密码设置为 discourse。其次,我将该用户设为超级用户,以便它可以创建测试数据库。以下是我的 data.yml 文件中的 hooks 部分:

hooks:
  after_postgres:
    - exec:
        stdin: |
          alter user discourse with password 'discourse';
        cmd: sudo -u postgres psql discourse
        raise_on_fail: false
    - exec:
        stdin: |
          alter user "discourse" with superuser;
        cmd: sudo -u postgres psql discourse
        raise_on_fail: false

再次强调,这只是为了以防你想构建自己的 Discourse 数据容器而不使用我的。请勿在生产环境中使用此容器——它完全不安全!

在此配置中,我们暴露了标准的 PostgreSQL 和 Redis 端口,并运行容器启动所需的 boot 命令。

一旦你的 docker-compose.yml 就位,就可以试运行一下:

docker-compose up

假设配置正确,你应该会看到 Redis 和 PostgreSQL 启动。按 Control-C 取消,或者如果由于某种原因无法干净关闭,请运行 docker-compose down

miscellaneous 库

大多数图像优化库可以使用 portbrew 安装。以下是使用 port 的方法:

sudo port install imagemagick pngquant optipng jhead jpegoptim gifsicle

svgo 可以在安装 npm 后安装。我不打算详细说明,因为这非常简单。

顺便一提,据我所知,这些工具都不是必需的。我在后续的各种步骤中看到过关于它们缺失的警告,但似乎并没有导致任何严重问题。

config/database.ymlspec/fixtures/multisite/two_dbs.yml

最后,我们需要对开发环境进行轻微重配置,以便正确连接到 PostgreSQL。默认情况下,它尝试使用 Unix socket,而我们的容器并未导出该 socket。

要修复此问题,你需要修改 config/database.yml。基本上,将所有出现以下内容的地方:

adapter: postgresql

替换为:

adapter: postgresql
host: localhost
username: discourse
password: discourse

添加 host 会使 Discourse 不使用 socket,而 usernamepassword 会使 Discourse 使用默认的 Discourse 数据库用户以及我们上面设置的密码进行连接。

我不得不在 config/database.yml 中进行三次此更改:一次在 development 下,一次在 test 下,最后一次在 profile 下。为了让测试套件正常工作,我还不得不在 spec/fixtures/multisite/two_dbs.yml 中进行类似的更改。

开始吧…

好了,让我们开始吧!在一个窗口中使用 docker-compose 启动开发环境:

docker-compose up

在第二个窗口中,让我们运行数据库设置步骤:

bundle exec rake db:create

假设这步成功了,你现在可以在 brew 基础的 macOS 指南 中的相应位置继续操作。

当你完成工作后,停止 docker-compose,你就可以将开发环境保存起来,留待下次使用。

如果你想永久删除数据库和 Redis 的内容,只需运行 docker-compose down -v 以清除持久卷以及容器本身。但如果没有 -v 标志,docker-compose down 将在开发会话之间保留你的数据库。

测试能通过吗?

我的设置有两个测试用例失败了:

Failures:

  1) UploadCreator#create_for pngquant should apply pngquant to optimized images
     Failure/Error: expect(upload.filesize).to eq(9558)

       expected: 9558
            got: 9550

       (compared using ==)
     # ./spec/lib/upload_creator_spec.rb:115:in `block (4 levels) in <main>'

  2) tasks/uploads uploads:secure_upload_analyse_and_update when store is external when secure media is enabled rebakes the posts attached
     Failure/Error: expect(post1.reload.baked_at).not_to eq(post1_baked)

       expected: value != 2020-03-08 03:20:01.777117000 +0000
            got: 2020-03-08 03:20:01.777117000 +0000

       (compared using ==)

       Diff:
         <The diff is empty, are your objects producing identical `#inspect` output?>
     # ./spec/tasks/uploads_spec.rb:90:in `block (5 levels) in <main>'

Finished in 19 minutes 21 seconds (files took 13.67 seconds to load)
4297 examples, 2 failures, 11 pending

对我来说,第一个看起来像是 pngquant 的工作效果比预期的要好。我不确定为什么这代表失败。第二个我也不太理解。但这在我看来是合理的。

祝你编码愉快!

5 个赞