从docker容器中内访问host的端口

背景

在服务器上跑着许多服务,
这些服务通常没有关联,因此在网段上也是独立的.
但有时需要以nginx作为代理.将请求转发到其他container内部.
比如两个服务都想使用80端口,需要借助nginx根据请求url不同,转发给不同的服务.

希望能有个方式,让nginx所在的container能够发消息给其他container.
但containr相互加网络的方式很严重的依赖问题.因此希望找到新的方法.

container相互加网络

  1. 让服务特别声明一个网络(否则让docker自己起名字有点不省心)
  2. 让nginx加入这个服务的网络
  3. 在nginx中就能够使用服务所在container的hostname来找到该服务

比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: "3"

services:
nginx:
image: nginx:alpine
container_name: nginx
# ...
networks:
- gitlab

networks:
gitlab:
external: true
name: gitlab_gitlab # 依赖服务的网络

对应地,需要gitlab建立网络

1
2
3
4
5
6
7
8
9
10
11
12
version: "3"

services:
gitlab:
image: gitlab/gitlab-ce:latest
container_name: gitlab
hostname: minilab
# ...
networks:
- gitlab
networks:
gitlab: # 建立网络

然后nginx

1
2
3
4
5
6
7
8
server {
listen 80;
server_name minilab;

location / {
proxy_pass http://minilab;
}
}

优点

  1. container之间可以访问许多没有公开给host的端口.可能会比较方便.

缺点

  1. 造成了很严重的依赖问题.
    如果想重启服务A,则必须先关停作为代理的nginx实例.
    如果出现依赖链,则每次重启docker都更加痛苦.
  2. 有些网站可能会出现跨域问题.
    使用nps桥解了一个远程的服务,本地网络下访问起来地址可能是(192.168.1.x:8001)
    但当真正访问服务时,发现网站做得不好(就是gitlab-ce),部分图片的请求链接被写成=https://abd1213osh/xxx=
    即便配置nginx,将遇到80端口来的 abd1213osh/xxx 请求时转发给 host地址:8001.
    也可能由于跨域问题依然加载不出图片.
    最后只能直接让整个网站的访问都从 abd1213osh 起,全部经过nginx的代理.

使用固定地址

如果使用docker的默认网络配置.
可以使用

1
ip a show docker0

查到docker自己的网关地址.比如默认值通常是 172.17.0.1/16
然后配置nginx将请求转发到 172.17.0.1:端口 即可.

优点:

  1. 的确能将请求从container中转访给host

缺点:

  1. 方法还不够优雅.

新版开始,能够使用变量指代

docker 20.10 之后,可以:

  1. 在container内部可以有一个hostname代称 host.docker.internal
  2. 该hostname不在container内部的hosts文件中配置,而是由外部指定.

指定方式:

1
2
3
4
5
6
7
services:
nginx:
image: nginx:alpine
container_name: nginx
# ...
extra_hosts:
- "host.docker.internal:host-gateway"

nginx的配置

1
2
3
4
5
6
7
8
server {
listen 80;
server_name abd1213osh;

location / {
proxy_pass http://host.docker.internal:8001;
}
}

问题

依然会有跨域问题,但好在转发已经解决,可以直接使用nps连接到的远程hostname访问服务.

参考

  1. How to access host port from docker container