使用覆盖网络在 docker swarm 中隐藏 OpenVPN 后面的 docker 容器

Jim*_*mbo 5 dns openvpn docker docker-swarm traefik

目标:在 docker swarm 上部署一组服务,其中一个服务仅在我连接到 OpenVPN 服务器时才可用,该服务器也已在 docker swarm 上启动。

当我连接到 VPN 时,如何一步一步地只连接到 whoami 示例容器,在浏览器中有一个域?

背景

总体思路是,例如,kibana 和 elasticsearch 在内部运行,只能在 VPN(而不是公司网络)上访问,而其他服务正常公开运行。这些都将位于不同的节点上,因此我使用的是覆盖网络

我确实在 docker swarm 和whoami容器上运行了 OpenVPN ,我可以连接到 VPN,但是看起来 IP 没有变化,我不知道如何制作它以便 whoami 容器只是在 VPN 上可用,特别是考虑到我使用的是多主机的覆盖网络。我也在使用traefik,这是一个反向代理,它为我提供了一个用于通配符域的几乎自动的 letencrypt 设置(通过 DNS 挑战)。有了这个,我可以得到:

https://traefik.mydomain.com

但我也想连接到vpn.mydomain.com(我现在可以这样做),然后能够访问:

https://whoami.mydomain.com

......我不能。然而。我已经将我的traefik 配置发布在不同的地方,以防你想看一看,因为如果我把它发布在这里,这个线程会变得太大。

让我们从我现在所处的位置开始。

开放式VPN

首先,关于 OpenVPN 和 docker swarm 的有趣之处在于 OpenVPN 需要在特权模式下运行,因为它必须更改网络接口等,而swarm 还没有 CAP_ADD功能。因此,我们的想法是通过一种“代理容器”启动容器,该容器将手动运行容器,并为您添加这些权限。这是目前的一种解决方法,但这意味着您可以使用 swarm 部署服务。

这是我用于 OpenVPN 的 docker-compose:

    vpn-udp:
        image: ixdotai/swarm-launcher:latest
        hostname: mainnode
        environment:
            LAUNCH_IMAGE: ixdotai/openvpn:latest
            LAUNCH_PULL: 'true'
            LAUNCH_EXT_NETWORKS: 'app-net'
            LAUNCH_PROJECT_NAME: 'vpn'
            LAUNCH_SERVICE_NAME: 'vpn-udp'
            LAUNCH_CAP_ADD: 'NET_ADMIN'
            LAUNCH_PRIVILEGED: 'true'
            LAUNCH_ENVIRONMENTS: 'OVPN_NATDEVICE=eth1'
            LAUNCH_VOLUMES: '/etc/openvpn:/etc/openvpn:rw'
        volumes:
            - '/var/run/docker.sock:/var/run/docker.sock:rw'
        networks:
            - my-net
        deploy:
            placement:
                constraints:
                    - node.hostname==mainnode
Run Code Online (Sandbox Code Playgroud)

我可以使用以下方法部署上述内容:docker stack deploy --with-registry-auth --compose-file docker/docker-compose.prod.yml my-app-name这就是我用于其余部分的内容。重要的是,我不能只部署它,​​因为它尚未加载。OpenVPN 配置需要存在于/etc/openvpn节点上,然后安装在容器中,我在配置期间执行此操作:

// Note that you have to create the overlay network with --attachable for standalone containers
docker network create -d overlay app-net --attachable

// Create the config
docker run -v /etc/openvpn:/etc/openvpn --log-driver=none --rm ixdotai/openvpn ovpn_genconfig -u udp://vpn.mydomain.com:1194 -b

// Generate all the vpn files, setup etc
docker run -v /etc/openvpn:/etc/openvpn --log-driver=none --rm ixdotai/openvpn bash -c 'yes yes | EASYRSA_REQ_CN=vpn.mydomain.com ovpn_initpki nopass'

// Setup a client config and grab the .ovpn file used for connecting
docker run -v /etc/openvpn:/etc/openvpn --log-driver=none --rm ixdotai/openvpn easyrsa build-client-full client nopass

docker run -v /etc/openvpn:/etc/openvpn --log-driver=none --rm ixdotai/openvpn ovpn_getclient client > client.ovpn
Run Code Online (Sandbox Code Playgroud)

所以现在,我有一个可连接的覆盖网络,当我部署它时,OpenVPN 在第一个节点上启动并运行。我可以获取一份副本client.ovpn并连接到 VPN。即使我检查了“通过 VPN 发送所有流量”,看起来 IP 没有被更改,而且我仍然无法在其后面隐藏一个容器。


我是谁

这个简单的容器可以在 docker-compose 中使用以下内容进行部署:

    whoami:
        image: "containous/whoami"
        hostname: mainnode
        networks:
            - ${DOCKER_NETWORK_NAME}
        ports:
            - 1337:80
        deploy:
            placement:
                constraints:
                    - node.hostname==mainnode
Run Code Online (Sandbox Code Playgroud)

我将端口放在1337那里进行测试,因为我可以访问我的 IP:1337 并查看它,但这并不能实现我whoami.mydomain.com仅在连接到 OpenVPN 时进行解析的目标。


