Search code examples
dockerkubernetesportnginx-ingress

Which ports needed to be set for a k8s deployment?


I do not understand how to configure ports correctly for a k8s deployment.

Assume there is a nextJS application which listens to port 3003 (default is 3000). I build the docker image:

FROM node:16.14.0
RUN apk add dumb-init

# ...

EXPOSE 3003

ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD npx next start -p 3003

So in this Dockerfile there are two places defining the port value 3003. Is this needed?

Then I define this k8s manifest:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example
spec:
    spec:
      containers:
        - name: example
          image: "hub.domain.com/example:1.0.0"
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 3003
---
apiVersion: v1
kind: Service
metadata:
  name: example
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3003
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example
  namespace: default
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
spec:
  tls:
    - hosts:
        - domain.com
      secretName: tls-key
  rules:
    - host: domain.com
      http:
        paths:
          - pathType: Prefix
            path: "/"
            backend:
              service:
                name: example
                port:
                  number: 80

The deployment is not working correctly. Calling domain.com shows me a 503 Service Temporarily Unavailable error.

If I do a port forward on the pod, I can see the working app at localhost:3003. I cannot create a port forward on the service.

So obviously I'm doing something wrong with the ports. Can someone explain which value has to be set and why?


Solution

  • You are missing labels from the deployment and the selector from the service. Try this:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example
      labels:
        app: example
    spec:
      selector:
        matchLabels:
          app: example
      template:
        metadata:
          labels:
            app: example
        spec:
          containers:
            - name: example
              image: "hub.domain.com/example:1.0.0"
              imagePullPolicy: IfNotPresent
              ports:
                - containerPort: 3003
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: example
    spec:
      selector:
        app: example
      ports:
        - protocol: TCP
          port: 80
          targetPort: 3003
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: example
      namespace: default
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-prod
        kubernetes.io/ingress.class: nginx
        kubernetes.io/tls-acme: "true"
        nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    spec:
      tls:
        - hosts:
            - domain.com
          secretName: tls-key
      rules:
        - host: domain.com
          http:
            paths:
              - pathType: Prefix
                path: "/"
                backend:
                  service:
                    name: example
                    port:
                      number: 80
    

    Deployment: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

    Service: https://kubernetes.io/docs/concepts/services-networking/service/

    Labels and selectors: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/

    You can name your label keys and values anything you like, you could even have a label as whatever: something instead of app: example but these are some recommended labels: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/ https://kubernetes.io/docs/reference/labels-annotations-taints/