如何以分离模式将 Bitbucket 服务器作为容器启动?

How to start Bitbucket server as a container in detached mode?

关于如何 运行 处于分离模式的容器存在许多问题。

我的问题有点特定于 运行在分离模式容器中使用 Atlassian Bitbucket 服务器。

我尝试将下面的内容作为我的 dockerfile 的最后一层,当我 运行 带有 -d 的容器时,进程未启动

运行 /opt/atlassian-bitbucket/bin/start-bitbucket.sh

我试过像下面那样使用 ENTRYPOINT

入口点 ["/opt/atlassian-bitbucket/bin/start-bitbucket.sh"]

但容器总是在启动脚本完成后退出。

不确定是否有人在容器中设置了 Bitbucket 数据中心,但我很想知道他们如何拥有 运行 同一图像的多个容器并使它们加入单个集群。

查看官方docker图片:https://hub.docker.com/r/atlassian/bitbucket-server/

只是 运行:

docker run -v /data/bitbucket:/var/atlassian/application-data/bitbucket --name="bitbucket" -d -p 7990:7990 -p 7999:7999 atlassian/bitbucket-server

你也可以看看官方的docker文件:https://hub.docker.com/r/atlassian/bitbucket-server/dockerfile

完全披露:我在 Atlassian Premier Support 工作,与我们的 Bitbucket Server 团队密切合作,并且在过去几年中一直是 atlassian/bitbucket-server Docker 图像的主要维护者。

简短版

首先:使用我们的 official image,多年来我们已经解决了许多问题,因此与其尝试从头开始,不如以我们的问题为基础。

其次:您确实可以在 Docker 中 运行 一个数据中心集群。我的个人测试环境由 3 个集群节点和几个智能镜像组成,全部使用官方镜像,前面有 HAProxy 作为负载均衡器和外部 Elasticsearch 实例管理搜索。查看上面的自述文件以获取常见配置选项列表 - 您可能需要的那些可以通过传递环境变量来设置

长版

又名"How can I spin up a full DC cluster in a test environment?"

这是我很久以前为我们自己的内部支持团队整理的一个简单教程。它使用自定义 HAProxy Docker 容器为您提供开箱即用的负载均衡器。它旨在用于在单个主机上进行测试,因此如果您想做一些不同的或更接近生产部署的事情,这将不包括在内。

这里要讲的内容很多,所以让我们从基础开始吧。

网络

有几种方法可以连接各个 Docker 容器,以便它们可以找到彼此并进行通信(例如 --link 参数),但是 Docker 网络目前还不够最灵活。使用专用网络,我们得到以下内容:

  • 容器间通信:同一网络上的容器可以相互通信并从其他容器访问服务,而无需向主机发布特定端口。
  • 自动 DNS:容器可以通过它们的容器名称(由 --name 参数定义)找到彼此。然而,与真正的 DNS 不同的是,当容器关闭时,其 DNS 解析将不复存在。这可能会导致 HAProxy 等服务出现一些问题 - 但我们稍后会谈到。另外值得注意的是,这并没有设置机器的主机名,如果需要的话需要单独设置。
  • 静态 IP 分配:对于某些用例,在其网络中为 Docker 容器提供静态 IP 地址很有用
  • 多播:Docker 网络默认支持多播,这非常适合通过 Hazelcast 进行通信的数据中心节点

Docker 网络没有做的一件事是将主机连接到它的网络,因此您(用户)无法通过容器名称连接到容器,您仍然需要将端口发布到本地机器。但是,在某些情况下这样做既有用又必要。最简单的解决方法是向您的主机文件添加条目,将您希望访问的每个容器名称指向环回地址,127.0.0.1

要创建一个 Docker 网络,运行 以下命令。在我的示例中,我们将把我们的网络命名为 atlasNetwork。如果您想使用其他名称,请记住在所有后续 docker 命令中更改网络名称。

docker network create --driver bridge \
    --subnet=10.255.0.0/16 \
    atlasNetwork

在这里,我们正在使用网桥驱动程序创建一个网络 - 这是最简单的网络类型。更复杂的网络类型允许网络跨越多个主机。我们还手动指定子网 - 如果我们将其遗漏,Docker 将随机选择一个,并且它可能与现有网络子网冲突,因此选择我们自己的子网是最安全的。我们还指定了一个 /16 掩码,以允许我们使用最后两个八位字节内的 IP 地址范围 - 这将在稍后出现!

存储空间

