作为Write for DOnations计划的一部分,作者选择了女性 代码来接受捐赠。
介绍
Docker可以是在生产中运行Web应用程序的有效方法,但您可能希望在同一个Docker主机上运行多个应用程序。 在这种情况下,您需要设置反向代理,因为您只想将端口80
和443
暴露给世界其他地方。
Traefik是一个支持Docker的反向代理,包括自己的监控仪表板。 在本教程中,您将使用Traefik将请求路由到两个不同的Web应用程序容器: Wordpress容器和Adminer容器,每个容器都与MySQL数据库通信。 您将使用Let的加密将Traefik配置为通过HTTPS提供所有内容。
先决条件
要继续学习本教程,您需要具备以下条件:
- 一个Ubuntu 18.04服务器按照Ubuntu 18.04初始服务器设置指南设置 ,包括一个sudo非root用户和防火墙。
- 一个正在运行的Docker主机。 如果您还没有Docker,请按照如何在Ubuntu 18.04上安装和使用Docker来创建一个。
- Docker Compose安装了如何在Ubuntu 18.04上安装Docker Compose的说明 。
- 一个域和三个A记录,
db-admin
,blog
和monitor
,每个记录都指向Docker主机的IP地址。 您可以按照如何使用DigitalOcean设置主机名教程了解如何将域指向DigitalOcean Droplet。 在本教程中,将您的域替换为配置文件和示例中的your_domain
。
第1步 - 配置和运行Traefik
Traefik项目有一个官方Docker镜像 ,因此我们将使用它在Docker容器中运行Traefik。
但在我们启动并运行Traefik容器之前,我们需要创建配置文件并设置加密密码,以便我们可以访问监控仪表板。
我们将使用htpasswd
实用程序来创建此加密密码。 首先,安装该实用程序,该实用程序包含在apache2-utils
包中:
sudo apt-get install apache2-utils
然后使用htpasswd
生成密码。 用您想要用于Traefik管理员用户的密码替换secure_password
:
htpasswd -nb admin secure_password
程序的输出如下所示:
Outputadmin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/
您将在Traefik配置文件中使用此输出为Traefik运行状况检查和监视仪表板设置HTTP基本身份验证。 复制整个输出行,以便稍后粘贴。
要配置Traefik服务器,我们将使用TOML格式创建一个名为traefik.toml
的新配置文件。 TOML是一种类似于INI文件的配置语言,但标准化。 该文件允许我们配置Traefik服务器以及我们想要使用的各种集成或提供程序 。 在本教程中,我们将使用Traefik提供的三个提供程序: api
,docker和acme
,它们用于使用Let的加密来支持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通信定义其他entryPoint
,而不是针对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接收的信息存储在名为acme.json
的JSON文件中。 entryPoint
键需要指向入口点处理端口443
,在我们的例子中是https
入口点。
关键的onHostRule
决定了Traefik应如何生成证书。 我们希望在创建具有指定主机名的容器后立即获取证书,这就是onHostRule
设置将执行的操作。
acme.httpChallenge
部分允许我们指定Let的加密如何验证是否应该生成证书。 我们将其配置为通过http
入口点作为挑战的一部分来提供文件。
最后,让我们通过docker
添加到文件来配置docker
provider:
...
[docker]
domain = "your_domain"
watch = true
network = "web"
docker提供程序使Traefik能够充当Docker容器前的代理。 我们已经将提供程序配置为在web
网络上watch
新容器(我们将很快创建)并将它们作为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的加密信息。 我们将这个分享到容器中,以便Traefik可以使用它:
touch acme.json
然后锁定此文件的权限,以便只有root用户可以读取和写入此文件。 如果你不这样做,Traefik将无法启动。
chmod 600 acme.json
最后,使用以下命令创建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.2-alpine
命令有点长,让我们分解它。
我们使用-d
标志在后台运行容器作为守护进程。 然后,我们将docker.sock
文件共享到容器中,以便Traefik进程可以监听容器的更改。 我们还将traefik.toml
配置文件和我们创建的acme.json
文件共享到容器中。
接下来,我们将Docker主机的端口:80
和:443
映射到Traefik容器中的相同端口,以便Traefik接收到服务器的所有HTTP和HTTPS流量。
然后我们设置了两个Docker标签,告诉Traefik将流量引导到主机名monitor. your_domain
monitor. your_domain
to port :8080
Traefik容器中的:8080
,公开监控仪表板。
我们将容器的网络设置为web
,并将容器命名为traefik
。
最后,我们使用traefik:1.7.2-alpine
图像作为这个容器,因为它很小。
Docker镜像的ENTRYPOINT
是一个始终在从图像创建容器时运行的命令。 在这种情况下,该命令是容器内的traefik
二进制文件。 您可以在启动容器时将其他参数传递给该命令,但我们已在traefik.toml
文件中配置了所有设置。
启动容器后,您现在可以访问仪表板以查看容器的运行状况。 您还可以使用此仪表板显示Traefik已注册的前端和后端。 通过将浏览器指向https://monitor. your_domain
来访问监视仪表板https://monitor. your_domain
https://monitor. your_domain
。 系统将提示您输入用户名和密码,即管理员和您在第1步中配置的密码。
登录后,您将看到类似于此的界面:
目前还没有太多东西可以看,但是打开这个窗口,当你为Traefik添加容器时,你会看到内容发生了变化。
我们现在运行Traefik代理,配置为与Docker一起使用,并准备监视其他Docker容器。 让我们为Traefik开始一些容器作为代理。
第3步 - 使用Traefik注册容器
运行Traefik容器后,您就可以在其后面运行应用程序了。 让我们在Traefik后面推出以下cotainers:
- 使用官方Wordpress图像的博客。
- 使用官方Adminer映像的数据库管理服务器。
我们将使用docker-compose.yml
文件使用Docker Compose管理这两个应用程序。 在编辑器中打开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图像。 将此配置添加到文件中:
version: "3"
...
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.backend
中的后端服务的名称(指向实际的blog
容器)。 -
traefik.frontend.rule=Host:blog. your_domain
traefik.frontend.rule=Host:blog. your_domain
告诉Traefik检查所请求的主机以及它是否与blog. your_domain
模式匹配blog. your_domain
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
键告诉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.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
容器的内容完全匹配。
但是,由于我们将Docker主机上的端口80
所有流量直接指向blog
容器,因此我们需要以不同方式配置此容器,以便将流量传输到我们的adminer
容器。 线路traefik.frontend.rule=Host:db-admin. your_domain
traefik.frontend.rule=Host:db-admin. your_domain
告诉Traefik检查所请求的主机。 如果它与db-admin. your_domain
的模式匹配db-admin. your_domain
db-admin. your_domain
,Traefik会将流量路由到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管理仪表板。 你会看到现在有两个暴露的服务器的backend
和frontend
:
导航到blog. your_domain
blog. your_domain
,用你的域名取代your_domain
。 您将被重定向到TLS连接,现在可以完成Wordpress设置:
现在访问db-admin. your_domain
访问Adminer db-admin. your_domain
您的浏览器中的db-admin. your_domain
,再次将your_domain
替换为您的域名。 mysql
容器不会暴露给外部世界,但是adminer
容器可以通过它们使用mysql
容器名称作为主机名共享的internal
Docker网络访问它。
在Adminer登录屏幕上,使用用户名root ,使用mysql
作为服务器 ,并使用您为MYSQL_ROOT_PASSWORD
设置的值作为密码。 登录后,您将看到Adminer用户界面:
这两个站点现在都在工作,您可以在monitor. your_domain
使用仪表板monitor. your_domain
monitor. your_domain
以密切关注您的应用程序。
结论
在本教程中,您将Traefik配置为将请求代理到Docker容器中的其他应用程序。
Traefik在应用程序容器级别的声明性配置使得配置更多服务变得容易,并且在向代理流量添加新应用程序时无需重新启动traefik
容器,因为Traefik通过它正在监视的Docker套接字文件立即注意到更改。
要了解有关Traefik可以做些什么的更多信息,请访问Traefik官方文档 。