作者选择了 Girls Who Code以作为 Write for Donations计划的一部分获得捐款。
介绍
Docker可以是运行生产中的Web应用程序的有效方法,但您可能希望在同一个Docker主机上运行多个应用程序。
在本教程中,您将使用 Traefik 将请求路由到两个不同的 Web 应用容器:一个 Wordpress容器和一个 Adminer容器,每一个都与一个 MySQL数据库交谈。
前提条件
要跟随本教程,您将需要以下内容:
- 一个 Debian 9 服务器设置如下 初始服务器设置与 Debian 9,包括一个 sudo 非根用户和防火墙。
- Docker 安装在您的服务器上,您可以这样做,如下 如何安装和使用 Docker 在 Debian 9。
- Docker Compose 安装与 如何安装 Docker Compose 在 Debian 9的说明。
- 一个域和三个 A 记录,
db-admin
,blog
,和monitor
,每个指向您的服务器的 IP 地址。
步骤 1 – 配置和运行 Traefik
Traefik 项目有一个 官方 Docker 图像,所以我们将使用它在 Docker 容器中运行 Traefik。
然而,在我们安装和运行 Traefik 容器之前,我们需要创建配置文件并设置加密密码,以便我们可以访问监控仪表板。
我们将使用htpasswd
实用程序来创建这个加密密码. 首先,安装该实用程序,该实用程序包含在apache2-utils
包中:
1sudo apt install apache2-utils
然后用htpasswd
生成密码. 用secure_password
代替您想为 Traefik 管理员用户使用的密码:
1htpasswd -nb admin secure_password
该计划的结果将是这样的:
1[secondary_label Output]
2admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/
您将在 Traefik 配置文件中使用此输出来为 Traefik 健康检查和监控仪表板设置 HTTP Basic Authentication。
为了配置Traefik服务器,我们将使用TOML格式创建一个名为traefik.toml的新配置文件。 TOML是一个类似于INI文件的配置语言,但标准化。 这个文件允许我们配置Traefik服务器和我们想要使用的各种集成,或 providers。 在本教程中,我们将使用三个可用的Traefik提供商: 'api'、 'docker'和 'acme',用于使用Let's Encrypt来支持TLS。
在nano
或您最喜欢的文本编辑器中打开新文件:
1nano traefik.toml
首先,添加两个名为http
和https
的输入点,所有后端将默认访问:
1[label traefik.toml]
2defaultEntryPoints = ["http", "https"]
我们将在此文件中稍后配置http
和https
输入点。
接下来,配置api
提供商,它为您提供访问仪表板界面,在这里您将粘贴htpasswd
命令的输出:
1[label traefik.toml]
2...
3[entryPoints]
4 [entryPoints.dashboard]
5 address = ":8080"
6 [entryPoints.dashboard.auth]
7 [entryPoints.dashboard.auth.basic]
8 users = ["admin:your_encrypted_password"]
9
10[api]
11entrypoint="dashboard"
仪表板是一个单独的 Web 应用程序,将在 Traefik 容器中运行,我们将仪表板设置为在端口 8080
上运行。
entrypoints.dashboard
部分配置了我们将如何与api
提供商连接,而entrypoints.dashboard.auth.basic
部分为仪表板配置了 HTTP Basic Authentication。 使用您刚刚运行的htpasswd
命令的输出为用户
输入的值。
我们已经定义了我们的第一个entryPoint
,但我们需要为标准的HTTP和HTTPS通信定义其他,而不是针对api
提供商。
1[label traefik.toml]
2...
3 [entryPoints.http]
4 address = ":80"
5 [entryPoints.http.redirect]
6 entryPoint = "https"
7 [entryPoints.https]
8 address = ":443"
9 [entryPoints.https.tls]
10...
http
输入点处理80
端口,而https
输入点用于TLS/SSL的443
端口,我们自动将端口80
上的所有流量重定向到https
输入点,以强制所有请求的安全连接。
接下来,添加此部分来配置为 Traefik 的 Let's Encrypt 证书支持:
1[label traefik.toml]
2...
3[acme]
4email = "your_email@your_domain"
5storage = "acme.json"
6entryPoint = "https"
7onHostRule = true
8 [acme.httpChallenge]
9 entryPoint = "http"
这个部分被称为acme
,因为 ACME是与 Let's Encrypt 进行通信以管理证书的协议的名称。 Let's Encrypt 服务需要使用有效的电子邮件地址进行注册,因此,为了让 Traefik 为我们的主机生成证书,请将电子邮件
密钥设置为您的电子邮件地址。我们然后指定我们将将从 Let's Encrypt 获取的信息存储在一个名为acme.json
的 JSON 文件中。
onHostRule
的密钥决定了Traefik应该如何生成证书,我们希望在创建指定主机名称的容器后立即获取我们的证书,这就是onHostRule
设置所做的。
acme.httpChallenge
部分允许我们指定Let's Encrypt如何验证该证书应该被生成,我们正在配置它以通过http
输入点作为挑战的一部分提供文件。
最后,让我们通过将这些行添加到文件中来配置docker
提供商:
1[label traefik.toml]
2...
3[docker]
4domain = "your_domain"
5watch = true
6network = "web"
docker
提供商允许Traefik在Docker容器前作为代理服务器,我们已配置该提供商监视
在Web
网络上的新容器(我们将很快创建),并将其暴露为your_domain
的子域。
在此时,‘traefik.toml’应该有以下内容:
1[label traefik.toml]
2defaultEntryPoints = ["http", "https"]
3
4[entryPoints]
5 [entryPoints.dashboard]
6 address = ":8080"
7 [entryPoints.dashboard.auth]
8 [entryPoints.dashboard.auth.basic]
9 users = ["admin:your_encrypted_password"]
10 [entryPoints.http]
11 address = ":80"
12 [entryPoints.http.redirect]
13 entryPoint = "https"
14 [entryPoints.https]
15 address = ":443"
16 [entryPoints.https.tls]
17
18[api]
19entrypoint="dashboard"
20
21[acme]
22email = "your_email@your_domain"
23storage = "acme.json"
24entryPoint = "https"
25onHostRule = true
26 [acme.httpChallenge]
27 entryPoint = "http"
28
29[docker]
30domain = "your_domain"
31watch = true
32network = "web"
保存文件并离开编辑器. 有了所有这些配置,我们可以开火 Traefik。
步骤2 - 运行 Traefik 集装箱
接下来,创建一个Docker网络,让代理人与容器共享。Docker网络是必要的,以便我们可以使用使用Docker Compose运行的应用程序使用它。
1docker network create web
当 Traefik 容器启动时,我们会将其添加到该网络中,然后我们可以稍后将额外的容器添加到该网络中,以便 Traefik 进行代理。
接下来,创建一个空的文件,该文件将包含我们的 Let's Encrypt 信息,我们将将此信息共享到容器中,以便 Traefik 可以使用它:
1touch acme.json
Traefik 只能使用此文件,如果容器内的 root 用户有独特的读写访问权限. 要做到这一点,请锁定 acme.json
上的权限,以便只有文件所有者才有读写权限。
1chmod 600 acme.json
一旦文件传递到Docker,所有者将自动更改为容器内的 root用户。
最后,用这个命令创建 Traefik 容器:
1docker run -d \
2 -v /var/run/docker.sock:/var/run/docker.sock \
3 -v $PWD/traefik.toml:/traefik.toml \
4 -v $PWD/acme.json:/acme.json \
5 -p 80:80 \
6 -p 443:443 \
7 -l traefik.frontend.rule=Host:monitor.your_domain \
8 -l traefik.port=8080 \
9 --network web \
10 --name traefik \
11 traefik:1.7.6-alpine
命令有点长,所以让我们打破它。
我们使用d
旗在背景中运行容器作为一个戴蒙,然后我们将我们的docker.sock
文件共享到容器中,以便Traefik过程可以听取对容器的更改。
接下来,我们将 Docker 主机的端口80
和443
地图到 Traefik 容器中的相同端口,以便 Traefik 接收所有 HTTP 和 HTTPS 流量到服务器。
然后我们设置了两个Docker标签,告诉Traefik将流量导向托管名称monitor.your_domain
到Traefik容器中的端口8080
,暴露了监控仪表板。
我们将容器的网络设置为网
,我们将容器命名为traefik
。
最后,我们使用这个容器的traefik:1.7.6-alpine
图像,因为它很小。
Docker 图像的 ENTRYPOINT
是一个命令,在从图像中创建一个容器时总是运行。在这种情况下,命令是容器内的 traefik
二进制。当您启动容器时,您可以向该命令传递额外的参数,但我们已经在 traefik.toml
文件中配置了所有设置。
随着容器的启动,你现在有一个仪表板,你可以访问,以查看你的容器的健康状况。你也可以使用这个仪表板来可视化Treefik注册的前端和后端。 访问监控仪表板,将你的浏览器指向https://monitor.your_domain`。 你将被提示你的用户名和密码,这是 admin和你在步骤 1设置的密码。
一旦登录,你会看到一个类似于此的界面:
目前还没有太多要看的,但留下这个窗口打开,你会看到内容的变化,当你添加集装箱为 Traefik 工作。
我们现在有我们的 Traefik 代理程序运行,配置为与 Docker 工作,并准备监控其他 Docker 容器。
步骤 3 – 使用 Traefik 注册集装箱
随着 Traefik 容器的运行,您已经准备好在其背后运行应用程序,让我们在 Traefik 背后推出以下容器:
- 使用 [官方 Wordpress 图像] 的博客(https://hub.docker.com/_/wordpress/)。
- 使用 [官方 Adminer 图像] 的数据库管理服务器(https://hub.docker.com/_/adminer/)。
我们将使用 Docker Compose 管理这两个应用程序,使用docker-compose.yml
文件,在您的编辑器中打开docker-compose.yml
文件:
1nano docker-compose.yml
将下列行添加到文件中,以指定我们将使用的版本和网络:
1[label docker-compose.yml]
2version: "3"
3
4networks:
5 web:
6 external: true
7 internal:
8 external: false
我们使用 Docker Compose 版本 3
,因为它是 Compose 文件格式的最新主要版本。
为了让 Traefik 识别我们的应用程序,它们必须是同一网络的一部分,并且由于我们手动创建了网络,我们通过指定网络名称为web
并将外部
设置为真实
来引进它,然后我们将另一个网络定义为真实
。
接下来,我们将定义我们每个服务
,一次。让我们从博客
容器开始,我们将基于官方的WordPress图像。
1[label docker-compose.yml]
2version: "3"
3...
4
5services:
6 blog:
7 image: wordpress:4.9.8-apache
8 environment:
9 WORDPRESS_DB_PASSWORD:
10 labels:
11 - traefik.backend=blog
12 - traefik.frontend.rule=Host:blog.your_domain
13 - traefik.docker.network=web
14 - traefik.port=80
15 networks:
16 - internal
17 - web
18 depends_on:
19 - mysql
环境
键允许您指定将设置在容器内部的环境变量. 通过不为WORDPRESS_DB_PASSWORD
设置一个值,我们告诉Docker Compose从我们的壳中获取该值,并在我们创建容器时传输它。
标签
部分是您为 Traefik 指定配置值的地方。Docker 标签不会自行做任何事情,但 Traefik 会读取这些标签,以便知道如何处理容器。
traefik.backend
指示 Traefik 中的后端服务的名称(指向实际的 'blog' 容器)。traefik.frontend.rule=Host:blog.your_domain
告诉 Traefik 检查所请求的主机,如果它匹配了 'blog.your_domain' 的模式,它应该将流量路由到 'blog' 容器。- 'traefik.docker.network=web' 指明要在哪个网络上搜索 Traefik 以找到此容器的内部 IP。
通过此配置,所有发送到 Docker 主机端口 80 的流量将被路由到博客
容器。
我们将此容器分配给两个不同的网络,以便Traefik可以通过Web
网络找到它,并通过内部
网络与数据库容器进行通信。
最后,depends_on
键告诉Docker Compose该容器需要启动 _after_它的依赖性正在运行.由于WordPress需要一个数据库来运行,我们必须在启动我们的博客
容器之前运行我们的mysql
容器。
接下来,通过将此配置添加到您的文件来配置MySQL服务:
1[label docker-compose.yml]
2services:
3...
4 mysql:
5 image: mysql:5.7
6 environment:
7 MYSQL_ROOT_PASSWORD:
8 networks:
9 - internal
10 labels:
11 - traefik.enable=false
我们正在使用这个容器的官方MySQL 5.7图像。您会注意到,我们再次使用一个环境
项目而没有一个值。MYSQL_ROOT_PASSWORD
和WORDPRESS_DB_PASSWORD
变量将需要设置为相同的值,以确保我们的WordPress容器可以与MySQL进行通信。我们不希望将mysql
容器暴露在Treefik或外部世界,所以我们只将此容器分配到内部
网络。由于Treefik可以访问Docker插槽,这个过程仍然会默认地暴露一个前端的mysql
容器,所以我们会添加标签efik.traik.enfalse=false
来说明Treefik不应该暴露这个容器。
最后,添加此配置来定义adminer
容器:
1[label docker-compose.yml]
2services:
3...
4 adminer:
5 image: adminer:4.6.3-standalone
6 labels:
7 - traefik.backend=adminer
8 - traefik.frontend.rule=Host:db-admin.your_domain
9 - traefik.docker.network=web
10 - traefik.port=8080
11 networks:
12 - internal
13 - web
14 depends_on:
15 - mysql
这个容器的网络
和depends_on
配置完全匹配我们正在使用的博客
容器。
然而,由于我们正在将所有流量转移到 Docker 主机上的端口 `80 直接到‘博客’容器,我们需要将此容器配置不同的方式,以便流量转移到我们的 ‘adminer’ 容器。‘traefik.frontend.rule=Host:db-admin.your_domain’ 指示 Traefik 检查所要求的主机。
在此时,‘docker-compose.yml’应该有以下内容:
1[label docker-compose.yml]
2version: "3"
3
4networks:
5 web:
6 external: true
7 internal:
8 external: false
9
10services:
11 blog:
12 image: wordpress:4.9.8-apache
13 environment:
14 WORDPRESS_DB_PASSWORD:
15 labels:
16 - traefik.backend=blog
17 - traefik.frontend.rule=Host:blog.your_domain
18 - traefik.docker.network=web
19 - traefik.port=80
20 networks:
21 - internal
22 - web
23 depends_on:
24 - mysql
25 mysql:
26 image: mysql:5.7
27 environment:
28 MYSQL_ROOT_PASSWORD:
29 networks:
30 - internal
31 labels:
32 - traefik.enable=false
33 adminer:
34 image: adminer:4.6.3-standalone
35 labels:
36 - traefik.backend=adminer
37 - traefik.frontend.rule=Host:db-admin.your_domain
38 - traefik.docker.network=web
39 - traefik.port=8080
40 networks:
41 - internal
42 - web
43 depends_on:
44 - mysql
保存文件并离开文本编辑器。
接下来,在启动容器之前,为WORDPRESS_DB_PASSWORD
和MYSQL_ROOT_PASSWORD
变量设置壳中的值:
1export WORDPRESS_DB_PASSWORD=secure_database_password
2export MYSQL_ROOT_PASSWORD=secure_database_password
用您想要的数据库密码替换secure_database_password
,请记住为WORDPRESS_DB_PASSWORD
和MYSQL_ROOT_PASSWORD
使用相同的密码。
使用这些变量设置,使用docker-compose
运行容器:
1docker-compose up -d
现在再看看Treefik管理仪表板,你会看到现在有两个曝光的服务器的后端
和前端
:
导航到blog.your_domain
,以您的域代替your_domain
。
现在访问管理员,访问您的浏览器中的「db-admin.your_domain」,再次用您的域代替「your_domain」。
在 Adminer 登录屏幕上,使用用户名 root,用于 服务器的 mysql
,并使用您为密码设置的 MYSQL_ROOT_PASSWORD
值。
现在两个网站都在工作,您可以使用monitor.your_domain
的仪表板来监控您的应用程序。
结论
在本教程中,您将 Traefik 配置为向 Docker 容器中的其他应用程序发送代理请求。
Traefik 在应用程序容器级别的声明配置使其易于配置更多的服务,当您将新应用程序添加到代理流量时,无需重新启动traefik
容器,因为 Traefik 会通过其监控的 Docker 接口文件立即注意到变化。
如果您想进一步探索 Docker 容器,请参阅 如何在 Ubuntu 18.04 上设置私人 Docker 注册表或 如何使用 Nginx、Let's Encrypt 和 Docker Compose 保护集装 Node.js 应用程序。