You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过DNS子域名访问Docker Swarm集群中的容器?

实现Docker Swarm容器的子域名访问(容器名作为子域名)

当然可以实现!核心思路是Wildcard DNS解析 + Swarm-aware反向代理,反向代理会自动发现Swarm中的服务,把对应子域名的流量转发到目标容器。下面是具体的实现步骤,我会用最适合Swarm生态的Traefik来做演示——它自带服务发现,能自动适配Swarm的动态服务部署。

第一步:配置Wildcard DNS记录

首先要让所有*.example.com的子域名都解析到你的物理机公网IP。登录你的域名服务商后台,添加一条A记录:

  • 主机记录:*
  • 记录值:你的物理机公网IPv4地址
  • TTL:选默认或短一点(比如5分钟)方便调试

这样不管是mysqldb.example.com还是webapp.example.com,都会指向你的服务器。

第二步:准备Swarm网络

创建一个Swarm overlay网络,让Traefik和你的服务能跨节点通信(单节点Swarm也适用):

docker network create --driver=overlay traefik-public

第三步:部署Traefik反向代理

Traefik是专门为容器化环境设计的反向代理,原生支持Swarm模式的服务自动发现。下面是生产可用的docker-compose配置(保存为traefik.yml):

version: '3.8'

services:
  traefik:
    image: traefik:v2.10
    command:
      - "--providers.docker=true"
      - "--providers.docker.swarmMode=true"
      - "--providers.docker.exposedbydefault=false" # 只处理显式声明的服务
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      # 自动申请Let's Encrypt证书(可选,用于HTTPS)
      - "--certificatesresolvers.myresolver.acme.httpchallenge=true"
      - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.myresolver.acme.email=your-email@example.com" # 用于证书过期提醒
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
      # 可选:Traefik仪表盘,生产环境建议限制内网访问
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro" # 只读权限,安全起见
      - "./letsencrypt:/letsencrypt" # 存储证书
    networks:
      - traefik-public
    deploy:
      placement:
        constraints:
          - node.role == manager # 部署在Swarm管理节点
      labels:
        # 配置仪表盘的子域名访问
        - "traefik.enable=true"
        - "traefik.http.routers.traefik.entrypoints=websecure"
        - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
        - "traefik.http.routers.traefik.tls.certresolver=myresolver"
        - "traefik.http.services.traefik.loadbalancer.server.port=8080"

networks:
  traefik-public:
    external: true

执行部署命令:

docker stack deploy -c traefik.yml traefik

第四步:配置你的服务(以MySQL为例)

现在部署你的mysqldb服务,通过Traefik标签指定子域名。注意MySQL是TCP协议,所以要配置TCP路由(和HTTP服务的配置略有不同):

保存为mysql.yml:

version: '3.8'

services:
  mysqldb:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=your-secure-password # 替换成你的密码
    volumes:
      - mysql-data:/var/lib/mysql # 持久化数据
    networks:
      - traefik-public
    deploy:
      labels:
        - "traefik.enable=true"
        # 配置TCP路由,用SNI匹配子域名(TCP没有HTTP Host头)
        - "traefik.tcp.routers.mysqldb.entrypoints=websecure"
        - "traefik.tcp.routers.mysqldb.rule=HostSNI(`mysqldb.example.com`)"
        - "traefik.tcp.routers.mysqldb.tls=true"
        - "traefik.tcp.routers.mysqldb.tls.certresolver=myresolver"
        # 指向MySQL容器的3306端口
        - "traefik.tcp.services.mysqldb.loadbalancer.server.port=3306"

volumes:
  mysql-data:

networks:
  traefik-public:
    external: true

部署服务:

docker stack deploy -c mysql.yml mysqldb

测试访问

用MySQL客户端连接:

mysql -h mysqldb.example.com -P 443 -u root -p --ssl-mode=REQUIRED

输入密码后就能访问容器里的MySQL了。

对于HTTP服务的配置(比如Nginx)

如果是Web服务,配置会更简单,用HTTP路由即可:

deploy:
  labels:
    - "traefik.enable=true"
    - "traefik.http.routers.webapp.entrypoints=websecure"
    - "traefik.http.routers.webapp.rule=Host(`webapp.example.com`)"
    - "traefik.http.routers.webapp.tls.certresolver=myresolver"
    - "traefik.http.services.webapp.loadbalancer.server.port=80"

注意事项

  1. 防火墙配置:确保物理机开放80、443端口(比如ufw allow 80/tcp、ufw allow 443/tcp)。
  2. 安全建议:
    • 不要直接把MySQL等数据库暴露到公网,建议搭配VPN或IP白名单限制访问。
    • 生产环境关闭Traefik的api.insecure=true(如果配置了),改用HTTPS访问仪表盘并限制内网IP。
  3. 动态适配:如果你的服务缩放、重启,Traefik会自动更新路由配置,不需要手动修改。

内容的提问来源于stack exchange,提问作者Vladyslav Baidak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:17:01