dockerkubernetesnginxnext.jskubernetes-ingress

Kubernetes 502 Bad Gateway error: connect() failed (111: Connection refused) while connecting to upstream


First of all I'm new to Nginx, Docker and Kubernetes so I may made an obvious mistake but after a complete week of searching and trying stuffs, I'm facing the same error. Also, I've seen other similar questions exists but unfortunately the provided solutions does not fix my problem.

When I access my URL, I get a 502 Bad Gateway (nginx) message and when I log my nginx container from my pod, it returns this:

[error] 7#7: *102 connect() failed (111: Connection refused) while connecting to upstream, client: <ip_address>, server: _, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:9000/", host: <host_name>

My project uses Next JS 14. I'm running 3 pods and each pod has two containers: my-project-nextjs and my-project-nginx (the default container).

For the Docker part, I've tried different configurations. My application is in a monorepo using turbo so I follow this documentation to create my Dockerfile:

FROM node:20.9.0-alpine AS base

FROM base AS builder
RUN apk update
RUN apk add --no-cache libc6-compat

WORKDIR /app

RUN yarn global add turbo
COPY . .

RUN turbo prune @monorepo/my-project --docker

FROM base AS installer
RUN apk update
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY --from=builder /app/out/json/ .
RUN yarn install

COPY --from=builder /app/out/full/ .
COPY --from=builder /app/tsconfig.json ./tsconfig.json
RUN yarn turbo run build --filter=@monorepo/my-project

FROM base AS runner
WORKDIR /app

ENV NODE_ENV production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
USER nextjs

COPY --from=installer --chown=nextjs:nodejs /app/apps/my-project/.next/standalone ./
COPY --from=installer --chown=nextjs:nodejs /app/apps/my-project/.next/static ./apps/my-project/.next/static
COPY --from=installer --chown=nextjs:nodejs /app/apps/my-project/public ./apps/my-project/public

EXPOSE 9000

ENV PORT 9000

CMD node apps/my-project/server.js

For the Dockerfile of nginx, I have tried debian:strech-line and nginx:stable-alpine: the result is the same, error 502. Here is the debian version:

FROM debian:stretch-slim

ENV DEBIAN_FRONTEND="noninteractive" \
    TERM="xterm"
RUN echo "deb http://archive.debian.org/debian stretch main contrib non-free" > /etc/apt/sources.list
RUN apt-get update && apt-get upgrade -y &&\
    apt-get install -y nginx-light

RUN echo "Acquire::http {No-Cache=True;};" > /etc/apt/apt.conf.d/no-cache &&\
    apt-get -q update && \
    apt-get -qy dist-upgrade && \
    apt-get install -qy \
      nginx-light \
      nano \
    && \
    apt-get -y autoremove && \
    apt-get -y clean && \
    rm -rf /var/lib/apt/lists/*

COPY .docker/nginx/nginx.conf /etc/nginx/nginx.conf

RUN rm -v /etc/nginx/sites-enabled/default

ADD .docker/nginx/sites-enabled /etc/nginx/sites-enabled
ADD .docker/nginx/conf.d /etc/nginx/conf.d

COPY . /app
WORKDIR /app

CMD ["nginx"]

My application configuration is, I suppose, really basic:

server {
    listen 80;
    server_name _;

    root /app/apps/my-project/.next;

    location / {
        proxy_pass http://localhost:9000;
    }

    location /nginx-health {
        access_log off;
        return 200 "OK\n";
    }
}

When I check my pods status, they are all running. My container my-project-nextjs return this log:

  ▲ Next.js 14.2.3
  - Local:        http://<pod_name>:9000
  - Network:      http://<ip_address>:9000

 ✓ Starting...
 ✓ Ready in 161ms

So I suppose my Next JS Docker image is correct.

My container my-project-nginx returns this log (after I tried to reach my website from its URL):

[error] 7#7: *102 connect() failed (111: Connection refused) while connecting to upstream, client: <ip_address>, server: _, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:9000/", host: <host_name>

From other solutions on SO, I thought the problem comes from the PORT or the proxy_pass. The PORT looks good to me so I don't know what I could tried. For the proxy_pass, I've tried to replace my current value (proxy_pass http://localhost:9000;) with http://127.0.0.1:9000, http://0.0.0.0:9000 or create an upstream (but if I'm right, it's when the containers are not in the same pod).

Do you have any ideas why I get a 502 error message?

EDIT and SOLUTION:

Here is my deployment code:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-project-deployment
  labels:
    app: my-project
  namespace: beta
spec:
  replicas: 2
  selector:
    matchLabels:
      name: my-project
  template:
    metadata:
      labels:
        name: my-project
    spec:
      containers:
        - name: my-project-nginx
          image: <my_image>
          imagePullPolicy: Always
          ports:
          - containerPort: 80
          env:
          - name: PORT
            value: "80"
          resources:
              limits:
                memory: 768Mi
              requests:
                memory: 256Mi
          readinessProbe:
            tcpSocket:
              port: 80 
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            tcpSocket:
              port: 80
            initialDelaySeconds: 15
            periodSeconds: 20
            successThreshold: 1
            failureThreshold: 3
        - name: my-project-nextjs
          image: <my_image>
          imagePullPolicy: Always
          ports:
          - containerPort: 9000
          env:
          - name: PORT
            value: "9000"
          - name: DD_AGENT_HOST
            valueFrom:
              fieldRef:
                fieldPath: status.hostIP
          - name: DD_SERVICE_NAME
            value: "my-project-beta"
          resources:
              limits:
                memory: 1Gi
              requests:
                memory: 512Mi
          readinessProbe:
            tcpSocket:
              port: 9000
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            tcpSocket:
              port: 9000
            initialDelaySeconds: 15
            periodSeconds: 20
            successThreshold: 1
            failureThreshold: 3
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: <name>

---
apiVersion: v1
kind: Service
metadata:
  name: my-project
  namespace: beta
  labels:
    name: my-project
spec:
  type: ClusterIP
  ports:
    - name: nginx-container
      port: 80
      targetPort: 80 
    - name: nextjs-container
      port: 9000
      targetPort: 9000
  selector:
    name: my-project

I manage to make the thing works by opening the port 9000. I've changed the proxy_pass to my service name my-project and add this part to fix my problem:

- name: nextjs-container
      port: 9000
      targetPort: 9000

Solution

  • In the configuration Instead of localhost, use the Kubernetes service name that exposes the my-project-nextjs container. Update it as below

     location / {
            proxy_pass http://<service_name>:9000;
        }
    

    The service should be something as below

    apiVersion: v1
    kind: Service
    metadata:
      name: my-project-nextjs-service
    spec:
      selector:
        app: my-project-nextjs
      ports:
        - protocol: TCP
          port: 9000
          targetPort: 9000
    

    Also make sure that there is a Kubernetes Service that exposes the my-project-nextjs container. And check with the below command, whether Kubernetes service is reachable from the my-project-nginx container

    kubectl exec -it <nginx-pod-name> -- curl http://<service_name>:9000