Article original : How to Provision a Nexus Sonatype OSS on an Orange PI 5 with Ansible
Nexus 3 OSS est un gestionnaire de dépôt d'artéfacts Open Source qui peut gérer plusieurs formats comme les images de conteneurs, Python PIP, Java jar, et bien d'autres.
Pourquoi avoir un gestionnaire d'artéfacts sur site ? Il y a plusieurs raisons pour cela :
Utilisez votre infrastructure privée : Vous pouvez avoir du code propriétaire qui doit être protégé.
Vitesse de téléchargement des artéfacts plus rapide : Si vous téléchargez constamment les mêmes artéfacts via Internet, vous pouvez les mettre en cache à un emplacement central, au bénéfice de vos multiples utilisateurs sur plusieurs serveurs en les mettant en cache.
Contrôlez quels artéfacts arrivent dans votre chaîne de construction : Centralisez l'emplacement des artéfacts, assurez-vous qu'ils sont approuvés pour l'utilisation, et confirmez également qu'ils ne contiennent pas de code malveillant.
Séparer qui peut avoir accès à vos artéfacts : Vous pouvez avoir des exigences plus strictes sur qui peut accéder à certains artéfacts au sein de votre propre organisation.
Dans cet article, je vais vous montrer comment télécharger, installer et configurer la version OSS de Nexus 3 en utilisant un playbook Ansible.
Nexus 3 fonctionnera sur un ordinateur Orange PI 5 avec 8 Go de RAM, mais cet approvisionnement peut être effectué sur n'importe quelle machine avec les exigences minimales. Une partie de la configuration consistera à définir un proxy pour PyPI.org, pour les machines listées dans mon fichier inventory.
Ce dont vous avez besoin pour exécuter le code de ce tutoriel
Une connexion Internet pour télécharger le code source pour le playbook Ansible, Nexus et les modules PIP
Deux machines Linux ou plus (j'ai utilisé Debian, Armbian et Fedora IOT), avec au moins 8 Go de RAM. Mon cluster est un mélange de Raspberry PI 4 et d'un OrangePI 5.
Le contrôleur Ansible fonctionnera sur la machine Fedora, mais n'importe quel serveur peut être le contrôleur. Les instructions d'installation pour Ansible sont faciles à suivre.
Organisation du Playbook
J'ai divisé les tâches en groupes et le playbook résultant ressemble à ceci :
[josevnz@dmaf5 Nexus3OnOrangePI]$ tree -N ansible/
ansible/
├── inventories
│ └── home
│ └── hosts.yaml
├── roles
│ ├── clients
│ │ ├── tasks
│ │ │ └── main.yaml
│ │ └── templates
│ │ └── pip.conf.j2
│ └── nexus
│ ├── files
│ │ └── swagger.json
│ ├── tasks
│ │ ├── download.yaml
│ │ ├── install.yaml
│ │ ├── main.yaml
│ │ ├── post_install.yaml
│ │ ├── pre_install.yaml
│ │ ├── repositories.yaml
│ │ ├── third_party.yaml
│ │ └── user.yaml
│ └── templates
│ ├── logrotate.nexus3.j2
│ ├── nexus3.service.j2
│ ├── nexus.rc.j2
│ └── nexus.vmoptions.j2
├── site.yaml
├── vars
│ ├── clients.yaml
│ └── nexus.yaml
└── vault
├── nexus_password.enc
└── README.md
13 directories, 21 files
Maintenant, un peu d'explications :
Il y a deux rôles : 'nexus' et 'clients'. Le rôle nexus est utilisé pour configurer le logiciel de gestion des artéfacts, tandis que le rôle client configure les paramètres pip sur chaque machine.
Vars contient des variables utilisées dans chaque rôle, séparées par fichiers pour rendre leur utilisation plus claire
Nous avons des mots de passe, et nous les gérons en utilisant la fonctionnalité Ansible vault.
Le fichier 'site.yaml' orchestres l'exécution des rôles :
- hosts: all
tags: clients
vars_files:
- vars/clients.yaml
roles:
- clients
- hosts: nexus_server
tags: nexus
become_user: root
become: true
vars_files:
- vars/nexus.yaml
roles:
- nexus
Passons maintenant à l'univers où le playbook sera exécuté.
L'Inventaire des Hôtes
Dans mon cas, il est assez simple - j'ai deux groupes principaux : 'clients' et la machine où le serveur Nexus 3 lui-même fonctionnera :
all:
children:
nexus_server:
hosts:
orangepi5.home:
home_lab:
hosts:
dmaf5.home:
raspberrypi.home:
orangepi5.home:
La prochaine tâche importante est de télécharger et de configurer Nexus 3.
Comment Installer Nexus 3
Le fichier main.yaml décrit l'ordre et le but de chaque tâche d'installation pour le rôle Nexus :
# Tasks listed here are related to the remote Nexus 3 server
# Included tasks are called in order
---
- include_tasks: third_party.yaml
- include_tasks: pre_install.yaml
- include_tasks: download.yaml
- include_tasks: install.yaml
- include_tasks: post_install.yaml
- include_tasks: user.yaml
- include_tasks: repositories.yaml
Voyons d'abord ce que j'aime appeler les "tâches principales" :
third_party.yaml : Ici, nous installons OpenJDK8 (Nexus 3 est écrit en Java) et logrotate pour gérer les anciens logs.
pre_install.yaml : Beaucoup de choses se passent ici, comme la création des répertoires requis pour nexus, un utilisateur non privilégié dédié qui exécutera le processus.
download.yaml : Comme son nom l'indique, nous obtenons une version fraîche du logiciel Nexus 3 OSS et nous assurons qu'il a la bonne somme de contrôle. Nous ne voulons pas installer de logiciels malveillants depuis Internet.
Ensuite viennent les tâches qui tombent dans le groupe "installation personnalisée" :
install.yaml : Décompressez le logiciel, préparez l'unité systemd pour le démarrer automatiquement, configurez les paramètres JVM pour Nexus et déployez la configuration logrotate.
post_install.yaml : Des choses passionnantes se passent ici - le logiciel est installé et nous l'exécutons pour la première fois. Nous changeons également le mot de passe par défaut en utilisant l'API REST, afin de pouvoir passer à l'étape de personnalisation.
user.yaml : Ici, nous préparons l'accès de nos utilisateurs finaux aux services offerts par Nexus. Nous faisons cela en utilisant une combinaison de l'API REST et du code client Ansible :
# https://help.sonatype.com/repomanager3/installation-and-upgrades/post-install-checklist
# https://help.sonatype.com/repomanager3/integrations/rest-and-integration-api
---
- name: Enable anonymous user
tags: anonymous
ansible.builtin.uri:
user: ""
password: ""
url: "/v1/security/anonymous"
method: PUT
body_format: raw
status_code: [ 200, 202, 204 ]
headers:
Content-Type: application/json
body: |-
{ "enabled" : true, "userId" : "anonymous", "realmName" : "NexusAuthorizingRealm" }
force_basic_auth: true
return_content: true
any_errors_fatal: true
- name: Enable Docker security realm
tags: docker_realm
ansible.builtin.uri:
user: ""
password: ""
url: "/v1/security/realms/active"
method: PUT
body_format: raw
status_code: [ 200, 202, 204 ]
headers:
Content-Type: application/json
body: |-
[ "NexusAuthenticatingRealm", "NexusAuthorizingRealm", "DockerToken" ]
force_basic_auth: true
return_content: true
any_errors_fatal: true
La logique est facile à suivre, en utilisant la méthode http 'PUT', vous pouvez dire qu'il s'agit d'une opération de modification (ce qui signifie que les rôles et utilisateurs existants existent déjà). La détection des erreurs est effectuée en obtenant les codes HTTP retournés par Nexus.
L'étape suivante consiste à préparer notre proxy local PyPi. Il s'agit d'une tâche en plusieurs étapes et sera décrite en détail ci-dessous.
Comment Configurer le Proxy PyPI sur Nexus 3
Le dernier fichier du rôle Nexus 3 est 'repositories.yaml'. Ici, nous passons par les étapes suivantes :
Vérifiez si le proxy a déjà été configuré (opération GET ou lecture seule)
S'il n'existe pas, créez-en un nouveau (méthode POST avec une charge utile JSON contenant les détails pour créer un tout nouveau dépôt)
Remarquez que ce playbook n'offre pas l'option de mise à jour des paramètres du dépôt. Il est possible de le faire avec l'API REST, mais je laisserai cela comme exercice au lecteur.
Les tâches pour préparer le proxy PyPi sont présentées ci-dessous :
# Create proxy for repositories
# https://help.sonatype.com/repomanager3/integrations/rest-and-integration-api
# PyPi: https://pip.pypa.io/en/stable/user_guide/
---
- name: Check if the PyPi proxy exists
tags: pypi_proxy_exists
ansible.builtin.uri:
user: ""
password: ""
url: "/v1/repositories/pypi/proxy/python_proxy"
method: GET
body_format: raw
status_code: [ 200, 202, 204, 404 ]
headers:
Content-Type: application/json
force_basic_auth: true
return_content: true
any_errors_fatal: true
register: python_local
- name: Create PyPI proxy
tags: pypi_proxy_create
ansible.builtin.uri:
user: ""
password: ""
url: "/v1/repositories/pypi/proxy"
method: POST
body_format: raw
status_code: [ 201 ]
headers:
Content-Type: application/json
body: |-
{
"name": "python_proxy",
"online": true,
"storage": {
"blobStoreName": "default",
"strictContentTypeValidation": true
},
"proxy": {
"remoteUrl": "https://pypi.org/",
"contentMaxAge": -1,
"metadataMaxAge": 1440
},
"negativeCache": {
"enabled": true,
"timeToLive": 1440
},
"httpClient": {
"blocked": false,
"autoBlock": true,
"connection": {
"retries": 0,
"timeout": 60,
"enableCircularRedirects": false,
"enableCookies": true,
"useTrustStore": false
}
}
}
force_basic_auth: true
return_content: true
any_errors_fatal: true
when: python_local.status == 404
Nous y sommes presque. Maintenant, nous devons dire à nos clients PyPi qu'ils doivent utiliser notre Nexus local et non le site PyPi direct pour obtenir nos bibliothèques Python.
Comment Configurer les Clients
Le rôle des clients est beaucoup plus simple et ne nécessite que le déploiement d'un modèle pour pip.conf avec suffisamment d'informations pour forcer la recherche dans notre nouveau dépôt :
# Tasks here are meant to be used on our clients user
---
- name: Create installation directory for pip.conf
tags: pip_basedir
ansible.builtin.file:
state: directory
path: ""
owner: ""
group: ""
mode: "u+rwx,go-rwx"
- name: Copy pip.conf file
tags: pip_copy
ansible.builtin.template:
src: pip.conf.j2
dest: "/pip.conf"
owner: ""
group: ""
mode: u=rxw,g=r,o=r
Le fichier résultant est déployé sur '~/.config/pip/pip.conf' de chaque machine :
# https://pip.pypa.io/en/stable/topics/configuration/
[global]
timeout = 60
[install]
index = http://orangepi5.home:8081/repository/python_proxy/pypi
index-url = http://orangepi5.home:8081/repository/python_proxy/simple/
trusted-host = orangepi5.home
Le fichier ci-dessus montre un exemple de l'apparence de la version finale du fichier une fois déployé sur mon cluster (le vôtre sera différent avec l'URL résolue).
Il est maintenant temps d'exécuter l'ensemble du playbook et de voir à quoi il ressemble.
Comment Exécuter le Playbook
Pour exécuter le playbook, nous passons quelques arguments :
L'emplacement de notre inventaire d'hôtes
L'emplacement du fichier de mot de passe chiffré et un fichier principal contenant le mot de passe principal pour déverrouiller le contenu du fichier protégé
Et enfin l'emplacement de notre fichier principal de playbook
cd ansible
ansible-playbook --inventory inventories --extra-vars @vault/nexus_password.enc --vault-password-file $HOME/vault/ansible_vault_pass site.yaml
Comment tester le nouveau proxy PyPI
Pour tester notre nouveau proxy, nous allons installer Python Rich en utilisant pip et un environnement virtuel.
josevnz@orangepi5:~$ python3 -m venv ~/virtualenv/rich
(rich) josevnz@orangepi5:~$ . ~/virtualenv/rich/bin/activate
(rich) josevnz@orangepi5:~$ pip install rich
Looking in indexes: http://orangepi5.home:8081/repository/python_proxy/simple/
Collecting rich
Downloading http://orangepi5.home:8081/repository/python_proxy/packages/rich/13.3.4/rich-13.3.4-py3-none-any.whl (238 kB)
238.7/238.7 KB 14.8 MB/s eta 0:00:00
Collecting pygments<3.0.0,>=2.13.0
Downloading http://orangepi5.home:8081/repository/python_proxy/packages/pygments/2.15.0/Pygments-2.15.0-py3-none-any.whl (1.1 MB)
1.1/1.1 MB 23.8 MB/s eta 0:00:00
Collecting markdown-it-py<3.0.0,>=2.2.0
Downloading http://orangepi5.home:8081/repository/python_proxy/packages/markdown-it-py/2.2.0/markdown_it_py-2.2.0-py3-none-any.whl (84 kB)
84.5/84.5 KB 6.9 MB/s eta 0:00:00
Collecting mdurl~=0.1
Downloading http://orangepi5.home:8081/repository/python_proxy/packages/mdurl/0.1.2/mdurl-0.1.2-py3-none-any.whl (10.0 kB)
Installing collected packages: pygments, mdurl, markdown-it-py, rich
Successfully installed markdown-it-py-2.2.0 mdurl-0.1.2 pygments-2.15.0 rich-13.3.4
Et ensuite nous pouvons confirmer que le cache a effectivement été utilisé en voyant les nouveaux artéfacts dans le nouveau dépôt :

Voir les artéfacts PyPi
Voyons une démonstration du client en action, installant autre chose :
Personnalisation Avancée en Utilisant l'API REST
Chaque installation de Nexus vous permet de télécharger un fichier JSON qui décrit l'API prise en charge par le serveur. Par exemple, sur mon serveur, vous pouvez obtenir une copie comme ceci depuis mon serveur orangepi5.home :
curl --fail --remote-name http://orangepi5.home:8081/service/rest/swagger.json
De plus, l'interface utilisateur vous permet d'essayer les autres points de terminaison de l'API REST pour personnaliser votre installation.

Test de l'API REST
Conclusion
Je recommande de passer un peu de temps et de lire le livre Nexus 3 pour vous familiariser avec les fonctionnalités que cet outil peut offrir.
La communauté a préparé des installeurs Debian et RPM, si vous avez besoin de ce type de configuration plutôt que d'utiliser Ansible.
Nexus 3 a beaucoup de paramètres configurables. Nous n'avons couvert que la surface ici. En préparant cet article, j'ai trouvé 'ThoTeam Nexus3-oss repository' avec un playbook très complet et à jour, mais il était bien plus complexe que tout ce dont j'avais besoin pour mon laboratoire à domicile.
Archiva est un autre gestionnaire d'artéfacts Open Source, il est plus limité en fonctionnalités mais aussi plus simple à configurer.
Il y a une liste de contrôle post-installation avec certaines tâches que je n'ai pas eu besoin de compléter pour mon laboratoire à domicile. Veuillez la consulter pour vous assurer que votre configuration est complète.