Repositorio de artefactos privado con Nexus

Escrito por picodotdev el .
java planeta-codigo programacion
Enlace permanente Comentarios

Los repositorios de software almacenan los artefactos, son utilizados por las herramientas de construcción que los descargan y almacenan de forma local para posteriores usos las dependencias que los proyectos declaran en el archivo de construcción. Los desarrolladores de los artefactos publican en los repositorios de software las nuevas versiones. Nexus es un repositorio de software con soporte para repositorios de software de varios tipos, Maven para Java, imágenes de Docker, paquetes npm para JavaScript además de artefactos para los lenguajes Python y Go.

Los proyectos de software son complejos, las librerías permiten crear módulos de las aplicaciones y reutilizar código ya implementado sin tener que implementar la misma funcionalidad en cada proyecto. Todos los lenguajes de una forma u otra permiten reutilizar librerías. En Java las librerías son archivos jar, en Docker imágenes de contenedores y en JavaScript paquetes npm.

Para reutilizar las librerías los proyectos declaran las librerías de las que dependen, la herramienta de construcción se encargan de descargarlas y almacenarlas en un repositorio local para evitar una nueva descargacon su transferencia de red en usos posteriores. En Java las herramientas de construcción Gradle y Maven automatizan la descarga y enlazado de las dependencias declaradas con el código del proyecto. Para JavaScript una herramienta de dependencias es npm.

Las librerías requieren de la funcionalidad de un repositorio de librerías o artefactos que permite descargarlas cuando un proyecto las declare como dependencias. En Java el repositorio más popular es Maven Central, las imágenes para iniciar un contenedor de Docker también tienen su propio repositorio de imágenes de Docker con Docker Hub o el repositorio de librerías JavaScript que utiliza npm.

Los repositorios anteriores son públicos donde los desarrolladores suben sus artefactos cada vez que publican una nueva versión de sus librerías o frameworks. Una organización en sus proyectos utiliza numerosas dependencias de los repositorios oficiales de cada lenguaje o herramienta pero también con seguridad desarrollará sus propias librerías que necesita compartir en diferentes proyectos de forma interna sin compartirlos en los repositorios públicos.

Repositorio de artefactos con Nexus

Nexus es un software que ofrece la funcionalidad de repositorio de artefactos. Permite a una organización compartir de forma privada los artefactos entre los diferentes proyectos. Soporta diferentes tipos de repositorios según el tipo de artefactos, librerías jar para Java, paquetes npm para JavaScript, imágenes de contenedores para Docker, paquetes de Python y Go.

Nexus OSS es la versión de código abierto que permite su uso sin coste, la versión Nexus Pro tiene características empresariales como autenticación SSO.

Github Packages permite hacer las funcionalidades de repositorio de artefactos pero no soporta todos los tipos de artefactos de todos los lenguajes. Google Artifact Registry también ofrece un servicio para almacenar los artefactos resultado de compilación, Amazon con AWS CodeArtifact también tiene su servicio administrado de artefactos.

Arquitectura de un repositorio de artefactos con Nexus

Ejemplo de repositorio con Nexus

Nexus ofrece una imagen de Docker que permite iniciar el servidor de Nexus de forma fácil como un contenedor. El siguiente script lo inicia en el puerto 8081 y en el puerto adicional 8082 para el repositorio de Docker.

1
2
$ docker run -it --rm -p 8081:8081 -p 8082:8082 --name nexus sonatype/nexus3

docker-run.sh

El usuario administrador es admin y la contraseña aleatoria generada al inicio del contenedor se almacena en el archivo /nexus-data/admin.password del sistema de archivos del contenedor.

1
2
3
4
5
6
$ docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS          PORTS                              NAMES
6b7d7495ad0c   sonatype/nexus3   "sh -c ${SONATYPE_DI}"   50 seconds ago   Up 49 seconds   0.0.0.0:8081-8082->8081-8082/tcp   nexus
$ docker exec -it 6b7d7495ad0c bash
# cat /nexus-data/admin.password
41693644-b54a-4aef-9cf0-cb151e9ef440
docker-exec.sh

Nexus

Publicar un artefacto a un repositorio Maven local

Usando Gradle o Maven las dependencias de un proyecto se cachean en un directorio local del directorio de inicio del usuario, ~/.gradle o ~/.m2. Al desarrollar es posible publicar una versión de una librería en estos repositorios de caché. Para publicar un artefacto en un repositorio de Maven con Gradle se utiliza el plugin Maven Publish.

1
2
$ ./gradlew publishToMavenLocal
$ ./gradlew publishLibraryPublicationToMavenLocal
gradlew-publishToMavenLocal.sh

Publicar un artefacto a un repositorio Maven en Nexus con Gradle

Gradle ofrece el plugin Maven Publish para publicar artefactos en repositorios de Maven. Hay que configurar y definir los artefactos y los repositorios en los que se puede publicar. El plugin añade varias tareas de Gradle con las que elegir de forma específica que artefacto publicar, en que repositorio, el grupo del artefacto, su nombre y versión.

