如何在 Ubuntu 16.04 上使用 Traefik 作为 Docker 容器的反向代理
介绍
Docker 是在生产环境中运行 Web 应用程序的有效方式,但您可能希望在同一台 Docker 主机上运行多个应用程序。在这种情况下,您需要设置反向代理,因为您只想将端口 80
和 443
暴露给世界其他地方。
让我们加密。
先决条件
要学习本教程,您需要具备以下条件:
- <李> 按照 Ubuntu 16.04 初始服务器设置指南设置一台 Ubuntu 16.04 服务器,包括 sudo 非根用户和防火墙。 <李> Docker 安装在您的服务器上,您可以按照如何在 Ubuntu 16.04 上安装和使用 Docker 来完成。 <李> 按照如何在 Ubuntu 16.04 上安装 Docker Compose 中的说明安装 Docker Compose。 <李> 一个域和三个 A 记录,
db-admin
、blog
和 monitor
,每个记录都指向您服务器的 IP 地址。您可以通过阅读 DigitalOcean 的域和 DNS 文档来了解如何将域指向 DigitalOcean Droplet。在本教程中,将配置文件和示例中的 example.com
替换为您的域。 第 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/
您将在 Traefic 配置文件中使用此输出来为 Traefik 健康检查和监控仪表板设置 HTTP 基本身份验证。复制整个输出行,以便稍后粘贴。
要配置 Traefik 服务器,我们将使用 TOML 格式创建一个名为 traefik.toml
的新配置文件。 TOML 是一种类似于 INI 文件的配置语言,但它是标准化的。这个文件让我们配置我们想要使用的 Traefik 服务器和各种集成,或者 providers。在本教程中,我们将使用 Traefik 的三个可用提供程序:web
、docker
和 acme
,它们用于支持使用 Let's Encrypt 的 TLS .
- nano traefik.toml
首先,添加两个命名入口点,http
和 https
,默认情况下所有后端都可以访问:
defaultEntryPoints = ["http", "https"]
我们稍后将在此文件中配置 http
和 https
入口点。
接下来,配置 web
提供程序,它使您可以访问仪表板界面。您将在此处粘贴 htpasswd
命令的输出:
...
[web]
address = ":8080"
[web.auth.basic]
users = ["admin:your_encrypted_password"]
仪表板是一个单独的 Web 应用程序,将在 Traefik 容器中运行。我们将仪表板设置为在端口 8080
上运行。
web.auth.basic
部分为仪表板配置 HTTP 基本身份验证。使用您刚刚运行的 htpasswd
命令的输出作为 users
条目的值。您可以通过用逗号分隔来指定其他登录名。
接下来,定义入口点。 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@example.com"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
onDemand = false
此部分称为 acme
,因为 ACME 是用于与 Let's Encrypt 通信以管理证书的协议的名称。为了让 Traefik 为我们的主机生成证书,我们将 email
键设置为您的电子邮件地址。然后我们指定我们将从 Let's Encrypt 收到的信息存储在一个名为 acme.json
的 JSON 文件中。 entryPoint
键需要指向入口点处理端口 443
,在我们的例子中是 https
入口点。
最后两个键,onHostRule
和 onDemand
,决定了 Traefik 应该如何生成证书。我们希望在创建具有指定主机名的容器后立即获取我们的证书,这就是 onHostRule
设置要做的事情。 onDemand
设置将尝试在第一次发出请求时生成证书。这会减慢第一个请求的速度,并且会引起访问者的注意,因此我们将避免这种情况。
保存文件并退出编辑器。所有这些配置就绪后,我们就可以启动 Traefik。
第 2 步 – 运行 Traefik 容器
接下来,为代理创建一个 Docker 网络以与容器共享。 Docker 网络是必需的,这样我们就可以将它与使用 Docker Compose 运行的应用程序一起使用。我们称此网络为 proxy
。
- docker network create proxy
当 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.example.com \
- -l traefik.port=8080 \
- --network proxy \
- --name traefik \
- traefik:1.3.6-alpine --docker
该命令有点长,所以让我们分解一下。
我们使用 -d
标志在后台将容器作为守护进程运行。然后,我们将我们的 docker.sock
文件共享到容器中,以便 Traefik 进程可以监听容器的变化。我们还将 traefik.toml
配置文件和我们在容器中创建的 acme.json
文件共享。
接下来,我们将 Docker 主机的端口 :80
和 :443
映射到 Traefik 容器中的相同端口,以便 Traefik 接收到服务器的所有 HTTP 和 HTTPS 流量。
然后我们设置两个 Docker 标签,告诉 Traefik 将流量定向到主机名 monitor.example.com
到 Traefik 容器内的端口 :8080
,暴露监控仪表板。
我们将容器的网络设置为proxy
,并将容器命名为traefik
。
最后,我们为这个容器使用 traefik:1.3.6-alpine
镜像,因为它很小。
Docker 镜像的 ENTRYPOINT
是一个命令,它总是在从镜像创建容器时运行。在这种情况下,命令是容器内的 traefik
二进制文件。启动容器时,您可以将其他参数传递给该命令。在我们的例子中,我们将参数 --docker
传递给 ENTRYPOINT
以确保使用默认设置注册 docker
提供程序。 docker
提供程序使 Traefik 能够充当 Docker 容器前面的代理。 Docker 提供程序的默认配置对我们来说效果很好,所以我们不需要在我们的 traefik.toml
中配置它。
容器启动后,您现在有一个仪表板,您可以访问它来查看容器的运行状况。您还可以使用此仪表板可视化 Traefik 已注册的前端和后端。通过将浏览器指向 https://monitor.example.com
来访问监控仪表板。系统将提示您输入用户名和密码,即 admin 和您在步骤 1 中配置的密码。
登录后,。你会看到类似这样的界面:

