Nexus Repository Manager3 の Docker コンテナを HTTPS 化

Sonatype の[Nexus Repository Manager 3](https://www.sonatype.com/nexus-repository-oss)はMaven/yum/Python/Ruby/Dockerなどのローカルリポジトリ・キャッシュリポジトリとしてはたらくサーバーソフトウェア。

1. [Nexus Repository Manager 3の公式サイト](https://www.sonatype.com/nexus-repository-oss)
1. [Nexus Repository Manager 3のドキュメント](https://help.sonatype.com/repomanager3)
1. [DockerHub上のコンテナ](https://hub.docker.com/r/sonatype/nexus3/)

DockerHub のコンテナをただ動かす場合には 3. 番目のサイトの情報に従いコマンドを打つだけでよい。コンテナの 8081 番のポートで HTTP を待ち受けているので、これをホスト側にマッピングする。

```
# docker run --name nexus -d -p 8081:8081 sonatype/nexus3
```

この HTTP ポート1つの状態でも、Maven/yum/Python/Ruby などのローカルリポジトリは作成できる。
しかし Docker のプライベートリポジトリを作るには HTTPS 化が必要になるので、いろいろ段取りがややこしくなる。手順が Sonatype 社のブログ記事([Using a Dockerized Nexus as a Docker Registry](https://blog.sonatype.com/maxences-technical-corner))で公開されているので、これを参考にして実験してみる。
なおホスト側には Java がインストール済みとする。

まず Nexus コンテナ内ではプロセスが UID 200 番で動作し、主要なデータが `/nexus-data` に記録されている。HTTPS 化のためにはこの `/nexus-data` 内のファイルを編集可能なように、ホスト側のディレクトリ(`/var/opt/nexus`とする)にマッピングする。また 8081 番以外にいくつかマッピング用のポートを予約しておく。

```
# mkdir /var/opt/nexus/
# chown -R 200 /var/opt/nexus/
# docker run --name nexus -d -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8084:8084 -v /var/opt/nexus:/nexus-data sonatype/nexus3
```

コンテナを起動すると、ファイルが見えるようになる。

```
$ ls -laF /var/opt/nexus
drwxr-xr-x.  16  200 root  248 Dec  2 00:09 ./
drwxr-xr-x.   4 root root   33 Dec  1 23:54 ../
drwxr-xr-x.   3  200  200   21 Dec  2 00:09 blobs/
drwxr-xr-x. 276  200  200 8192 Dec  2 00:08 cache/
drwxr-xr-x.   9  200  200  160 Dec  2 00:09 db/
drwxr-xr-x.   3  200  200   19 Dec  2 00:09 elasticsearch/
drwxr-xr-x.   3  200  200   45 Dec  2 00:08 etc/
drwxr-xr-x.   2  200  200    6 Dec  2 00:08 generated-bundles/
drwxr-xr-x.   2  200  200   33 Dec  2 00:08 instances/
drwxr-xr-x.   3  200  200   19 Dec  2 00:08 javaprefs/
drwxr-xr-x.   2  200  200    6 Dec  2 00:08 kar/
drwxr-xr-x.   3  200  200   18 Dec  2 00:09 keystores/
-rw-r--r--.   1  200  200   14 Dec  2 00:08 lock
drwxr-xr-x.   2  200  200   74 Dec  2 00:09 log/
drwxr-xr-x.   2  200  200    6 Dec  2 00:09 orient/
-rw-r--r--.   1  200  200    5 Dec  2 00:08 port
drwxr-xr-x.   2  200  200    6 Dec  2 00:09 restore-from-backup/
drwxr-xr-x.   7  200  200 4096 Dec  2 00:09 tmp/
```

HTTPS 化のために `/var/opt/nexus/keystores` の下に移動し、Java に付属する keytool を使い鍵と証明書を作成する。`changebit` がパスワードになる。
Nexus を動作させるサーバーの DNS 名が host.example.com で IP アドレスが 10.20.230.17 だとすると、以下のように keystore.jks を作成した。

```
$ cd /var/opt/nexus/keystores
$ keytool
    -genkeypair
    -keystore keystore.jks
    -storepass changebit
    -keypass changebit
    -alias jetty
    -keyalg RSA
    -keysize 2048
    -validity 5000
    -dname "CN=*.host.example.com, OU=Unspecified, O=Unspecified, L=Unspecified, ST=Unspecified, C=JP"
    -ext "SAN=DNS:host.example.com,IP:10.20.230.17"
    -ext "BC=ca:true"
```

Nexus は Java Servlet コンテナ/Web サーバである Jetty で動作しており、HTTPS 化は Jetty の設定ファイルである jetty-https.xml の変更が必要になる。
しかしコンテナのデータ置き場である `/nexus-data` には jetty-https.xml が含まれていない。コンテナの中に手を突っ込んで引きづり出すことになる。

まず jetty-https.xml を配置するディレクトリを作成する。

```
# mkdir /var/opt/nexus/etc/jetty
# chown 200 /var/opt/nexus/etc/jetty
```

次にコンテナで bash コマンドを実行し、内部にある jetty-https.xml を先ほどのディレクトリにコピーする。

```
# docker exec -it nexus bash
bash-4.2$ cp /opt/sonatype/nexus/etc/jetty/jetty-https.xml /nexus-data/etc/jetty/
bash-4.2$ exit
```

取り出した jetty-https.xml をホスト側で変更する。

- keytool で入力したパスワードを設定
- "ssl.etc" を指定した Property 要素を削除する。

```diff
   <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
-    <Set name="KeyStorePath"><Property name="ssl.etc"/>/keystore.jks</Set>
-    <Set name="KeyStorePassword">password</Set>
-    <Set name="KeyManagerPassword">password</Set>
-    <Set name="TrustStorePath"><Property name="ssl.etc"/>/keystore.jks</Set>
-    <Set name="TrustStorePassword">password</Set>
+    <Set name="KeyStorePath">/nexus-data/keystores/keystore.jks</Set>
+    <Set name="KeyStorePassword">changebit</Set>
+    <Set name="KeyManagerPassword">changebit</Set>
+    <Set name="TrustStorePath">/nexus-data/keystores/keystore.jks</Set>
+    <Set name="TrustStorePassword">changebit</Set>
     <Set name="EndpointIdentificationAlgorithm"></Set>
     <Set name="NeedClientAuth"><Property name="jetty.ssl.needClientAuth" default="false"/></Set>
```

次に `/var/opt/nexus/etc/nexus.properties` を修正し、jetty-https.xml を追加するとともに HTTPS のポート番号を指定する。今回は 8082 番とする。

```diff

  # application-port=8081
+ application-port-ssl=8082
  # application-host=0.0.0.0
  # nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-requestlog.xml
+ nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-requestlog.xml,/nexus-data/etc/jetty/jetty-https.xml
  # nexus-context-path=/${NEXUS_CONTEXT}
```

設定変更はこれで終わり。
Docker を起動する。

```
# docker stop nexus
# docker start nexus
```

自己証明書を使ったが 8082 番にアクセスすると HTTPS で Nexus3 にアクセスが可能になった。

Docker のプライベートリポジトリの作成は次回に。