Kubernetes上的Nginx代理

问题描述:

我在k8s集群中有一个nginx部署,它可以代理我的api/调用,如下所示:

I have a nginx deployment in k8s cluster which proxies my api/ calls like this:

server {
  listen 80;

  location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    try_files $uri $uri/ /index.html =404;
  }

  location /api {
    proxy_pass http://backend-dev/api;
  }
}

这在大多数情况下都有效,但是有时当api容器未准备好时,nginx会失败并显示错误:

This works most of the time, however sometimes when api pods aren't ready, nginx fails with error:

nginx: [emerg] host not found in upstream "backend-dev" in /etc/nginx/conf.d/default.conf:12

几个小时的互联网浏览后,我发现了文章几乎相同的问题.我已经尝试过了:

After couple of hours exploring internets, I found the article which pretty much the same issue. I've tried this:

  location /api {
    set $upstreamName backend-dev;
    proxy_pass http://$upstreamName/api;
  }

现在nginx返回 502 . 而这个:

Now nginx returns 502. And this:

  location /api {
    resolver 10.0.0.10 valid=10s;
    set $upstreamName backend-dev;
    proxy_pass http://$upstreamName/api;
  }

Nginx返回 503 .

在k8s上修复它的正确方法是什么?

What's the correct way to fix it on k8s?

如果您的API容器尚未准备好,Nginx将无法将流量路由到它们.

If your API pods are not ready, Nginx wouldn't be able to route traffic to them.

从Kubernetes 文档:

From Kubernetes documentation:

kubelet使用就绪探针来了解何时Container准备开始接受流量.当Pod的所有容器都准备就绪时,即视为准备就绪.此信号的一种用法是控制将哪些Pod用作服务的后端.当Pod尚未就绪时,会将其从服务负载平衡器中删除.

The kubelet uses readiness probes to know when a Container is ready to start accepting traffic. A Pod is considered ready when all of its Containers are ready. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.

如果您不使用活动或就绪探测器,那么即使您在容器内运行的应用程序尚未完成启动过程并准备接受流量,您的Pod也将被标记为就绪".

If you are not using liveness or readiness probes, then your pod will be marked as "ready" even if your application running inside the container has not finished it's startup process and is ready to accept traffic.

可以在此处找到有关Pod和DNS记录的相关部分.

由于未为Pod名称创建A记录,因此要创建Pod的A记录需要主机名.没有主机名但带有子域的Pod只会为无头服务创建A记录(default-subdomain.my-namespace.svc.cluster-domain.example),指向Pod的IP地址.另外,除非在服务上设置了publishNotReadyAddresses = True,否则Pod需要准备就绪才能记录.

Because A records are not created for Pod names, hostname is required for the Pod’s A record to be created. A Pod with no hostname but with subdomain will only create the A record for the headless service (default-subdomain.my-namespace.svc.cluster-domain.example), pointing to the Pod’s IP address. Also, Pod needs to become ready in order to have a record unless publishNotReadyAddresses=True is set on the Service.

更新:我建议使用NGINX作为入口控制器.

UPDATE: I would suggest using NGINX as an ingress controller.

当您将NGINX用作入口控制器时,NGINX服务将成功启动,并且只要入口规则,NGINX配置为

When you use NGINX as an ingress controller, the NGINX service starts successfully and whenever an ingress rule is deployed, the NGINX configuration is reloaded on the fly.

这将帮助您避免NGINX Pod重新启动.

This will help you avoid NGINX pod restarts.