前言

最近在给咸鱼客户部署服务时发现刚恢复不久的 Docker Hub 又访问不了了,以及安装 Docker 的程序也无法正常访问,这让人很痛苦,本来几分钟能搞定的,结果愣是花了十几二十分钟。

于是又花时间去找解决方案,目前比较有效的就是如下几种方案:

  • 用 Cloudflare 搭建 Docker Registry Proxy
  • 基于现有的 Proxy 实现更通用的代理
  • 本地下载 Docker 镜像,然后通过一系列操作,导出、上传到服务器、导入服务器,再重命名 tag

在此之前,我都是用第三种方式进行安装和部署的,虽然没啥问题,但是太麻烦,每次都要拉取 AMD64 架构的镜像,然后完成部署后再删除本地的镜像。

为什么不用第一种呢,主要是需要将镜像的 docker.io 前缀替换成自己的域名,在服务编排比较复杂的项目中,这也挺让人头疼的。

于是我就想着是否够通过 TCP Tunnel,让云服务器使用本地的 Surge Proxy 作为代理,确定方案后,就开始尝试,经过几轮测试发现效果还不错。

但这种方案对于内网的带宽和服务器的 Upload 带宽有一定要求,否则速度也不是很理想!

要求

  • 在国内有公网服务器
  • 本地有科学上网神器

部署 Expose 服务

这部分内容可以参考我之前的文章《私有化部署 Expose 实现内网 Tunnel》,这里就不再在赘述。

之前的文章,没有涉及 TCP Tunnel 的部分,这里需要根据自己的服务端配置,暴露 TCP Tunnel 的端口!

services:
  expose:
    image: beyondcodegmbh/expose-server:latest
    ports:
      - 0.0.0.0:8888-8890:8888-8890/tcp
    labels:
      - traefik.enable=true
      - traefik.http.routers.expose.tls=true
      - traefik.http.routers.expose.tls.certResolver=example
      - traefik.http.routers.expose.rule=Host(`example.com`)
      - traefik.http.routers.expose.service=expose
      - traefik.http.routers.expose.entrypoints=http,https
      - traefik.http.services.expose.loadbalancer.server.port=443

      - traefik.http.routers.tunnel.tls=true
      - traefik.http.routers.tunnel.tls.certResolver=example
      - traefik.http.routers.tunnel.tls.domains[0].main=example.com
      - traefik.http.routers.tunnel.tls.domains[0].sans=*.example.com
      - traefik.http.routers.tunnel.rule=HostRegexp(`^.+.example.com$`)
      - traefik.http.routers.tunnel.service=tunnel
      - traefik.http.routers.tunnel.priority=5
      - traefik.http.routers.tunnel.entrypoints=http,https
      - traefik.http.services.tunnel.loadbalancer.server.port=443
    restart: always
    volumes:
      - ./config/expose.php:/src/config/expose.php
      - ./database/expose.db:/root/.expose
    hostname: expose
    networks:
      - traefik
    extra_hosts:
      - host.docker.internal:host-gateway
    environment:
      port: 443
      domain: example.com
      username: YOUR_USERNAME
      password: YOUR_PASSWORD
    container_name: expose

networks:
  traefik:
    external: true

修改服务配置,默认 TCP Tunnel 端口是 50000~60000,我这里不需要那么多,就设置的小一点。

<?php

return [
    ......

    'admin' => [

        /*
        |--------------------------------------------------------------------------
        | TCP Port Sharing
        |--------------------------------------------------------------------------
        |
        | Control if you want to allow users to share TCP ports with your Expose
        | server. You can add fine-grained control per authentication token,
        | but if you want to disable TCP port sharing in general, set this
        | value to false.
        |
        */
        'allow_tcp_port_sharing' => true,

        /*
        |--------------------------------------------------------------------------
        | TCP Port Range
        |--------------------------------------------------------------------------
        |
        | Expose allows you to also share TCP ports, for example when sharing your
        | local SSH server with the public. This setting allows you to define the
        | port range that Expose will use to assign new ports to the users.
        |
        | Note: Do not use port ranges below 1024, as it might require root
        | privileges to assign these ports.
        |
        */
        'tcp_port_range' => [
            'from' => 8888,
            'to' => 8890,
        ],

        ......
    ],
];

除了这些配置还需要将云服务商的安全组策略中添加对应端口的房型策略!

创建 TCP Tunnel

完成配置后启动服务,就可以了,然后再本地运行如下命令来创建 TCP Tunnel:

expose share-port 6152
Thank you for using expose.
Local-Port:		6152
Shared-Port:	8888
Expose-URL:		tcp://example.com:8888

出现上述的内容输出,Tunnel 就创建成功了,接下来在服务上使用代理!

使用方式

完成上述操作后,在其他服务器上,只需要像使用普通代理一样使用这个 TCP Tunnel 即可。

export HTTPS_PROXY=http://example.cmo:8888
# 验证是否生效
curl -I https://www.google.com
HTTP/1.0 200 Connection established

HTTP/2 200
......

总结

这种方式只适合于个人小批量使用,如果需要频繁拉取镜像,或者访问其他资源,建议还是选择其他更有效的解决方案!

I hope this is helpful, Happy hacking…