Este es un archivo de construcción de Gradle con un repositorio Maven de Nexus en el que publicar los artefactos de la librería.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
plugins {
    id 'java-library'
    id 'maven-publish'
}

repositories {
    maven {
        url "http://localhost:8081/repository/maven-releases/"
    }
    mavenCentral()
}

dependencies {
}

tasks.named('test') {
    useJUnitPlatform()
}

publishing {
    publications {
        library(MavenPublication) {
            groupId = 'io.github.picodotdev'
            artifactId = 'java-library'
            version = '1.0'

            from components.java
        }
    }
    repositories {
        maven {
            name = 'nexus'
            allowInsecureProtocol = true
            url "http://localhost:8081/repository/maven-releases/"
            credentials {
                username 'admin'
                password 'admin'
            }
        }
    }
}
build-library.gradle
1
2
$ ./gradlew publishLibraryPublicationToNexusRepository

gradlew-publishToNexusRepository.sh

Librería de Java publicada en repositorio Nexus

Una vez publicado el artefacto otro proyecto puede declararlo como una dependencia en la sección dependencies y añadir el repositorio de Maven donde buscar dependencias en la sección repositories. Al ejecutar el programa Gradle descarga la dependencia y la añade al proyecto como cualquier dependencia del repositorio de mavenCentral.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
plugins {
    id 'application'
}

repositories {
    maven {
          allowInsecureProtocol = true
          url "http://localhost:8081/repository/maven-releases/"
    }
    mavenCentral()
}

dependencies {
    implementation 'io.github.picodotdev:java-library:1.0'
}

application {
    mainClass = 'io.github.picodotdev.blogbitix.nexus.Main'
}

tasks.named('test') {
    useJUnitPlatform()
}
build-application.gradle

El programa trata las clases de la librería del repositorio de Nexus como cualquier otra clase de una librería de Maven Central.

1
2
3
4
5
6
7
package io.github.picodotdev.blogbitix.nexus.library;

public class Library {
    public boolean someLibraryMethod() {
        return true;
    }
}
Library.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package io.github.picodotdev.blogbitix.nexus.application;

import io.github.picodotdev.blogbitix.nexus.library.Library;

public class Main {

    public String getGreeting() {
        return "Hello World!";
    }

    public static void main(String[] args) {
        System.out.println("Main: " + new Main().getGreeting());
        System.out.println("Library: " + new Library().someLibraryMethod());
    }
}
Main.java
1
2
$ ./gradlew run

gradlew-run.sh
1
2
Main: Hello World!
Library: true
System.out

Publicar una imagen Docker a un repositorio repositorio en Nexus

Para usar el repositorio de imágenes de Docker en Nexus es necesario crear un repositorio y configurar Nexus para que se ubique en un puerto diferente del del puerto estándar. En este caso el contenedor de Docker de Nexus además del puerto 8081 se inicia en el puerto 8082.

Repositorios de Nexus

Para subir una imagen de un contenedor al repositorio hay que crear su tag y realizar la subida de la imagen. Crear una imagen de Docker con un Dockerfile genera una imagen de un contenedor en el repositorio local, una vez se ha generado se le añade la etiqueta y se sube al repositorio.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$ docker images
REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
busybox           latest    a9d583973f65   2 days ago     1.23MB
sonatype/nexus3   latest    f07af611e0df   8 days ago     662MB
$ docker tag a9d583973f65 localhost:8082/repository/docker/busybox:latest
$ docker images
REPOSITORY                                 TAG       IMAGE ID       CREATED        SIZE
busybox                                    latest    a9d583973f65   2 days ago     1.23MB
localhost:8082/repository/docker/busybox   latest    a9d583973f65   2 days ago     1.23MB
sonatype/nexus3                            latest    f07af611e0df   8 days ago     662MB
$ docker login localhost:8082
Username: admin
Password:
Login Succeeded
$ docker push localhost:8082/repository/docker/busybox:latest
The push refers to repository [localhost:8082/repository/docker/busybox]
2983725f2649: Pushed 
latest: digest: sha256:410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd size: 527
docker-push.sh

Imagen de Docker publicada en repositorio Nexus

Una vez la imagen del contenedor se ha subido se puede utilizar especificando la URL del repositorio de imágenes. Para comprobar que la imagen se descarga del repositorio de Nexus primero se elimina de la caché local.

1
2
$ docker rmi localhost:8082/repository/docker/busybox:latest

docker-rmi.sh
1
2
3
4
$ docker pull localhost:8082/repository/docker/busybox:latest
$ docker run -it --rm localhost:8082/repository/docker/busybox:latest
/ # date
Fri Mar 12 19:12:56 UTC 2021
docker-pull.sh

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub.

Comparte el artículo: