Traefik & Docker

标签和容器的故事

Docker

将标签贴到您的容器上,让Traefik完成其余工作!

Traefik可与Docker(独立)引擎Docker Swarm模式一起使用 .

快速入门使用Docker

如果还没有,也许您想通过使用docker provider的快速入门!

Configuration Examples

配置Docker和部署/公开服务

启用Docker提供程序

[providers.docker]
providers:
  docker: {}
--providers.docker=true

将标签粘贴到容器(在docker compose文件中)

version: "3"
services:
  my-container:
    # ...
    labels:
      - traefik.http.routers.my-container.rule=Host(`mydomain.com`)
配置Docker Swarm和部署/公开服务

启用Docker提供程序(群模式)

[providers.docker]
  # swarm classic (1.12-)
  # endpoint = "tcp://127.0.0.1:2375"
  # docker swarm mode (1.12+)
  endpoint = "tcp://127.0.0.1:2377"
  swarmMode = true
providers:
  docker:
    # swarm classic (1.12-)
    # endpoint = "tcp://127.0.0.1:2375"
    # docker swarm mode (1.12+)
    endpoint: "tcp://127.0.0.1:2375"
    swarmMode: true
--providers.docker.endpoint=tcp://127.0.0.1:2375
--providers.docker.swarmMode=true

在Swarm模式下(在docker compose文件中)将标签附加到服务(而不是容器)

version: "3"
services:
  my-container:
    deploy:
      labels:
        - traefik.http.routers.my-container.rule=Host(`mydomain.com`)
        - traefik.http.services.my-container-service.loadbalancer.server.port=8080

Routing Configuration

当使用Docker作为提供程序时 ,Trafik使用容器标签来检索其路由配置.

请参阅专用路由部分中的标签列表.

Routing Configuration with Labels

默认情况下,Traefik在独立的Docker Engine上监视容器级别的标签 .

使用Docker Compose时,标签由"服务"对象中的指令labels指定.

不仅是Docker

请注意,任何能够定义带有标签的Docker容器的工具(例如Nomad,Terraform,Ansible等)都可以与Traefik和Docker提供程序一起使用.

Port Detection

Traefik从Docker API检索容器的私有IP和端口.

端口检测的工作方式如下:

  • 如果一个容器仅暴露一个端口,则Traefik将使用此端口进行专用通信.
  • 如果容器公开了多个端口,或者未公开任何端口,则必须使用标签traefik.http.services.<service_name>.loadbalancer.server.port手动指定Traefik应该使用哪个端口进行通信traefik.http.services.<service_name>.loadbalancer.server.port 路由中专用部分的标签).

Docker API Access

Traefik需要访问docker套接字以获取其动态配置.

您可以指定与指令endpoint一起使用的Docker API endpoint .

安全须知

在没有任何限制的情况下访问Docker API是一个安全问题:如果Traefik受到攻击,则攻击者可能会访问底层主机.

如Docker文档中所述:( Docker Daemon Attack Surface页面 ):

Quote

[...]只应允许受信任的用户控制您的Docker守护进程[...]

Solutions

通过TCP公开Docker套接字,而不是默认的Unix套接字文件. 根据您的安全评估,它允许AAA(身份验证,授权,计费)概念的不同实现级别:

  • "保护Docker守护程序套接字"中所述,使用客户端证书进行身份验证.
  • 使用TecnativaDocker套接字代理授权和过滤请求以限制可能的操作.
  • 使用Docker授权插件机制进行授权
  • 通过仅在Docker专用网络中公开套接字(仅适用于Traefik)在网络级别进行计费.
  • 通过将套接字暴露在Traefik以外的另一个容器上,在容器级别进行计费. 使用Swarm模式时,它允许在工作程序节点上调度Traefik,而在管理程序节点上仅使用"套接字暴露者"容器.
  • 通过使用SELinux之类的机制强制执行内核调用,可以在内核级别进行计费,从而仅允许Traefik进程(或"套接字暴露者"进程)的一组确定的操作.
更多资源和示例

Docker Swarm Mode

要将Docker Swarm(而不是独立的Docker)启用为配置提供程序,请将swarmMode指令设置为true .

Routing Configuration with Labels

在群模式下,Traefik使用在服务而非单个容器上找到的标签.

因此,如果在Swarm模式下使用撰写文件,则应在服务的deploy部分中定义标签.

仅在docker-compose版本3+( Compose file reference )中启用了此行为.

Port Detection

Docker Swarm不向Traefik提供任何端口检测信息.

因此,您必须使用标签traefik.http.services.<service_name>.loadbalancer.server.port来指定用于通信的端口(在Docker路由部分中检查此标签的引用).

Docker API Access

Docker Swarm Mode遵循与Docker API Access相同的规则.

由于Swarm API仅在管理器节点上公开,因此默认情况下,您应该在节点的"角色"上部署具有约束的 Traefik,从而在Traarm节点上调度Traefik:

docker service create \
  --constraint=node.role==manager \
  #... \
version: '3'

services:
  traefik:
    # ...
    deploy:
      placement:
        constraints:
          - node.role == manager

在工作节点上调度Traefik

遵循上一部分" Docker API访问"中给出的准则,如果您通过TCP公开Docker API,那么只要TCP套接字可访问,就可以在任何节点上调度Traefik.

请通过阅读安全说明来考虑安全隐患.

Bret Fisher的存储库中可以找到一个很好的例子.

Provider Configuration

endpoint

必需,默认=" unix:///var/run/docker.sock"

[providers.docker]
  endpoint = "unix:///var/run/docker.sock"
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
--providers.docker.endpoint=unix:///var/run/docker.sock

有关更多信息,请参阅" Docker API访问"和" Docker Swarm API访问 "部分.

使用docker.sock

docker-compose文件与Traefik容器共享docker袜子

version: '3'

services:
  traefik:
     image: traefik:v2.0 # The official v2.0 Traefik docker image
     ports:
       - "80:80"
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock

We specify the docker.sock in traefik's configuration file.

[providers.docker]
  endpoint = "unix:///var/run/docker.sock"
  # ...
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
     # ...
--providers.docker.endpoint=unix:///var/run/docker.sock
# ...

useBindPortIP

可选,默认= false

[providers.docker]
  useBindPortIP = true
  # ...
providers:
  docker:
    useBindPortIP: true
    # ...
--providers.docker.useBindPortIP=true
# ...

Traefik将请求路由到匹配容器的IP /端口. 设置useBindPortIP=true ,您告诉Traefik使用附加到容器绑定的IP /端口,而不是其内部网络IP /端口.

当与traefik.http.services.<name>.loadbalancer.server.port标签结合使用(告诉Traefik将请求路由到特定端口)时,Traefik尝试在端口traefik.http.services.<name>.loadbalancer.server.port上找到绑定traefik.http.services.<name>.loadbalancer.server.port 如果找不到这样的绑定,Traefik将使用容器的内部网络IP,但仍使用标签中设置的traefik.http.services.<name>.loadbalancer.server.port .

在不同情况下使用usebindportip示例.
端口标签 容器的绑定 前往的路线
- - IntIP:IntPort
- ExtPort:IntPort IntIP:IntPort
- ExtIp:ExtPort:IntPort ExtIp:ExtPort
LblPort - IntIp:LblPort
LblPort ExtIp:ExtPort:LblPort ExtIp:ExtPort
LblPort ExtIp:ExtPort:OtherPort IntIp:LblPort
LblPort ExtIp1:ExtPort1:IntPort1和ExtIp2:LblPort:IntPort2 ExtIp2:LblPort

在上表中:

  • ExtIp代表"绑定中找到的外部IP"
  • IntIp代表"内部网络容器的IP",
  • ExtPort代表"绑定中找到的外部端口"
  • IntPort代表"内部网络容器的端口".

exposedByDefault

可选,默认= true

[providers.docker]
  exposedByDefault = false
  # ...
providers:
  docker:
    exposedByDefault: false
    # ...
--providers.docker.exposedByDefault=false
# ...

默认情况下,通过Traefik公开容器. 如果设置为false,则没有traefik.enable=true标签的容器将从生成的路由配置中忽略.

另请参阅限制服务发现范围 .

network

可选,默认=空

[providers.docker]
  network = "test"
  # ...
providers:
  docker:
    network: test
    # ...
--providers.docker.network=test
# ...

定义用于连接所有容器的默认docker网络.

可以基于容器使用traefik.docker.network标签覆盖此选项.

defaultRule

可选,默认为Host(`{{ normalize .Name }}`)

[providers.docker]
  defaultRule = "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)"
  # ...
