本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 [署名 4.0 国际 (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/deed.zh) 本文作者: 苏洋 创建时间: 2021年04月18日 统计字数: 7591字 阅读时间: 16分钟阅读 本文链接: https://soulteary.com/2021/04/18/phabricator-switched-to-bitnami-docker-image.html ----- # Phabricator 切换使用 Bitnami 容器镜像 分享如何将自定义容器镜像切换到 Bitnami 容器镜像,以及如何搭配反向代理软件(如 Traefik)配置使用。 ## 写在前面 去年曾分享过一篇关于 Phabricator 的内容,[《使用 Docker 和 Traefik v2 搭建 Phabricator》](https://soulteary.com/2020/02/02/phabricator-with-docker-and-traefik-v2.html),当时介绍了如何构建自定义的容器镜像,以及如何搭配汉化补丁使用应用。 时隔一年,伴随着软硬件升级,Phabricator 的服务迁移也被提上了日程。 考虑到尽可能省心的长期使用,我选择将镜像切换至了 Bitnami 的镜像,这样可以使用到每小时都由 GitHub 构建的透明可信的镜像,以及更少的操心各种安全补丁和升级的事情。 ## 梳理问题 Bitnami 的镜像提供非常多的环境变量配置,用来应对各种场景。然而针对以下两个场景的支持却不够完善: - 使用已有数据库运行软件,而非从零到一进行初始化。 - 使用反向代理服务,而非直接提供服务。 ## 收集线索 浏览仓库代码中的 [Dockerfile](https://github.com/bitnami/bitnami-docker-phabricator/blob/master/2021/debian-10/Dockerfile) ,可以看到项目启动前的入口脚本和预执行脚本各有一个文件: ```bash ENTRYPOINT [ "/opt/bitnami/scripts/phabricator/entrypoint.sh" ] CMD [ "/opt/bitnami/scripts/phabricator/run.sh" ] ``` 观察 `entrypoint.sh` 脚本,可以看到这个脚本调用了 Web 服务器、数据库、以及应用初始化相关的脚本。 ```bash #!/bin/bash # shellcheck disable=SC1091 set -o errexit set -o nounset set -o pipefail # set -o xtrace # Uncomment this line for debugging purpose # Load Phabricator environment . /opt/bitnami/scripts/phabricator-env.sh # Load libraries . /opt/bitnami/scripts/libbitnami.sh . /opt/bitnami/scripts/liblog.sh . /opt/bitnami/scripts/libwebserver.sh print_welcome_page if [[ "$1" = "/opt/bitnami/scripts/phabricator/run.sh" || "$1" = "/opt/bitnami/scripts/$(web_server_type)/run.sh" || "$1" = "/opt/bitnami/scripts/nginx-php-fpm/run.sh" ]]; then info "** Starting Phabricator setup **" /opt/bitnami/scripts/"$(web_server_type)"/setup.sh /opt/bitnami/scripts/php/setup.sh /opt/bitnami/scripts/mysql-client/setup.sh /opt/bitnami/scripts/phabricator/setup.sh /post-init.sh info "** Phabricator setup finished! **" fi echo "" exec "$@" ``` 其中有一个脚本路径 `/opt/bitnami/scripts/phabricator/setup.sh` 比较可疑,对这个脚本进行 `phabricator/setup.sh` 翻阅,可以看到除了一些检查环境就绪与否的准备工作外,还可以找到两个基础依赖: ```bash ... # Load libraries . /opt/bitnami/scripts/libphabricator.sh . /opt/bitnami/scripts/libwebserver.sh ... ``` 继续翻阅 `/opt/bitnami/scripts/libphabricator.sh` 这个脚本,会看到这个脚本真正定义了 phabricator 所有的应用配置,有一部分和容器环境变量(包含未被文档说明的),也和这个脚本进行了绑定,所以从这里入手进行修改,再合适不过了。 ## 调整脚本:添加时区设置 如果想让 phabricator 时间展示正确,需要进行时区设置,我们找到 `phabricator_initialize` 函数,在其中添加对 `phabricator.timezone` 的设置: ```bash ######################## # Ensure Phabricator is initialized # Globals: # PHABRICATOR_* # Arguments: # None # Returns: # None ######################### phabricator_initialize() { # Check if Phabricator has already been initialized and persisted in a previous run local -r app_name="phabricator" local -r port="${WEB_SERVER_HTTP_PORT_NUMBER:-"$WEB_SERVER_DEFAULT_HTTP_PORT_NUMBER"}" if ! is_app_initialized "$app_name"; then info "Creating Phabricator configuration file" # Modified by @soulteary phabricator_conf_set "phabricator.timezone" "Asia/Shanghai" ``` ## 调整脚本:更新数据库命名空间 找到 `phabricator_configure_database_credentials` 函数,对 `storage.default-namespace` 配置项目进行更新,如果你没有设置过,需要将这个项目删除或注释掉,避免应用启动之后找不到之前的数据: ```bash ######################### # Configure Phabricator database # Globals: # PHABRICATOR_* # Arguments: # $1 - database user name # $2 - database user password # Returns: # None ######################### phabricator_configure_database_credentials() { local -r db_user="${1:?missing database user}" local -r db_pass="${2:?missing database password}" info "Configuring database" phabricator_conf_set "mysql.host" "$PHABRICATOR_DATABASE_HOST" phabricator_conf_set "mysql.port" "$PHABRICATOR_DATABASE_PORT_NUMBER" phabricator_conf_set "mysql.user" "$db_user" phabricator_conf_set "mysql.pass" "$db_pass" # Modified by @soulteary # phabricator_conf_set "storage.default-namespace" "bitnami_phabricator" phabricator_conf_set "storage.mysql-engine.max-size" "0" } ``` ## 调整编排文件:设置数据库 因为我们要直接使用老数据库,所以这里不能让脚本运行“数据库初始化”那一套流程,需要针对编排文件进行环境变量设置,让脚本认为数据库结构已就绪,不需要进行初始化,并且使用已有的数据库配置提供服务: ```yaml ... environment: ... # 需要和 PHABRICATOR_SKIP_BOOTSTRAP 一起使用,否则还需要设置更多的冗余内容 - ALLOW_EMPTY_PASSWORD=yes - PHABRICATOR_SKIP_BOOTSTRAP=yes - PHABRICATOR_DATABASE_HOST=database - PHABRICATOR_DATABASE_PORT_NUMBER=3306 - PHABRICATOR_EXISTING_DATABASE_USER=root - PHABRICATOR_EXISTING_DATABASE_PASSWORD=QV8}!P![&QmR ... ``` ## 调整脚本:调整应用链接以支持反向代理 为了能够支持反向代理环境,尤其是支持由反向代理网关提供“HTTPS”协议访问的能力,我们需要修改 `phabricator_configure_host` 和 `phabricator_configure_alternate_file_domain` 函数,让应用能够在运行在非 HTTPS 状况下,将页面链接渲染为 `https://` 协议。 ```bash ######################### # Configure Phabricator host # Globals: # PHABRICATOR_* # Arguments: # None # Returns: # None ######################### phabricator_configure_host() { local host local scheme get_hostname() { if [[ -n "${PHABRICATOR_HOST:-}" ]]; then echo "$PHABRICATOR_HOST" else dns_lookup "$(hostname)" "v4" fi } host="$(get_hostname)" if is_boolean_yes "$PHABRICATOR_ENABLE_HTTPS"; then scheme="https" [[ "$PHABRICATOR_EXTERNAL_HTTPS_PORT_NUMBER" != "443" ]] && host+=":${PHABRICATOR_EXTERNAL_HTTPS_PORT_NUMBER}" else scheme="http" [[ "$PHABRICATOR_EXTERNAL_HTTP_PORT_NUMBER" != "80" ]] && host+=":${PHABRICATOR_EXTERNAL_HTTP_PORT_NUMBER}" fi info "Configuring Phabricator URL to ${scheme}://${host}" # Modified by @soulteary scheme="https" phabricator_conf_set "phabricator.base-uri" "${scheme}://${host}" } ######################### # Configure Phabricator alternate file domain # Globals: # PHABRICATOR_* # Arguments: # None # Returns: # None ######################### phabricator_configure_alternate_file_domain() { local afd="$PHABRICATOR_ALTERNATE_FILE_DOMAIN" local scheme if is_boolean_yes "$PHABRICATOR_ENABLE_HTTPS"; then scheme="https" [[ "$PHABRICATOR_EXTERNAL_HTTPS_PORT_NUMBER" != "443" ]] && afd+=":${PHABRICATOR_EXTERNAL_HTTPS_PORT_NUMBER}" else scheme="http" [[ "$PHABRICATOR_EXTERNAL_HTTP_PORT_NUMBER" != "80" ]] && afd+=":${PHABRICATOR_EXTERNAL_HTTP_PORT_NUMBER}" fi # Modified by @soulteary scheme="https" info "Configuring Phabricator Alternate File Domain to ${scheme}://${afd}" phabricator_conf_set "security.alternate-file-domain" "${scheme}://${afd}" } ``` 编排文件对应的配置也需要声明: ```yaml ... environment: ... - PHABRICATOR_ENABLE_HTTPS=false - PHABRICATOR_HOST=board.lab.com - PHABRICATOR_ALTERNATE_FILE_DOMAIN=board-file.lab.com ... ``` ## 完整的容器编排配置 将上面提到的内容更新到 `libphabricator.sh` 中,然后编写容器编排配置文件: ```yaml version: '3.7' services: phabricator: image: bitnami/phabricator:2021.13.0 expose: - 8080 environment: - APACHE_HTTP_PORT_NUMBER=8080 - PHABRICATOR_ENABLE_HTTPS=false - PHABRICATOR_HOST=board.lab.com - PHABRICATOR_ALTERNATE_FILE_DOMAIN=board-file.lab.com - ALLOW_EMPTY_PASSWORD=yes - PHABRICATOR_SKIP_BOOTSTRAP=yes - PHABRICATOR_DATABASE_HOST=board.data.lab.com - PHABRICATOR_DATABASE_PORT_NUMBER=3306 - PHABRICATOR_EXISTING_DATABASE_USER=root - PHABRICATOR_EXISTING_DATABASE_PASSWORD=QV8}!P![&QmR - PHABRICATOR_ENABLE_PYGMENTS=true networks: - traefik labels: - "traefik.enable=true" - "traefik.docker.network=traefik" - "traefik.http.routers.phab0.middlewares=https-redirect@file" - "traefik.http.routers.phab0.entrypoints=http" - "traefik.http.routers.phab0.rule=Host(`board.lab.com`, `board-file.lab.com`, `phabricator.lab.io`, `phabricator-file.lab.io`)" - "traefik.http.routers.phab1.middlewares=content-compress@file" - "traefik.http.routers.phab1.entrypoints=https" - "traefik.http.routers.phab1.tls=true" - "traefik.http.routers.phab1.rule=Host(`board.lab.com`, `board-file.lab.com`, `phabricator.lab.io`, `phabricator-file.lab.io`)" - "traefik.http.services.phabbackend.loadbalancer.server.scheme=http" - "traefik.http.services.phabbackend.loadbalancer.server.port=8080" volumes: - ./libphabricator.sh:/opt/bitnami/scripts/libphabricator.sh:ro networks: traefik: external: true ``` 将上面的内容保存为 `docker-compose.yml`, 使用 `docker-compose up -d`,即可将应用启动起来了。 ## 重设用户密码 在切换数据库和应用版本后,我们可能会遇到用户无法登陆的状况。 这里可以采取[官方issue](https://secure.phabricator.com/D18901)中的方式进行用户密码重置,以用户名 `soulteary` 为例,执行下面的脚本,可以快速获得密码重置链接: ```bash docker-compose exec phabricator /opt/bitnami/phabricator/bin/auth recover soulteary Use this link to recover access to the "soulteary" account from the web interface: https://board.lab.com/login/once/recover/1/eedkghmtxrvkktaqof7di54n5lkabcd/ After logging in, you can use the "Auth" application to add or restore authentication providers and allow normal logins to succeed. ``` 访问链接,即可重置密码,再次登陆应用中。 ## 最后 这篇关于 Phabricator 切换 Bitnami 镜像的内容,就先写到这里。 --EOF