オフライン環境構築 Nexus Repository3編

[オフライン環境構築 目次へ](https://qiita.com/kannkyo/items/1e5f8362ed591ebda33d)

# 概要

## はじめに
オフライン環境でフロントエンド及びバックエンド（java）開発用のリポジトリを構築する手順を示す。

## リポジトリマネージャの選定

オフラインリポジトリを構成するツール（以降、リポジトリマネージャ）として著名なものはSonatype Nexus、Apache Archiva、JFrog Artifactoryの3つがある。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Google トレンドで「Apache Archiva, sonatype nexus, jfrog artifactory - すべての国、過去 12 か月間」の 人気度の動向 を見る - <a href="https://t.co/3bb4CxYQZR">https://t.co/3bb4CxYQZR</a></p>&mdash; kannkyo (@kannkyoshi) <a href="https://twitter.com/kannkyoshi/status/965062752187252736?ref_src=twsrc%5Etfw">2018年2月18日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

以下の比較を見ると、このうちOSS版でフロントエンド開発に対応しているものはNexus3だけであることがわかる。

> [アーティファクトリポジトリマネージャの比較 Nexus/Archiva/Artifactory](https://qiita.com/shrkw/items/fbd0aeb3bcaf4dd006ba)

そこで、リポジトリマネージャとしてNexus3を選択する。以下のパッケージマネージャに対応する。

* npm
* bower
* maven2
* docker
* pypi

# 全体像
Nexus3 のリポジトリは３種類ある。

* 単体でリポジトリを構成するhostedリポジトリ。
* 別のリポジトリへアクセスを中継するproxyリポジトリ。なお、proxyリポジトリは中継する際に自動的に別のリポジトリから取得したアーティファクトを自身に保存する。
* hostedとproxyを集約するgroupリポジトリ。

本手順では各パッケージマネージャに対して以下作業を実施する。

* 5種類のリポジトリを構築
* proxyリポジトリを経由してウェブ上のOSSのアーティファクトを取得

<!--
* 自作したアーティファクトをhostedリポジトリに格納
-->

# 準備
ブラウザでNexus3を表示する。ＵＲＬは http://localhost/nexus/ である。

![screenshot.1.png](https://qiita-image-store.s3.amazonaws.com/0/114392/e2a16c75-11d4-5541-e983-587cc358e76d.png)

Nexus3にアドミニ権限でログインする。初期設定ではユーザ名は`admin`でパスワードは`admin123`である。

![screenshot.2.png](https://qiita-image-store.s3.amazonaws.com/0/114392/4bbead40-cf4e-b696-a225-2f1729d853b0.png)

左上の歯車形のアイコンをクリックして、`Administration`メニューを表示する。

![screenshot.3.png](https://qiita-image-store.s3.amazonaws.com/0/114392/bf6e00e7-7d06-e7d6-2cd6-48493983eae0.png)

左側のツリーから`Repository > Repositories`をクリックする。

![screenshot.4.png](https://qiita-image-store.s3.amazonaws.com/0/114392/ca103ec4-bb03-6825-4266-2fc5e2b4e3bc.png)

この画面から各パッケージマネージャ毎の手順を実施する。

# bower
## リポジトリ構築
### hostedリポジトリ
以下の設定でリポジトリを新規作成する。

* Name: bower-hosted

![screenshot.5.png](https://qiita-image-store.s3.amazonaws.com/0/114392/5b3b94f5-5e28-1822-8f31-0d4fb9da76a4.png)

### proxyリポジトリ
以下の設定でリポジトリを新規作成する。

* Name: bower-proxy
* Remote storage: https://registry.bower.io

![screenshot.16.png](https://qiita-image-store.s3.amazonaws.com/0/114392/68cc7ee8-1f82-c651-79d0-fc2a1bb03607.png)

![screenshot.17.png](https://qiita-image-store.s3.amazonaws.com/0/114392/7ba33590-d962-38d8-634e-be6c607edb22.png)

### groupリポジトリ
以下の設定でリポジトリを新規作成する。

* Name: bower-group
* Members:
    * bower-hosted
    * bower-proxy

![screenshot.18.png](https://qiita-image-store.s3.amazonaws.com/0/114392/92545886-f309-74c3-1c29-a6ee88b2d91c.png)

## パッケージ取得
Nexus3でbowerを使うためのリゾルバをインストールする。

```bash:リゾルバインストール
sudo npm install -g bower-nexus3-resolver
```

任意のディレクトリに以下の２つのファイルを作成する。

```json:.bowerrc
{
  "registry" : {
    "search" : [ "http://localhost/nexus/repository/bower-group" ]
   },
  "resolvers" : [ "bower-nexus3-resolver" ]
}
```

```json:bower.json
{
  "name": "bower",
  "description": "for Nexus3",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {}
}
```

インターネット上のリポジトリから必要なパッケージをNexus3のproxy経由で取得する。proxy経由で取得することで、ダウンロードするとともに自動的にNexus3に保存される。

以下のコマンドを上記2ファイルを格納したディレクトリで実行する。

```bash:ダウンロードスクリプト
bower install --save <パッケージ名>
```

上記コマンドを実行した結果、パッケージが保存される。

![screenshot.25.png](https://qiita-image-store.s3.amazonaws.com/0/114392/3a74c5aa-b554-b7fa-b57c-d72d4b583338.png)

# maven2
## リポジトリ構築
### hostedリポジトリ
以下の設定でリポジトリを新規作成する。

* Name: maven2-hosted

![screenshot.8.png](https://qiita-image-store.s3.amazonaws.com/0/114392/01015845-d8c0-f094-5e6b-ec6fe73f230b.png)

### proxyリポジトリ
以下の設定でリポジトリを新規作成する。

* Name: maven2-proxy
* Remote storage: https://repo1.maven.org/maven2/

![screenshot.26.png](https://qiita-image-store.s3.amazonaws.com/0/114392/a05f88b6-49d8-9179-1558-4d4f9207b005.png)

![screenshot.27.png](https://qiita-image-store.s3.amazonaws.com/0/114392/4139a74b-2892-e414-6556-c40633f8104d.png)

### groupリポジトリ
以下の設定でリポジトリを新規作成する。

* Name: maven2-group
* Members: maven2-hosted maven2-proxy

![screenshot.28.png](https://qiita-image-store.s3.amazonaws.com/0/114392/7e289ced-959e-00b7-b516-cb327aba0644.png)

## パッケージ取得
eclipseでmavenプロジェクトを作成する。

mavenプロジェクト選択
![Screenshot from 2018-02-22 06-09-50.png](https://qiita-image-store.s3.amazonaws.com/0/114392/a0b0b1dd-0237-ec6b-3b5f-560d0011b0b2.png)

プロジェクト基本設定

* groupId: nexus
* artifactId: maven2

![Screenshot from 2018-02-22 06-11-52.png](https://qiita-image-store.s3.amazonaws.com/0/114392/1a69624a-aee4-fb34-4693-51564abc403c.png)

pom.xmlファイルを編集。たとえばJUnitのパッケージを取得したい場合は以下のように書く。

```xml:pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>nexus</groupId>
	<artifactId>maven2</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
	</dependencies>

	<repositories>
		<repository>
			<id>maven-group</id>
			<name>My Maven Group Repository</name>
			<url>http://localhost/nexus/repository/maven2-group/</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
	</repositories>

	<pluginRepositories>
		<pluginRepository>
			<id>maven-group</id>
			<name>My Maven Group Repository</name>
			<url>http://localhost/nexus/repository/maven2-group/</url>
		</pluginRepository>
	</pluginRepositories>

	<distributionManagement>
		<repository>
			<id>maven2-private</id>
			<name>My Maven Hosted Repository</name>
			<url>http://localhost/nexus/repository/maven2-hosted/</url>
		</repository>
	</distributionManagement>
</project>
```

mavenはすでに取得済みのパッケージはWeb上からダウンロードしないため、パッケージがproxyリポジトリに保存されない。そこで、強制的にweb上からパッケージを再取得させるため、`~/.m2`フォルダを削除する。

削除対象ディレクトリ
![Screenshot from 2018-02-23 07-26-10.png](https://qiita-image-store.s3.amazonaws.com/0/114392/10234c50-ff4e-cda4-deaa-c0492fd5886b.png)

`maven > Update project...`を選択して、表示された`Update Maven Project`ウィンドウでOK。

Update Maven Project
![Screenshot from 2018-02-23 07-07-38.png](https://qiita-image-store.s3.amazonaws.com/0/114392/011d7367-f837-c5dd-6a9a-08636b09d50b.png)

上記コマンドを実行した結果、パッケージが保存される。

![Screenshot from 2018-02-23 07-35-17.png](https://qiita-image-store.s3.amazonaws.com/0/114392/6dbb6a34-fd4d-5414-dce7-c65b3bb97e8f.png)

# npm
## リポジトリ構築
### hostedリポジトリ
以下の設定でリポジトリを新規作成する。

* Name: npm-hosted

![screenshot.9.png](https://qiita-image-store.s3.amazonaws.com/0/114392/4694fd4a-ddfa-7e45-da9f-e466e4f73473.png)

### proxyリポジトリ
以下の設定でリポジトリを新規作成する。

* Name: npm-proxy
* Remote storage: https://registry.npmjs.org

![screenshot.13.png](https://qiita-image-store.s3.amazonaws.com/0/114392/de890093-734a-4564-c6fd-e45cd687160c.png)

![screenshot.14.png](https://qiita-image-store.s3.amazonaws.com/0/114392/45416fc4-a709-cfd7-28e7-b73f51a12891.png)

### groupリポジトリ
以下の設定でリポジトリを新規作成する。

* Name: npm-group
* Members:
    * npm-hosted
    * npm-proxy

![screenshot.15.png](https://qiita-image-store.s3.amazonaws.com/0/114392/d271369f-dcc2-33d6-468a-a67e6348f8ef.png)

## パッケージ取得
任意のディレクトリに以下の２つのファイルを作成する。

```text:.npmrc
email=foo@example.com
always-auth=true
_auth=YWRtaW46YWRtaW4xMjM=

registry=http://localhost/nexus/repository/npm-group/
```

```json:package.json
{
  "name": "npm-hosted",
  "version": "1.0.0",
  "description": "for nexus3",
  "dependencies": {
  }
}
```

ここで、`.npmrc`の`_auth`の値は以下の方法で生成した認証情報である。

```bash:入力
echo -n 'admin:admin123' | openssl base64
```

```text:出力
YWRtaW46YWRtaW4xMjM=
```

インターネット上のリポジトリから必要なパッケージをNexus3のproxyリポジトリ経由で取得する。proxyリポジトリ経由で取得することで、ダウンロードするとともに自動的にNexus3に保存される。

以下のコマンドを上記2ファイルを格納したディレクトリで実行する。

```bash:ダウンロードスクリプト
npm install --save <パッケージ名>
```

上記コマンドを実行した結果、パッケージが保存される。

![screenshot.24.png](https://qiita-image-store.s3.amazonaws.com/0/114392/0eb32ea9-3379-08f6-6afa-4615874dfebb.png)

## 自作パッケージの登録


```json:package.json
{
  "name": "npm-hosted",
  "version": "1.0.0",
  "description": "for nexus3",
  "dependencies": {
  },
  "publishConfig": {
    "registry": "http://localhost/nexus/repository/npm-hosted/"
  }
}
```

# docker
## リポジトリ構築
### hostedリポジトリ
以下の設定でリポジトリを新規作成した。

* Name: docker-hosted
* Repository Connectors/HTTP:48083
* Force basic authentication : true
* Enable Docker V1 API: true

![screenshot.6.png](https://qiita-image-store.s3.amazonaws.com/0/114392/2c847552-871c-798a-874c-af6d4b3de37c.png)

![screenshot.7.png](https://qiita-image-store.s3.amazonaws.com/0/114392/007279ce-883e-23dd-7b45-8b336cca3a5c.png)

### proxyリポジトリ
以下の設定でリポジトリを新規作成した。

* Name: docker-proxy
* Repository Connectors/HTTP:48082
* Force basic authentication : true
* Enable Docker V1 API: true
* Remote storage: https://registry-1.docker.io
* Docker Index: Use Docker Hub

![screenshot.19.png](https://qiita-image-store.s3.amazonaws.com/0/114392/6368beea-d4d2-1d2d-88f9-c4a661de71f9.png)

![screenshot.20.png](https://qiita-image-store.s3.amazonaws.com/0/114392/a839fcb7-c367-7c80-8c0d-b523e5c287b0.png)

![screenshot.21.png](https://qiita-image-store.s3.amazonaws.com/0/114392/f46b7bf7-6da9-3219-5fbf-3113701d71fb.png)

### groupリポジトリ
以下の設定でリポジトリを新規作成した。

* Name: docker-group
* Force basic authentication : true
* Enable Docker V1 API: true
* Members:
    * docker-hosted
    * docker-proxy

![screenshot.22.png](https://qiita-image-store.s3.amazonaws.com/0/114392/7bc4cbf4-9a23-f850-3629-6df6c423f2a2.png)

![screenshot.23.png](https://qiita-image-store.s3.amazonaws.com/0/114392/41424279-929e-2281-182b-0b6d647e0fbe.png)

## パッケージ取得
### ログイン

任意のディレクトリで以下のコマンドを実行する。

```bash:入力
docker login localhost:48082
```

コマンドを実行すると、Username/Passwordを聞かれるので、admin/admin123を入力する。

```text:出力
Username: admin
Password: 
WARNING! Your password will be stored unencrypted in /home/hogehoge/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
```

### プル

一度プルしてローカルに保存し、その後イメージを削除する。
以下のコマンドを実行する。

```bash:入力
docker pull localhost:48082/jenkins
docker rmi localhost:48082/jenkins
```

すると、プルと削除に成功したログが出力される。

```text:出力
Using default tag: latest
latest: Pulling from jenkins
Digest: sha256:0de43cde2c4b864a8e4a84bbd9958e47c5d851319f118203303d040b0a74f159
Status: Downloaded newer image for localhost:48082/jenkins:latest
Untagged: localhost:48082/jenkins:latest
Untagged: localhost:48082/jenkins@sha256:0de43cde2c4b864a8e4a84bbd9958e47c5d851319f118203303d040b0a74f159
```


# pypi
## リポジトリ構築
### hostedリポジトリ
以下の設定でリポジトリを新規作成した。

* Name: pypi-hosted

### proxyリポジトリ
以下の設定でリポジトリを新規作成した。

* Name: pypi-proxy
* Remote storage: https://pypi.org/

### groupリポジトリ
以下の設定でリポジトリを新規作成した。

* Name: pypi-group
* Members:
    * pypi-hosted
    * pypi-proxy

## パッケージ取得
### ログイン

任意のディレクトリで以下のコマンドを実行する。

```bash:入力
sudo pip install --index-url http://localhost/nexus/repository/pypi-group/simple piplint
sudo pip uninstall piplint -y
```

コマンドを実行すると、Username/Passwordを聞かれるので、admin/admin123を入力する。

```text:出力
sudo pip install --index-url http://localhost/nexus/repository/pypi-group/simple piplint
The directory '/home/jinn/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/home/jinn/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Looking in indexes: http://localhost/nexus/repository/pypi-group/simple
Collecting piplint
  Downloading http://localhost/nexus/repository/pypi-group/packages/a2/19/606766036576aecff058b79fcf0a9f4361940d66429070ef89fcad0e099a/piplint-0.2.0.tar.gz
Installing collected packages: piplint
  Running setup.py install for piplint ... done
Successfully installed piplint-0.2.0
sudo pip uninstall piplint -y
The directory '/home/jinn/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Uninstalling piplint-0.2.0:
  Successfully uninstalled piplint-0.2.0
```


# 参考資料

* [Sonatype Nexus 3を使用して、PrivateなMavenリポジトリ、npm Registry、Docker Registryを構築する](http://d.hatena.ne.jp/Kazuhira/20170109/1483972099)
* [Sonatype Help - Bower Repositories](https://help.sonatype.com/display/NXRM3/Bower+Repositories)
* [Sonatype Help - Maven Repositories](https://help.sonatype.com/display/NXRM3/Maven+Repositories)
* [Sonatype Help - Private Registry for Docker](https://help.sonatype.com/display/NXRM3/Private+Registry+for+Docker)
* [Sonatype Help - Node Packaged Modules and npm Registries](https://help.sonatype.com/display/NXRM3/Node+Packaged+Modules+and+npm+Registries)