192.168连接到 vpn 时我可以 ping 一个地址

我在主机节点上运行了以下命令:

ip -4 地址添加 192.168.146.16/24 dev eth0

然后当连接到VPN时,我可以解析这个地址!所以看起来至少有些东西在起作用。

我怎样才能实现上面提到的目标?需要什么?需要存在什么样的 OpenVPN 配置、什么样的网络配置、什么样的容器配置?我是否需要一个自定义的 DNS 解决方案,就像我在下面建议的那样?有什么更好的选择?


一些考虑:

  • 我可以拥有域,包括私有域和whoami.mydomain.com公共域。这意味着我将拥有 https 并轻松为他们获取通配符证书,我想?但我的困惑是 - 我怎样才能在不使用自签名证书的情况下仅在 VPN 上获取这些域,而且还为它们提供 tls 证书?

  • 我也可以运行自己的 DNS 服务器进行解析。我试过这个,但我无法让它工作,可能是因为 VPN 部分还没有正常工作。我为此找到了dnsmasq,我必须添加上述本地 ip 才能resolve.conf在本地进行任何操作。但是域在连接到 VPN 时仍然无法解析,所以看起来 DNS 流量也没有通过 VPN(即使我这样设置 - 我的客户端是粘性的

  • 有人提到使用桥接网络,但桥接网络不适用于多主机

到目前为止的资源(我会更新更多)

-使用 swarm-launcher 部署 OpenVPN

-一个关于 stackexchange 的完全非解释性的答案,我认为它被其他 Github 线程中的多人引用为基本上没有帮助,并且其中一个链接已失效

小智 1

所以我对这个问题一直在头撞砖墙,然后通过改变你的想法来“解决”它:

基本上我向其主机打开了 VPN 容器的端口。然后启用代理。这意味着我可以通过访问 VPN 所在的 PC(又名 VPN 容器/堆栈的 Docker 主机)的 IP 来访问该代理。

和我一起挂:

我使用了gluetunvpn,但我认为如果您使用 openvpn,这也适用。我只是发现glutun更容易。

另外重要提示:我在本地主机环境中尝试了此操作,但理论上这也应该在多主机情况下工作,因为我正在使用单独的堆栈。也许,在多主机情况下,您需要使用主 docker 主机的公共 IP。

1. 创建网络

因此,首先为此 docker swarm 堆栈创建一个可连接网络:

docker network create --driver overlay --attachable --scope swarm vpn-proxy
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我开始认为这段话是多余的,但需要进行更多测试。

2. 设置VPN堆栈

然后创建你的 VPN 堆栈文件,让我们调用它stack-vpn.yml

(这里我gluetun通过 swarm-launcher “trick” 使用。这个glutun 服务通过 Wireguard 通过 VPN 连接。它还在端口 8888 启用 http 代理 - 该端口也通过设置映射到其主机LAUNCH_PORTS: '8888:8888/tcp'

docker network create --driver overlay --attachable --scope swarm vpn-proxy
Run Code Online (Sandbox Code Playgroud)

请注意, 和swarm-launcher容器gluetun正在使用先前创建的网络vpn-proxy

3.设置worker栈

目前我们将在这里设置一个包含 3 个高山图像副本的示例(文件名stack-workers.yml):

version: '3.7'

services:
  vpn_launcher:
    image: registry.gitlab.com/ix.ai/swarm-launcher
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock:rw'
    networks:
      - vpn-proxy
    environment:
      LAUNCH_IMAGE: qmcgaw/gluetun
      LAUNCH_PULL: 'true'
      LAUNCH_EXT_NETWORKS: 'vpn-proxy'
      LAUNCH_PROJECT_NAME: 'vpn'
      LAUNCH_SERVICE_NAME: 'vpn-gluetun'
      LAUNCH_CAP_ADD: 'NET_ADMIN'
      LAUNCH_ENVIRONMENTS: 'VPNSP=<your-vpn-service> VPN_TYPE=wireguard WIREGUARD_PRIVATE_KEY=<your-private-key> WIREGUARD_PRESHARED_KEY=<your-preshared-key> WIREGUARD_ADDRESS=<addrs> HTTPPROXY=on HTTPPROXY_LOG=on'
      LAUNCH_PORTS: '8888:8888/tcp'
    deploy:
      placement:
        constraints: [ node.role == manager ]
      restart_policy:
        condition: on-failure

networks:
  vpn-proxy:
    external: true
Run Code Online (Sandbox Code Playgroud)

他们还使用vpn-proxy覆盖网络。

4.启动我们的堆栈

docker stack deploy -c stack-vpn.yml vpn
docker stack deploy -c stack-workers workers
Run Code Online (Sandbox Code Playgroud)

一旦它们启动,您就可以访问任何工作任务,并尝试使用代理所在的主机 IP 来使用代理。

这是它有效的证明

正如我之前所说,理论上这应该适用于多主机情况,但可能您需要使用主 docker 主机的公共 ip(尽管如果它们共享相同的覆盖网络,它也可以使用内部 ip 地址(192 ...))。