LoginSignup
7
3

More than 3 years have passed since last update.

Nexus Repository Manager 3のDocker Registryを試す

Last updated at Posted at 2019-07-08

タグ付に困る製品名。何かに使うようなので調べてます。

tl;dr

  • Nexus Repository Manager 3が提供するDocker Registry機能のhosted,proxy,groupの動作を試した
  • 現時点(2019/07/08)でregistry-mirrorsとしての利用が出来ていない

中身が薄いので画像入れてごまかしてます。

特徴

Nexus Repository Manager 3は、パッケージの提供場所となるリポジトリを扱うソフトウェア。キャッシュとして使ったり、プライベートに使ったり。
プラグインで扱えるリポジトリを増やすことも出来る。一覧はDocumentで。アンオフィシャルだけどCPANもある(Perl好き)

今回の目標

こんな感じの構成を組む。表現力の乏しさが垣間見えるポンチ絵がこちらです。

ポンチ絵.png

この構成にすることで以下が実現できる(はず)

  • Hostedリポジトリ
    • ローカルでイメージを管理したい
  • Proxyリポジトリ
    • プロキシとしてアクセスを集約したい
    • Docker Hubさんへの通信負荷を減らしたい、Pullを早くしたい
  • Groupリポジトリ
    • 独自イメージやDocker Hubイメージを意識せずに扱いたい(※今回出来てません)

頑張りましょう。

導入

以下を読みながら進めている。

導入する環境はメモリ4GBのCentOS 7.5なLinux環境。

Java Runtime Environmentの導入

# JREの導入
sudo yum install -y java-1.8.0-openjdk.x86_64

# 確認
java -version

nexusユーザ作成

sudo useradd nexus -s /sbin/nologin

Nexus Repository Manager 3のインストール

curl -LO https://download.sonatype.com/nexus/3/latest-unix.tar.gz
tar xzvf latest-unix.tar.gz

NEXUS_DIR_NAME=$(ls | grep "^nexus-3" | tail -n 1)

sudo mv "$NEXUS_DIR_NAME" /opt
sudo ln -ns "$NEXUS_DIR_NAME" /opt/nexus-3
sudo chown -R nexus:nexus /opt/nexus-3*
sudo chmod -R go-rw /opt/nexus-3*

作業ディレクトリの確保

Nexus Repository Manager 3は相対ディレクトリ../sonatype-workを参照しようとするので、ここにディレクトリを作っておく

sudo mkdir /opt/sonatype-work
sudo chown nexus:nexus /opt/sonatype-work
sudo chmod -R go-rw /opt/sonatype-work

サービス登録


sudo tee /etc/systemd/system/nexus.service << 'EOF'

[Unit]
Description=nexus service
After=network.target

[Service]
Type=forking
LimitNOFILE=65536
ExecStart=/opt/nexus-3/bin/nexus start
ExecStop=/opt/nexus-3/bin/nexus stop
User=nexus
Restart=on-abort

[Install]
WantedBy=multi-user.target
EOF

# systemdファイル読み込み
sudo systemctl daemon-reload

# 自動起動設定 & 起動
sudo systemctl enable nexus.service
sudo systemctl start nexus.service

# 起動確認
systemctl status nexus.service

ブラウザでhttp://localhost:8081へアクセスできることを確認する。(リモートサーバ上ならSSHで繋いでポートフォワーディングなどする)

Nexus Repository Manager 3の設定(主にDocker Registry)

adminユーザのログイン

Nexus Repository Manager 3を起動するとadminのパスワードが以下に記録されるので確認する

sudo -u nexus cat /opt/sonatype-work/nexus3/admin.password

ブラウザの右上のSigninからアクセスして、ユーザ名にadmin、パスワードに上記のコマンドで確認したパスワードを入力する。その後、パスワードリセットを促されるので適宜行う。

image.png

匿名のアクセスを受け付けるようにするかどうかだが、今回は無効にしておく。

Nexus Repository Manager 3上にDockerのリポジトリを作成する

