Windows Server ContainerなDockerのイメージをNexus 3.xに作ったプライベートリポジトリに入れておく

追記: 現在では、より直接的な、"allow-nondistributable-artifacts"を使える: http://www.sonatype.org/nexus/2017/11/28/setting-up-sonatype-nexus-3-as-your-windows-docker-container-registry/ ( https://github.com/docker/docker-ce/commit/8fabd69470bfcba5445665b203af29224eb2df5d )
(タイトル長いな...)

Windows Server 2016 / Windows 10からWindowsネイティブのコンテナがDockerで作成できるようになった。ただ大体のWindowsソフトは再配布ができないためプライベートリポジトリに入れておくことが望ましいがこれがなかなか難しい。

  • Windows固有では無い点
    • プライベートリポジトリとしてはNexus3がたぶん一番簡単に構築できる
    • Dockerは基本的にSSL必須なので適当に署名したSSL証明書を用意する必要がある
  • Windows固有
    • デフォルトではMS公式イメージはアップロードできないためイメージの巻き直しが必要

Nexus3のインストールと設定

Dockerのリポジトリを実現する環境は公式のものを含めいくつか選択肢が有るが、Windows上ではSonatypeのNexus3が一番簡単に構築できると思う。Nexus3はJavaで実装されており、Windows版バイナリ配布も有る。

基本的にはドキュメントの通りに配置すれば良い。

  1. .zipを展開し、bin/nexus.vmoptionsを編集してデータディレクトリの場所を指定する
  2. データディレクトリのetc/nexus.propertiesを編集してポート番号等を指定

設定を終えたら"nexus.exe /run"で起動できる。

Nexus3にSSL証明書を設定する

blog記事( https://support.sonatype.com/hc/en-us/articles/217542177 )の通りにやれば良いが、Windowsの場合は証明書マネージャを使用して証明書を組込む必要がある。

  • 証明書の生成
"c:\Program Files (x86)\Java\jre1.8.0_121\bin\keytool.exe" -genkeypair -keystore keystore.jks
 -storepass pass00 -keypass pass00 -alias jetty -keyalg RSA -keysize 2048 -validity 5000
 -dname "CN=*.stripe.local OU=nexus3 O=stripe" -ext "SAN=DNS:stripe.local" -ext "BC=ca:true"

(jre1.8.0_121は適当なJREのインストールのパスに替える必要がある)
ここではstripe.localがNexus3を起動するサーバのアドレスということになる。Windows10以降はmDNSによる名前解決が使えるため、コンピュータ名さえ設定してあれば直ぐに使用できるのが便利。
証明書を生成したら記事やドキュメントの通りにデータディレクトリのetc/nexus.propertiesを編集し、SSLを有効にしてNexus3を再起動する。

  • .cerの生成と組込み
"c:\Program Files (x86)\Java\jre1.8.0_121\bin\keytool.exe" -printcert -sslserver stripe.local:8443 -rfc > out.cer

keystoreから直接証明書データを得るより、接続してしまった方が簡単なので-sslserverオプションを使う。ここでは、Nexus3をstripe.local:8443に起動している。
out.cerをDockerを使うWindowsサーバにコピーしてダブルクリックし、証明書を"信頼されたルート証明機関"に組込む。

Nexus3にDockerのプライベートリポジトリを作る

Nexusリポジトリにいくつかの種類があるが、通常のプライベートリポジトリは"hosted"に分類される。

Dockerのリモートプロトコルリポジトリ名に2段以上のパスを含められないという酷ぇ仕様になっているため、リポジトリには専用のHTTPサーバインスタンスを割り当てられるようになっている。HTTPSを適当なポートに立て、Dockerのタグ名としてはそちらのポートを使用する。

Windowsイメージの巻き直し

MSがDocker Hubで配布しているWindowsのコンテナイメージはDocker HubのMSのリポジトリからのダウンロードを強制するように設定されている。この規制はライセンス上の都合( https://github.com/docker/docker/issues/27580#issuecomment-261258874 )で、このイメージを含むコンテナイメージを(Docker Hub以外の)プライベートリポジトリに送信すると

"Skipped foreign layer"と表示された後にエラーで失敗してしまう。
EULA的にはプライベートリポジトリ内での配布自体は特に問題無いため、イメージの"巻き直し"を行ってforeign属性を外すことでプライベートリポジトリに含めることができる。

  1. Dockerは普通に導入する https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/quick_start/quick_start_windows_server
  2. docker pull microsoft/windowsservercore してServer Coreイメージを取得
  3. docker save microsoft/windowsservercore -o score.tar してイメージを保存
  4. ここでdocker rmiを使用して全イメージを削除する -- これをやらないとlayer情報がキャッシュされたままになり属性の削除が反映されない
  5. saveコマンドで作成したscore.tarを展開し、manifest.jsonからLayerSources値を全て削除する
  6. 改変したmanifest.jsonを含めて.tarを作成しなおしdocker loadでロードする
  7. 適当にタグを打ってDockerfileから使う

LayerSourcesを削除した.jsonは次のような内容になる:

[{"Config":"4d83c32ad497f063ae77377afb9285ed3f8a2d2dc52eb53268a7152777b25add.json",
"RepoTags":["wins:import"],"Layers":["e1b1db55a3c19a5e4a13ec189f9327aaedc4b2a0b9282422dab1dc3ec73b030f\\layer.tar",
"1e49c27c5a0fe5187d41446870fa34fc3e8f0fb86d9783b5ab804c622d5f7dd8\\layer.tar"]}]

Foreign属性は実装されてから日が浅く、単にNexus3では未実装のようだ。そう遠くないうちにこのような巻き直しを行わなくてもアップロードができるようになると思われるが(上記のIssueではforce uploadオプションの検討が示唆されている)、実際のところ世間ではプライベートリポジトリ + Dockerはどのくらい運用されているんだろうか。。ちゃんとみんなDockerHubを契約している?