Docker环境下使用nginx反向代理

当在 docker 环境下使用 Nginx 作为反向代理和负载均衡到其他容器时,有时需要在我们的堆栈中定义某种启动顺序,因为它们相互依赖。通常情况下需要把后端服务全部启动起来后,再来启动这个 Nginx服务。
首先这种环境循环依赖的问题就不应该存在,退一步来讲,我就部署个几个简单的服务,还要去考虑先有鸡还是先有蛋问题。谁有这功夫,反正我是没有。

上游服务不可用致nginx无法启动

当你先把 nginx 服务启动时,通常会某种原因公示失败,执行检查日志时

docker logs nginx_container

下面类似的消息日志会伴随告诉你:

NameOfService could not be resolved (1: Host not found)

然后,我们nginx配置如下:

    upstream upstreamName {
    server ghost:2368;
}


server {
    listen 80;
    server_name demo.vqiu.cn;
    return 307 https://$host$request_uri;
}

server {
    listen 80;
    server_name demo.vqiu.cn;

    location / {
    proxy_pass http://upstreamName;
    proxy_http_version 1.1;
    proxy_set_header Host               $host;
    proxy_set_header X-Real-IP          $remote_addr;
    proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto  $scheme;
    }
}

动态upstream

从上述得知,当 nginx 反向代理上游服务时,首先这个上游服务能具备能解析,否则nginx无法正常启动。换种说法就是,nginx的proxy_pass指令,因为没有目标,不知道转给谁,然后就抛出异常了。
那么如何解决upstream server启动时不可解析的问题呢?
答案很简单,让DNS告诉nginx上游服务的地址,resolver 指令用起来。

resolver 指令的作用是阻止 nginx 执行代码,如果我无法解析我们要代理的服务器,则不会抛出不可恢复的错误,并将继续尝试解析它直到它可以。

docker 环境的DNS服务一般为:127.0.0.11(这是固定的)

配置参考:

server {
	listen	80 reuseport;
	server_name demo.vqiu.cn;

	location / {
        resolver 127.0.0.11 valid=60s ipv6=off;
        resolver_timeout 2s;
        set $upstream_name  ghost;
        set $upstream_port  2368;
        proxy_pass  http://$upstream_name:$upstream_port;
        proxy_http_version 1.1;
        proxy_set_header   Host               $host;
        proxy_set_header   X-Real-IP          $remote_addr;
        proxy_set_header   X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto  $scheme;
	}
}

只需在变量中设置上游指令,proxy_pass的ip将由resolver来提供,此时无论上游地址是否能正常解析,它也不会去关心这个流程--解析失败直接返回502而已。

重点配置如下:

    # ...
	resolver 127.0.0.11 valid=60s ipv6=off;
	resolver_timeout 2s;
    # ...
  • valid代表DNS解析地址TTL为60s(即60s后重新发起一次解析)
  • resolver_timeout解析超时时间
  • 关闭ipv6栈的解析

以上同样适用于kubernetes环境。