ここでいう「リポジトリ」はNexus Repository Manager 3の用語。

  • proxy: その名の通りプロキシするリポジトリ。プロキシ先にDocker Hubを指定すれば、Docker Hubのイメージを取ってきて、溜め込むことが出来る。
  • hosted: 自前イメージを置いておくリポジトリ。Pushする先。
  • group: 上記を統合したリポジトリを提供できる。Hostedリポジトリにあるプライベートなイメージと。ProxyリポジトリにあるDocker Hubのイメージを一緒に扱えるようになる。

また、pushするときはhosted、pull等をするときはgroupを使う。groupにpushしてもエラーになるので注意。
というわけで、使うときはhostedとgroupのために2ポート開ける必要がある。

StorageはDefault(ローカルディスク)があるので、今回はそれを使う。

HostedなDockerリポジトリを作成

Repository →Repositoriesから作成する。

  • docker (hosted)を選ぶ
  • HTTPSを有効にして5001を指定する
  • Enable Docker V1 APIを有効にする(手元のdockerクライアントがV1で投げるようなので。)

image.png

ProxyなDockerリポジトリを作成

  • docker (Proxy)を選ぶ
  • Enable Docker V1 APIを有効にする
  • Remote Storageにhttps://registry-1.docker.ioを指定
  • Docker Indexに Use Docker Hub を指定

image.png

image.png

GroupなDockerリポジトリを作成

  • docker (Group)を選ぶ
  • HTTPSを有効にして5000を指定する
  • Enable Docker V1 APIを有効にする
  • Member repositoriesへ先ほど作成したリポジトリをMembersに追加する

image.png

image.png

自己署名証明書によるSSL対応

今回はローカルのみの動作で良いものとして自己署名証明書を使う。以下の記事を参考に構築してた

keystoreの場所は/opt/nexus-3/etc/jetty/jetty-https.xmlに記述されている位置を参照する。デフォルトで<install-dir>/etc/ssl/keystore.jksを参照する。しかし、アップデート時に再設定が面倒になりそうなので別の場所に配置する。

keystoreのパスワードはすべてpasswordにしている。もし変更する場合は、/opt/nexus-3/etc/jetty/jetty-https.xmlの修正も必要なので注意。

# keystoreを作成する先のpath
KEYSTORE_PATH=/opt/sonatype-work/nexus3/etc/ssl/keystore.jks

# ドメイン
NEXUS_DOMAIN=$(hostname)

# keystoreを保存するディレクトリを作成
sudo -u nexus mkdir -p "$(dirname $KEYSTORE_PATH)"

# keystoreを作成
sudo -u nexus keytool -genkeypair -keystore "$KEYSTORE_PATH" -storepass password -keypass password -alias jetty -keyalg RSA -keysize 2048 -validity 3650 -deststoretype pkcs12 -dname "CN=*.${NEXUS_DOMAIN}, OU=Example, O=Sonatype, L=Unspecified, ST=Unspecified, C=US" -ext "SAN=DNS:${NEXUS_DOMAIN},DNS:localhost" -ext "BC=ca:true"
sudo chmod 0600 "$KEYSTORE_PATH"

# keystoreを確認
sudo -u nexus keytool -v -list -keystore "$KEYSTORE_PATH" -storepass password

設定でkeystoreの配置を変え、HTTPS接続を有効化する。

sudo -u nexus tee -a /opt/sonatype-work/nexus3/etc/nexus.properties << 'EOF'

# keystore等のパスを変更
ssl.etc = /opt/sonatype-work/nexus3/etc/ssl
# `${jetty.etc}/jetty-https.xml` を追加し、HTTPSをサポートさせる
nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-https.xml,${jetty.etc}/jetty-requestlog.xml
# (おまけ)HTTPSで管理画面にアクセスできるようにする
application-port-ssl = 8443
EOF

再起動

sudo systemctl restart nexus

再起動してからListenするまで時間がかかるのでしばらく待つ。

最後にdockerの信頼できる証明書として登録・更新

keytool -printcert -sslserver ${NEXUS_DOMAIN}:5000 -rfc | sudo tee /etc/pki/ca-trust/source/anchors/${NEXUS_DOMAIN}.crt
keytool -printcert -sslserver localhost:5000 -rfc | sudo tee /etc/pki/ca-trust/source/anchors/localhost.crt
sudo update-ca-trust

registry-mirrorの設定(※2019/07/08時点では機能しない)

Dockerデーモンの設定を変更し、イメージをプライベートレジストリから返すようにする。

しかし、Docker側のバグがあり期待通りに機能しない。理由は後ろの方に書いた

sudo tee /etc/docker/daemon.json << EOF
{
  "registry-mirrors": ["https://${NEXUS_DOMAIN}:5000"]
}
EOF

# デーモン再起動して設定読み直し
sudo systemctl restart docker

動作確認

  • hostedの動作をpushできることで確認する
  • groupとproxyの動作をpull、run、searchを用いて行う

プライベートレジストリを経由してイメージをpullしてrun。

mkdir sample
cd sample
echo 'console.log("Hello World")' > app.js

# プライベートレジストリへログイン(とりあえずadminで繋がる、Userを作りRoleを与えればそのユーザで繋がる)
sudo docker login localhost:5000

sudo docker run -v $(pwd):/tmp localhost:5000/node:10 node /tmp/app.js

次にDockerfileからイメージを作成し、それをプライベートレジストリにPush。

cat << 'EOF' > Dockerfile
from localhost:5000/node:10
COPY app.js /tmp/app.js
EOF

sudo docker build -t  fukasawah/fukasawah-node-hello:1 .

# イメージを試す(イメージにapp.jsが含まれているのでマウント無しで使える)
sudo docker run fukasawah/fukasawah-node-hello:1 node /tmp/app.js

イメージが問題ないようなのでHostedリポジトリ(ポート番号:5001)へPushする。

# タグをPush用に複製する
sudo docker tag fukasawah/fukasawah-node-hello:1 localhost:5001/fukasawah-node-hello:1
# プライベートレジストリへログイン(とりあえずadminで繋がる)
sudo docker login localhost:5001
# イメージをPushする
sudo docker push localhost:5001/fukasawah-node-hello:1

PushしたイメージをGroupリポジトリ(ポート番号:5000)経由で取得して実行(Hostedではないことに注意)

sudo docker run -v $(pwd):/tmp localhost:5000/fukasawah-node-hello:1 node /tmp/app.js

プライベートレジストリを使い、nodeに関するイメージを検索。

# docker-hub上にあるイメージをプロキシリポジトリを介して検索
sudo docker search localhost:5000/node

# pushしたイメージを検索
sudo docker search localhost:5000/fukasawah-node-hello

# Hostedリポジトリからnodeを検索
sudo docker search localhost:5001/node

お試し計測

一番気になってたregistry-mirrorとして使ったときのPullにかかる時間の改善具合を見たかった。
しかし、registry-mirrorが機能しなかったし、明示的に指定してPullしてもあまり効果なかった。


そして環境が貧弱で真の結果ではない気がするので伏せておく。興味があれば開いてお読みください。
  • Azure VM DS1v2を2台用意
    • docker registry
    • docker daemon + docker client (操作側)
  • ディスクは Standard HDD (これが良くない)
  • 対象は「node:10(プライベートレジストリ未使用)」「$NEXUS_DOMAIN:5000/node:10(プライベートレジストリ利用)」
    • registry-mirrorは諸事情で機能しなかったので。

前準備

NEXUS_DOMAIN=foo.example

# 自己署名証明書を信頼する
openssl s_client -showcerts -connect ${NEXUS_DOMAIN}:5000 < /dev/null | awk "/BEGIN CERTIFICATE/,/END CERTIFICATE/" | sudo tee /etc/pki/ca-trust/source/anchors/${NEXUS_DOMAIN}.crt
sudo update-ca-trust

# ログイン
sudo docker login "${NEXUS_DOMAIN}:5000"

# registry-mirrorを有効
sudo tee /etc/docker/daemon.json << EOF
{
  "registry-mirrors": ["https://${NEXUS_DOMAIN}:5000"]
}
EOF

# registry-mirrorを無効
sudo tee /etc/docker/daemon.json << EOF
{
}
EOF

sudo systemctl restart docker 

# docker infoを見ると、Registry Mirrosの項目が追加される
sudo docker info

1回測る毎に以下を実行

# 情報でRegistry Mirrorsの情報を確認する
sudo docker info | grep -A5 "Registry Mirrors"

# イメージを全て削除したりゴミを削除したり
sudo docker images -q | sudo xargs docker rmi -f
sudo docker system prune

# 実行
time sudo docker pull node:10
# or
time sudo docker pull $NEXUS_DOMAIN:5000/node:10
Mirror有 Mirror無
1回目 1:22.09 1:17.36
2回目 1:18.53 1:18.10
3回目 1:15.62 1:18.22

(単位は 分:秒.ミリ秒)

うーん、誤差ですね。展開に時間がかかりすぎている。
ダウンロード自体はどちらも10秒ぐらいで終わるが、その後の展開に70秒以上かかっているという感じ(Standard HDDのせいだと思う)

感想

自己証明書のSSL対応しようとしたり、ベンチマーク取ろうとしたり、実はまだregistry-mirrorが使えなかったり、Anonymouseも試したけどようわからん、という感じで無駄に時間がかかってしまった。
意外とLinux上でごにょごにょとやってしまったのでDockerで1発で動かせるようにした方が良さそう。

ボタンポチポチでリポジトリが立ち上がるのでお手軽感はある。Mavenやnpmのリポジトリを使うとなっても、ある程度は操作が一緒なので、同じ感覚で建てられて良さそう。(実際に運用できるかは自信がない)

registry-mirrorが使えれば・・・という感じ。

遭遇したエラー

先にDockerの環境を。ちょっと古いが、CentOS 7の安定板がこれらしい。

$ sudo docker version
Client:
 Version:      17.05.0-ce
 API version:  1.29
 Go version:   go1.7.5
 Git commit:   89658be
 Built:        Thu May  4 22:06:25 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.05.0-ce
 API version:  1.29 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   89658be
 Built:        Thu May  4 22:06:25 2017
 OS/Arch:      linux/amd64
 Experimental: false

HostedリポジトリへPushしてエラー

以下のような感じ。

# sudo docker push localhost:5000/fukasawah-node-hello:1
The push refers to a repository [localhost:5000/fukasawah-node-hello]
ea53379b117c: Layer already exists
954f92adc866: Layer already exists
adca1e83b51a: Layer already exists
73982c948de0: Layer already exists
84d0c4b192e8: Layer already exists
a637c551a0da: Layer already exists
2c8d31157b81: Layer already exists
7b76d801397d: Layer already exists
f32868cde90b: Layer already exists
0db06dff9d9a: Layer already exists
error parsing HTTP 404 response body: invalid character  '<' looking for beginning of value: 

Push先を間違えているかもしれない。ちゃんとHostedなDockerのRepositoryのポートになっているかどうか確認する。これで4時間溶かした

再起動時にCould not configure HTTPS connector on port (ポート番号) for docker repository (リポジトリ名)のログが出てHTTPS接続できない

DockerのHTTPSコネクタを有効にした後に出た。

/opt/sonatype-work/nexus3/log/nexus.log
2019-07-07 19:20:44,714+0000 WARN  [FelixStartLevel]  *SYSTEM org.sonatype.nexus.repository.docker.internal.DockerConnectorFacetImpl - Could not configure HTTPS connector on port 5000 for docker repository docker
org.sonatype.nexus.bootstrap.jetty.UnsupportedHttpSchemeException: Unsupported HTTP Scheme: https
        at org.sonatype.nexus.internal.jetty.ConnectorRegistrarImpl.validate(ConnectorRegistrarImpl.java:128)
        at org.sonatype.nexus.internal.jetty.ConnectorRegistrarImpl.addConnector(ConnectorRegistrarImpl.java:84)
        at org.sonatype.nexus.repository.docker.internal.DockerConnectorFacetImpl.doStart(DockerConnectorFacetImpl.java:121)
        at org.sonatype.nexus.repository.FacetSupport.start(FacetSupport.java:156)
        at org.sonatype.nexus.repository.docker.internal.DockerConnectorFacetImpl$$EnhancerByGuice$$613f4292.CGLIB$start$20(<generated>)
        at org.sonatype.nexus.repository.docker.internal.DockerConnectorFacetImpl$$EnhancerByGuice$$613f4292$$FastClassByGuice$$c00a5460.invoke(<generated>)

原因はjettyがhttpsの設定ファイルを読みこんでおらず、Keystoreを認識できていなかった。デフォルトでは読んでくれない。

なのでプロパティで読むようにする必要があった。以下のファイルを以下のように変更

/opt/sonatype-work/nexus3/etc/nexus.properties

# ${jetty.etc}/jetty-https.xml を追加している
nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-https.xml,${jetty.etc}/jetty-requestlog.xml

registry-mirrorsが機能しない

これに関するIssueが上がっていた。見た感じ同じ現象に見える。

registry-mirrorsは設定しておくと、docker pull node:10とすれば、registry-mirrorsにあるレジストリから取得を試みる、というのが期待する動きなのだが認証の問題でそうならない。

以下、そのときのdockerデーモンのログ。プライベートレジストリにアクセスしたが認証失敗し、Docker Hubの方を見に行ってしまっている。

Jul  8 19:03:52 localhost dockerd: time="2019-07-08T08:03:52.920737964Z" level=debug msg="Trying to pull node from https://remote-addrss:5000/ v2"
Jul  8 19:03:52 localhost dockerd: time="2019-07-08T08:03:52.965148289Z" level=debug msg="Increasing token expiration to: 60 seconds"
Jul  8 19:03:53 localhost dockerd: time="2019-07-08T08:03:53.002164344Z" level=info msg="Attempting next endpoint for pull after error: unauthorized: access to the requested resource is not authorized"
Jul  8 19:03:53 localhost dockerd: time="2019-07-08T08:03:53.002212643Z" level=debug msg="Trying to pull node from https://registry-1.docker.io v2"
Jul  8 19:03:55 localhost dockerd: time="2019-07-08T08:03:55.126096378Z" level=debug msg="Pulling ref from V2 registry: node:10"

この時、認証情報は使っていないのではなく、docker hubにログインしたときの認証情報を使っているらしい。
実際にdocker hubに登録したID/Passwordを使って、Nexus上のユーザを作成し適切にRoleを割り当てたら、一応registory-mirrorとして機能した。しかしnexusのログレベルをDebugにするとログにパスワードが平文で流れていくので、おとなしく修正を待った方が良さそう。

後は、Issueにも書いてありますが、前段にNginx等のリバースプロキシを置いて、認証情報をNginx側で上書きして、Dockerデーモンからは認証関係なくアクセスできるようにする、という手法もあるみたい。Nginxにアクセスできる人は誰でも使えるようになってしまいますが、プライベートレジストリなのでそんなに問題はない気がする。

これがうまく扱えないと魅力が9割減だと思うので、改善されると良いなー。

不明点

  • イメージの管理方法に何かあるか(ブラックリスト、ホワイトリスト方式とか)
  • 古くなったイメージの更新をやってくれるのか(腐ったイメージを使うのは避けたい)
  • キャッシュ用途の場合、ディスクの空き容量が心配(いい感じに古いのは削除してくれるのかどうか)
  • 冗長構成 (High Availability)
  • 他の機能
    • Blob Storage(他のバックエンド、増設など)
    • Routing Rules
    • Cleanup Policies
    • Content Selectors
    • Task
    • Anonymous認証
    • LDAP連携
    • IQ Server連携
    • Webhooks
    • Rest API
7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3