作为Write for DOnations计划的一部分,作者选择了“编码女孩”来接受捐赠。
注意:本教程适用于 Traefik v1。如果你想安装和配置 Traefik v2,请使用这个较新的教程。
介绍
Docker是在生产环境中运行 Web 应用程序的一种有效方式,但您可能希望在同一个 Docker 主机上运行多个应用程序。在这种情况下,你需要建立一个反向代理,因为你只是想揭露港口80
和443
世界其他地区。
Traefik是一个 Docker 感知的反向代理,包括它自己的监控仪表板。在本教程中,您将使用 Traefik 将请求路由到两个不同的 Web 应用程序容器:WordPress容器和Adminer容器,每个容器都与MySQL数据库通信。您将使用Let’s Encrypt将 Traefik 配置为通过 HTTPS 提供所有服务。
先决条件
要遵循本教程,您将需要以下内容:
- 按照Ubuntu 20.04 初始服务器设置指南设置一台 Ubuntu 20.04 服务器,包括一个 sudo 非 root 用户和一个防火墙。
- Docker 安装在您的服务器上,您可以按照如何在 Ubuntu 20.04 上安装和使用 Docker 来完成。
- 按照如何在 Ubuntu 20.04 上安装 Docker Compose 中的说明安装 Docker Compose。
- 一个域和三个 A 记录 、和。每个都应该指向您服务器的 IP 地址。您可以通过阅读 DigitalOcean 的域和 DNS 文档来了解如何将域指向 DigitalOcean Droplets。在本教程中,在配置文件和示例中替换您的域。
db-admin.your_domain
blog.your_domain
monitor.your_domain
your_domain
第 1 步 – 配置和运行 Traefik
Traefik 项目有一个官方的 Docker 镜像,所以我们将使用它在 Docker 容器中运行 Traefik。
但是在我们启动并运行 Traefik 容器之前,我们需要创建一个配置文件并设置一个加密密码,以便我们可以访问监控仪表板。
我们将使用该htpasswd
实用程序来创建此加密密码。首先,安装包含在apache2-utils
包中的实用程序:
- sudo apt-get install apache2-utils
然后生成密码htpasswd
。替换secure_password
为您想用于 Traefik 管理员用户的密码:
- htpasswd -nb admin secure_password
程序的输出将如下所示:
Outputadmin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/
您将使用 Traefik 配置文件中的唯一输出为 Traefik 健康检查和监控仪表板设置 HTTP 基本身份验证。复制整个输出行,以便稍后粘贴。不要使用示例输出。
为了配置 Traefik 服务器,我们将创建一个名为traefik.toml
TOML 格式的新配置文件。TOML是一种类似于 INI 文件的配置语言,但是是标准化的。这个文件让我们配置Traefik服务器和各种集成,或者providers
,我们要使用。在本教程中,我们将使用三个Traefik的可用提供商:api
,docker
,和acme
。最后一个acme
支持使用 Let’s Encrypt 的 TLS 证书。
在nano
或您喜欢的文本编辑器中打开您的新文件:
- nano traefik.toml
首先,添加两个命名入口点http
和https
,默认情况下所有后端都可以访问:
defaultEntryPoints = ["http", "https"]
我们稍后将在此文件中配置http
和https
入口点。
接下来,配置api
提供程序,它使您可以访问仪表板界面。您将在此处粘贴htpasswd
命令的输出:
...
[entryPoints]
[entryPoints.dashboard]
address = ":8080"
[entryPoints.dashboard.auth]
[entryPoints.dashboard.auth.basic]
users = ["admin:your_encrypted_password"]
[api]
entrypoint="dashboard"
仪表板是一个单独的 Web 应用程序,它将在 Traefik 容器中运行。我们将仪表板设置为在端口上运行8080
。
该entrypoints.dashboard
部分配置我们将如何与api
提供者连接,该entrypoints.dashboard.auth.basic
部分为仪表板配置 HTTP 基本身份验证。使用htpasswd
刚刚运行的命令的输出作为users
条目的值。您可以通过用逗号分隔来指定其他登录名。
我们已经定义了我们的第一个entryPoint
,但我们需要为标准 HTTP 和 HTTPS 通信定义其他的,这些通信不指向api
提供者。该entryPoints
部分配置 Traefik 和代理容器可以侦听的地址。将这些行添加到entryPoints
标题下方的文件中:
...
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
...
该http
入口点手柄端口80
,而 https
入口点使用的端口443
为TLS / SSL。我们自动将端口80
上的所有流量重定向到https
入口点,以强制所有请求的安全连接。
接下来,添加此部分以配置 Traefik 的 Let’s Encrypt 证书支持:
...
[acme]
email = "your_email@your_domain"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
之所以调用此部分,是acme
因为ACME是用于与 Let’s Encrypt 通信以管理证书的协议的名称。Let’s Encrypt 服务需要使用有效的电子邮件地址进行注册,因此为了让 Traefik 为我们的主机生成证书,请将email
密钥设置为您的电子邮件地址。然后我们指定我们将从 Let’s Encrypt 接收到的信息存储在一个名为 的 JSON 文件中acme.json
。该entryPoint
按键需要点到入口点装卸港443
,这对我们来说是https
切入点。
关键onHostRule
决定了 Traefik 应该如何生成证书。我们希望在创建具有指定主机名的容器后立即获取我们的证书,这就是onHostRule
设置将执行的操作。
该acme.httpChallenge
部分允许我们指定 Let’s Encrypt 如何验证应生成证书。我们将它配置为通过http
入口点作为挑战的一部分提供文件。
最后,让我们docker
通过将这些行添加到文件来配置提供程序:
...
[docker]
domain = "your_domain"
watch = true
network = "web"
该docker
供应商能够Traefik作为在Docker容器的前代理。我们已经watch
为web
网络上的新容器配置了提供程序,我们将很快创建这些容器,并将它们公开为your_domain
.
此时,traefik.toml
应该有以下内容:
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.dashboard]
address = ":8080"
[entryPoints.dashboard.auth]
[entryPoints.dashboard.auth.basic]
users = ["admin:your_encrypted_password"]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[api]
entrypoint="dashboard"
[acme]
email = "your_email@your_domain"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
[docker]
domain = "your_domain"
watch = true
network = "web"
保存文件并退出编辑器。有了这些配置,我们就可以初始化 Traefik。
第 2 步 – 运行 Traefik 容器
接下来,为代理创建一个 Docker 网络以与容器共享。Docker 网络是必要的,以便我们可以将它与使用 Docker Compose 运行的应用程序一起使用。我们称这个网络为web
:
- docker network create web
当 Traefik 容器启动时,我们会将其添加到这个网络中。然后我们可以稍后向这个网络添加额外的容器,以便 Traefik 代理。
接下来,创建一个空文件来保存我们的 Let’s Encrypt 信息。我们会将其共享到容器中,以便 Traefik 可以使用它:
- touch acme.json
如果容器内的 root 用户对它具有唯一的读写访问权限,Traefik 将只能使用该文件。为此,请锁定权限,acme.json
以便只有文件的所有者具有读写权限:
- chmod 600 acme.json
一旦文件被传递给 Docker,所有者将自动更改为容器内的root用户。
最后,使用以下命令创建 Traefik 容器:
- docker run -d \
- -v /var/run/docker.sock:/var/run/docker.sock \
- -v $PWD/traefik.toml:/traefik.toml \
- -v $PWD/acme.json:/acme.json \
- -p 80:80 \
- -p 443:443 \
- -l traefik.frontend.rule=Host:monitor.your_domain \
- -l traefik.port=8080 \
- --network web \
- --name traefik \
- traefik:1.7-alpine
命令有点长,让我们分解一下。
我们使用该-d
标志在后台运行容器作为守护进程。然后我们将docker.sock
文件共享到容器中,以便 Traefik 进程可以侦听容器的更改。我们还将traefik.toml
配置文件和acme.json
我们创建的文件共享到容器中。
接下来,我们将Docker 主机的端口:80
和端口映射:443
到 Traefik 容器中的相同端口,以便 Traefik 接收到服务器的所有 HTTP 和 HTTPS 流量。
然后我们设置了两个 Docker 标签,告诉 Traefik 将流量定向到主机名到Traefik 容器内的端口,这将公开监控仪表板。monitor.your_domain
:8080
我们将容器的网络设置为 ,并将容器web
命名为traefik
。
最后,我们使用traefik:1.7-alpine
这个容器的图像,因为它很小。
Docker 镜像ENTRYPOINT
是一个在从镜像创建容器时始终运行的命令。在这种情况下,命令是traefik
容器内的二进制文件。您可以在启动容器时向该命令传递其他参数,但我们已在traefik.toml
文件中配置了所有设置。
容器启动后,您现在有一个仪表板,可以访问以查看容器的运行状况。您还可以使用此仪表板来可视化 Traefik 已注册的前端和后端。通过将浏览器指向 来访问监控仪表板。系统将提示您输入用户名和密码,即admin和您在步骤 1 中配置的密码。https://monitor.your_domain
登录后,您将看到类似如下的界面:
目前还没有什么可看的,但是让这个窗口保持打开状态,当你添加容器供 Traefik 管理时,你会看到内容发生变化。
现在我们的 Traefik 代理正在运行,配置为与 Docker 一起使用,并准备好监控其他 Docker 容器。让我们为 Traefik 添加一些容器来代理。
第 3 步 – 使用 Traefik 注册容器
运行 Traefik 容器后,您就可以在其后面运行应用程序了。让我们在 Traefik 后面启动以下容器:
- 使用官方 WordPress 图像的博客。
- 使用官方 Adminer 映像的数据库管理服务器。
我们将使用 Docker Compose 使用一个docker-compose.yml
文件来管理这两个应用程序。
docker-compose.yml
在编辑器中创建并打开文件:
- nano docker-compose.yml
将以下行添加到文件中以指定我们将使用的版本和网络:
version: "3"
networks:
web:
external: true
internal:
external: false
我们使用 Docker Compose 版本,3
因为它是 Compose 文件格式的最新主要版本。
为了让 Traefik 识别我们的应用程序,它们必须是同一网络的一部分,并且由于我们手动创建了网络,因此我们通过指定网络名称web
和设置external
为将其拉入true
。然后我们定义另一个网络,以便我们可以将我们公开的容器连接到我们不会通过 Traefik 公开的数据库容器。我们称这个网络为internal
。
接下来,我们将定义我们的每services
一个,一次一个。让我们从blog
容器开始,我们将基于官方 WordPress 图像。将此配置添加到文件底部:
...
services:
blog:
image: wordpress:4.9.8-apache
environment:
WORDPRESS_DB_PASSWORD:
labels:
- traefik.backend=blog
- traefik.frontend.rule=Host:blog.your_domain
- traefik.docker.network=web
- traefik.port=80
networks:
- internal
- web
depends_on:
- mysql
该environment
键可让您指定将在容器内设置的环境变量。通过不为 设置值WORDPRESS_DB_PASSWORD
,我们告诉 Docker Compose 从我们的 shell 获取值并在我们创建容器时传递它。在启动容器之前,我们将在我们的 shell 中定义这个环境变量。这样我们就不会将密码硬编码到配置文件中。
该labels
部分是您为 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 的网络。由于我们的 Traefik 容器可以访问所有 Docker 信息,internal
如果我们不指定它,它可能会占用网络IP 。traefik.port
指定 Traefik 应该用于将流量路由到此容器的公开端口。
使用此配置,发送到 Docker 主机端口的所有流量80
都将路由到blog
容器。
我们将这个容器分配给两个不同的网络,这样 Traefik 就可以通过web
网络找到它,并且它可以通过网络与数据库容器进行internal
通信。
最后,depends_on
key 告诉 Docker Compose 这个容器需要在它的依赖项运行后启动。由于 WordPress 需要一个数据库来运行,我们必须mysql
在启动容器之前运行我们的blog
容器。
接下来,通过将此配置添加到文件底部来配置 MySQL 服务:
...
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD:
networks:
- internal
labels:
- traefik.enable=false
我们正在为此容器使用官方 MySQL 5.7 映像。您会注意到我们再次使用了一个environment
没有值的项目。该MYSQL_ROOT_PASSWORD
和WORDPRESS_DB_PASSWORD
变量需要被设置为相同的值,以确保我们的WordPress的容器可以与MySQL进行通信。我们不想将mysql
容器暴露给 Traefik 或外部世界,所以我们只是将这个容器分配给internal
网络。由于 Traefik 可以访问 Docker 套接字,mysql
因此默认情况下该进程仍会公开容器的前端,因此我们将添加标签traefik.enable=false
以指定 Traefik 不应公开此容器。
最后,将此配置添加到文件底部以定义 Adminer 容器:
...
adminer:
image: adminer:4.6.3-standalone
labels:
- traefik.backend=adminer
- traefik.frontend.rule=Host:db-admin.your_domain
- traefik.docker.network=web
- traefik.port=8080
networks:
- internal
- web
depends_on:
- mysql
这个容器基于官方的 Adminer 镜像。此容器的network
和depends_on
配置与我们用于容器的完全匹配blog
。
但是,由于我们将所有流量定向到80
我们的 Docker 主机上的端口直接到blog
容器,我们需要以不同的方式配置这个容器,以便流量能够进入我们的adminer
容器。该行告诉 Traefik 检查请求的主机。如果它匹配 的模式,Traefik 会将流量路由到容器。traefik.frontend.rule=Host:db-admin.your_domain
db-admin.your_domain
adminer
此时,docker-compose.yml
应该有以下内容:
version: "3"
networks:
web:
external: true
internal:
external: false
services:
blog:
image: wordpress:4.9.8-apache
environment:
WORDPRESS_DB_PASSWORD:
labels:
- traefik.backend=blog
- traefik.frontend.rule=Host:blog.your_domain
- traefik.docker.network=web
- traefik.port=80
networks:
- internal
- web
depends_on:
- mysql
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD:
networks:
- internal
labels:
- traefik.enable=false
adminer:
image: adminer:4.6.3-standalone
labels:
- traefik.backend=adminer
- traefik.frontend.rule=Host:db-admin.your_domain
- traefik.docker.network=web
- traefik.port=8080
networks:
- internal
- web
depends_on:
- mysql
保存文件并退出文本编辑器。
接下来,在启动容器之前,在 shell 中为WORDPRESS_DB_PASSWORD
和MYSQL_ROOT_PASSWORD
变量设置值:
- export WORDPRESS_DB_PASSWORD=secure_database_password
- export MYSQL_ROOT_PASSWORD=secure_database_password
替换secure_database_password
为您想要的数据库密码。请记住,使用相同的密码都WORDPRESS_DB_PASSWORD
和MYSQL_ROOT_PASSWORD
。
设置这些变量后,使用以下命令运行容器docker-compose
:
- docker-compose up -d
现在再看一下 Traefik 管理仪表板。你会看到两个暴露的服务器现在有 abackend
和 a frontend
:
导航到。您将被重定向到 TLS 连接,现在可以完成 WordPress 设置:blog.your_domain
现在通过在浏览器中访问来访问 Adminer ,再次替换为您的域。该容器未暴露于外界,但集装箱具有通过访问它多克尔网络,他们共享使用容器名称作为主机名。db-admin.your_domain
your_domain
mysql
adminer
internal
mysql
在管理员登录屏幕上,将系统下拉菜单设置为MySQL。现在进入mysql
的服务器,输入root
了用户名,然后输入您设置的值MYSQL_ROOT_PASSWORD
的密码。将数据库留空。现在按登录。
登录后,您将看到管理员用户界面:
这两个站点现在都在运行,您可以使用仪表板来密切关注您的应用程序。monitor.your_domain
结论
在本教程中,您将 Traefik 配置为将请求代理到 Docker 容器中的其他应用程序。
Traefik 在应用程序容器级别的声明式配置可以轻松配置更多服务,并且在traefik
向代理流量添加新应用程序时无需重新启动容器,因为 Traefik 会立即通过它正在监控的 Docker 套接字文件注意到更改。
要了解有关使用 Traefik 可以做什么的更多信息,请转到官方 Traefik 文档。