$BITBUCKET_HOME 等持久性数据或您的数据库文件需要存储在容器本身之外的某个地方。对于我们的测试环境,我们可以简单地将这些直接存储在主机上,我们的本地OS。这意味着我们可以使用我们最喜欢的文本编辑器来编辑配置文件,这非常方便! 在下面的示例中,我们将把数据文件存储在文件夹 ~/dockerdata 中。无需创建此文件夹或任何子文件夹,因为 Docker 会自动执行此操作。如果您想使用不同的文件夹,请确保更新下面的示例。

您可能想知道为什么我们不使用 Docker 的命名卷而不是在主机上安装文件夹。命名卷更易于管理抽象,通常被推荐;然而,出于测试环境的目的(特别是在 Docker for Mac 上,您无法直接访问虚拟化文件系统)能够检查每个容器的持久性具有巨大的实际好处数据直接。您可能想要在 Bitbucket、Postgres 或 HAProxy 中编辑许多配置文件,这在使用命名卷时可能会很困难,因为它需要您在容器中打开一个 shell - 许多容器不' 包含基本的文本编辑器实用程序(甚至不包括 vi!)。但是,如果您更喜欢使用卷,只需将以下所有示例中的主机文件夹替换为命名卷即可。

数据库

我们网络上需要的第一项服务是数据库。让我们创建一个 Postgres 实例:

docker run -d \
    --name postgres \
    --restart=unless-stopped \
    -e POSTGRES_PASSWORD=mysecretpassword \
    -e PGDATA=/var/lib/postgresql/data/pgdata \
    -v ~/dockerdata/postgres:/var/lib/postgresql/data/pgdata \
    --network=atlasNetwork \
    -p 5432:5432 \
    postgres:latest

让我们检查一下我们在这里做什么:

  • -d
    • 运行 容器并从中分离(return 提示)。如果没有这个选项,当容器启动时,我们将直接附加到它的标准输出,取消将停止容器。
  • --name postgres
    • 将容器的名称设置为 postgres,这也是我们网络上的 DNS 记录。
  • --restart=unless-stopped
    • 将容器设置为在 Docker 启动时自动启动,除非您已明确停止容器。这样,当您重新启动计算机时,Postgres 会自动恢复
  • -e POSTGRES_PASSWORD=mysecretpassword
    • 将默认 postgres 用户的密码设置为 mysecretpassword
  • -e PGDATA=/var/lib/postgresql/data/pgdata
    • 官方 Postgres docker 图片建议在将数据文件夹挂载到外部卷时指定此自定义位置
  • -v ~/dockerdata/postgres:/var/lib/postgresql/data/pgdata
    • 将容器内的文件夹 /var/lib/postgresql/data/pgdata 挂载到位于主机 ~/dockerdata/postgres 上的外部卷。此文件夹将自动创建
  • --network=atlasNetwork
    • 将容器加入我们的自定义 Docker 网络
  • -p 5432:5432
    • 将 Postgres 端口发布到主机,因此我们可以访问 localhost:5432 上的 Postgres。这不是其他容器访问服务所必需的,但我们必须要访问它
  • postgres:latest
    • Postgres官方最新版本docker图片

运行 命令,很快,您现在可以访问一个功能齐全的 Postgres 实例。为了保持一致性,您可能需要在此处添加您的第一个主机条目:

127.0.0.1   postgres

现在您和任何 运行ning 容器都可以访问位于 postgres:5432 的实例 在继续之前,您应该使用您选择的数据库管理工具连接到您的数据库。使用用户名 postgres、默认数据库 postgres 和密码 mysecretpassword 连接到主机名 postgres,并创建一个准备就绪的 Bitbucket 数据库:

CREATE USER bitbucket WITH PASSWORD 'bitbucket';
CREATE DATABASE bitbucket WITH OWNER bitbucket ENCODING 'UTF8';

如果您手边没有数据库管理工具,可以直接在容器中使用 docker exec 到 运行 psql 创建数据库:

# We need to run two commands because psql won't let
# you run CREATE DATABASE from a multi-command string

docker exec -it postgres psql -U postgres -c \
    "CREATE USER bitbucket WITH PASSWORD 'bitbucket';"
docker exec -it postgres psql -U postgres -c \
    "CREATE DATABASE bitbucket WITH OWNER bitbucket ENCODING 'UTF8';"

弹性搜索

