网站首页 > 教程文章 正文
什么是traefik
Traefik 是一个现代的反向代理和负载均衡器,专为微服务架构设计。它能够与 Docker、Kubernetes 等容器编排工具集成,并支持自动发现服务。Traefik 具有简单易用的配置方式,并提供了丰富的中间件支持,如身份验证、速率限制、流量控制等。
前提
本文基于dockerSwarm部署,通过Traefik做反向代理,Service服务需要获取客户端的真实IP,header信息:X-Real-IP、X-Forwarded-For。
- Docker Swarm 集群:已部署并运行 Docker Swarm 集群。
- Traefik:在 Swarm 中作为服务运行,并充当集群的入口网关。
- 一个服务:需要在 Swarm 中运行,并希望从中获取客户端的真实 IP。
问题
在容器化环境中,特别是在使用反向代理时,获取客户端的真实 IP 可能会受到影响。通常情况下,代理服务器会将客户端的 IP 地址隐藏在多个网络层中,并将其转发到后端服务。为了确保后端服务可以获取到真实的客户端 IP,需要进行适当的配置。
如果不通过header传递真实IP,Service中获取到的是内网地址。无法做正确的业务处理。
docker-compose.yml
services:
traefik:
image: "traefik:v3.1.2"
command:
- --log.level=INFO
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.swarm
- --providers.swarm.endpoint=unix:///var/run/docker.sock
- --providers.swarm.exposedByDefault=false
- --providers.swarm.refreshSeconds=3
- --providers.swarm.network=traefik-net
- --providers.swarm.httpClientTimeout=300
- --api
- --api.dashboard=true
- --certificatesresolvers.leresolver.acme.caserver=https://acme-v02.api.letsencrypt.org/directory
# update your email here
- --certificatesresolvers.leresolver.acme.email=your-email@example.com
# Make sure the this file is available and permission is set correctly
- --certificatesresolvers.leresolver.acme.storage=/le/acme.json
- --certificatesresolvers.leresolver.acme.tlschallenge=true
# prometheus
- --metrics
- --metrics.prometheus=true
- --metrics.prometheus.addEntryPointsLabels=true
- --metrics.prometheus.buckets=0.100000, 0.300000, 1.200000, 5.000000
- --entryPoints.metrics.address=:9005
- --metrics.prometheus.entryPoint=metrics
# Enable forwarding client real IP
- --entrypoints.web.forwardedHeaders.trustedIPs=0.0.0.0/0
- --entrypoints.websecure.forwardedHeaders.trustedIPs=0.0.0.0/0
- --entrypoints.web.forwardedHeaders.insecure=true
- --entrypoints.websecure.forwardedHeaders.insecure=true
ports:
- target: 80
published: 80
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
- target: 9005
published: 9005
protocol: tcp
mode: host
networks:
- traefik-net
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
# Make sure the volume folder is created
- "/data/traefik/acme.json:/le/acme.json"
deploy:
# 指定服务部署到哪个节点上
placement:
constraints:
- node.role == manager
# 指定服务的副本数量
replicas: 1
# 限定资源的使用限制
resources:
limits:
cpus: '2'
memory: 1024M
# 定义服务更新的策略
update_config:
# 指定并行更新的副本数量
parallelism: 1
# 指定更新之间的延迟时间
delay: 10s
# 指定更新失败时的操作
failure_action: rollback
# 指定监视服务健康状态的间隔时间
monitor: 1s
# 指定允许的最大更新失败率
max_failure_ratio: 0.3
# 指定服务更新的策略
order: start-first
# 定义服务回滚的策略
rollback_config:
# 指定并行回滚的副本数量
parallelism: 1
# 指定回滚之间的延迟时间
delay: 5s
# 指定回滚失败时的操作
failure_action: continue
# 指定监视服务健康状态的间隔时间
monitor: 3s
# 指定允许的最大回滚失败率
max_failure_ratio: 0.5
# 指定回滚失败时的回滚策略
order: start-first
# 定义容器重启策略
restart_policy:
# 指定容器重启的条件为失败时
condition: on-failure
labels:
# Dashboard
- "traefik.enable=true"
# Change the host url here
- "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.services.traefik.loadbalancer.server.port=8080"
- "traefik.http.routers.traefik.tls.certresolver=leresolver"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.middlewares=authtraefik"
# Change the auth password here
- "traefik.http.middlewares.authtraefik.basicauth.users=admin:$2y$05$4AsQ5Mu/uZJmR4eGn5gtgu9PnceJJcQechlr32K0dew1HadrZOaoO" # user/password
# global redirect to https
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
# middleware redirect
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
# Forward real client IP to backend services
- "traefik.http.middlewares.forwardedheaders.headers.customrequestheaders.X-Real-IP={client.ip}"
- "traefik.http.middlewares.forwardedheaders.headers.customrequestheaders.X-Forwarded-For={client.ip}"
networks:
traefik-net:
external: true
详细解读
services: traefik
image:traefik:v3.1.2:(指定使用 Traefik 3.1.2 版本镜像)。
command
这是 Traefik 的启动参数,配置项包括:
- --log.level=INFO: 设置日志级别为 INFO。
- --entrypoints.web.address=:80: 定义 web 入口点,监听端口 80。
- --entrypoints.websecure.address=:443: 定义 websecure 入口点,监听端口 443。
- --providers.swarm: 启用 Docker Swarm 提供者,用于自动发现服务。
- --providers.swarm.endpoint=unix:///var/run/docker.sock: 指定 Docker 的 UNIX 套接字作为 Swarm 提供者的端点。
- --providers.swarm.exposedByDefault=false: 默认情况下不自动暴露容器。
- --providers.swarm.refreshSeconds=3: 每 3 秒刷新一次服务配置。
- --providers.swarm.network=traefik-net: 指定 Traefik 应该使用的 Docker 网络。
- --providers.swarm.httpClientTimeout=300: 设置 HTTP 客户端的超时时间为 300 秒。
- --api: 启用 Traefik 的 API。
- --api.dashboard=true: 启用 Traefik 的 Dashboard。
- --certificatesresolvers.leresolver.acme.caserver=https://acme-v02.api.letsencrypt.org/directory: 配置 Let’s Encrypt 的 CA 服务器。
- --certificatesresolvers.leresolver.acme.email=your-email@example.com: 配置用于 SSL 证书注册的邮箱地址。
- --certificatesresolvers.leresolver.acme.storage=/le/acme.json: 指定证书存储路径。
- --certificatesresolvers.leresolver.acme.tlschallenge=true: 启用 TLS 证书挑战方式获取证书。
- --metrics: 启用指标监控。
- --metrics.prometheus=true: 启用 Prometheus 监控支持。
- --metrics.prometheus.addEntryPointsLabels=true: 为 Prometheus 指标添加入口点标签。
- --metrics.prometheus.buckets=0.100000, 0.300000, 1.200000, 5.000000: 配置 Prometheus 的 buckets。
- --entryPoints.metrics.address=:9005: 定义 metrics 入口点,监听端口 9005。
- --metrics.prometheus.entryPoint=metrics: 将 metrics 入口点的数据暴露给 Prometheus。
- --entrypoints.web.forwardedHeaders.trustedIPs=0.0.0.0/0: 允许所有 IP 作为可信的前端 IP(即接受所有来源的 X-Forwarded-For 头)。
- --entrypoints.websecure.forwardedHeaders.trustedIPs=0.0.0.0/0: 同上,针对 HTTPS(443)入口点。
- --entrypoints.web.forwardedHeaders.insecure=true: 允许处理未信任的 X-Forwarded-* 头,针对 HTTP。
- --entrypoints.websecure.forwardedHeaders.insecure=true: 同上,针对 HTTPS。
ports
定义 Traefik 服务的端口映射:
- 80:80: 将主机的 80 端口映射到容器的 80 端口,用于 HTTP。
- 443:443: 将主机的 443 端口映射到容器的 443 端口,用于 HTTPS。
- 9005:9005: 将主机的 9005 端口映射到容器的 9005 端口,用于 Prometheus 指标。
networks
- traefik-net: 该服务将连接到 traefik-net 网络,确保 Traefik 能与其他服务通信。
volumes
定义了 Traefik 所需的挂载卷:
- /var/run/docker.sock:/var/run/docker.sock:ro: 挂载 Docker 套接字,以允许 Traefik 与 Docker 容器通信。
- /data/traefik/acme.json:/le/acme.json: 用于存储 Let’s Encrypt 的证书信息。
deploy
定义服务在 Swarm 中的部署策略:
- placement.constraints: 指定服务仅部署在 Swarm 管理节点上。
- replicas: 设置服务副本数为 1。
- resources.limits: 限定服务使用的 CPU 为 2 核,内存为 1024MB。
- update_config: 定义服务更新策略。parallelism=1: 更新时并行处理 1 个副本。delay=10s: 每个更新之间延迟 10 秒。failure_action=rollback: 如果更新失败,则回滚。monitor=1s: 监视更新的健康状态,每秒检查一次。max_failure_ratio=0.3: 最大允许 30% 的更新失败率。order=start-first: 更新时先启动新副本,再停止旧副本。
- rollback_config: 定义服务回滚策略,类似于更新策略。parallelism=1: 并行回滚 1 个副本。delay=5s: 每次回滚之间延迟 5 秒。failure_action=continue: 回滚失败后继续回滚操作。monitor=3s: 监视回滚的健康状态,每 3 秒检查一次。max_failure_ratio=0.5: 最大允许 50% 的回滚失败率。order=start-first: 回滚时先启动新副本,再停止旧副本。
- restart_policy: 定义容器的重启策略,设定为当失败时重启。
labels
定义 Traefik 路由和中间件配置:
- traefik.enable=true: 启用 Traefik 路由。
- traefik.http.routers.traefik.rule=Host('traefik.example.com'): 设置 Traefik 的路由规则为匹配 traefik.example.com 域名。
- traefik.http.routers.traefik.service=api@internal: 将 Traefik 的内部 API 作为服务。
- traefik.http.services.traefik.loadbalancer.server.port=8080: 指定服务的内部端口为 8080。
- traefik.http.routers.traefik.tls.certresolver=leresolver: 指定使用 Let’s Encrypt 的 leresolver 获取 TLS 证书。
- traefik.http.routers.traefik.entrypoints=websecure: 将 traefik 路由绑定到 websecure(443)入口点。
- traefik.http.routers.traefik.middlewares=authtraefik: 使用名为 authtraefik 的中间件进行认证。
- traefik.http.middlewares.authtraefik.basicauth.users=...: 配置基础认证的用户和密码。
- traefik.http.routers.http-catchall.rule=hostregexp('{host:.+}'): 配置一个捕获所有主机名的规则。
- traefik.http.routers.http-catchall.entrypoints=web: 将该规则绑定到 web 入口点(端口 80)。
- traefik.http.routers.http-catchall.middlewares=redirect-to-https: 应用 redirect-to-https 中间件,将 HTTP 请求重定向到 HTTPS。
- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https: 定义重定向到 HTTPS 的中间件。
- traefik.http.middlewares.forwardedheaders.headers.customrequestheaders.X-Real-IP={client.ip}: 添加自定义请求头 X-Real-IP,将客户端的真实 IP 传递给后端服务。
- traefik.http.middlewares.forwardedheaders.headers.customrequestheaders.X-Forwarded-For={client.ip}: 同上,设置 X-Forwarded-For 请求头。
networks: traefik-net
定义了 Traefik 所使用的网络:
- external: true: 指定该网络为外部定义的网络(即非自动创建),需要在 Docker 中预先存在。
核心
获取客户端真实IP
第一部分:
- --entrypoints.web.forwardedHeaders.trustedIPs=0.0.0.0/0
- --entrypoints.websecure.forwardedHeaders.trustedIPs=0.0.0.0/0
- --entrypoints.web.forwardedHeaders.insecure=true
- --entrypoints.websecure.forwardedHeaders.insecure=true
第二部分:
- target: 80
published: 80
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
- target: 9005
published: 9005
protocol: tcp
mode: host
需要使用host网络,因为如果使用docker swarm的ingress网络,swarm内部又做了反向代理、负载均衡,且实现比较粗暴,无法传递header中的X-Real-IP。
第三部分:
# Forward real client IP to backend services
- "traefik.http.middlewares.forwardedheaders.headers.customrequestheaders.X-Real-IP={client.ip}"
- "traefik.http.middlewares.forwardedheaders.headers.customrequestheaders.X-Forwarded-For={client.ip}"
通过中间件,传递header信息。
在应用中获取真实IP
func getRealIP(r *http.Request) string {
realIP := r.Header.Get("X-Real-IP")
if realIP == "" {
realIP = r.Header.Get("X-Forwarded-For")
}
if realIP == "" {
realIP = r.RemoteAddr
}
return realIP
}
总结
完结
我为人人,人人为我,美美与共,天下大同。
- 上一篇: 两小时部署一个自己的博客
- 下一篇: Kong的代理详解之五——代理行为
猜你喜欢
- 2024-12-05 Nginx 路径匹配规则
- 2024-12-05 5分钟了解游戏加速器的原理与搭建
- 2024-12-05 推荐一个极简的开源项目管理-Taiga
- 2024-12-05 Nginx 部署负载均衡服务全解析
- 2024-12-05 Nginx-反向代理后应用程序获取客户端真实IP
- 2024-12-05 [ DeWeb使用技巧 ] DeWeb 实用化部署
- 2024-12-05 如何给公司节约成本,搭建免费开源监控系统uptime-kuma
- 2024-12-05 远程代码执行漏洞
- 2024-12-05 从开发环境到生产环境,部署 Tornado 应用程序
- 2024-12-05 本地调试微信之内网穿透
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- md5 sha1 (32)
- mybatis plus page (35)
- semaphore 使用详解 (32)
- update from 语句 (32)
- vue @scroll (38)
- 堆栈区别 (33)
- 在线子域名爆破 (32)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)