Инструменты пользователя

Инструменты сайта


service:nexus

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
service:nexus [07.03.2025 08:51] – [Nexus как веб-сервер] viacheslavservice:nexus [12.04.2025 06:57] (текущий) – [apt] viacheslav
Строка 1: Строка 1:
 +====== Nexus ======
 +Система хранения артефактов, поддерживает множество форматов: maven, yum, npm, docker, helm, raw и другие.
 +
 +Типы:
 +  * hosted — располагающиеся локально на собственном хранилище
 +  * proxy — ссылка на удалённый репозиторий, но кеширующиеся при выкачивании
 +  * group — позволяет объединять несколько репозиториев в одну группу
 +
 +В Nexus при создании репозитория типа maven2 спрашивается, какие типы артефактов будут в нём храниться: Snapshot, Release или Mixed. В мире Maven принято, что для разных этапов готовности продукта артефакт хранится в своём собственном репозитории.\\
 +Когда продукт сырой и мы ещё не готовы опубликовать готовую версию, но нужно её запустить и проверить (например, артефакт, который скомпилируется для прогона тестов на прикоммите), мы добавляем к имени версии постфикс ''-SNAPSHOT'', и тогда maven по умолчанию будет заливать в snapshot-репозиторий. Без этого постфикса все артефакты будут публиковаться в release-репозиторий.
 +
 +===== Заливка =====
 +These are bare bones bash scripts to import a Nexus 2 Maven, NuGet or npm repository (and likely other file system based repos) into Nexus Repository 3. It imports artifacts into a Nexus Repository 3 Maven2, NuGet or npm hosted repo.\\
 +https://github.com/sonatype-nexus-community/nexus-repository-import-scripts/tree/master
 +
 +Если заливать одну и ту же версию, то поведение Нексуса зависит от политики Deployment policy в настройках репозитория.
 +  * Disable redeploy (по умолчанию) - если версия уже есть, то заливаться ничего не будет, даже если файл отличается.
 +  * Allow redeploy - если файл той же версии, но сам по себе отличается, то он будет залит. Если файл тот же самый - заливаться не будет.
 +==== Maven ====
 +''NEXUS_REPO_USER'', ''NEXUS_REPO_PASS'' и прочие заносятся в переменные Gitlab.
 +
 +<file xml pom.xml>
 +<distributionManagement>
 +  <repository>
 +       <id>testapp</id>
 +       <name>testapp</name>
 +       <url>${env.NEXUS_REPO_URL}/repository/${env.NEXUS_REPO_BACKEND_NAME}</url>
 +   </repository>
 +</distributionManagement>
 +</file>
 +
 +<file xml settings.xml>
 +  <settings xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd"
 +      xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 +    <servers>
 +      <server>
 +        <id>testapp</id>
 +        <username>${env.NEXUS_REPO_USER}</username>
 +        <password>${env.NEXUS_REPO_PASS}</password>
 +      </server>
 +    </servers>
 +  </settings>
 +</file>
 +
 +<file yaml .gitlab-ci.yml>
 +stages:
 +  - release
 +
 +# backend
 +upload-backend-release:
 +  stage: release
 +  only:
 +    changes:
 +      - backend/**/*
 +  needs:
 +    - build-backend-code-job
 +  script:
 +    - cd backend
 +# Вместо mvn package теперь mvn deploy
 +    - >
 +    mvn deploy -DskipTests
 +    -Dmaven.repo.local=${CI_PROJECT_DIR}/.m2/repository
 +    -s settings.xml -Dversion.application=${VERSION} 
 +
 +# frontend заливается через curl
 +upload-frontend-release:
 +  stage: release
 +  only:
 +    changes:
 +    - frontend/**/*
 +  needs:
 +    - build-frontend-code-job
 +  script:
 +    - cd frontend/dist
 +    - tar czvf testapp-${VERSION}.tar.gz frontend
 +    - >
 +    curl -v -u "${NEXUS_REPO_USER}:${NEXUS_REPO_PASS}"
 +    --upload-file testapp-${VERSION}.tar.gz
 +    ${NEXUS_REPO_URL}/${NEXUS_REPO_FRONTEND_NAME}/${VERSION}/testapp-${VERSION}.tar.gz 
 +</file>
 +
 +==== curl ====
 +Curl-ом можно заливать файлы в репозитории Maven2, YUM и RAW. Репозитории NuGet, NPM и Docker не поддерживают такую загрузку.
 +<code bash>
 +# В URL maven-releases - название репозитория, org/foo - группа org.foo, lunar-lang - имя компонента, 1.0.0 - версия.
 +curl -u admin:admin -T artifact.jar http://k3.workgroup:8081/repository/maven-releases/org/foo/lunar-lang/1.0.0/lunar-lang-1.0.0.jar
 +</code>
 +{{:service:pasted:20240702-190746.png}}
 +
 +https://support.sonatype.com/hc/en-us/articles/115006744008-How-can-I-programmatically-upload-files-into-Nexus-3
 +
 +Залить все файлы из каталога, сохранив структуру.
 +<code bash>
 +# Здесь: из каталога ~/cka в репозиторий http://k3:8081/repository/test, логин-пароль admin
 +# 2 замены - первая меняет путь на URL, вторая - пробелы на %20
 +find ~/cka -type f -print0 |xargs -0 bash -c 'for f; do i=$(echo ${f/$PWD/http://k3:8081/repository/test}); i=$(echo ${i// /%20}); curl -u admin:admin --upload-file "$f" "$i" ; done'
 +</code>
 +По мотивам https://stackoverflow.com/questions/20050910/replacing-a-part-of-file-path-in-exec
 +
 +Powershell
 +<code powershell>
 +$folder = '$env:userprofile\Downloads\nexusartifacts'
 +$repo = 'http://k3:8081/repository/test'
 +$cred = 'admin:admin'
 +
 +$files = (dir $folder -Recurse -File).FullName
 +
 +foreach ($f in $files) {
 +    $url = $f.Replace("$folder","$repo").Replace('\','/')
 +    "$f ->`n$url`n"
 +    & curl.exe -ksu $cred -T $f $url
 +}
 +</code>
 +==== Docker ====
 +Предполагается, что Nexus опубликован просто по HTTP и сам запущен в Докере.
 +
 +  - Cоздать репозиторий ''docker (hosted)'', например, с именем docker, и обязательно в настройках прописать ему порт HTTP, отличный от веб-интерфейсного, например, 8082.
 +  - Отредактировать docker-compose или Dockerfile, чтобы этот порт был доступен снаружи, и перезапустить контейнер.
 +  - Cоздать в Нексусе пользователя для этого репозитория и дать ему права.
 +  - Чтобы Докер работал с незащищённым репозиторием, нужно ему прописать в конфигурацию ''insecure-registries'', например, ''k3:8082''.<file javascript /etc/docker/daemon.json>
 +{
 +    "registry-mirrors": [
 +        "https://mirror.gcr.io"
 +    ],
 +    "insecure-registries": [
 +        "k3:8082",
 +        "k3.workgroup:8082",
 +        "k1:8082"
 +    ]
 +}
 +</file>
 +  - Далее <code bash>
 +# Дать права Докеру на файл
 +sudo chown $USER:docker /etc/docker/daemon.json
 +# Перечитать настройки (может, и restart)
 +sudo systemctl reload docker
 +
 +# Залогиниться (Докер-клиент не поддерживает путей URL, только хост:порт)
 +docker login k3:8082
 +# Поставить тэг образу, который нужно залить
 +docker tag alpine:3.19 k3:8082/repository/docker/alpine:3.19
 +# Залить образ в Нексус
 +docker push k3:8082/repository/docker/alpine:3.19
 +</code>
 +
 +https://www.devopsschool.com/blog/how-to-upload-and-download-docker-images-using-nexus-registry-repository/\\
 +https://help.sonatype.com/en/hosted-repository-for-docker--private-registry-for-docker-.html\\
 +https://help.sonatype.com/en/ssl-and-repository-connector-configuration.html
 +
 +Заливка всех образов, имеющихся на машине, в Нексус. С тэгом ''latest'' будет заливаться как есть, так что, возможно, нужно отфильтровать их в ''awk'' и тэгировать руками, чтобы не было перезаписи при заливке.
 +<code bash>
 +# Логин в репу Нексуса
 +docker login k3:8082
 +# Адрес репы (без слэша в конце)
 +repo='k3:8082/repository/docker'
 +# Список образов (кроме <none>) с тэгами. egrep - если понадобится запустить ещё раз, а awk не раскрывает переменные в /.../
 +# egrep отфильтровывает образы с тэгами, начинающимися на host:port/
 +images=($(docker image ls | awk '!/REPOSITORY|<none>/ {print $1":"$2}' |egrep -v ^.*:[[:digit:]]*/))
 +# Тэгировать и залить
 +for i in "${images[@]}" ; do docker tag $i $repo/$i && docker push $repo/$i ; done
 +</code>
 +
 +==== Python ====
 +Используется twine. В конце URL необходим trailing slash, иначе будет ошибка при загрузке.
 +<code powershell>
 +# Upload all files in the folder
 +$twine = "$env:localappdata\Programs\Python\Python312\Scripts\twine.exe" # если нет в PATH
 +
 +& $twine upload --repository-url "http://k3:8081/repository/pypi-lib/" `
 +-u admin -p admin --non-interactive --skip-existing --disable-progress-bar `
 +C:\temp\pypi\*
 +</code>
 +Есть вариант прописывать реквизиты входа в файл ''.pypirc'', например,
 +<file ini ~/.pypirc>
 +[distutils]
 +index-servers = pypi
 +[pypi]
 +repository: http://k3:8081/repository/pypi-lib/
 +username: admin
 +password: admin
 +</file>
 +Тогда команда загрузки будет
 +<code powershell>
 +# -r - [имя репы], прописанной в .pypirc
 +twine upload -r pypi C:\temp\pypi\*.whl
 +</code>
 +
 +https://help.sonatype.com/en/pypi-repositories.html\\
 +https://twine.readthedocs.io/en/stable/\\
 +https://stackoverflow.com/questions/56592918/how-to-upload-the-python-packages-to-nexus-sonartype-private-repo
 +
 +
 +===== Скачивание =====
 +<file bash testapp-backend.service>
 +[Unit]
 +Description=testapp-backend
 +
 +[Service]
 +User=jarservice
 +Environment=REPORT_PATH=/var/testapp/reports
 +Environment=LOG_PATH=/var/testapp/logs
 +Restart=always
 +ExecStart=/usr/bin/java \
 +-Dmyserver.basePath='/home/jarservice/' \
 +-Dmyserver.bindAddr='127.0.0.1' \
 +-Dmyserver.bindPort='8080' \
 +-Dmyserver.hostName='testapp' \
 +-jar '/home/jarservice/testapp.jar'
 +SuccessExitStatus=143
 +
 +[Install]
 +WantedBy=multi-user.target
 +</file>
 +
 +<file bash deploy.sh>
 +#!/bin/bash
 +# Скрипт валится при любой ошибке
 +set -xe
 +# Перезалить дескриптор сервиса на ВМ для деплоя
 +sudo cp -rf testapp-backend.service /etc/systemd/system/testapp-backend.service
 +sudo rm -f /home/jarservice/testapp.jar || true
 +# Перенос артефакта в нужную папку
 +curl -u ${NEXUS_REPO_USER}:${NEXUS_REPO_PASS} -o testapp.jar ${NEXUS_REPO_URL}/${NEXUS_REPO_BACKEND_NAME}/ru/company/project/devops/testapp/${VERSION}/testapp-${VERSION}.jar
 +sudo cp ./testapp.jar /home/jarservice/testapp.jar || true
 +# Обновить конфиг systemd
 +sudo systemctl daemon-reload
 +# Перезапустить сервис
 +sudo systemctl restart testapp-backend
 +</file>
 +
 +<file yaml .gitlab-ci.yml>
 +deploy:
 +  stage: deploy
 +  script:
 +    - scp ./backend/testapp-backend.service ${DEV_USER}@${DEV_HOST}:/home/${DEV_USER}/testapp-backend.service
 +    - > 
 +      ssh ${DEV_USER}@${DEV_HOST} "
 +      export "CURRENT_VERSION=${VERSION}";
 +      export "VERSION=${VERSION}";
 +      export "DEV_HOST=${DEV_HOST}";
 +      export "NEXUS_REPO_URL=${NEXUS_REPO_URL}";
 +      export "NEXUS_REPO_USER=${NEXUS_REPO_USER}";
 +      export "NEXUS_REPO_PASS=${NEXUS_REPO_PASS}";
 +      setsid /bin/bash -s " < ./backend/deploy.sh
 +</file>
 +==== Gradle ====
 +Копия дистрибутива в локальном Nexus (raw-репозиторий)
 +<file bash gradle/wrapper/gradle-wrapper.properties>
 +distributionBase=GRADLE_USER_HOME
 +distributionPath=wrapper/dists
 +#distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
 +distributionUrl=http\://login:P@ssw0rd@URL[:PORT]/repository/gradle/gradle-7.3.3-bin.zip
 +zipStoreBase=GRADLE_USER_HOME
 +zipStorePath=wrapper/dists
 +</file>
 +
 +=== Аутентификация для gradlew ===
 +
 +<file yaml .gitlab-ci.yaml>
 +variables:
 +  GRADLE_OPTS: "-Dgradle.wrapperUser=$NEXUS_LOGIN -Dgradle.wrapperPassword=$NEXUS_PASSWORD"
 +
 +# Сборка на воркере
 +.build: &build
 +  - cd $CI_PROJECT_DIR
 +# Если нет в вышестоящих переменных
 +#  - export GRADLE_OPTS="-Dgradle.wrapperUser=$NEXUS_LOGIN -Dgradle.wrapperPassword=$NEXUS_PASSWORD"
 +  - cd test-module
 +  - chmod +x ./gradlew
 +  - >
 +    ./gradlew build
 +    -x test-metamodel:build
 +    -P gitLabPrivateToken=$REGISTRY_TOKEN
 +
 +# Сборка через ssh, нужно экранировать кавычки, иначе будет ошибка
 +# bash: line 0: export: `-Dgradle.wrapperPassword=[MASKED]': not a valid identifier
 +apiTests:
 +  stage: test
 +  script:
 +    - cd $CI_PROJECT_DIR
 +    - ssh dev-server
 +      "export "GRADLE_OPTS=\"$GRADLE_OPTS\"";
 +      cd /home/user/api-tests/test-module &&
 +      git init &&
 +      ./gradlew -x test clean build publishMavenPublicationToMavenLocal -P gitLabPrivateToken=$REGISTRY_TOKEN"
 +</file>
 +
 +В свойствах пишем URL без логина и пароля, они сами подхватятся из GRADLE_OPTS.
 +<file bash gradle/wrapper/gradle-wrapper.properties>
 +distributionUrl=http\://URL[:PORT]/repository/gradle/gradle-7.3.3-bin.zip
 +</file>
 +
 +https://docs.gradle.org/current/userguide/gradle_wrapper.html#customizing_wrapper\\
 +https://stackoverflow.com/a/69401685
 +
 +Для CI/CD. Дело в том, что при локальной сборке разработчиками у них нет данных для доступа в локальный репозиторий.\\
 +Это скрипт замены ссылки в файле ''/gradle/wrapper/gradle-wrapper.properties'', который меняет ссылку на локальную,\\
 +если в переменной ''GRADLE_OPTS'' есть значение ''wrapperUser''.
 +<code bash>
 +[[ $GRADLE_OPTS =~ wrapperUser ]] && \
 +sed -i 's#^\(distributionUrl=*\).*\/\(.*\)$#\1https\\://example.com/nexus/repository/gradle-zip/\2#' gradle/wrapper/gradle-wrapper.properties
 +# Было
 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
 +# Стало
 +distributionUrl=https\://example.com/nexus/repository/gradle-zip/gradle-7.3.3-bin.zip
 +</code>
 +
 +==== Python ====
 +Репозиторий pypi можно скачать curl-ом, а вот загружать им туда не получится, для этого нужен twine.\\
 +С иерархией каталогов, как в случае с maven, можно не заморачиваться и грузить все файлы в одну папку. При последующей выгрузке в nexus с помощью twine необходимая структура будет создана автоматически.
 +
 +Powershell
 +<code powershell>
 +$server = 'http://k3:8081'
 +$repo = 'pypi'
 +$cred = 'admin:admin'
 +$urls = "C:\temp\$repo.txt"
 +$dest = "C:\temp\$repo"
 +
 +mkdir $dest -ErrorAction SilentlyContinue > $null
 +$repoUrl = "$server/repository/$repo"
 +
 +# Make URLs list of packages
 +$packageList = curl.exe -ksu $cred "$repoUrl/simple/"
 +
 +$versionsList = ($packageList -match 'a href' -replace '<.*?>').trim() |% {
 +    (curl.exe -ksu $cred "$repoUrl/simple/$_/") -match 'a href'
 +}
 +
 +# Packages or not packages
 +# ($versionsList -replace '.*\.\./(.*)#.*','$1') -notmatch '^packages'
 +
 +$packages - $versionsList -replace '.*(packages.*)#.*','$1' -match '^packages/' # filter trash strings like <a href="../../../..">
 +# If list restriction is needed, e.g. low disk space
 +#$letters = ($([char[]](0..255) -match '[u-z]') |% {"packages/$_"}) -join '|'
 +if ($letters) {
 +    $packagesSelected = $packages -match "$letters"
 +}
 +else {
 +    $packagesSelected = $packages
 +}
 +
 +$packagesSelected |% {
 +    "$repoUrl/$_"
 +} > $urls
 +
 +# Download
 +gc $urls |% {
 +    echo $_
 +    curl.exe -ksu $cred -o "$dest\$($_ -replace '.*/')" $_
 +}
 +</code>
 +
 +https://help.sonatype.com/en/pypi-repositories.html\\
 +https://stackoverflow.com/questions/50348248/creating-a-full-replica-offline-copy-of-the-public-pypi-repository
 +
 +==== curl ====
 +Скачивание всего репозитория. В зависимости от типа репозитория (здесь пример для maven-репы), регулярку для sed надо корректировать.
 +<code bash>
 +server='http://k3:8081'
 +repo='repo'
 +cred='admin:admin'
 +urls='/tmp/repo_urls.txt'
 +
 +# Get assets list
 +assets="$server/service/rest/v1/assets?repository=$repo"
 +i=$(curl -ksu $cred -X GET $assets)
 +grep downloadUrl <<< $i |cut -d\" -f4 > $urls
 +token=$(grep continuationToken <<< $i |cut -d\" -f4)
 +while [[ -n $token ]]; do
 +  i=$(curl -ksu $cred -X GET "$assets&continuationToken=$token")
 +  grep downloadUrl <<< $i |cut -d\" -f4 >> $urls
 +  token=$(grep continuationToken <<< $i |cut -d\" -f4)
 +done
 +
 +# Create subdirs
 +mkdir -p $(sed -E "s#.*$repo/(.*)/.*#\1#" $urls |sort |uniq)
 +
 +# Download
 +for i in $(cat $urls); do
 +  echo $i
 +  curl -ksu $cred -o $(sed -E "s#.*$repo/##" <<< $i) $i
 +done
 +</code>
 +
 +<code bash>
 +# Примеры ссылок в $urls для репозитория Docker
 +# http://k3:8081/repository/docker/v2/-/blobs/sha256:31eec910d005bbfe2c5618507337f97c56a4f9fc0767bd314786d3406d06b5e1
 +# http://k3:8081/repository/docker/v2/repository/docker/maven/manifests/3.5.2
 +# Регулярки для sed
 +mkdir -p $(sed -E 's#.*v2/(-/)?(.*)/.*#\2#' $urls |sort |uniq)
 +curl -ksu $cred -o $(sed -E 's#.*v2/(-/)?##' <<< $i) $i
 +</code>
 +https://www.sonatype.com/blog/nexus-repository-new-beta-rest-api-for-content\\
 +https://stackoverflow.com/questions/68055906/how-can-i-get-components-in-repository-via-nexus3-api\\
 +https://help.sonatype.com/en/pagination.html\\
 +https://www.steventwheeler.com/java/2018/10/30/migrate-artifactory-to-nexus.html\\
 +https://github.com/LoadingByte/nexus3-exporter/tree/master\\
 +
 +==== Ansible ====
 +<code bash>
 +ansible k3 -m maven_artifact -a "
 +repository_url=http://k3.workgroup:8081/repository/maven-releases/
 +username=admin
 +password=admin
 +artifact_id=lunar-lang
 +group_id=org.foo
 +dest=/tmp/lunar-lang.jar"
 +</code>
 +
 +==== apt ====
 +Прокси-репа. На Нексусе надо сделать репозиторий apt (proxy), например, apt-ubuntu-jammy, и настроить его.
 +Удобно сделать анонимный доступ к серверу, в противном случае нужно будет настраивать аутентификацию на клиентах apt.
 +
 +^Параметр ^Значение ^Описание ^
 +|Distribution |jammy |Ubuntu 22.04 |
 +|Remote storage |http://mirror.yandex.ru/ubuntu/ |Удалённая репа |
 +
 +На клиентах прописать в ''/etc/apt/sources.list''
 +<code bash>
 +deb http://k3:8081/repository/apt-ubuntu-jammy/ jammy main
 +</code>
 +
 +https://help.sonatype.com/en/apt-repositories.html
 +
 +===== Поиск =====
 +<code bash>
 +# Артефакт lunar-lang, сортировать по версиям
 +curl -qu admin:admin 'http://k3.workgroup:8081/service/rest/v1/search/assets?maven.artifactId=lunar-lang&sort=version'
 +# Определённая версия
 +curl -qu admin:admin 'http://k3.workgroup:8081/service/rest/v1/search/assets?maven.artifactId=lunar-lang&version=1.0.0'
 +# В определённом репозитории
 +curl -qu admin:admin 'http://k3.workgroup:8081/service/rest/v1/search/assets?maven.artifactId=lunar-lang&repository=maven-releases&version=1.0.1'
 +</code>
 +https://help.sonatype.com/en/search-api.html
 +
 +Извлечение ссылок, Powershell
 +<code powershell>
 +($json |ConvertFrom-Json).items.downloadUrl
 +
 +# Вывод информации о найденных пакетах, сортировка по версиям
 +($json |ConvertFrom-Json).items.maven2 |sort {[version]$_.version}
 +
 +extension groupId artifactId version
 +--------- ------- ---------- -------
 +jar       org.foo lunar-lang 1.0.0  
 +jar       org.foo lunar-lang 1.0.1  
 +jar       org.foo lunar-lang 1.0.2  
 +jar       org.foo lunar-lang 1.0.3  
 +</code>
 +Bash
 +<code bash>
 +# jq -r - без кавычек
 +$json |jq .items[].downloadUrl
 +</code>
 +
 +==== Получить версию самой последней версии артефакта ====
 +Нужно, чтобы проставить версию в описании компонента при деплое. Надо парсить maven-metadata.xml
 +<code bash>
 +version=$(curl -qu admin:admin http://k3:8081/repository/maven-public/org/foo/lunar-lang/maven-metadata.xml |grep latest)
 +# В версиях встречаются цифры, точки и дефисы
 +sed 's#[^0-9.-]##g' <<< $version
 +1.0.12
 +</code>
 +
 +Это не всегда работает. Можно сначала запросить все версии (важно ''sort=version'' в запросе), а потом выбрать последнюю (первую в списке).
 +<code bash>
 +# curl
 +json=$(curl -qu admin:admin 'http://k3.workgroup:8081/service/rest/v1/search/assets?maven.artifactId=lunar-lang&maven.extension=jar&sort=version' |jq -r .items[0].maven2)
 +
 +jq -r .version <<< $json
 +</code>
 +
 +Ansible
 +<code yaml>
 +- name: Get artifact versions
 +  uri:
 +    url: http://k3.workgroup:8081/service/rest/v1/search/assets?maven.artifactId=lunar-lang&maven.extension=jar&sort=version
 +    user: admin
 +    password: admin
 +    method: GET
 +    force_basic_auth: true
 +    validate_certs: false
 +    body_format: json
 +  register: versions
 +
 +- name: Set variables
 +  set_fact:
 +    artifactId: "{{ versions['json']['items'][0]['maven2']['artifactId'] }}"
 +    extension: "{{ versions['json']['items'][0]['maven2']['extension'] }}"
 +    groupId: "{{ versions['json']['items'][0]['maven2']['groupId'] }}"
 +    version: "{{ versions['json']['items'][0]['maven2']['version'] }}"
 +
 +- name: Display variables
 +  debug:
 +    msg:
 +      - "{{ groupId }}"
 +      - "{{ artifactId }}.{{ extension }}"
 +      - "{{ version }}"
 +
 +# Как вариант - запрос json
 +# - debug:
 +#     msg: "{{ versions.json | json_query('items[0].maven2.version') }}"
 +</code>
 +https://www.reddit.com/r/ansible/comments/y7dh61/trying_to_create_a_variable_from_json/\\
 +
 +==== Список репозиториев ====
 +''ConvertFrom-Json'' с предыдущей командой надо заключать в скобки, иначе ''select'' не сработает.
 +<code bash>
 +(& curl.exe -ku admin:admin http://k3:8081/service/rest/v1/repositories |
 +ConvertFrom-Json) |select name,format,type,url |sort name
 +
 +name            format type   url                                      
 +----            ------ ----   ---                                      
 +docker          docker hosted http://k3:8081/repository/docker         
 +maven-central   maven2 proxy  http://k3:8081/repository/maven-central  
 +maven-public    maven2 group  http://k3:8081/repository/maven-public   
 +maven-releases  maven2 hosted http://k3:8081/repository/maven-releases 
 +maven-snapshots maven2 hosted http://k3:8081/repository/maven-snapshots
 +nuget.org-proxy nuget  proxy  http://k3:8081/repository/nuget.org-proxy
 +nuget-group     nuget  group  http://k3:8081/repository/nuget-group    
 +nuget-hosted    nuget  hosted http://k3:8081/repository/nuget-hosted   
 +pypi            pypi   group  http://k3:8081/repository/pypi           
 +pypi-lib        pypi   hosted http://k3:8081/repository/pypi-lib       
 +test            raw    hosted http://k3:8081/repository/test           
 +ubuntu2204      apt    proxy  http://k3:8081/repository/ubuntu2204     
 +ubuntu2204-sec  apt    proxy  http://k3:8081/repository/ubuntu2204-sec 
 +</code>
 +===== Удаление =====
 +<code powershell>
 +$apiUrl = 'http://k3:8081/service/rest/v1'
 +$cred = 'admin:admin'
 +(curl.exe -ksu $cred "$apiUrl/search/assets?repository=maven-public&version=1.0.?" |ConvertFrom-Json).items |% {
 +    curl.exe -ksu $cred -X DELETE "$apiUrl/assets/$($_.id)"
 +}
 +</code>
 +==== Docker ====
 +[[https://support.sonatype.com/hc/en-us/articles/360009696054-How-to-delete-docker-images-from-Nexus-Repository-3|How to delete docker images from Nexus Repository 3]]\\
 +
 +
 +===== Установка Nexus =====
 +
 +==== Docker ====
 +<file yaml docker-compose.yml>
 +services:
 +  nexus:
 +    image: sonatype/nexus3
 +    container_name: nexus
 +    restart: unless-stopped
 +    ports:
 +      - 8081:8081
 +    volumes:
 +      - ./nexus-data:/nexus-data
 +</file>
 +
 +<code bash>
 +# Узнать пароль админа после первоначальной установки
 +docker exec nexus cat /nexus-data/admin.password
 +</code>
 +
 +Пользователь id 200
 +<code bash>
 +docker run --rm -d --name nexus sonatype/nexus3
 +docker exec nexus grep nexus /etc/passwd
 +nexus:x:200:200:Nexus Repository Manager user:/opt/sonatype/nexus:/bin/false
 +</code>
 +
 +==== Gitlab Authentication Realm ====
 +
 +<code bash>
 +FROM sonatype/nexus3
 +USER root
 +
 +RUN mkdir -p /opt/sonatype/nexus/system/com/github/oassuncao/ && \
 +curl -Lo /opt/sonatype/nexus/system/com/github/oassuncao/nexus-gitlab-plugin-1.6.3.jar https://github.com/oassuncao/nexus-gitlab-plugin/releases/download/v1.6.3/nexus-gitlab-plugin-1.6.3.jar && \
 +echo "reference\:file\:com/github/oassuncao/nexus-gitlab-plugin-1.6.3.jar = 200" >> /opt/sonatype/nexus/etc/karaf/startup.properties
 +
 +USER nexus
 +
 +</code>
 +https://github.com/oassuncao/nexus-gitlab-plugin
 +
 +==== Миграция OrientDB > H2 ====
 +Nexus 3.70 - последняя версия, где поддерживается OrientDB. Чтобы обновить Nexus, нужно сконвертировать OrientDB в H2.
 +<code bash>
 +# Забэкапить базы из GUI, скопировать в папку backup.
 +# Остановить Nexus.
 +# Скачать мигратор
 +curl -L https://download.sonatype.com/nexus/nxrm3-migrator/nexus-db-migrator-3.70.1-03.jar -o backup/nexus-db-migrator.jar
 +# Запустить Nexus в командной строке
 +docker run -it --rm -v ./backup:/nexus-data -u root --entrypoint bash nexus
 +# В контейнере:
 +cd /nexus-data
 +java -Xmx16G -Xms1G -XX:+UseG1GC -XX:MaxDirectMemorySize=28672M -jar nexus-db-migrator.jar --migration_type=h2
 +# На хосте
 +cp backup/nexus.mv.db nexus-data/db/
 +echo "nexus.datastore.enabled=true" >> nexus-data/etc/nexus.properties
 +</code>
 +https://help.sonatype.com/en/migrating-to-a-new-database.html#migrating-from-orientdb-to-h2-162010\\
 +https://f3l1x-io.translate.goog/blog/2024/sonatype-nexus-repository-orientdb-a-h2?_x_tr_sl=auto&_x_tr_tl=ru&_x_tr_hl=ru&_x_tr_pto=wapp&_x_tr_hist=true
 +
 +==== SSL ====
 +Исходный сертификат с ключом должен быть в формате PCKS12.
 +<code bash>
 +# Если исходник в формате PEM, его надо сконвертировать
 +openssl pkcs12 -export -in cert.pem -out cert.pkcs12
 +
 +# Если исходник - это crt + key, то
 +openssl pkcs12 -export -in cert.crt -inkey private.key -out cert.pkcs12  
 +</code>
 +Если исходник в виде .pfx, то конвертировать ничего не надо.
 +
 +<code bash>
 +# Импортировать сертификат в хранилище ключей jks
 +# Важно: пароль оставить тем же, что и в сертификате
 +# Возможно, потребуется сначала создать каталог <nexus-install-location>/nexus-<version>/etc/ssl
 +keytool -v -importkeystore -srckeystore cert.pkcs12 -srcstoretype PKCS12 \
 +-destkeystore  <nexus-install-location>/nexus-<version>/etc/ssl/keystore.jks -deststoretype JKS
 +
 +nano <nexus-install-location>/sonatype-work/nexus3/etc/nexus.properties
 +# Добавить строку
 +application-port-ssl=443
 +# Раскомментировать строку с nexus-args и добавить туда
 +${jetty.etc}/jetty-https.xml
 +
 +nano <nexus-install-location>/nexus-<version>/etc/jetty/https-config.xml
 +# Заменить password на пароль сертификата (в 3 местах)
 +</code>
 +Перезапустить Nexus.
 +
 +https://www.coveros.com/ssl-on-nexus-3/
 +===== Дополнительно =====
 +==== Nexus как веб-сервер ====
 +Создаётся репозиторий hosted raw, и в его настройках нужно переключить Content Disposition на Inline, чтобы html-файлы отображались непосредственно в браузере, а не скачивались на диск.
 +
 +{{:service:pasted:20250306-071810.png}}
 +
 +
 +===== Проблемы =====
 +==== An error occured saving data. Duplicate key ====
 +Появляется при попытке загрузки после миграции БД с OrientDB на H2.
 +
 +предполагаемое решение: https://github.com/sonatype/nexus-public/issues/449
 +===== Литература =====
 +
 +[[https://help.sonatype.com/en/sonatype-nexus-repository.html|Документация]]\\
 +[[https://www.youtube.com/watch?v=6WU9nipfBGQ|Getting Started with Sonatype: The Best Way to Manage Your Java Releases]] (Daniel Persson on Youtube)
  

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki