Skip to main content

Nexus Repository

Al desarrollar una aplicación, es común generar diferentes artefactos (versiones compiladas) de los diferentes proyectos, librerías o componentes, así como de contenedores finales. Estos artefactos deben ser almacenados en un repositorio para compartirlos fácilmente.

En un desarrollo OpenSource, estos artefactos deberían estar en un repositorio público, pero sería aconsejable únicamente publicar las versiones definitivas y no las que se están probando, que solo actuarían como "basura digital".

Además de ello, una red con procesos de CI/CD puede descargar cientos de librerías a cada proceso a realizar. Es aconsejable que estos procesos tengan una caché, pero aun así puede ocasionar consumos extras en la conexión de internet y problemas de acceso limitado según en qué repositorios.

Debido a todo ello, es aconsejable tener un repositorio local, que permita almacenar nuestras versiones no estables o versiones que no queramos publicar, y también que haga de espejo de los repositorios que usamos, para que el acceso sea inmediato. De paso también sirve para almacenar versiones locales que únicamente sean necesarias en nuestra red.

La elección de un repositorio de artefactos depende en gran medida del uso que se le vaya a dar. Quizás sea aconsejable tener solo uno compatible con todas las tecnologías que utilizamos, quizás sea mejor tener varios especialistas debido a que estos tienden a dar más funcionalidades.

Sea como sea, en mi caso he elegido Nexus Repository OSS, la versión gratuita. Este dispone de todos los idiomas que voy a necesitar, unificados en un único punto.

Requisitos

Nexus requiere mucho espacio en disco y la velocidad no es tan importante, debido a ello sus volúmenes estarán montados acorde a NFS.

La carpeta compartida se debe crear previamente.

Despliegue

info

Más detalles en Artifact Hub.

Creamos un namespace para el proyecto.

kubectl create namespace nexus-repository-mngmt

Primero tenemos que crear el Persistent Volume y el Claims acorde al NFS creado previamente.

vi nexus-repository-pv.yaml

Indicamos los datos de conexión al NAS y la carpeta compartida.

nexus-repository-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nexus-nfs-pv
namespace: nexus-repository-mngmt
spec:
storageClassName: storage-nfs
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
nfs:
server: nas.domain.intranet
path: "/NFS_Nexus_Repository"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nexus-nfs-pvc
namespace: nexus-repository-mngmt
spec:
storageClassName: storage-nfs
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi
nota

En este caso he asignado 50 GiB, esto se debe actualizar según el espacio que creamos que sea necesario.

Aplicamos el fichero.

kubectl apply -f nexus-repository-pv.yaml

Añadimos el repositorio.

helm repo add sonatype https://sonatype.github.io/helm3-charts/
helm repo update

Creamos un fichero para asignar los valores.

vi nexus-repository-values.yaml
nexus-repository-values.yaml
nexus:
# Voy a crear 2 servicios de docker para utilizarlos después
docker:
enabled: true
registries:
- host: docker-private.domain.intranet
port: 5000
secretName: ""
- host: registry.domain.intranet
port: 5001
secretName: ""
# Reemplazo el environment por defecto para cambiar la carpeta del 'prefs' y evitar el aviso continuado en los logs
env:
- name: INSTALL4J_ADD_VM_PARAMS
value: "-Xms2703M -Xmx2703M -XX:MaxDirectMemorySize=2703M -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Djava.util.prefs.userRoot=/nexus-data"
- name: NEXUS_SECURITY_RANDOMPASSWORD
value: "true"
# Bajo el mínimo necesario para arrancar y limito el máximo debido a que los recursos recomendados son para entornos empresariales
resources:
requests:
cpu: 0.5
memory: 2Gi
limits:
cpu: 1
memory: 4Gi

# Habilito Ingress acorde a la intranet y a forzar el uso de SSL
ingress:
enabled: true
ingressClassName: nginx-intranet
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
hostPath: /
hostRepo: nexus-repository.domain.intranet

# Asigno el Persistence Volume Claims previamente creado
persistence:
enabled: true
existingClaim: nexus-nfs-pvc
tip

La opción de Docker generará los servicios e Ingress, pero estos Ingress no permiten elegir la clase, así que se utilizará la de por defecto.

Desplegamos el servicio acorde a los valores.

helm upgrade --install nexus-rm sonatype/nexus-repository-manager \
-f nexus-repository-values.yaml \
--namespace nexus-repository-mngmt

Configuración

La primera vez que Nexus Repository se inicia, genera la contraseña de administrador en la carpeta de datos. Accedemos a ella desde el NFS y buscamos el fichero admin.password para copiar la contraseña.

Al acceder por web, iniciamos sesión e indicamos el usuario admin y la contraseña del fichero. Esto iniciará un asistente para cambiar la contraseña y ajustar el acceso anónimo (que es aconsejable tener). Este también borrará el fichero que contenía la contraseña.

compte

Al acceder como admin puede aparecer un mensaje de que el hardware disponible no es suficiente según los requerimientos mínimos, estos son excesivos para el uso que le vamos a dar y no aportará ningún problema.

tip

La configuración que sigo es prácticamente la misma que ya detallé en el Nexus3 del Swarm Project.

E-mail

Para utilizar el e-mail relay tenemos que crear una excepción.

vi nexus-repository-allow-relay.yaml

Configuramos la excepción según el nombre de instancia y namespace.

nexus-repository-allow-relay.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-nexus-repository
namespace: email-relay-mngmt
spec:
podSelector:
matchLabels:
app.kubernetes.io/instance: smtp-relay
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: nexus-repository-mngmt
podSelector:
matchLabels:
app.kubernetes.io/instance: nexus-rm
ports:
- protocol: TCP
port: 25

Aplicamos los cambios.

kubectl apply -f nexus-repository-allow-relay.yaml

Volvemos a Nexus para configurar el e-mail en System > Email Server.

Ajustamos los siguientes datos, manteniendo el resto como están:

CampoValor
EnabledSeleccionado
Hostsmtp-relay.email-relay-mngmt
From address[email protected]

Almacén de datos

Cada repositorio tendrá su propio almacén de datos, lo que me permite tener un mayor control sobre cada uno de ellos.

La configuración se encuentra en Repository > Blob Stores.

Tenemos 2 opciones:

  • S3: Almacenará los datos en un S3 externo.
  • File: Acorde al volumen que hemos creado vía NFS, creará una carpeta nueva dentro de este por cada almacén. Esta es la que utilizaremos.

Únicamente debemos repetir los pasos para cada repositorio. El nombre del almacén será el mismo del repositorio.

Repositorio de Maven

Para Maven vamos a necesitar almacenar las librerías finales released y snapshots que son las versiones aún en proceso. Si por algún motivo necesitáramos publicar librerías que no se encuentran disponibles en un repositorio, se podría crear otro de third party, pero no es mi caso.

Además, hay que configurar varios repositorios que hagan de espejo de los originales como el de central o el de jboss, dependerá del uso que tengamos.

Para facilitarnos la vida, todos los repositorios serán accesibles desde un grupo, así que únicamente conectaremos al grupo y este ya se encargará de buscar en cada repositorio en el orden que le hemos indicado.

Este es el esquema de repositorios:

NombreTipoOtros
maven-releasesmaven2 (hosted)
maven-snapshotsmaven2 (hosted)Version policy: Snapshot
Deployment policy: Allow redeploy
maven-centralmaven2 (proxy)Remote storage: https://repo1.maven.org/maven2/
maven-jbossmaven2 (proxy)Remote storage: https://repository.jboss.org/nexus/content/repositories/thirdparty-releases/
maven-groupmaven2 (group)Repositorios en el orden de esta tabla

Para utilizar el repositorio habrá que definirlo en el fichero de configuración de Maven de cada PC que requiera utilizarlo.

<home>/.m2/settings.xml
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<mirrors>
<mirror>
<id>nexus</id>
<name>Nexus Repository</name>
<url>https://nexus-repository.domain.intranet/repository/maven-group/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
</settings>
compte

En caso de utilizar un certificado auto firmado, este tendrá que añadirse al repositorio de claves de Java para que pueda acceder a Nexus vía HTTPS

warning

Nexus Repository en su versión gratuita no permite subir librerías utilizando el grupo, así que los proyectos deben subir sus librerías usando la URL del proyecto de releases o de snapshots.

Repositorio de NPM

Similar idea que Maven, creamos un repositorio donde desplegar los componentes, aunque permitiendo la sobreescritura para las versiones latest. También el espejo hacia el repositorio principal y el grupo.

NombreTipoOtros
npm-releasesnpm (hosted)Deployment policy: Allow redeploy
npm-registrynpm (proxy)Remote storage: https://registry.npmjs.org
npm-groupnpm (group)Repositorios en el orden de esta tabla

En cada proyecto se tendrá que configurar la URL de acceso:

https://nexus-repository.domain.intranet/repository/npm-group/
warning

Igual que en Maven, para subir componentes se requiere utilizar la URL de releases.

NPM requiere un token de autenticación (_auth), este se crea con el siguiente comando:

echo -n 'user:password' | base64

Repositorio de Docker

El repositorio de Docker es bastante más complejo por la tecnología que utiliza. Al desplegar prefijamos 2 Ingress y servicios con puertos para este, ya que no puede ser publicado como el resto, requieren su propio dominio de acceso.

Similar al resto, creamos un repositorio propio y un espejo del de Docker, además de un grupo. La principal diferencia es que únicamente publicaremos la URL del privado para poder subir nuestras imágenes, y la del grupo completo. Los espejos no necesitan ser publicados porque son accesibles directamente por el grupo.

NombreTipoOtros
docker-privatedocker (hosted)HTTP: 5000
Allow anonymous docker pull
docker-hubdocker (proxy)Remote storage: https://registry-1.docker.io
Docker Index: Use Docker Hub
docker-groupdocker (group)HTTP: 5001
Allow anonymous docker pull
Repositorios en el orden de esta tabla

Acorde a los Ingress definidos previamente, podremos acceder al repositorio privado y al público con las siguientes URL:

  • docker-private.domain.intranet
  • registry.domain.intranet
compte

Si utilizamos un certificado auto firmado, tendremos que añadirlo a la lista de certificados del sistema que utilicemos, ya sea Docker, cri-o o cualquier otro.

El acceso anónimo requiere sea añadido. En Security > Realms añadimos el Docker Bearer Token Realm.

Usuarios y permisos

Los artefactos son accesibles de forma anónima, pero se requiere un usuario para poder crearlos en los repositorios privados.

Normalmente requeriría configurar un LDAP donde centralizar los usuarios, y definir una serie de roles para cada equipo, pero para un uso doméstico simplemente creamos un rol para cada repositorio y los asignamos a cada usuario que necesitemos.

Los roles se crean desde Security > Roles y de tipo Nexus role.

IdNameDescriptionPrivileges
maven-pushMaven PushWrite/delete Maven from API and UInx-component-upload
nx-repository-view-maven2-*-*
npm-pushNPM PushWrite/delete NPM from API and UInx-component-upload
nx-repository-view-npm-*-*
docker-pushDocker PushWrite/delete Docker from APInx-repository-view-docker-*-*

A partir de aquí, será crear usuarios locales desde Security > Users y asignarles el role que necesiten.