Установка Sonatype Nexus в Ubuntu Linux, а также пример использования совместно с SBT

24 июня 2015

Одна из первых вещей, которой программисты учатся при погружении в мир Java — установка артефактов из Maven Central. Nexus является очень популярным менеджером репозиториев (repository manager) от компании Sonatype. Он позволяет поднимать такой маленький Maven Central внутри вашей компании. В этой заметке будет рассмотрена установка и настройка Nexus, а также хождение в него из SBT. Но сначала мы, конечно же, разберемся, зачем вообще это может быть кому-то нужно.

Зачем это нужно

Вот некоторые юзкейсы, которые приходят на ум:

  • Самое очевидное. У вас есть артефакты, которые хотелось бы шарить между командами и/или проектами, но эти артефакты не хочется выкладывать в открытый доступ;
  • Nexus можно поднять в локальной сети и настроить в качестве прокси для Maven Central. За счет этого не приходится «скачивать интернет», когда, например, в команду приходит новый человек или кто-то меняет компьютер. Все артефакты быстро сливаются из кэша в локалке;
  • Представьте, что у вашего провайдера что-то сломалось и вы сидите без интернета. В этом случае работа не встанет из-за недоступности артефактов, так как в локальной сети есть кэшик;
  • Допустим, что артефакт, от которого вы зависите, по каким-то причинам вдруг исчезнет из публичного репозитория. Ходят слухи, что иногда такое случается. Возможно, это будет не артефакт целиком, а только определенная его версия, неважно. Тогда вы сможете залить закэшированный в вашей файловой системе артефакт в локальный Nexus и продолжать работать, как ни в чем не бывало;
  • Некоторые артефакты бывают не залиты в Maven Central. Например, они могут просто лежать в виде исходников на каком-нибудь BitBucket. Опять таки, возможно, это не весь артефакт, а какая-то его development версия с очень важными для вас изменениями. Не нужно копировать исходники к себе в проект и пересобирать их после каждого clean. Или, затаив дыхание, ждать релиза. Просто соберите артефакт и залейте в Nexus;
  • Есть еще много вариаций на тему предыдущего случая. Например, библиотека может быть заброшена. Еще ее автор может очень долго рассматривать ваш pull request или вовсе отклонить его. Создаем форк, собираем, заливаем в Nexus;
  • Вообще, неплохой идеей является распиливание крупных проектов на маленькие артефакты и хранение их в Nexus. Как минимум, это может существенно ускорить сборку проекта. Кроме того, можно повторно использовать некоторые компоненты в разных системах. При этом может получиться, например, что Android-разработчик фактически пишет кусочек бэкенда, когда он коммитит в проект, который используется как на бэкенде, так и в мобильном приложении;
  • Вы хотите сделать некоторые артефакты общедоступными, но Maven Central по каким-то причинам не подходит. Возможно, ваши артефакты не принимают туда из-за лицензии. Или у вас очень много артефактов, а также большая команда разработчиков, которые, вообще говоря, могут приходить в компанию и уходить из нее. В таких случаях может иметь смысл поднять self hosted менеджер репозиториев;

Как по мне, причин более, чем достаточно, для того, чтобы держать Nexus в любой компании, где пишут под JVM. Даже если он будем пустым. Типа, про запас. Чтобы был, если вдруг понадобится. Ради экономии ресурсов Nexus можно поселить на билд сервер рядом с Jenkins.

Установка и базовая настройка

Все описанные ниже шаги были проверены в Ubuntu Linux 14.04 LTS, но, по идее, будут верны и для других версий Ubuntu, а также мало отличаться для других дистрибутивов Linux.

Готового deb-пакета с Nexus нет, но, к счастью, руками он устанавливается не сложно. На машине должна быть установлена виртуальная машина Java. Не так давно, в заметке, посвященной Cassandra, мы выясняли, как она ставится:

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer
sudo apt-get install oracle-java8-unlimited-jce-policy

Далее качаем архив с Nexus и распаковываем его в /usr/local:

wget http://www.sonatype.org/downloads/nexus-latest-bundle.tar.gz

С этого места — под root’ом:

cp nexus-latest-bundle.tar.gz /usr/local/
cd /usr/local/
tar -xvzf nexus-latest-bundle.tar.gz
ln -s nexus-2.11.3-01 nexus

Заводим нового пользователя и делаем его владельцем распакованных файлов:

adduser --disabled-password --disabled-login nexus
chown -R nexus:nexus ./nexus-2.11.3-01/
chown -R nexus:nexus ./sonatype-work/

Делаем так, чтобы Nexus запускался при старте системы:

cp nexus/bin/nexus /etc/init.d/nexus
chmod 755 /etc/init.d/nexus
chown root /etc/init.d/nexus
update-rc.d nexus defaults

В файле /etc/init.d/nexus кое-что нужно поправить:

NEXUS_HOME="/usr/local/nexus"
RUN_AS_USER="nexus"
PIDDIR="/usr/local/nexus/tmp"

Теперь уже под обычным пользователем:

sudo service nexus start
tail -f /usr/local/nexus/logs/wrapper.log