我们要设置的下一个服务是 Elasticsearch。我们需要一个所有数据中心节点都可以访问的专用实例。关于如何安装兼容版本、配置它以与 Bitbucket 一起使用,以及安装 Atlassian 的 buckler 安全插件,我们有一套很好的说明:安装和配置远程 Elasticsearch 实例 那么我们如何在 Docker 中进行设置呢?嗯,很简单:

docker pull dchevell/bitbucket-elasticsearch:latest

docker run -d \
    --name elasticsearch \
    -e AUTH_BASIC_USERNAME=bitbucket \
    -e AUTH_BASIC_PASSWORD=mysecretpassword \
    -v ~/dockerdata/elastic:/usr/share/elasticsearch/data \
    --network=atlasNetwork \
    -p 9200:9200 \
    dchevell/bitbucket-elasticsearch:latest

简单地说,dchevell/bitbucket-elasticsearch 是根据 Atlassian 的 Install and configure a remote Elasticsearch instance 知识库文章中的说明设置的预配置 Docker 图像。 Atlassian的Buckler安全插件已经帮你安装好了,你可以通过上面看到的环境变量来配置用户名和密码。同样,我们将数据卷安装到我们的主机,将其加入我们的 Docker 网络,并发布一个端口以便我们可以直接访问它。这仅用于故障排除目的,因此如果您想在不通过 Bitbucket 的情况下浏览本地 Elasticsearch 实例,您可以。

现在我们完成了,您可以添加第二个主机条目:

127.0.0.1   elasticsearch

HAProxy

接下来,我们将设置 HAProxy。安装 Bitbucket Data Center 提供了一些示例配置,同样,我们有一个预配置的 Docker 映像,可以为我们完成所有艰苦的工作。但首先,我们需要先弄清楚一些事情。 HAProxy 不能很好地与 Docker 网络的 DNS 系统配合使用。在现实世界中,如果系统宕机,DNS 记录仍然存在,连接只会超时。 HAProxy 可以很好地处理这种情况。但在 Docker 网络中,当容器停止时,其 DNS 记录将不复存在,并且与其连接失败并出现 "Unknown host" 错误。发生这种情况时 HAProxy 不会启动,这意味着我们无法将其配置为通过容器名称代理连接到我们的节点。相反,我们需要为每个节点提供一个静态 IP 地址,并将 HAProxy 配置为使用该 IP 地址。

虽然我们还没有创建我们的节点,但我们现在可以决定它们的 IP 地址。我们的 Docker 网络的子网是 10.255.0.0/16,Docker 将在最后一个八位字节上动态分配容器地址(例如 10.255.0.110.255.0.2 等等)。由于我们知道这一点,我们可以使用倒数第二个八位字节安全地分配我们的 Bitbucket 节点静态 IP 地址:

10.255.1.1
10.255.1.2
10.255.1.3

除此之外,还有一件事。 HAProxy 将成为我们实例的代言人,因此它的容器名称将代表我们用来访问实例的 URL。在此示例中,我们将其称为 bitbucketdc。我们还将机器的主机名设置为相同。

docker run -d \
    --name bitbucketdc \
    --hostname bitbucketdc \
    -v ~/dockerdata/haproxy:/usr/local/etc/haproxy \
    --network=atlasNetwork \
    -e HTTP_NODES="10.255.1.1:7990,10.255.1.2:7990,10.255.1.3:7990" \
    -e SSH_NODES="10.255.1.1:7999,10.255.1.2:7999,10.255.1.3:7999" \
    -p 80:80 \
    -p 443:443 \
    -p 7999:7999 \
    -p 8001:8001 \
    dchevell/bitbucket-haproxy:latest

在上面的示例中,我们将未来 Bitbucket 节点的 HTTP 端点以及 SSH 端点指定为逗号分隔列表。容器会将其转换为有效的 HAProxy 配置。代理服务将在端口 80 和端口 443 上可用,因此我们将同时发布它们。此容器配置为根据机器的主机名自动生成自签名 SSL 证书,因此我们可以立即使用 HTTPS 访问。

因为我们也在代理 SSH,所以我们也发布端口 7999,Bitbucket Server 的默认 SSH 端口。您会注意到我们还发布了端口 8001。这是为了访问 HAProxy 的管理界面,因此我们可以在任何给定时间监控哪些节点被检测为打开或关闭。

最后,我们将 HAProxy 的配置文件夹安装到数据卷。这不是真正必要的,但它可以让您直接访问 haproxy.cfg,这样您就可以了解那里的配置选项。