providers:
  docker:
    defaultRule: "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)"
    # ...
--providers.docker.defaultRule=Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)
# ...

对于给定的容器,如果标签未定义任何路由规则,则由此defaultRule定义. 它必须是有效的Go模板 ,并带有sprig模板功能 . 可以将容器服务名称作为Name标识符进行访问,并且模板可以访问在此容器上定义的所有标签.

swarmMode

可选,默认= false

[providers.docker]
  swarmMode = true
  # ...
providers:
  docker:
    swarmMode: true
    # ...
--providers.docker.swarmMode=true
# ...

激活Swarm模式(而不是独立的Docker).

swarmModeRefreshSeconds

可选,默认= 15

[providers.docker]
  swarmModeRefreshSeconds = "30s"
  # ...
providers:
  docker:
    swarmModeRefreshSeconds: "30s"
    # ...
--providers.docker.swarmModeRefreshSeconds=30s
# ...

定义"群集"模式下的轮询间隔(以秒为单位).

constraints

可选,默认值=""

[providers.docker]
  constraints = "Label(`a.label.name`,`foo`)"
  # ...
providers:
  docker:
    constraints: "Label(`a.label.name`,`foo`)"
    # ...
--providers.docker.constraints=Label(`a.label.name`,`foo`)
# ...

约束是Traefik与容器标签匹配的表达式,以确定是否为该容器创建任何路线. 也就是说,如果容器的标签都不匹配表达式,则不会创建容器的路由. 如果表达式为空,则包括所有检测到的容器.

The expression syntax is based on the Label("key", "value"), and LabelRegex("key", "value") functions, as well as the usual boolean logic, as shown in examples below.

约束表达式示例
# Includes only containers having a label with key `a.label.name` and value `foo`
constraints = "Label(`a.label.name`, `foo`)"
# Excludes containers having any label with key `a.label.name` and value `foo`
constraints = "!Label(`a.label.name`, `value`)"
# With logical AND.
constraints = "Label(`a.label.name`, `valueA`) && Label(`another.label.name`, `valueB`)"
# With logical OR.
constraints = "Label(`a.label.name`, `valueA`) || Label(`another.label.name`, `valueB`)"
# With logical AND and OR, with precedence set by parentheses.
constraints = "Label(`a.label.name`, `valueA`) && (Label(`another.label.name`, `valueB`) || Label(`yet.another.label.name`, `valueC`))"
# Includes only containers having a label with key `a.label.name` and a value matching the `a.+` regular expression.
constraints = "LabelRegex(`a.label.name`, `a.+`)"

另请参阅限制服务发现范围 .

tls

Optional

tls.ca

用于安全连接到Docker的证书颁发机构.

[providers.docker.tls]
  ca = "path/to/ca.crt"
providers:
  docker:
    tls:
      ca: path/to/ca.crt
--providers.docker.tls.ca=path/to/ca.crt

tls.caOptional

遵循与TLS客户端身份验证到Docker的安全连接的策略. 需要定义tls.ca

  • true :VerifyClientCertIfGiven
  • false :RequireAndVerifyClientCert
  • 如果tls.ca是未定义的NoClientCert
[providers.docker.tls]
  caOptional = true
providers:
  docker:
    tls:
      caOptional: true
--providers.docker.tls.caOptional=true

tls.cert

用于安全连接到Docker的公共证书.

[providers.docker.tls]
  cert = "path/to/foo.cert"
  key = "path/to/foo.key"
providers:
  docker:
    tls:
      cert: path/to/foo.cert
      key: path/to/foo.key
--providers.docker.tls.cert=path/to/foo.cert
--providers.docker.tls.key=path/to/foo.key

tls.key

用于安全连接到Docker的私有证书.

[providers.docker.tls]
  cert = "path/to/foo.cert"
  key = "path/to/foo.key"
providers:
  docker:
    tls:
      cert: path/to/foo.cert
      key: path/to/foo.key
--providers.docker.tls.cert=path/to/foo.cert
--providers.docker.tls.key=path/to/foo.key

tls.insecureSkipVerify

如果insecureSkipVerifytrue ,则与Docker的连接的TLS接受服务器提供的任何证书以及该证书中的任何主机名.

[providers.docker.tls]
  insecureSkipVerify = true
providers:
  docker:
    tls:
      insecureSkipVerify: true
--providers.docker.tls.insecureSkipVerify=true