如何在 Ubuntu 20.04 上使用 Traefik v2 作为 Docker 容器的反向代理

作者选择了 Girls Who Code以作为 Write for Donations计划的一部分获得捐款。

介绍

Docker可以是运行生产中的Web应用程序的有效方法,但您可能希望在同一个Docker主机上运行多个应用程序。

Traefik是一个Docker意识的反向代理程序,包括监控仪表板。Traefik v1已经被广泛使用了一段时间,并且 您可以遵循此之前的教程来安装Traefik v1)。

Traefik v1 和 v2 之间的最大区别在于 frontendsbackends 被删除,它们的组合功能扩散到 routers, middlewaresservices. 以前,后端完成了对请求的修改,并将该请求转移到应该处理的任何地方。

在本教程中,您将配置 Traefik v2 以将请求路由到两个不同的 Web 应用程序容器:一个 Wordpress容器和一个 Adminer容器,每一个都与一个 MySQL数据库交谈。

前提条件

要完成本教程,您将需要以下内容:

您可以通过遵循我们的 Ubuntu 20.04 初始服务器设置指南设置此设置。

  • Docker 安装在您的服务器上,您可以通过遵循 [如何在 Ubuntu 20.04 上安装和使用 Docker 的步骤 1 和 2**(https://andsky.com/tech/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04)来实现。
  • Docker Compose 使用 How to Install Docker Compose on Ubuntu 20.04 的步骤 1 安装。
  • A domain and three records, db-admin.your_domain, blog.your_domainmonitor.your_domain 的指令。 每一个点都应该是您的服务器的 IP 地址。 您可以学习如何将域

步骤 1 – 配置和运行 Traefik

Traefik 项目有一个 官方 Docker 图像,因此您将使用它在 Docker 容器中运行 Traefik。

但是,在您启动和运行 Traefik 容器之前,您需要创建配置文件并设置加密密码,以便您可以访问监控仪表板。

您将使用htpasswd实用程序创建此加密密码. 首先,安装该实用程序,该实用程序包含在apache2-utils包中:

1sudo apt-get 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.tomltraefik_dynamic.tomlTOML是一种类似于 INI 文件的配置语言,但标准化。 这些文件让我们配置 Traefik 服务器和各种集成,或 `供应商’,您希望使用。

使用nano或您喜爱的文本编辑器创建并打开traefik.toml:

1nano traefik.toml

首先,您要指定特雷菲克应该使用您的配置文件的entryPoints部分来收听的端口。您需要两个端口,因为您想收听端口80443

添加以下配置:

 1[label traefik.toml]
 2[entryPoints]
 3  [entryPoints.web]
 4    address = ":80"
 5    [entryPoints.web.http.redirections.entryPoint]
 6      to = "websecure"
 7      scheme = "https"
 8
 9  [entryPoints.websecure]
10    address = ":443"

请注意,您还会自动重定向流量,以便通过TLS进行处理。

接下来,配置Traefik api,它为您提供访问API和仪表板界面。 [api] 的标题是您所需的,因为仪表板是默认启用的,但您暂时是明确的。

添加以下代码:

1[label traefik.toml]
2...
3[api]
4  dashboard = true

要完成您的 Web 请求的安全性,您需要使用 Let's Encrypt 来生成有效的 TLS 证书. Traefik v2 支持 Let's Encrypt 外出框,您可以通过创建一个 certificates resolver 的类型 acme 来配置它。

让我们现在使用名称let-encrypt来配置您的证书解析器:

1[label traefik.toml]
2...
3[certificatesResolvers.lets-encrypt.acme]
4  email = "your_email@your_domain"
5  storage = "acme.json"
6  [certificatesResolvers.lets-encrypt.acme.tlsChallenge]

这个部分被称为acme,因为 ACME是与 Let’s Encrypt 进行通信以管理证书的协议的名称。 Let’s Encrypt 服务需要使用有效的电子邮件地址进行注册,因此要让 Traefik 为您的主机生成证书,请将电子邮件密钥设置为您的电子邮件地址。

acme.tlsChallenge 部分允许我们指定 Let's Encrypt 如何验证该证书. 您正在配置该证书以便作为对端口 `443’ 的挑战的一部分提供文件。

最后,您需要配置 Traefik 来使用 Docker。

添加以下配置:

1[label traefik.toml]
2...
3[providers.docker]
4  watch = true
5  network = "web"

docker提供商允许 Traefik 在 Docker 容器前作为代理服务器。

我们的最终配置使用文件提供商. 使用 Traefik v2,静态和动态配置不能混合和匹配. 为了绕过这一点,您将使用traefik.toml来定义静态配置,然后将动态配置保存在另一个文件中,您将称之为traefik_dynamic.toml

添加以下文件提供商:

1[label traefik.toml]
2[providers.file]
3  filename = "traefik_dynamic.toml"

您的完成的「traefik.toml」將看起來像這樣:

 1[label traefik.toml]
 2[entryPoints]
 3  [entryPoints.web]
 4    address = ":80"
 5    [entryPoints.web.http.redirections.entryPoint]
 6      to = "websecure"
 7      scheme = "https"
 8
 9  [entryPoints.websecure]
10    address = ":443"
11
12[api]
13  dashboard = true
14
15[certificatesResolvers.lets-encrypt.acme]
16  email = "your_email@your_domain"
17  storage = "acme.json"
18  [certificatesResolvers.lets-encrypt.acme.tlsChallenge]
19
20[providers.docker]
21  watch = true
22  network = "web"
23
24[providers.file]
25  filename = "traefik_dynamic.toml"

保存并关闭文件。

现在让我们创建traefik_dynamic.toml。

你需要在自己的文件中保持的动态配置值是 middlewaresrouters. 要将你的仪表板置于密码后面,你需要定制 API 的 router 并配置一个 middleware 来处理 HTTP 基本身份验证。

该中间件是基于每协议配置的,因为您正在使用 HTTP,您将其指定为http.middlewares的链条部分,接下来是中间件的名称,以便您可以稍后参考它,然后是中间件的类型,在这种情况下将是basicAuth

创建并打开名为 `traefik_dynamic.toml’的新文件:

1nano traefik_dynamic.toml

添加以下代码. 这是您将从htpasswd命令中粘贴输出的地方:

1[label traefik_dynamic.toml]
2[http.middlewares.simpleAuth.basicAuth]
3  users = [
4    "admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/"
5  ]

为了为API配置路由器,您将再次从协议名称中删除链接,但不是使用http.middlewares,您将使用http.routers,然后使用路由器的名称。在这种情况下,API提供自己的命名路由器,您可以使用[http.routers.api]部分进行配置。

添加以下配置:

1[label traefik_dynamic.toml]
2...
3[http.routers.api]
4  rule = "Host(`monitor.your_domain`)"
5  entrypoints = ["websecure"]
6  middlewares = ["simpleAuth"]
7  service = "api@internal"
8  [http.routers.api.tls]
9    certResolver = "lets-encrypt"

「Web」入口點處理「80」端口,而「websecure」入口點使用「443」端口為 TLS/SSL。

注意这里的最后三行设置一个 service,启用 tls,并将certResolver配置为let-encrypt。服务是确定请求最终处理的最后一步。api@internal服务是一个内置的服务,位于您暴露的API背后。就像路由器和中间件一样,服务可以在此文件中配置,但您不需要这样做才能达到您想要的结果。

您的完成的「traefik_dynamic.toml」文件将看起来如下:

 1[label traefik_dynamic.toml]
 2[http.middlewares.simpleAuth.basicAuth]
 3  users = [
 4    "admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/"
 5  ]
 6
 7[http.routers.api]
 8  rule = "Host(`monitor.your_domain`)"
 9  entrypoints = ["websecure"]
10  middlewares = ["simpleAuth"]
11  service = "api@internal"
12  [http.routers.api.tls]
13    certResolver = "lets-encrypt"

保存文件并离开编辑器。

有了这些配置,您现在将启动 Traefik。

步骤2 - 运行 Traefik 集装箱

在此步骤中,您将创建一个Docker网络,让代理商与容器共享,然后您将访问Traefik仪表板。

创建一个名为Web的新Docker网络:

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/traefik_dynamic.toml:/traefik_dynamic.toml \
 5  -v $PWD/acme.json:/acme.json \
 6  -p 80:80 \
 7  -p 443:443 \
 8  --network web \
 9  --name traefik \
10  traefik:v2.2

这个命令有点长,让我们打破它。

您使用「-d」旗在背景中运行容器作为一个戴蒙,然后将您的「docker.sock」文件共享到容器中,以便 Traefik 流程可以听取对容器的更改。

接下来,您将 Docker 主机的端口 :80:443 地图到 Traefik 容器中的相同端口,以便 Traefik 接收所有 HTTP 和 HTTPS 流量到服务器。

您将容器的网络设置为Web,并将容器命名为traefik

最后,您可以为此容器使用traefik:v2.2图像,以便您可以保证您不会运行完全不同的版本,而本教程是为此编写的。

[Docker 图像的「ENTRYPOINT」是一个命令,在从图像中创建容器时总是运行(https://docs.docker.com/engine/reference/builder/#entrypoint)。在这种情况下,命令是容器内的「traefik」二进制。

随着集装箱的启动,你现在有一个仪表板,你可以访问,以查看你的集装箱的健康状况。你也可以使用这个仪表板来可视化路由器,服务和中间产品,Traefik已注册。你可以尝试访问监控仪表板,通过将你的浏览器指向 https://monitor.your_domain/dashboard/(需要追踪 /)。

您将被要求提供您的用户名和密码,这些是 admin和您在步骤 1中设置的密码。

一旦登录,你会看到 Traefik 界面:

Empty Traefik dashboard

您会注意到已经注册了一些路由器和服务,但这些都是带有Traefik和您为API编写的路由器配置的服务。

你现在有你的Traefik代理程序运行,你已经配置它与Docker工作,并监控其他容器. 在下一步,你将启动一些容器的Traefik代理程序。

步骤 3 – 使用 Traefik 注册集装箱

随着 Traefik 容器的运行,您已经准备好在其背后运行应用程序,让我们在 Traefik 背后推出以下容器:

  1. 使用 [官方 WordPress 图像] 的博客(https://hub.docker.com/_/wordpress/)。
  2. 使用 [官方 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]
 2...
 3
 4services:
 5  blog:
 6    image: wordpress:4.9.8-apache
 7    environment:
 8      WORDPRESS_DB_PASSWORD:
 9    labels:
10      - traefik.http.routers.blog.rule=Host(`blog.your_domain`)
11      - traefik.http.routers.blog.tls=true
12      - traefik.http.routers.blog.tls.certresolver=lets-encrypt
13      - traefik.port=80
14    networks:
15      - internal
16      - web
17    depends_on:
18      - mysql

环境键允许您指定将设置在容器内部的环境变量。如果您不为WORDPRESS_DB_PASSWORD设置一个值,则会告诉Docker Compose从您的壳中获取该值,并在创建容器时传输它。

标签部分是您为 Traefik 指定配置值的地方。Docker 标签不会自行做任何事情,但 Traefik 会读取这些标签,以便知道如何处理容器。

traefik.http.routers.adminer.rule=Host为您的集装箱创建一个新的 _router,然后指定用于确定请求是否匹配该集装箱的路由规则。 *traefik.routers.custom_name.tls=true指定该路由器应该使用 TLS。 *traefik.routers.custom_name.tls.certResolver=lets-encrypt指定您之前创建的解析证书应用于获取该路由器的证书。

通过此配置,在blog.your_domain域的80443端口发送到您的 Docker 主机的所有流量将被路由到blog容器。

您将此容器分配给两个不同的网络,以便 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_PASSWORDWORDPRESS_DB_PASSWORD变量将需要设置为相同的值,以确保您的 WordPress 容器可以与 MySQL 通信。您不希望将mysql容器暴露在 Traefik 或外部世界,所以您只会将此容器分配到内部网络。由于 Traefik 可以访问 Docker 接口,这个过程仍然会将路由器暴露在 mysql 容器的默认情况下,所以您会添加标签efiktraenable=false来指定 Traefik 不应该暴露这个容器。

最后,定义 Adminer 容器:

 1[label docker-compose.yml]
 2services:
 3...
 4  adminer:
 5    image: adminer:4.6.3-standalone
 6    labels:
 7      - traefik.http.routers.adminer.rule=Host(`db-admin.your_domain`)
 8      - traefik.http.routers.adminer.tls=true
 9      - traefik.http.routers.adminer.tls.certresolver=lets-encrypt
10      - traefik.port=8080
11    networks:
12      - internal
13      - web
14    depends_on:
15      - mysql

此容器的网络depends_on配置完全匹配你正在使用的博客容器。

traefik.http.routers.adminer.rule=Host 告诉 Traefik 检查所请求的主机。如果它匹配了db-admin.your_domain的模式,则 Traefik 会将流量路由到adminer容器,通过端口8080

完成的「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.http.routers.blog.rule=Host(`blog.your_domain`)
17      - traefik.http.routers.blog.tls=true
18      - traefik.http.routers.blog.tls.certresolver=lets-encrypt
19      - traefik.port=80
20    networks:
21      - internal
22      - web
23    depends_on:
24      - mysql
25
26  mysql:
27    image: mysql:5.7
28    environment:
29      MYSQL_ROOT_PASSWORD:
30    networks:
31      - internal
32    labels:
33      - traefik.enable=false
34
35  adminer:
36    image: adminer:4.6.3-standalone
37    labels:
38    labels:
39      - traefik.http.routers.adminer.rule=Host(`db-admin.your_domain`)
40      - traefik.http.routers.adminer.tls=true
41      - traefik.http.routers.adminer.tls.certresolver=lets-encrypt
42      - traefik.port=8080
43    networks:
44      - internal
45      - web
46    depends_on:
47      - mysql

保存文件并离开文本编辑器。

接下来,为WORDPRESS_DB_PASSWORDMYSQL_ROOT_PASSWORD变量设置壳中的值:

1export WORDPRESS_DB_PASSWORD=secure_database_password
2export MYSQL_ROOT_PASSWORD=secure_database_password

用您想要的数据库密码替换secure_database_password,请记住为WORDPRESS_DB_PASSWORDMYSQL_ROOT_PASSWORD使用相同的密码。

使用这些变量设置,使用docker-compose运行容器:

1docker-compose up -d

现在观看 Traefik admin 仪表板,当它挤满。

Populated Traefik dashboard

如果您浏览 ** 路由器** 部分,您会发现使用 TLS 配置的管理员博客的路由器:

HTTP Routers w/ TLS

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

WordPress setup screen

现在访问管理员,访问您的浏览器中的「db-admin.your_domain」,再次用您的域代替「your_domain」。

在管理员登录屏幕上,输入 用户名,输入 服务器mysql,然后输入您为 密码设置的MYSQL_ROOT_PASSWORD值。

一旦登录,您将看到 Adminer 用户界面。

Adminer connected to the MySQL database

现在两个网站都在工作,您可以使用monitor.your_domain的仪表板来监控您的应用程序。

结论

在本教程中,您将 Traefik v2 配置为向 Docker 容器中的其他应用程序发送代理请求。

Traefik 在应用程序容器级别的声明配置使其易于配置更多的服务,当您将新应用程序添加到代理流量时,无需重新启动traefik容器,因为 Traefik 会通过其监控的 Docker 接口文件立即注意到变化。

要了解有关您可以使用 Traefik v2 做什么的更多信息,请访问 官方 Traefik 文档

Published At
Categories with 技术
comments powered by Disqus