Traefik学习

Traefik学习

背景

  • 因为之前购入了NUC11,在查询Linux服务器能够做什么有意思的事情时,偶然在这篇文章中看到了Traefik这个老熟人,之前在学校项目中也曾计划使用,但是奈何时间不太够,没有进一步接触,现在则重新开始学习这个云原生时代的反向代理工具
  • 本文不打算也不可能完整的介绍Traefik,推荐参考Traefik的官方文档,写的真的很详细,本文如果详细介绍的话,也不过是官方文档的翻译罢了,这里仅大概介绍下自己的理解,以及自己的实际使用案例,慢慢探索!

Traefik与Nginx

  • Traefik作为一款反向代理/网关工具,不得不与其老大哥Nginx比一比,相比于Nginx,Traefik的特点如下:

    • 无须重启即可更新配置,即可以做所谓的动态配置,也就是热加载

      • Nginx中如果需要更新配置,则首先要更新.conf格式的配置文件,随后使用nginx -s reload执行配置的更新
      • Traefik将服务的代理配置集中在服务自身的声明式配置文件中,而不用进行额外的集中式的配置的更新操作
    • 针对其支持的一众服务(在Traefik中,服务提供方被称为Provider),可以实现自动的服务发现与负载均衡

      • Docker 完美集成,基于容器label属性的的配置实现自动的服务发现与负载均衡,这里实际上就是把Docker作为一种Provider

      • 其余的常用的ProviderKubernetesRancher等等,所以说Traefik是”云原生“时代的反向代理工具

        image-20220420160742951

  • 流程清晰,作为一个反向代理/网关产品,Traefik抽象了EntryPointsRoutersServicesProviders等概念,这使得整个代理流程更加清晰,相比Nginx的传统配置更加容易理解

  • 支持很漂亮的Dashboard,同时Dashboard对于上述的一些列抽象概念也有明晰的划分

  • 具有良好的可观测性,提供了对日志、Metrics、Tracing的支持

  • 支持一系列Middleware,可以以中间件的方式提供多种开箱即用的代理功能,比如文件压缩、登录验证、HTTP重定向到HTTPS等

    image-20220420161431870

基本概念

image-20220420192433179

EntryPoint

  • 定义网关的入口,最常用的就是定义两个端口提供服务,即80与443,traefik通过这两个端口监听外界的请求

    # 定义网关入口
    [entryPoints]
      [entryPoints.http]
        address = ":80"
      [entryPoints.https]
        address = ":443"
    
  • 除了定义端口,还可以定义端口监听的协议(TCP/UDP)

Router

  • 路由组件,将请求路由到指定的Service,在路由组件中可以使用各种中间件处理请求

    [http.routers.halo-redirect-https]
      rule = "Host(`blog.demoli.xyz`)"
      entryPoints = ["http"]
      service = "noop"
      middlewares = ["https-redirect"]
      priority = 100
    
    [http.routers.halo]
      rule = "Host(`blog.demoli.xyz`)"
      entrypoints = ["https"]
      service = "halo"
      [http.routers.halo.tls]
    
    • 可以使用rule定义路由规则,类似Nginx中的location
    • tls属性执行该路由使用TLS加密,即支持HTTPS协议
  • 同样的可以设置支持TCP或UDP的路由

Service

  • 可以用来配置声明代理网关背后真正工作的服务

    [http.services]
      [http.services.halo.loadBalancer]
        [[http.services.halo.loadBalancer.servers]]
          url = "http://halo:8090"
    
  • 支持一系列负载均衡的配置

  • 同样支持TCP/UDP服务的配置

Provider

  • 服务的提供方,也可以理解为是动态配置的实现方,支持Docker、Kubernetes、Rancher、Marathon、File等

  • 对于最常用的Docker来说,支持使用Docker Label来声明动态配置

    version: '3.1'
    services:
      halo:
        image: halohub/halo
        container_name: halo
        restart: unless-stopped
        volumes:
          - /root/blog/halo:/root/.halo 
        labels:
          - traefik.http.routers.halo.rule=Host(`blog.demoli.xyz`)
          - traefik.http.routers.halo.tls=true
          - traefik.http.routers.halo.entrypoints=https
          - traefik.http.services.halo.loadbalancer.server.port=8090
          - traefik.http.routers.halo-redirect-https.rule=Host(`blog.demoli.xyz`)
          - traefik.http.routers.halo-redirect-https.entrypoints=http
          - traefik.http.routers.halo-redirect-https.service=noop@file
          - traefik.http.routers.halo-redirect-https.middlewares=https-redirect@file
          - traefik.http.routers.halo-redirect-https.priority=100
    networks:
      default:
        external:
          name: traefik
    

