如何在Ubuntu20.04上使用Traefikv1作为Docker容器的反向代理

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Girls Who Code 来接受捐赠。

注意: 本教程适用于 Traefik v1。 如果你想安装和配置 Traefik v2,请使用这个更新的教程


介绍

Docker 可以是在生产环境中运行 Web 应用程序的有效方式,但您可能希望在同一个 Docker 主机上运行多个应用程序。 在这种情况下,您需要设置反向代理,因为您只想向世界其他地方公开端口 80443

Traefik 是一个支持 Docker 的反向代理,包括自己的监控仪表板。 在本教程中,您将使用 Traefik 将请求路由到两个不同的 Web 应用程序容器:一个 Wordpress 容器和一个 Adminer 容器,每个容器都与一个 MySQL 通信数据库。 您将使用 Let's Encrypt 将 Traefik 配置为通过 HTTPS 提供所有服务。

先决条件

要学习本教程,您将需要以下内容:

第 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 服务器,我们将使用 TOML 格式创建一个名为 traefik.toml 的新配置文件。 TOML 是一种类似于 INI 文件的配置语言,但已标准化。 这个文件让我们配置 Traefik 服务器和我们想要使用的各种集成providers。 在本教程中,我们将使用 Traefik 的三个可用提供程序:apidockeracme。 最后一个,acme 支持使用 Let's Encrypt 的 TLS 证书。

nano 或您喜欢的文本编辑器中打开您的新文件:

nano traefik.toml

首先,添加两个命名入口点,httphttps,默认情况下所有后端都可以访问它们:

traefik.toml

defaultEntryPoints = ["http", "https"]

我们稍后将在此文件中配置 httphttps 入口点。

接下来,配置 api 提供程序,它使您可以访问仪表板界面。 您将在此处粘贴 htpasswd 命令的输出:

traefik.toml

...
[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,但是我们需要为不针对 api 提供程序的标准 HTTP 和 HTTPS 通信定义其他的。 entryPoints 部分配置 Traefik 和代理容器可以监听的地址。 将这些行添加到 entryPoints 标题下的文件中:

traefik.toml

...
  [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 证书支持:

traefik.toml

...
[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's Encrypt 如何验证应该生成证书。 我们将其配置为通过 http 入口点提供文件作为挑战的一部分。

最后,让我们通过将这些行添加到文件中来配置 docker 提供程序:

traefik.toml

...
[docker]
domain = "your_domain"
watch = true
network = "web"

docker 提供程序使 Traefik 能够在 Docker 容器前充当代理。 我们已经为 web 网络上的新容器配置了提供程序 watch,我们将很快创建它,并将它们公开为 your_domain 的子域。

此时,traefik.toml应该有以下内容:

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

Traefik 只有在容器内的 root 用户对它具有唯一的读写权限时才能使用这个文件。 为此,请锁定 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 已注册的前端和后端。 通过将浏览器指向 https://monitor.your_domain 来访问监控仪表板。 系统将提示您输入用户名和密码,即 admin 和您在步骤 1 中配置的密码。

登录后,您会看到类似这样的界面:

目前还没有什么可看的,但是让这个窗口保持打开状态,当你添加容器供 Traefik 管理时,你会看到内容发生了变化。

现在我们的 Traefik 代理正在运行,配置为与 Docker 一起使用,并准备好监控其他 Docker 容器。 让我们为 Traefik 添加一些容器来代理。

第三步——用 Traefik 注册容器

随着 Traefik 容器的运行,您就可以在它后面运行应用程序了。 让我们在 Traefik 后面启动以下容器:

  1. 使用官方WordPress图片的博客。
  2. 使用官方Adminer镜像的数据库管理服务器。

我们将使用 docker-compose.yml 文件通过 Docker Compose 管理这两个应用程序。

在编辑器中创建并打开 docker-compose.yml 文件:

nano docker-compose.yml

将以下行添加到文件中以指定版本和我们将使用的网络:

码头工人-compose.yml

version: "3"

networks:
  web:
    external: true
  internal:
    external: false

我们使用 Docker Compose 版本 3 因为它是 Compose 文件格式的最新主要版本。

为了让 Traefik 识别我们的应用程序,它们必须属于同一网络,并且由于我们手动创建了网络,因此我们通过指定 web 的网络名称并将 external 设置为 [ X208X]。 然后我们定义另一个网络,以便我们可以将暴露的容器连接到我们不会通过 Traefik 暴露的数据库容器。 我们称这个网络为 internal

接下来,我们将定义我们的每个 services,一次一个。 让我们从 blog 容器开始,我们将基于官方 WordPress 镜像。 将此配置添加到文件的底部:

码头工人-compose.yml

...

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 键告诉 Docker Compose,该容器需要在 其依赖项运行后启动 。 由于 WordPress 需要一个数据库来运行,我们必须在启动我们的 blog 容器之前运行我们的 mysql 容器。

接下来,通过将此配置添加到文件底部来配置 MySQL 服务:

码头工人-compose.yml

...
  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD:
    networks:
      - internal
    labels:
      - traefik.enable=false

我们为此容器使用官方 MySQL 5.7 映像。 您会注意到我们再次使用没有值的 environment 项目。 MYSQL_ROOT_PASSWORDWORDPRESS_DB_PASSWORD 变量需要设置为相同的值,以确保我们的 WordPress 容器可以与 MySQL 通信。 我们不想将 mysql 容器暴露给 Traefik 或外部世界,因此我们只将此容器分配给 internal 网络。 由于 Traefik 可以访问 Docker 套接字,因此该进程默认仍会为 mysql 容器公开一个前端,因此我们将添加标签 traefik.enable=false 以指定 Traefik 不应公开此容器.

最后,将此配置添加到文件底部以定义管理员容器:

码头工人-compose.yml

...
  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 镜像。 此容器的 networkdepends_on 配置与我们用于 blog 容器的配置完全匹配。

然而,由于我们将所有到 Docker 主机上的端口 80 的流量直接引导到 blog 容器,因此我们需要以不同的方式配置这个容器,以便让流量进入我们的adminer 容器。 traefik.frontend.rule=Host:db-admin.your_domain 行告诉 Traefik 检查请求的主机。 如果它匹配 db-admin.your_domain 的模式,Traefik 会将流量路由到 adminer 容器。

此时,docker-compose.yml应该有以下内容:

码头工人-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_PASSWORDMYSQL_ROOT_PASSWORD 变量设置值:

export WORDPRESS_DB_PASSWORD=secure_database_password
export MYSQL_ROOT_PASSWORD=secure_database_password

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

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

docker-compose up -d

现在再看看 Traefik 管理仪表板。 您会看到两个暴露的服务器现在有一个 backend 和一个 frontend

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

现在通过在浏览器中访问 db-admin.your_domain 来访问 Adminer,再次将 your_domain 替换为您的域。 mysql 容器不暴露给外界,但 adminer 容器可以通过他们使用 [X172X 共享的 internal Docker 网络访问它] 容器名称作为主机名。

在管理员登录屏幕上,将 System 下拉菜单设置为 MySQL。 现在为 Server 输入 mysql,为 用户名 输入 root,然后为 MYSQL_ROOT_PASSWORD 设置的值X134X]密码。 将 Database 留空。 现在按登录

登录后,您将看到管理员用户界面:

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

结论

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

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

要了解有关使用 Traefik 可以做什么的更多信息, 前往 Traefik 官方文档