目前还没有什么可看的,但是让这个窗口保持打开状态,当您添加容器供 Traefik 使用时,您会看到内容发生变化。
现在我们的 Traefik 代理正在运行,配置为与 Docker 一起工作,并准备好监控其他 Docker 容器。让我们为 Traefik 启动一些容器作为代理。
第 3 步 — 使用 Traefik 注册容器
随着 Traefik 容器的运行,您就可以在它后面运行应用程序了。让我们在 Traefik 背后启动以下容器:
- 使用官方 WordPress 图片的博客。
- 使用官方 Adminer 图像的数据库管理服务器。
我们将使用 docker-compose.yml
文件通过 Docker Compose 管理这两个应用程序:
- nano docker-compose.yml
将以下行添加到文件中以指定我们将使用的版本和网络:
version: "3"
networks:
proxy:
external: true
internal:
external: false
我们使用 Docker Compose 版本 3
,因为它是 Compose 文件格式的最新主要版本。
为了让 Traefik 识别我们的应用程序,它们必须属于同一网络,并且由于我们手动创建了网络,所以我们通过指定 proxy
的网络名称并设置 external
来将其拉入 到 true
。然后我们定义另一个网络,这样我们就可以将我们公开的容器连接到我们不会通过 Traefik 公开的数据库容器。我们将此网络称为 internal
。
接下来,我们将定义我们的每个 services
,一次一个。让我们从 blog
容器开始,我们将基于官方 WordPress 图像。将此配置添加到文件中:
version: "3"
...
services:
blog:
image: wordpress:4.7.5-apache
environment:
WORDPRESS_DB_PASSWORD:
labels:
- traefik.backend=blog
- traefik.frontend.rule=Host:blog.example.com
- traefik.docker.network=proxy
- traefik.port=80
networks:
- internal
- proxy
depends_on:
- mysql
environment
键允许您指定将在容器内部设置的环境变量。通过不为 WORDPRESS_DB_PASSWORD
设置值,我们告诉 Docker Compose 从我们的 shell 获取值并在我们创建容器时传递它。在启动容器之前,我们将在我们的 shell 中定义这个环境变量。这样我们就不会将密码硬编码到配置文件中。
labels
部分是您为 Traefik 指定配置值的地方。 Docker 标签本身不会做任何事情,但 Traefik 会读取这些标签,因此它知道如何处理容器。以下是每个标签的作用:
traefik.backend
指定Traefik中后端服务的名称(指向实际的blog
容器)。traefik.frontend.rule=Host:blog.example.com
告诉 Traefik 检查请求的主机,以及它是否与blog 的模式相匹配。< mark>example.com
它应该将流量路由到blog
容器。traefik.docker.network=proxy
指定 Traefik 在哪个网络下查找此容器的内部 IP。由于我们的 Traefik 容器可以访问所有 Docker 信息,如果我们没有指定它,它可能会占用internal
网络的 IP。traefik.port
指定 Traefik 应该用来将流量路由到此容器的公开端口。
使用此配置,发送到我们的 Docker 主机端口 80
的所有流量都将路由到 blog
容器。
我们将这个容器分配到两个不同的网络,以便 Traefik 可以通过 proxy
网络找到它,并且它可以通过 internal
网络与数据库容器通信。
最后,depends_on
键告诉 Docker Compose 此容器需要在其依赖项运行后 启动。由于 WordPress 需要一个数据库来运行,我们必须在启动我们的 blog
容器之前运行我们的 mysql
容器。
接下来,通过将此配置添加到您的文件来配置 MySQL 服务:
services:
...
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 容器:
services:
...
adminer:
image: adminer:4.3.1-standalone
labels:
- traefik.backend=adminer
- traefik.frontend.rule=Host:db-admin.example.com
- traefik.docker.network=proxy
- traefik.port=8080
networks:
- internal
- proxy
depends_on:
- mysql
这个容器基于官方的 Adminer 镜像。此容器的 network
和 depends_on
配置与我们用于 blog
容器的配置完全匹配。
但是,由于我们将所有流向 Docker 主机上端口 80
的流量直接引导至 blog
容器,因此我们需要以不同方式配置此容器,以便流量能够进入我们的 adminer
容器。 traefik.frontend.rule=Host:db-admin.example.com
这行告诉 Traefik 检查请求的主机。如果它匹配 db-admin.example.com
的模式,Traefik 会将流量路由到 adminer
容器。
保存文件并退出文本编辑器。
接下来,在启动容器之前,在 shell 中为 WORDPRESS_DB_PASSWORD
和 MYSQL_ROOT_PASSWORD
变量设置值:
- export WORDPRESS_DB_PASSWORD=secure_database_password
- export MYSQL_ROOT_PASSWORD=secure_database_password
将 secure_database_password
替换为您想要的数据库密码。
设置好这些变量后,使用 docker-compose
运行容器:
- docker-compose up -d
现在再看一下 Traefik 管理仪表板。您会看到两个暴露的服务器现在有一个 backend
和一个 frontend
:

导航至 blog.example.com
,将 example.com
替换为您的域。您将被重定向到 TLS 连接,现在可以完成 WordPress 设置:

现在,通过在浏览器中访问 db-admin.example.com
来访问 Adminer,再次将 example.com
替换为您的域。 mysql
容器没有暴露给外界,但是 adminer
容器可以通过它们共享的 internal
Docker 网络访问它mysql
容器名称作为主机名。
在管理员登录屏幕上,使用用户名 root,服务器使用 mysql
,密码使用您为 MYSQL_ROOT_PASSWORD
设置的值。登录后,您将看到管理员用户界面:

这两个站点现在都在运行,您可以使用位于 monitor.example.com
的仪表板来关注您的应用程序。
结论
在本教程中,您将 Traefik 配置为将请求代理到 Docker 容器中的其他应用程序。
Traefik 在应用程序容器级别的声明式配置使得配置更多服务变得容易,并且当您将新应用程序添加到代理流量时无需重新启动 traefik
容器,因为 Traefik 会立即通过 Docker 通知更改它正在监视的套接字文件。
要了解有关 Traefik 可以做什么的更多信息,请访问 Traefik 官方文档。