Phabricator 切换使用 Bitnami 容器镜像

894 阅读4分钟

分享如何将自定义容器镜像切换到 Bitnami 容器镜像,以及如何搭配反向代理软件(如 Traefik)配置使用。

写在前面

去年曾分享过一篇关于 Phabricator 的内容,《使用 Docker 和 Traefik v2 搭建 Phabricator》,当时介绍了如何构建自定义的容器镜像,以及如何搭配汉化补丁使用应用。

时隔一年,伴随着软硬件升级,Phabricator 的服务迁移也被提上了日程。

考虑到尽可能省心的长期使用,我选择将镜像切换至了 Bitnami 的镜像,这样可以使用到每小时都由 GitHub 构建的透明可信的镜像,以及更少的操心各种安全补丁和升级的事情。

梳理问题

Bitnami 的镜像提供非常多的环境变量配置,用来应对各种场景。然而针对以下两个场景的支持缺不够完善:

  • 使用已有数据库运行软件,而非从零到一进行初始化。
  • 使用反向代理服务,而非直接提供服务。

收集线索

浏览仓库代码中的 Dockerfile ,可以看到项目启动前的入口脚本和预执行脚本各有一个文件:

ENTRYPOINT [ "/opt/bitnami/scripts/phabricator/entrypoint.sh" ]
CMD [ "/opt/bitnami/scripts/phabricator/run.sh" ]

观察 entrypoint.sh 脚本,可以看到这个脚本调用了 Web 服务器、数据库、以及应用初始化相关的脚本。

#!/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 翻阅,可以看到除了一些检查环境就绪与否的准备工作外,还可以找到两个基础依赖:

...

# Load libraries
. /opt/bitnami/scripts/libphabricator.sh
. /opt/bitnami/scripts/libwebserver.sh

...

继续翻阅 /opt/bitnami/scripts/libphabricator.sh 这个脚本,会看到这个脚本真正定义了 phabricator 所有的应用配置,有一部分和容器环境变量(包含未被文档说明的),也和这个脚本进行了绑定,所以从这里入手进行修改,再合适不过了。

调整脚本:添加时区设置

如果想让 phabricator 时间展示正确,需要进行时区设置,我们找到 phabricator_initialize 函数,在其中添加对 phabricator.timezone 的设置:

########################
# 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 配置项目进行更新,如果你没有设置过,需要将这个项目删除或注释掉,避免应用启动之后找不到之前的数据:

#########################
# 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"
}

调整编排文件:设置数据库

因为我们要直接使用老数据库,所以这里不能让脚本运行“数据库初始化”那一套流程,需要针对编排文件进行环境变量设置,让脚本认为数据库结构已就绪,不需要进行初始化,并且使用已有的数据库配置提供服务:

...
    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_hostphabricator_configure_alternate_file_domain 函数,让应用能够在运行在非 HTTPS 状况下,将页面链接渲染为 https:// 协议。

#########################
# 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}"
}

编排文件对应的配置也需要声明:

...
    environment:
      ...
      - PHABRICATOR_ENABLE_HTTPS=false
      - PHABRICATOR_HOST=board.lab.com
      - PHABRICATOR_ALTERNATE_FILE_DOMAIN=board-file.lab.com
      ...

完整的容器编排配置

将上面提到的内容更新到 libphabricator.sh 中,然后编写容器编排配置文件:

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中的方式进行用户密码重置,以用户名 soulteary 为例,执行下面的脚本,可以快速获得密码重置链接:

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


我们有一个小小的折腾群,里面聚集了一些喜欢折腾的小伙伴。

在不发广告的情况下,我们在里面会一起聊聊软硬件、HomeLab、编程上的一些问题,也会在群里不定期的分享一些技术沙龙的资料。

喜欢折腾的小伙伴欢迎扫码添加好友。(请注明来源和目的,备注实名,否则不会通过审核)

关于折腾群入群的那些事


本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

本文作者: 苏洋

创建时间: 2021年04月18日 统计字数: 7591字 阅读时间: 16分钟阅读 本文链接: soulteary.com/2021/04/18/…