В браузере открываем http://nexus.example.ru:8081/nexus/ — здесь и далее предполагается, что машина называется nexus.example.ru. Справа вверху жмем Log in, вводим логин admin и пароль admin123. После входа справа вверху открываем Profile, меняем пароль. В Security → Users отключаем всех лишних пользователей, меняем email у админа. Там же можно завести пользователей с нужными правами, это не сложно.

Далее переходим к списку репозиториев:

Список репозиториев в Sonatype Nexus

Создаем новый hosted репозиторий, поля заполняем как-то так:

Создание нового hosted репозитория в Nexus

На этом настройку будем считать завершенной. При желании совсем несложно ограничить доступ к Nexus, воспользовавшись iptables, или поднять рядом Nginx с шифрованием трафика. Но эти вопросы мы ранее уже рассматривали, поэтому перейдем непосредственно к работе с репозиториями.

Сборка артефакта и его заливка вручную

Создаем новый Scala-проект, как мы это уже много раз делали, пишем код в таком стиле:

package me.eax.test

object TestPackage {
  def test() {
    println(s"Hello from test.package!")
  }
}

Говорим:

sbt package

В итоге получим файл target/scala-2.11/test-package_2.11-0.1.jar или вроде того. Заливаем артефакт в Nexus в последний созданный репозиторий через вкладку Artifact Upload. Указываем Group, Artifact, Version.

Заводим еще один проект, в коде пишем:

import me.eax.test._
 
object Example extends App {
  TestPackage.test()
}

В файл build.sbt дописываем:

credentials += Credentials(
  "Sonatype Nexus Repository Manager", // don't change!
  "nexus.example.ru",
  "user",
  "password")

resolvers += {
  "Nexus" at ("http://nexus.example.ru:8081/nexus/content/" +
              "repositories/test-repo/")
}

libraryDependencies ++= Seq(
  "me.eax" % "test-package" % "0.1"
)

Собираем, проверяем, что все работает.

Еще есть команды sbt package-doc и sbt package-src. Как можно без труда догадаться, они собирают jar’ники с документацией и исходниками.

Заливать артефакты вручную неудобно и чревато ошибками. Поэтому ниже будет показано, как автоматизировать заливку. Но сначала нам потребуются кое-какие дополнительные знания, которые проще всего получить, рассмотрев работу Nexus в качестве прокси.

Использование Nexus как прокси

Чтобы все артефакты качались через Nexus, создаем файл ~/.sbt/repositories такого содержания:

[repositories]
  local
  maven-proxy: http://nexus.example.ru:8081/.../repositories/central/

Приведенная выше ссылка не уместилась по ширине, но вы можете скопировать ее в списке репозиториев. Это репозиторий с именем Central.

Далее создаем ~/.sbt/0.13/plugins/nexus-example-ru.sbt:

credentials += Credentials(
  "Sonatype Nexus Repository Manager", // don't change!
  "nexus.example.ru",
  "user",
  "password")

Можете взять какой-нибудь из своих проектов, посмотреть на его зависимости, удалить пару соответствующих артефактов в каталоге ~/.ivy2/cache/ и затем сказать sbt compile. Если все было сделано правильно, вы увидите, что теперь артефакты тянутся через nexus.example.ru.

Автоматическая заливка

Возвращаемся к проекту test-package. Файл build.sbt редактируем как-то так:

name := "test-package"

organization := "me.eax"

version := "0.2"

scalaVersion := "2.11.6"

libraryDependencies ++= Seq()

publishTo := Some("Nexus" at "<длинная ссылка на test-repo>")

Если вы хотите заливать -SNAPSHOT и релизные версии артефакта в разные репозитории, тут написано, как это настроить.

Все credentials мы уже настроили на шаге про использование Nexus в роли прокси. Поэтому просто говорим sbt publish. Будет залит обычный jar’ник, а также javadoc и sources.

Во втором проекте, который зависит от test-package, изменяем build.sbt:

// кстати, credentials из файла можно уже убрать
// так как они теперь есть в ~/.sbt/0.13/plugins/

libraryDependencies ++= Seq(
  "me.eax" %% "test-package" % "0.2"
)

Обратите внимание, что теперь используется два знака процента, а не один. То есть, при заливке sbt автоматически указал имя артефакта test-package_2.11, как, собственно, и принято в мире Scala. Проверяем, что все собирается.

Также SBT поддерживает кросс-сборку. То есть, в одном проекте можно собирать артефакт для нескольких версий языка Scala. Например, чтобы артефакт собирался для Scala 2.10 и 2.11, в build.sbt нужно дописать:

crossScalaVersions := Seq("2.10.5", "2.11.6")

Тестирование, сборка и публикация всех версий артефакта:

sbt '+ test'
sbt '+ package'
sbt '+ publish'

Бывает так, что нужно использовать немного разные версии библиотек или флаги компилятора в зависимости от версии Scala. Это делается примерно так:

scalacOptions ++= {
  CrossVersion.partialVersion(scalaVersion.value) match {
    case Some((2, 11)) => Seq("-Ywarn-infer-any")
    case _ => Seq.empty
  }
}

Нужно отметить, что перед sbt publish не лишним будет делать sbt publish-local для «заливки» артефакта в кэш, протестировать, что все ОК, и только потом заливать артефакт в репозиторий.

Заключение

Немного ссылок по теме:

А куда вы заливаете артефакты?

Метки: , , , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.