What is the connection or difference between Deployment, Pod, Service?

I have this backend pod and service I wrote

apiVersion: v1
kind: Pod
metadata:
  name: iloveu-backend
  labels:
    role: backend
  namespace: iloveu
spec:
    containers:
    - name: backend
      image: registry.icod.de/iloveu/backend/iloveu-3e46d27deb3b924b7bad8de8eeab40cd
      command: [iloveu]
      args: ["restful", "--bp=false", "--debug=false", "--addr=tcp::7777", "--conn=mongodb://iloveu:iloveu@mongodb.mongodb.svc.cluster.local:27017/iloveu"]
      ports:
        - containerPort: 7777
          name: backend-port
    imagePullSecrets:
      - name: registrycredentials
    restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: iloveu-backend-service
  namespace: iloveu
spec:
  selector:
    name: iloveu-backend
  ports:
    - port: 7777
      protocol: TCP
      name: backend-service-port
      targetPort: backend-port

and this of course creates a pod and a service.
But when I create a deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: iloveu-backend
  labels:
    app: iloveu-backend
  namespace: iloveu
spec:
  replicas: 1
  selector:
    matchLabels:
      app: iloveu-backend
  template:
    metadata:
      name: iloveu-backend
      labels:
        app: iloveu-backend
    spec:
      containers:
        - name: backend
          image: registry.icod.de/iloveu/backend/iloveu-3e46d27deb3b924b7bad8de8eeab40cd
          imagePullPolicy: IfNotPresent
          command: [ iloveu ]
          args: [ "restful", "--bp=false", "--debug=false", "--addr=tcp::7777", "--conn=mongodb://iloveu:iloveu@mongodb.mongodb.svc.cluster.local:27017/iloveu" ]
          ports:
            - containerPort: 7777
              protocol: TCP
              name: backend-port
      imagePullSecrets:
        - name: registrycredentials
      restartPolicy: Always

No service is being created

It’s very confusing.
Why would I prefer deployment over pod and service, or do I have to also define services in the deployment file?

Seems like deployment replaces pod and I have to create a service regardless.
That is very weird.

Almost never want to create a Pod directly. A Deployment is a managed group of Pods (meaning: the number of replicas is maintained across time).

Deployment is, for most users, the primary workload interface. If a Pod dies (e.g. a node goes away), Deployment will make sure that a new one comes up.

A Service is a related but distinct concept. A service is a group of pods which serve the same purpose on the network. That could be one Deployment, or it could be many Deployments. Not all Deployments want to be exposed as a Service, and some Services are backed by things other than Deployments.

This is a prime example of what kubernetes docs describe as “loose coupling”.

So I could have a frontend deployment listening on :8080 and a backend deployment listening on :7777 as a single service and exposing those 2 ports internally?

Related:
I tried creating a nginx ingress under the same namespace and the frontend was mounted unter Prefix / and the backend under Prefix /api.
However I have wrapped the frontend in a Go binary, aka embedded and any 404 would be served as /index.html, essentially the same as nginx try_files $uri $uri/ index.html etc.
However when trying to curl /api/v1/profile/ I would get the frontend with a 404.
I can’t seem to be able to do a

location / {
}

location /api/ {
}

The nginx ingress defines those prefix routes as ~* (or was it *~) aka a regexp and this of course then collides, as it’s not the proper way to define something like this.
Maybe I should create an issue on the nginx ingress repo.
I’m on the phone can post the ingress conf later, if anyone would like to take a look at it

I don’t think you want both Deployments in the same Service

1 Like

I agree.

They’re already grouped under the same namespace.

The ingress config

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: iloveu-ingress
  namespace: iloveu
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
    - hosts:
        - iloveu.luketic
      secretName: iloveu-secret-tls
  ingressClassName: nginx
  rules:
    - host: iloveu.luketic
      http:
        paths:
          - path: /api/
            pathType: Prefix
            backend:
              service:
                name: iloveu-backend-service
                port:
                  number: 7777
          - path: /
            pathType: Prefix
            backend:
              service:
                name: iloveu-frontend-service
                port:
                  number: 8080
---
apiVersion: v1
kind: Secret
metadata:
  name: iloveu-secret-tls
  namespace: iloveu
data:
  tls.crt: base64encoded_cert=
  tls.key: base64encoded_key=
type: kubernetes.io/tls

With this curl -v -k https://iloveu.luketic/api/v1/profile/ returns html mounted under the / path, instead of hitting the backend mounted under /api/.

That was on a microk8s v1.28 cluster with microk8s enable ingress. Meanwhile I’ve destroyed that cluster so I can’t give details, but I know what it wasn’t using location / and location /api/.
I’m now on a k0s cluster, and installed the ingress-nginx via helm and will see what kind of configuration this produces.

But maybe I should create a new topic for that?

Below is my current live config (domain name changed), no k8s.
There’s a websocket route. Idk how to do that with an ingress nginx or other.

server {
        listen 80;
        listen [::]:80;
        server_name iloveu;
        include /etc/nginx/acme.conf;
        error_log /var/log/nginx/iloveu_error.log;
        access_log /var/log/nginx/iloveu_access.log;
        location / {
                return 301 https://iloveu$request_uri;
        }
}

server {
        listen 443 ssl;
        listen [::]:443 ssl;
        http2 on;

        server_name iloveu;
        root /var/www/iloveu/pwa;

        add_header X-Frame-Options "SAMEORIGIN";
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options "nosniff";

        ssl_certificate /etc/letsencrypt/live/iloveu/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/iloveu/privkey.pem;

        error_log /var/log/nginx/iloveu_error.log;
        access_log /var/log/nginx/iloveu_access.log;

        location / {
                try_files $uri $uri/ /index.html;
        }

        location /api/ {
               include cors.conf;
               proxy_pass http://unix:/tmp/iloveu-restful.sock;
               proxy_read_timeout 30;
               proxy_connect_timeout 30;
               proxy_redirect off;
               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;

        }

    location = /api/v1/ws/notify {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        rewrite ^/(.*)$  /$1  break;
        proxy_pass http://unix:/tmp/iloveu-restful.sock;
    }

}

With this … returns html mounted under the / path, instead of hitting the backend mounted under /api/.

You told nginx to rewrite the target to / so it did?

The rest (nginx) I am not an expert on, so I will have to defer to someone else.

I’m obviously copying things I see somewhere on the internet and adjusting, since there is no proper documentation