使用 Traefik 进行 HTTP 路由

简介

在本地开发过程中,需要运行多个 HTTP 服务是很常见的。您可能同时拥有一个 API 和一个前端应用,一个用于模拟数据端点的 WireMock 服务,或者一个数据库可视化工具(如 phpMyAdmin 或 pgAdmin)。在许多开发设置中,这些服务暴露在不同的端口上,这不仅要求您记住哪个服务在哪个端口,还可能引入其他问题(例如 CORS)。

反向代理可以极大地简化这种设置,它作为唯一暴露的服务,然后根据请求 URL(通过路径或主机名)将请求路由到适当的服务。Traefik 是一个现代化的云原生反向代理和负载均衡器,它使开发和部署多服务应用程序变得更加容易。本指南将向您展示如何将 Traefik 与 Docker 结合使用,以增强您的开发环境。

在本指南中,您将学习如何

  1. 使用 Docker 启动 Traefik
  2. 配置路由规则以在两个容器之间分配流量
  3. 在容器化开发环境中使用 Traefik
  4. 使用 Traefik 将请求发送到非容器化工作负载

先决条件

要跟随本操作指南,需要满足以下先决条件

在 Docker 中使用 Traefik

Traefik 的一个独特功能是它可以通过多种方式进行配置。当使用 Docker provider 时,Traefik 使用标签从其他正在运行的容器中获取其配置。Traefik 会监视引擎事件(用于容器启动和停止),提取标签,并更新其配置。

虽然有许多 Traefik 监控的标签,但最常见的两个是:

让我们快速演示一下如何启动 Traefik,然后配置两个额外的容器,以便使用不同的主机名进行访问。

  1. 为了让两个容器能够相互通信,它们需要位于同一个网络上。使用 docker network create 命令创建一个名为 traefik-demo 的网络。

    $ docker network create traefik-demo
    
  2. 使用以下命令启动一个 Traefik 容器。该命令将 Traefik 暴露在 80 端口,挂载 Docker 套接字(用于监控容器以更新配置),并传递 --providers.docker 参数以配置 Traefik 使用 Docker provider。

    $ docker run -d --network=traefik-demo -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock traefik:v3.1.2 --providers.docker
    
  3. 现在,启动一个简单的 Nginx 容器,并定义 Traefik 正在监视的标签以配置 HTTP 路由。请注意,Nginx 容器没有暴露任何端口。

    $ docker run -d --network=traefik-demo --label 'traefik.http.routers.nginx.rule=Host(`nginx.localhost`)' nginx
    

    容器启动后,在浏览器中打开 http://nginx.localhost 以查看该应用(所有基于 Chromium 的浏览器都会在本地路由 *.localhost 请求,无需额外设置)。

  4. 启动第二个将使用不同主机名的应用程序。

    $ docker run -d --network=traefik-demo --label 'traefik.http.routers.welcome.rule=Host(`welcome.localhost`)' docker/welcome-to-docker
    

    容器启动后,在浏览器中打开 http://welcome.localhost。您应该会看到一个“Welcome to Docker”网站。

在开发中使用 Traefik

现在您已经体验了 Traefik,是时候尝试在开发环境中使用它了。在这个例子中,您将使用一个具有前后端分离的示例应用程序。该应用栈具有以下配置:

  1. 所有到 /api 的请求都转到 API 服务
  2. 所有其他到 localhost 的请求都转到前端客户端
  3. 由于该应用使用 MySQL,db.localhost 应提供 phpMyAdmin,以便在开发过程中轻松访问数据库
Architecture diagram showing Traefik routing requests to other containers based on the path of the request