Middleware

  • 作用与Routers与Services之间,可在请求到达Services之前或者是响应从Services发出但是到达Client之前对请求或响应进行处理,实际上是一些常用的Web能力的封装,常用的有:
    • BasicAuth 提供Basic Auth身份验证
    • Buffering,提供请求缓存,过滤体积过大的请求
    • Compress,使用gzip压缩响应,提升响应速度
    • RateLimit,提供限流
    • IPWhiteList,IP白名单设置
    • Retry,如果后端服务没有成功响应,则重试多次

配置文件

  • Traefik提供了两种类型的配置方式
    • 静态配置
    • 动态配置

静态配置

  • 静态配置,或者说启动配置,一般用来设置Providers与Entrypoints,因为一般情况下这两者在整个系统中是不会发生改变的,可以使用yaml或者toml两种格式的配置文件提供静态配置
    • 常用的配置可以参考Traefik提供的配置文件模板Traefik.sample.toml
    • 还可以使用命令行参数和环境变量的形式提供静态配置
  • 关于静态配置的一个关键的认识就是,如果不对配置设定值,或者没有显式设置某配置,则该配置使用其默认值,对于一些子配置同样有效,比如使用命令行参数的情况下,--providers.docker表示开启使用Docker作为Provider的功能,但是实际上并没有为改参数设置值,等价于--providers.docker=true,即便是指定--providers.docker.endpoint这个子配置,也会默认开启Docker作为Provider的功能。其他形式下的静态配置类比即可

动态配置

  • 动态配置一般用来设置其余的配置,可以实现热更新,动态配置的提供源就是一众Provider

案例

Traefik的部署

  • 使用Docker Compose部署Traefik,首先创建Traefik的配置环境,文件系统结构如下所示

    • traefik
      • config
        • 存放动态配置文件
      • ssl
        • 存放HTTPS证书
      • traefik.toml --静态配置文件
      • traefik.yaml --Docker Compose配置文件
  • traefik.toml静态配置如下:

    [global]
      checkNewVersion = false
      sendAnonymousUsage = false
    
    [log]
      level = "WARN"
      format = "common"
    
    # dashboard与API设置
    [api]
      dashboard = true
      insecure = false
    # ping设置
    [ping]
    
    # accessLog设置
    [accessLog]
    
    # 配置provider
    [providers]
      [providers.docker]
        endpoint = "unix:///var/run/docker.sock"
        network = "traefik"
      [providers.file]
        watch = true
        directory = "/etc/traefik/config"
        debugLogGeneratedTemplate = true
    
    # 定义网关入口
    [entryPoints]
      [entryPoints.http]
        address = ":80"
      [entryPoints.https]
        address = ":443"
    # 定义metrics
    [metrics]
      [metrics.prometheus]
         addEntryPointsLabels = true
         addRoutersLabels = true
         addServicesLabels = true
    
    • 配置了Dashboard功能与API服务
    • 配置了Docker与File两个Provider,其中File中指定了/etc/traefik/config目录下的配置文件的变动会被监听以实现动态配置与配置的热加载
    • 定义了http与https两个EntryPoint
    • 定义了Prometheus存储的Metrics,可结合Grafana做Metrics展示,metrics默认在${TraefikIP}:8080/metrics下提供
  • config目录下的tls的配置文件如下:

    [tls]
      [tls.options]
        [tls.options.default]
          minVersion = "VersionTLS12"
          maxVersion = "VersionTLS12"
        [tls.options.test-tls13]
          minVersion = "VersionTLS13"
          cipherSuites = [
            "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
            "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
            "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
            "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
            "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
            "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
          ]
      # 配置两个证书
      [[tls.certificates]]
        certFile = "/data/ssl/blog.demoli.xyz.pem"
        keyFile = "/data/ssl/blog.demoli.xyz.key"
    
      [[tls.certificates]]
        certFile = "/data/ssl/dashboard.demoli.xyz.pem"
        keyFile = "/data/ssl/dashboard.demoli.xyz.key"
    
    • Traefik 可以定制每个请求响应使用的 TLS 版本,还可以定制加密算法、以及独立为某个/某些域名单独进行配置
    • ssl文件夹下的证书可以根据证书文件的命名中的domain与对应的路由进行自动匹配
  • config目录下用于配置HTTP到HTTPS跳转的配置文件default.toml如下:

    [http.middlewares.https-redirect.redirectScheme]
      scheme = "https"
    [http.middlewares.content-compress.compress]
    
    # tricks
    # https://github.com/containous/traefik/issues/4863#issuecomment-491093096
    [http.services]
      [http.services.noop.LoadBalancer]
         [[http.services.noop.LoadBalancer.servers]]
            url = "" # or url = "localhost"
    
    [http.routers]
      [http.routers.https-redirect]
        entryPoints = ["http"]
        rule = "HostRegexp(`{any:.*}`)"
        middlewares = ["https-redirect"]
        service = "noop"
    
    • 使用官方提供的redirectScheme中间件定义https-redriect中间件
    • 配置了noop这个Service,后续需要设置此Service做为跳转路由的后端服务
    • 定义了名为https-redirect的Router,使用正则匹配匹配所有域名都实现这种跳转
    • 将调准配置维护到一个单独的配置文件中,相当于定义了几个公共方法,好处是可以为后续使用 Traefik 的每一个服务单独配置是否进行 HTTP->HTTPS 跳转
  • config目录下的Dashboard/API配置文件dashboard.demoli.xyz.toml如下:

    [http.middlewares.dash-compress.compress]
    [http.middlewares.dash-auth.basicAuth]
      users = [
        "${username}:${password}"
      ]
    [http.routers.dashboard-redirect-https]
      rule = "Host(`dashboard.demoli.xyz`)"
      entryPoints = ["http"]
      service = "noop"
      middlewares = ["https-redirect"]
      priority = 100
    
    [http.routers.dashboard]
      rule = "Host(`dashboard.demoli.xyz`)"
      entrypoints = ["https"]
      service = "dashboard@internal"
      middlewares = ["dash-auth", "dash-compress"]
      [http.routers.dashboard.tls]
    
    [http.routers.api]
      rule = "Host(`dashboard.demoli.xyz`) && PathPrefix(`/api`)"
      entrypoints = ["https"]
      service = "api@internal"
      middlewares = ["dash-auth", "dash-compress"]
      [http.routers.api.tls]
    
    [http.routers.ping]
      rule = "Host(`dashboard.demoli.xyz`) && PathPrefix(`/ping`)"
      entrypoints = ["https"]
      service = "ping@internal"
      middlewares = ["dash-auth", "dash-compress"]
      [http.routers.ping.tls]
    
    • 定义了dash-authdash-compress两个middleware(在文件开头定义),前者用来提供BasicAuth验证,后者用来提供gzip文件压缩
    • 使用https-redirect中间件添加了dashboard-redirect-https的路由,用来实现HTTP访问自动重定向到HTTPS访问,因为是重定向,其后边的服务配置的是noop,即是空服务(在default.toml中配置)
      • https-redirect中间件是在config/default.toml中自定义的
    • 定义了dashboard@internalapi@internalping@internal三种服务的路由,其中API用来提供API服务,ping用来支持健康检查,同时设置了这三种服务对HTTPS的支持
      • 三者同时使用了dash-authdash-compress两个middleware(在文件开头定义)
    • Host部分配置的访问域名可以自行更改,注意在自己的DNS提供商中添加对应的解析即可
  • traefik.yaml Docker Compose配置文件如下:

    version: '3'
    services:
      reverse-proxy:
        image: traefik
        restart: always
        ports:
          - "80:80"
          - "443:443"
        networks:
          - traefik
        volumes:
          - ./traefik.toml:/etc/traefik/traefik.toml
          - /var/run/docker.sock:/var/run/docker.sock
          - ./ssl/:/data/ssl/:ro
          - ./config/:/etc/traefik/config/:ro
        container_name: traefik
        # 网关健康检查
        healthcheck:
          test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:8080/ping || exit 1"]
          interval: 3s
          timeout: 5s
    # 创建外部网络 docker network create traefik
    networks:
      traefik:
        external: true
    
  • 首先执行docker network create traefik创建外部网络,再执行docker-compose -f traefik.yaml up -d开启服务

  • Halo博客的yaml配置文件blog.yaml:

    version: '3.1'
    services:
      halo:
        image: halohub/halo
        container_name: halo
        restart: unless-stopped
        volumes:
          - /root/blog/halo:/root/.halo 
        labels:
          - traefik.http.routers.halo.rule=Host(`blog.demoli.xyz`)
          - traefik.http.routers.halo.tls=true
          - traefik.http.routers.halo.entrypoints=https
          - traefik.http.services.halo.loadbalancer.server.port=8090
          - traefik.http.routers.halo-redirect-https.rule=Host(`blog.demoli.xyz`)
          - traefik.http.routers.halo-redirect-https.entrypoints=http
          - traefik.http.routers.halo-redirect-https.service=noop@file
          - traefik.http.routers.halo-redirect-https.middlewares=https-redirect@file
          - traefik.http.routers.halo-redirect-https.priority=100
          - traefik.http.middlewares.halo-compress.compress=true
          - traefik.http.routers.halo.middlewares=halo-compress
    networks:
      default:
        external:
          name: traefik
    
    • traefik.http.routers.halo.rule定义路由规则

    • traefik.http.routers.halo.tls表示使用HTTPS

    • traefik.http.services.halo.loadbalancer.server.port指定Service的服务端口,注意此项设置是必须的,否则Traefik无法监视到Halo应用,参考Port Dection

    • 剩余的部分则是仿照Dashboard设置HTTP到HTTPS的重定向以及定义并使用了Compress插件,以减少响应的体积

    • 除了使用Docker的label提供动态配置,还可以在conf文件夹中以文件的形式提供动态配置(即使用File类型的Provider),blog.demoli.xyz.toml:

      [http.routers.halo-redirect-https]
        rule = "Host(`blog.demoli.xyz`)"
        entryPoints = ["http"]
        service = "noop"
        middlewares = ["https-redirect"]
        priority = 100
      
      [http.routers.halo]
        rule = "Host(`blog.demoli.xyz`)"
        entrypoints = ["https"]
        service = "halo"
        [http.routers.halo.tls]
      
      [http.services]
        [http.services.halo.loadBalancer]
          [[http.services.halo.loadBalancer.servers]]
            url = "http://halo:8090"
      
  • 执行docker-compose -f blog.yaml up -d启动博客应用,启动完毕后,Dashboard中可以看到博客应用已经被Traefik捕获到

