三种对象形成一条严格的请求处理链:

客户端请求 → EntryPoint → Router → Service → 后端服务器

各自职责

对象 类比 职责
EntryPoint 小区大门 监听端口、接收网络包,决定用 TCP 还是 HTTP 协议
Router 前台接待 检查请求特征(域名、路径、Header),决定"谁来处理这个请求"
Service 分配任务的经理 决定"把请求转发给哪个后端",以及如何负载均衡

组合关系:一个完整示例

假设你有一个电商系统,对外暴露两个端口:

互联网
  │
  ├── :443 (HTTPS EntryPoint "websecure")
  │     │
  │     ├── Router "dashboard"  域名=dashboard.example.com
  │     │     └── Service "dashboard-svc" → 10.0.1.5:3000
  │     │
  │     ├── Router "api"        域名=api.example.com
  │     │     └── Service "api-svc" → 10.0.1.10:8080, 10.0.1.11:8080  (负载均衡)
  │     │
  │     └── Router "shop"       域名=shop.example.com
  │           └── Service "shop-svc" → 10.0.1.20:3000
  │
  └── :9000 (TCP EntryPoint "mysql")
        │
        └── Router "mysql-route"  HostSNI=*.db.example.com
              └── Service "mysql-svc" → 10.0.2.1:3306

关键关系:

  • 一个 EntryPoint 可以挂多个 Router(:443 上挂了 3 个 HTTP Router)
  • 一个 Router 只能指向一个 Service,但一个 Service 可以包含多个后端实例
  • Router 通过规则匹配连接到 EntryPoint 上的特定请求流

代码层面怎么看

用 Traefik 的静态配置 + 动态配置来看这个过程:
Let me also look at how the three concepts connect in the server code to show the relationship.
Let me read a broader section of the BuildHandlers function to show how EntryPoint → Router → Service chain is built in code.
Now let me also check how routers connect to services. Let me find the buildEntryPointHandler function.

代码中的实际组装过程

pkg/server/router/router.go 可以看到,三者的关系在代码里是这样建立的:

BuildHandlers()
  │
  ├── 1. 获取每个 EntryPoint 下挂的所有 Router
  │      m.getHTTPRouters(ctx, entryPoints, tls)
  │
  └── 2. 为每个 EntryPoint 构建 Handler
         buildEntryPointHandler()
           │
           ├── 创建 Muxer(HTTP 路由表)
           │
           ├── 遍历该 EntryPoint 下的每个 Router
           │     │
           │     ├── buildRouterHandler()  → 根据 Router.Service 找到对应的 Service
           │     │                          → 组装 Middleware 链
           │     │                          → 返回最终 handler
           │     │
           │     └── muxer.AddRoute(router.Rule, handler)  → 把规则+处理器注册到 Muxer
           │
           └── 返回 Muxer 作为该 EntryPoint 的 HTTP Handler

一个具体的 Docker 部署示例

# 静态配置:定义 EntryPoint
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

# 动态配置(file provider):定义 Router → Service 映射
http:
  routers:
    # Router "dashboard" 挂在 websecure 入口上
    dashboard:
      entryPoints: ["websecure"]          # ← 指定绑在哪个 EntryPoint
      rule: "Host(`dashboard.example.com`)"  # ← 匹配规则
      service: dashboard-svc              # ← 指向哪个 Service
      middlewares: ["auth@file"]          # ← 可选的中间件链
      tls: {}

    api-router:
      entryPoints: ["websecure"]
      rule: "Host(`api.example.com`) && PathPrefix(`/v1`)"
      service: api-svc

  services:
    dashboard-svc:
      loadBalancer:
        servers:
          - url: "http://10.0.1.5:3000"

    api-svc:
      loadBalancer:
        servers:
          - url: "http://10.0.1.10:8080"
          - url: "http://10.0.1.11:8080"
        healthCheck:                     # 健康检查
          path: /health

  middlewares:
    auth:
      basicAuth:
        users:
          - "admin:$2y$05$..."

一次请求的完整链路:

curl https://api.example.com/v1/users

1. EntryPoint "websecure" (:443)
   → TLS 终止,得到 HTTP 请求 "GET /v1/users  Host: api.example.com"

2. Router "api-router" 
   → 规则匹配成功: Host==api.example.com && PathPrefix==/v1 ✓
   → 选定 Service: api-svc

3. Service "api-svc"
   → 从 [10.0.1.10:8080, 10.0.1.11:8080] 中选一个(WRR 算法)
   → 转发请求到后端

核心要点

关系 说明
EntryPoint → Router 一对多,一个端口可以服务多个域名
Router → Service 一对一,每个 Router 精确指向一个 Service
Service → Backend 一对多,一个 Service 下可以挂多个后端实例做负载均衡
Router → Middleware 一对多,Router 可选地串联多个中间件(auth、限流、重写等)

三者就像流水线上的三个工位:EntryPoint 负责接包,Router 负责分流,Service 负责分发

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