Kubernetes,  QNAP

Kubernetes. k0s – Creación de un registry

¿Qué es un Registry?. Pues es un lugar donde guardar las imágenes que van a utilizar los despliegues de Kubernetes. ¿Sencillo no?

Hasta ahora he utilizado las imágenes disponibles en el repositorio oficial, pero lo habitual es que una vez vas creando imágenes propias, necesites un repositorio privado.

El propio registro de imágenes, no deja de ser otra imagen también disponible en el sitio oficial, y para subir el nivel de abstracción también puede ser un Deploy que corra dentro del cluster.

Voy a describir entonces los despliegues y utilidades que he utilizado para disfrutar de mi propio registro.

  • Para los kind; namespace, service, ingress.

Aquí he utilizado lo mismo que para los anteriores despliegues. Solo me he tenido que pelear con el ingress ya que cuando subía las imágenes de daba un error “413 Request Entity Too Large“. Este error es del estandard html para cuando el servidor web no acepta la petición por ser ésta muy grande. Para solucionarlo es necesario incluir una annotation.

annotations:
  # Añado para eliminar el límite de tamaño de las imágenes que se pueden
  # subir al registry
  nginx.ingress.kubernetes.io/proxy-body-size: "0"
  • El el deploy es donde está el grueso de la configuración y donde más problemas he encontrado y tenido que solucionar sobre la marcha.

Uno de estos problemas ha sido la autenticación del registro y de su uso por los deploy. Para el propio registry lo más sencillo es optar por autenticación básica generando una contraseña con htpasswd. La configuración se le pasa a la imagen como variables y son suficientes las siguientes; REGISTRY_AUTH, REGISTRY_AUTH_HTPASSWD_REALM y REGISTRY_AUTH_HTPASSWD_PATH. La última yo la guardo en un recurso de servidor NAS que monto en /auth. También guardo en recursos nfs todo lo relativo a la persistencia. Por el momento no veo la necesidad de utilizar la persistencia de kubernetes mediante los PV y PVC.

... 
        env:
          - name: REGISTRY_AUTH
            value: "htpasswd"
          - name: REGISTRY_AUTH_HTPASSWD_REALM
            value: "Registry Realm"
          - name: REGISTRY_AUTH_HTPASSWD_PATH
            value: "/auth/htpasswd"
...
        nfs:
          server: nfs-server
          path: /DPVs/registro/auth
          readOnly: false
...
          - name: nfs-registro-auth
            mountPath: /auth

Para generar la contraseña si no dispones del binario de htpasswd puedes utilizar el propio docker, podman, …

$ docker run --entrypoint htpasswd httpd:2 -Bbn usuario contraseña > htpasswd

Aunque el método de autenticación no sea el más seguro hay que tener en cuenta que viaja sobre el ssl del ingress.

Al proporcionar autenticación al registry, es necesario que los despliegues que lo utilicen, realicen los Push y Pull autenticándose previamente. Se puede definir un pequeño script que ejecute algo similar a esto:

kubectl create secret docker-registry regcred --docker-server=tuservidor --docker-username=usuario --docker-password=contraseña --docker-email=tucorreo --namespace=tunamespace

Al ejecutarse se genera en el namespace indicado un secret con un JSON que codifica usuario y contraseña.

  • Comprobación básica.

Aunque no existe un UI como tal, sí que puedes comprobar si funciona desde un navegador, si pones https://tudominio.com/v2/_catalog, te aparece un listado con las imágenes que tiene disponibles. Por ejemplo:

{“repositories”:[“imagen1”]}

Faltaría ahora describir el uso como tal del registro pero eso lo dejo para otro día.

  • El yaml completo sería el siguiente.

apiVersion: v1
kind: Namespace
metadata:
  name: registro

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: registro
  name: registro
  namespace: registro
spec:
  ports:
  - port: 5000
    targetPort: 5000
  selector:
    app: registro


---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    # Añado el cluster-issuer definido para letsencrypt
    cert-manager.io/cluster-issuer: letsencrypt-production
    # Añado para eliminar el límite de tamaño de las imágenes que se pueden
    # subir al registry
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
  name: registro
  namespace: registro
spec:
  rules:
    - host: tudominio.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: registro
                port:
                  number: 5000
  tls:
    - hosts:
      - tudominio.com
      # En este certificate cert-manager guarda el certificado.
      # kubectl get certificate -n motioneye
      secretName: registro-cert


---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: registro
  namespace: registro
  labels:
    app: registro
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registro
  template:
    metadata:
      labels:
        app: registro
    spec:
      volumes:
      - name: nfs-registro-var-lib
        nfs:
          server: nfs-server
          path: /DPVs/registro/var-lib-registry
          readOnly: false
      - name: nfs-registro-auth
        nfs:
          server: nfs-server
          path: /DPVs/registro/auth
          readOnly: false
      - name: localtime
        hostPath:
          path: "/etc/localtime"
      containers:
        - image: registry:2
          name: registro
          imagePullPolicy: IfNotPresent
          env:
          - name: REGISTRY_AUTH
            value: "htpasswd"
          - name: REGISTRY_AUTH_HTPASSWD_REALM
            value: "Registry Realm"
          - name: REGISTRY_AUTH_HTPASSWD_PATH
            value: "/auth/htpasswd"
          ports:
            - containerPort: 5000
          volumeMounts:
          - name: nfs-registro-var-lib
            mountPath: /var/lib/registry
          - name: nfs-registro-auth
            mountPath: /auth

Sólo te queda el consiguiente apply del fichero anterior y, ya estaría! (0‿~).