补充

Traefik监控系统

Traefik代理Wireguard VPN

  • 结合使用Wireguard搭建VPN服务食用更香,在这篇文章中,实现了内网主机部署Wireguard VPN,然后通过Frp做内网穿透。现在要做的就是将公网上的Frp服务以及并随的Wireguard UDP服务统一纳入Traefik的管理

  • 首先为Frp服务以及伴随的UDP服务添加Entrypoint

    [entryPoints]
      [entryPoints.http]
        address = ":80"
      [entryPoints.https]
        address = ":443"
      [entryPoints.tcp]
        address = ":6000"
      [entryPoints.udp]
        address = ":443/udp"
    
  • Traefik的Docker Compose文件添加两个EntryPoint的端口映射

    version: '3'
    services:
      reverse-proxy:
        image: traefik
        restart: always
        ports:
          - "80:80"
          - "443:443"
          - "443:443/udp"
          - "6000:6000"
        networks:
          - traefik
        volumes:
          - ./traefik.toml:/etc/traefik/traefik.toml
          - /var/run/docker.sock:/var/run/docker.sock
          - ./ssl/:/data/ssl/:ro
          - ./config/:/etc/traefik/config/:ro
        container_name: traefik
        # 网关健康检查
        healthcheck:
          test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:8080/ping || exit 1"]
          interval: 3s
          timeout: 5s
    # 创建外部网卡 docker network create traefik
    networks:
      traefik:
        external: true
    
  • 修改Frps的Docker Compose配置文件

    version: '3'
    services:
      frps:
        image: snowdreamtech/frps
        container_name: frps
        restart: unless-stopped
        volumes:
          - ./frps.ini:/etc/frp/frps.ini
        # dashboard端口直接使用SSH端口映射,不使用网关处理
        ports:
          - 6001:6001
        labels:
          - traefik.tcp.routers.frps.rule=HostSNI(`*`)
          - traefik.tcp.routers.frps.entryPoints=tcp
          - traefik.tcp.services.frps.loadbalancer.server.port=6000
          - traefik.udp.routers.frps.entryPoints=udp
          - traefik.udp.services.frps.loadbalancer.server.port=51820
    networks:
      default:
        external:
          name: traefik
    
    • 6001端口被设置为Frp Dashboard的端口,此端口使用端口映射映射到内网服务器,不对外开放,因此只做Docker的端口映射,而不做Traefik的管理

    • 对TCP Routers与TCP Services的设置参考Configure TCP Routers

      • 需要注意的是traefik.tcp.routers.frps.rule的设置之所以使用*是因为:

        It is important to note that the Server Name Indication is an extension of the TLS protocol. Hence, only TLS routers will be able to specify a domain name with that rule. However, non-TLS routers will have to explicitly use that rule with * (every domain) to state that every non-TLS request will be handled by the router.

    • 对UDP Routers与UDP Services的设置参考 Configure UDP Routers

      • traefik.udp.services.frps.loadbalancer.server.port指定的端口正是内网的Wireguard 服务通过Frp内网穿透映射的端口
  • 在Wireguard的客户端,对端节点需要设置为:公网IP:443

  • 经过上述的一番操作,实际上有利有弊,好处在于进一步的将对外访问服务收归Traefik的统一管理,弊端在于后续如果使用该Frp Server做其他的端口映射时,需要修改Frps的Docker Compose配置文件,甚至是Traefik的静态配置文件,应该会有更高的方法待进一步改进

使用Let's Encrypt支持HTTPS证书签发

参考

posted @   Demolee  阅读(801)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示