linux docker 中访问 host 主机


新版的 docker for win/mac 已经可以使用host.docker.internal来访问host的服务, 然而linux却没有提供, 显然作为亲爹的linux不该被如此对待啦. 自己来搞一发吧, 另外简单说下openresty下怎么访问host:

第一步: 获取host ip
DOCKER_HOST=$(netstat -nr | grep '^0.0.0.0' | awk '{print $2}')
嗯, 简单来说, 获取host的ip就是获取路由表里的默认网关, docker的bridge网络模型和vbox的nat蛮像的哈, 只是少了一层. 不知道理解的对不对.

第二步: 加入/etc/hosts
echo $DOCKER_HOST "host.docker.internal" >> /etc/hosts
本想到此nginx就可以使用它了, 但显然没那么顺利, nginx不去读取hosts, lua里无论如何是不能使用.

第三步: 给nginx设置resolver
echo resolver $(awk 'BEGIN{ORS=" "} $1=="nameserver" {print $2}' /etc/resolv.conf) "ipv6=off;" > $resolver_file
脚本的意思就是, 获取本机的NS, 加入到nginx的resolver里(通过include就可以了), 可以了吗? 显然不行, 虽然不是那么显然. (单纯的为了ngx-lua可以请求域名, 这个resolver的配置也是需要的)
到此, 该做的已经做了, 但还是不行. 这是什么原因呢? 待查! 但我们暂时迂回一下吧!

第四步: 给nginx设置env
nginx安全的原因, 除了TZ环境变量, 其它的都不会传入worker, 需要手动设置:
echo "env DOCKER_HOST=$DOCKER_HOST;" >> $openresty_base_path/nginx/conf/env.conf
这个include进nginx的main conf里. lua里面使用os.getenv('DOCKER_HOST')获取host主机IP.

到此算是解决了这个问题, 但到底为何resolver不会去解析hosts文件呢? 还不可知, 先写项目之后再查, 反正这样的场景也只在dev环境下才会碰到, 产品环境的话, 这样做一定是架构哪里出了问题, :)

最终的docker启动脚本是这个样子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
#!/bin/sh
openresty_base_path=/usr/local/openresty
resolver_file=$openresty_base_path/nginx/conf/resolvers.conf
nginx_conf_file=/data/nginx/nginx.conf

echo resolver $(awk 'BEGIN{ORS=" "} $1=="nameserver" {print $2}' /etc/resolv.conf) "ipv6=off;" > $resolver_file
DOCKER_HOST=$(netstat -nr | grep '^0.0.0.0' | awk '{print $2}')
echo $DOCKER_HOST "host.docker.internal" >> /etc/hosts
echo "env DOCKER_HOST=$DOCKER_HOST;" >> $openresty_base_path/nginx/conf/env.conf

echo "host " $DOCKER_HOST
cat $resolver_file
echo ""

if [ -e "$nginx_conf_file" ]; then
    cp "$nginx_conf_file" $openresty_base_path/nginx/conf/nginx.conf
fi

$openresty_base_path/bin/openresty -g "daemon off;"