该应用程序可以在 GitHub 上访问,地址为 dockersamples/easy-http-routing-with-traefik

  1. compose.yaml 文件中,Traefik 使用以下配置:

    services:
      proxy:
        image: traefik:v3.1.2
        command: --providers.docker
        ports:
          - 80:80
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock

    请注意,这与之前使用的配置基本相同,但现在是 Compose 语法。

  2. 客户端服务具有以下配置,它将启动容器并为其提供在 localhost 接收请求的标签。

    services:
      # …
      client:
        image: nginx:alpine
        volumes:
          - "./client:/usr/share/nginx/html"
        labels:
          traefik.http.routers.client.rule: "Host(`localhost`)"
  3. api 服务具有类似的配置,但您会注意到路由规则有两个条件——主机必须是“localhost”,并且 URL 路径必须以“/api”为前缀。由于此规则更具体,Traefik 将会比客户端规则优先评估它。

    services:
      # …
      api:
        build: ./dev/api
        volumes:
          - "./api:/var/www/html/api"
        labels:
          traefik.http.routers.api.rule: "Host(`localhost`) && PathPrefix(`/api`)"
  4. 最后,phpmyadmin 服务被配置为接收对主机名“db.localhost”的请求。该服务还定义了环境变量以自动登录,这使得进入应用程序变得更容易一些。

    services:
      # …
      phpmyadmin:
        image: phpmyadmin:5.2.1
        labels:
          traefik.http.routers.db.rule: "Host(`db.localhost`)"
        environment:
          PMA_USER: root
          PMA_PASSWORD: password
  5. 在启动堆栈之前,如果 Nginx 容器仍在运行,请停止它。

就是这样。现在,您只需要用 docker compose up 启动 Compose 堆栈,所有的服务和应用程序就都准备好进行开发了。

将流量发送到非容器化工作负载

在某些情况下,您可能希望将请求转发到未在容器中运行的应用程序。在下面的架构图中,使用了与之前相同的应用程序,但 API 和 React 应用现在在本机上运行。

An architecture diagram showing several components and the routing between them. Traefik is able to send requests to both non-containerized and containerized workloads

要实现这一点,Traefik 将需要使用另一种方法来配置自身。文件提供程序允许您在 YAML 文档中定义路由规则。这是一个示例文件:

http:
  routers:
    native-api:
      rule: "Host(`localhost`) && PathPrefix(`/api`)"
      service: native-api
    native-client:
      rule: "Host(`localhost`)"
      service: native-client

  services:
    native-api:
      loadBalancer:
        servers:
          - url: "http://host.docker.internal:3000/"
    native-client:
      loadBalancer:
        servers:
          - url: "http://host.docker.internal:5173/"

此配置指示对 localhost/api 的请求将被转发到名为 native-api 的服务,该服务再将请求转发到 http://host.docker.internal:3000。主机名 host.docker.internal 是 Docker Desktop 提供的一个名称,用于向主机发送请求。

有了这个文件,唯一的变化就是 Traefik 的 Compose 配置。具体来说,有两件事发生了变化:

  1. 配置文件被挂载到 Traefik 容器中(具体的目标路径由您决定)
  2. command 已更新,以添加文件提供程序并指向配置文件的位置
services:
  proxy:
    image: traefik:v3.1.2
    command: --providers.docker --providers.file.filename=/config/traefik-config.yaml --api.insecure
    ports:
      - 80:80
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./dev/traefik-config.yaml:/config/traefik-config.yaml

启动示例应用

要运行将请求从 Traefik 转发到原生运行的应用的示例应用,请使用以下步骤:

  1. 如果您的 Compose 堆栈仍在运行,请使用以下命令停止它:

    $ docker compose down
    
  2. 使用提供的 compose-native.yaml 文件启动应用程序。

    $ docker compose -f compose-native.yaml up
    

    打开 https:// 将返回 502 Bad Gateway,因为其他应用程序尚未运行。

  3. 通过运行以下步骤启动 API:

    cd api
    yarn install
    yarn dev
    
  4. 在一个新的终端中运行以下步骤来启动前端(从项目根目录开始):

    cd client
    yarn install
    yarn dev
    
  5. https:// 打开应用。您应该会看到一个从 https:///api/messages 获取消息的应用。您也可以打开 http://db.localhost 直接从 Mongo 数据库查看或调整可用的消息。Traefik 将确保请求被正确路由到正确的容器或应用程序。

  6. 完成后,运行 docker compose down 停止容器,并通过按 ctrl+c 停止 Yarn 应用。

回顾

运行多个服务不必需要复杂的端口配置和良好的记忆力。借助像 Traefik 这样的工具,可以轻松启动所需的服务并轻松访问它们——无论是应用本身(例如前端和后端)还是用于额外的开发工具(例如 phpMyAdmin)。

© . This site is unofficial and not affiliated with Kubernetes or Docker Inc.