现在是我们的第三个主机条目的时候了。这个是,因为它会影响像 Base URL 访问这样的事情,所以是绝对需要的

127.0.0.1   bitbucketdc

Bitbucket 节点

我们终于准备好创建我们的 Bitbucket 节点了。由于这些都将通过负载均衡器访问,因此我们不必发布任何端口。但是,出于故障排除和测试目的,有时您会希望直接访问特定节点,因此我们将每个节点发布到不同的本地端口,以便我们可以在需要时直接访问它。

docker run -d \
    --name=bitbucket_1 \
    -e ELASTICSEARCH_ENABLED=false \
    -e HAZELCAST_NETWORK_MULTICAST=true \
    -e HAZELCAST_GROUP_NAME=bitbucket-docker \
    -e HAZELCAST_GROUP_PASSWORD=bitbucket-docker \
    -e SERVER_PROXY_NAME=bitbucketdc \
    -e SERVER_PROXY_PORT=443 \
    -e SERVER_SCHEME=https \
    -e SERVER_SECURE=true \
    -v ~/dockerdata/bitbucket-shared:/var/atlassian/application-data/bitbucket/shared \
    --network=atlasNetwork \
    --ip=10.255.1.1 \
    -p 7001:7990 \
    -p 7991:7999 \
    atlassian/bitbucket-server:latest

docker run -d \
    --name=bitbucket_2 \
    -e ELASTICSEARCH_ENABLED=false \
    -e HAZELCAST_NETWORK_MULTICAST=true \
    -e HAZELCAST_GROUP_NAME=bitbucket-docker \
    -e HAZELCAST_GROUP_PASSWORD=bitbucket-docker \
    -e SERVER_PROXY_NAME=bitbucketdc \
    -e SERVER_PROXY_PORT=443 \
    -e SERVER_SCHEME=https \
    -e SERVER_SECURE=true \
    -v ~/dockerdata/bitbucket-shared:/var/atlassian/application-data/bitbucket/shared \
    --network=atlasNetwork \
    --ip=10.255.1.2 \
    -p 7002:7990 \
    -p 7992:7999 \
    atlassian/bitbucket-server:latest

docker run -d \
    --name=bitbucket_3 \
    -e ELASTICSEARCH_ENABLED=false \
    -e HAZELCAST_NETWORK_MULTICAST=true \
    -e HAZELCAST_GROUP_NAME=bitbucket-docker \
    -e HAZELCAST_GROUP_PASSWORD=bitbucket-docker \
    -e SERVER_PROXY_NAME=bitbucketdc \
    -e SERVER_PROXY_PORT=443 \
    -e SERVER_SCHEME=https \
    -e SERVER_SECURE=true \
    -v ~/dockerdata/bitbucket-shared:/var/atlassian/application-data/bitbucket/shared \
    --network=atlasNetwork \
    --ip=10.255.1.3 \
    -p 7003:7990 \
    -p 7993:7999 \
    atlassian/bitbucket-server:latest

您可以看到我们正在指定我们在设置 HAProxy 时决定的静态 IP 地址。是否为这些节点添加主机条目,或者只是通过本地主机访问它们的端口,这取决于您。由于没有其他容器需要通过主机名访问我们的节点,所以这不是必需的,我个人也没有打扰。

官方 Docker 图像添加了设置 Docker-only 变量的功能,ELASTICSEARCH_ENABLED=false 以防止 Elasticsearch 在容器中启动。其余的 Hazelcast 属性在官方 docker 镜像中是原生支持的,因为 Bitbucket 5 基于 Springboot 并且可以为我们自动将环境变量转换为它们等效的点属性。

全部打开

现在我们准备好了!

https://bitbucketdc (or whatever name you chose). Add a Data Center evaluation license (You can generate a 30 day one on https://my.atlassian.com) 上访问您的实例并将其连接到您的 Postgres 数据库。登录,然后转到服务器管理并连接您的 Elasticsearch 实例(请记住,它在端口 9200 上 运行ning,因此将 Elasticsearch URL 设置为 http://elasticsearch:9200 并使用我们配置的用户名和密码当我们创建 Elasticsearch 容器时。

访问 Server Admin 中的集群部分,您应该会在那里看到所有节点,这表明多播正在运行并且节点已找到彼此。

就是这样!您的数据中心实例已全面运行。您可以通过关闭除一个节点以外的所有节点将其用作日常实例,并将其用作单节点测试实例 - 然后,无论何时需要,都可以打开其他节点。