路由到在默认端口上通过 Docker 运行的不同 SQL Server 实例

Posted

技术标签:

【中文标题】路由到在默认端口上通过 Docker 运行的不同 SQL Server 实例【英文标题】:Routing to Different SQL Server Instances Running through Docker on Default Port 【发布时间】:2019-01-08 13:48:50 【问题描述】:

我可以将 Traefik 用于网站,因为它们在连接时使用标题。 但我希望通过 docker 运行多个不同的 SQL Server 实例,这些实例将在外部可用(在 docker 主机之外,可能在本地网络之外)

那么,有没有什么东西可以连接到在同一个 docker 实例上运行的不同 sql server 实例,而不必为它们提供不同的端口或外部 IP 地址以便有人可以访问

sql01.docker.local,1433 AND sql02.docker.local,1433 来自 SQL 工具。

开始附加问题

由于没有回复,也许有一种方法可以有不同的实例,例如:sql.docker.local\instance1sql.docker.local\instance2 虽然我想这也可能是不可能的

结束附加问题

这是我尝试使用的 docker-compose 文件的一个示例(在我意识到对 sql server 的查询不会通过主机头发送之前 - 还是我错了?)

version: '2.1'
services:
  traefik:
    container_name: traefik
    image: stefanscherer/traefik-windows
    command: --docker.endpoint=tcp://172.28.80.1:2375 --logLevel=DEBUG
    ports:
      - "8080:8080"
      - "80:80"
      - "1433:1433"
    volumes:
      - ./runtest:C:/etc/traefik
      - C:/Users/mvukomanovic.admin/.docker:C:/etc/ssl
    networks:
      - default
    restart: unless-stopped
    labels:
      - "traefik.enable=false"

  whoami:
    image: stefanscherer/whoami
    labels:
      - "traefik.backend=whoami"
      - "traefik.frontend.entryPoints=http"
      - "traefik.port=8080"
      - "traefik.frontend.rule=Host:whoami.docker.local"
    networks:
      - default
    restart: unless-stopped


  sql01:
    image: microsoft/mssql-server-windows-developer
    environment:
      - ACCEPT_EULA=Y
    hostname: sql01
    domainname: sql01.local
    networks:
      - default
    restart: unless-stopped
    labels:
      - "traefik.frontend.rule=Host:sql01.docker.local,sql01,sql01.local"
      - "traefik.frontend.entryPoints=mssql"
      - "traefik.port=1433"
      - "traefik.frontend.port=1433"
    networks:
      - default
    restart: unless-stopped    
  sql02:
    image: microsoft/mssql-server-windows-developer
    environment:
      - ACCEPT_EULA=Y
    hostname: sql02
    domainname: sql02.local
    networks:
      - default
    restart: unless-stopped
    labels:
      - "traefik.frontend.rule=Host:sql02.docker.local,sql02,sql02.local"
      - "traefik.frontend.entryPoints=mssql"
      - "traefik.port=1433"
      - "traefik.frontend.port=1433"
    networks:
      - default
    restart: unless-stopped    

networks:
  default:
    external:
      name: nat

【问题讨论】:

与 SQL Server 的通信是通过 TDS 协议完成的,这是一个与 HTTP 非常不同的二进制协议。 (对于初学者来说,TDS 连接通常是持久的,而 HTTP 连接通常不是。)至少,您需要一个通用的 TCP 代理。 SQL Server 也不关心它的主机名——你不能在同一个端口上运行两个实例。在同一“机器”(无论是虚拟的还是真实的)上的实例必须使用不同的端口。实例名称仅用作将这些名称解析为端口的机制。 可以根据客户端在连接时指定的服务器名称来代理 TDS 连接——我知道是因为我构建了一个概念证明。但我不知道(值得生产的)TDS 代理。最终,通过为同一台机器分配不同的主机名,并将这些解析到不同的网络接口,可以更好地解决此类问题,因此即使服务器在同一节点上运行,它们也具有不同的 IP 地址。无需代理即可完成这项工作。 在 docker 中,它们已经在不同的接口上,但是当从 docker 服务器外部访问它时,它是一个单一的网络接口,所以我不能那样做。显然,如果可能的话,我将不得不进一步研究。 只回答你问题的一个方面:There are no named instances in SQL Server for Linux. 【参考方案1】:

你不能使用 traefik,因为它是一个 HTTP 反向代理。

你是 sql server 通过 TCP 监听和通信。

我不明白你的最终目标是什么。 你为什么使用 2 个不同的 sql-server ?

这取决于你想要什么,但你可能有两种解决方案:

您能使用更简单的解决方案吗?不同的数据库、角色和权限进行分离。 您可以搜索SQL Server Always On 的文档,但将查询路由到特定服务器似乎并不容易。

【讨论】:

我正在使用两个不同的服务器,因为我想将它们作为 docker 容器运行。所以在这种情况下角色和权限无济于事【参考方案2】:

没有像 HTTP 服务器那样对数据库的“虚拟”访问。所以 - 没有其他指向同一 IP 的主机名可以帮助您。

如果您坚持为所有实例使用端口 1433,那么我认为您除了使用两个不同的外部 IP 之外别无他法。

如果您使用的是 Linux 机器,您可以尝试一些 iptables 魔法,但它并不优雅,并且在任何时候都只允许访问您的一个实例。 Windows 可能有 iptables 等效项(我从未听说过),但您仍然无法逃脱一次。

我的建议 - 使用多个端口来公开您的服务器。

【讨论】:

【参考方案3】:

如前所述,traefik 不是正确的解决方案,因为它是仅 HTTP 的 LoadBalancer。

我现在可以用 3 种不同的方式来实现你想做的事情:

使用像 HAproxy 这样的 TCP 负载均衡器 在 Docker Swarm 模式 (https://docs.docker.com/engine/swarm/) 下设置您的服务器,这将允许通过它们之间的透明路由绑定相同的端口 使用服务发现服务,如 consul 和 SRV 记录,可以抽象端口号(这可能会超出您的需求并且设置复杂)

【讨论】:

现在这已经不正确了。 Traefik 现在也能够负载均衡 TCP 和 UDP。 这样一个快速发展的生态系统有什么好处 :-) 很高兴知道。谢谢@emuu

以上是关于路由到在默认端口上通过 Docker 运行的不同 SQL Server 实例的主要内容,如果未能解决你的问题,请参考以下文章

Docker容器跨主机通信之:直接路由方式

使用zuul路由到docker中的不同容器不起作用

将 env 变量从 Google 的 Secret Manager 加载到在 Google Cloud Run 上运行但未通过 Cloud Build 部署的 Docker 容器中?

003.OpenShift网络

通过docker host对nginx映射路由,为每个路由调用不同的容器

docker 在不同的端口上运行 mongo 映像