aptlyによるnvidia dockerミラーリポジトリ構築

# はじめに
こんにちは。ちょっと秘密なデータを利用する機械学習や深層学習の開発環境を社内に構築する場合、インターネットにアクセスできない引き籠りなネットワーク上に構築することが求められたりします。技術的な理由ではなくて、社内規定や契約内容などの制限由来の要件ですね。このような場合には引き籠り環境内に独自のミラーリポジトリを持ち込むことになります。この記事では、そのような要件が求められたときにnvidia dockerのミラーリポジトリを独自に作ろうとそしてハマったので書き留めておきます。

* OSはUbuntu 20.04 Server
* 以下の三つのリポジトリをミラーしたサーバを構築
  * [nvidia docker]("https://nvidia.github.io/nvidia-docker/")
  * [libnvidia container]("https://nvidia.github.io/libnvidia-container/")
  * [nvidia container runtime]("https://nvidia.github.io/nvidia-container-runtime/")

# この記事のポイント
* apt-mirrorではミラー処理は完了しても、いざ利用しようとするとエラーが出る。ミラーサイトの検証で引っかかっているようだ。
* 代わりにaptlyを利用する。aptlyは自分でリポジトリサーバを公開する時に使うので、apt-mirrorよりも高機能でリポジトリ作成からスナップショット作成、公開という操作が必要になる。
* 自前のリポジトリサーバを作るので信頼性を保証するためにgpgキーを生成する等の操作が必要になるが、この時__gpg1__コマンドを利用する必要があった。

# 構築の方法
## 流れ
1. aptlyでミラーしたいリポジトリにあるパッケージを取得する。
1. ミラー元の公開鍵を使ってパッケージの正当性を検証する。
1. 独自のキーペアを使ってミラーしたパッケージの正当性を保証する。
1. 正当性を保証したパッケージと、利用する場合にその正当性を検証するのに用いる公開鍵をセットで配布する。

## 準備
まずは独自のキーペアを作成しておきます。aptlyはapt-mirrorやaptとは異なり/etc/apt以下のキーリングは使用しないようです。aptlyを起動するユーザの${HOME}/.gnupg以下を使用します。

```
$ gpg1 --gen-key
```

この鍵生成時にエントロピー不足で処理が進まない場合は管理者権限を用いて以下のパッケージを導入、実行することで解決します。

```
# apt install rng tools
# rngd -r /dev/urandom
```

次にNVIDIAの公開鍵をインポートしておきます。これは取ってきたパッケージの正当性を検証するのに必要です。

```
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | gpg1 --no-default-keyring --keyring trustedkeys.gpg --import
```

## ミラーリポジトリの作成
ではリポジトリを作成しましょう。

```
 $ aptly mirror create libnvidia-container https://nvidia.github.io/libnvidia-container/stable/ubuntu20.04/amd64 /
 $ aptly mirror create nvidia-container-runtime https://nvidia.github.io/nvidia-container-runtime/stable/ubuntu20.04/amd64 /
 $ aptly mirror create nvidia-docker https://nvidia.github.io/nvidia-docker/ubuntu20.04/amd64 /
```

### リポジトリデータの取得
NVIDIAからデータを取得してきます。

```
$ aptly mirror update libnvidia-container
$ aptly mirror update nvidia-container-runtime
$ aptly mirror update nvidia-docker
```

### リポジトリスナップショットの作成
\<yyyymmdd>の部分はいつ作成したスナップショットか分かるようにするために私が付けているものです。

```
$ aptly snapshot create libnvidia-container_<yyyymmdd> from mirror libnvidia-container
$ aptly snapshot create nvidia-container-runtime_<yyyymmdd> from mirror nvidia-container-runtime
$ aptly snapshot create nvidia-docker_<yyyymmdd> from mirror nvidia-docker
```

### スナップショットの公開
公開先のストレージに関する設定を${HOME}/.aptly.confに記述します。今回はローカルストレージ（/mnt/data/aptly）にデータを置いて公開します。rootDirの項目の所は環境に応じて書き換えて下さい。

```
{​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
  "rootDir": "${ホームディレクトリ}/.aptly",
  "downloadConcurrency": 4,
  "downloadSpeedLimit": 0,
  "architectures": [],
  "dependencyFollowSuggests": false,
  "dependencyFollowRecommends": false,
  "dependencyFollowAllVariants": false,
  "dependencyFollowSource": false,
  "dependencyVerboseResolve": false,
  "gpgDisableSign": false,
  "gpgDisableVerify": false,
  "gpgProvider": "gpg",
  "downloadSourcePackages": false,
  "skipLegacyPool": true,
  "ppaDistributorID": "ubuntu",
  "ppaCodename": "",
  "skipContentsPublishing": false,
  "FileSystemPublishEndpoints": {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
    "nvidia": {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
      "rootDir": "/mnt/data/aptly/nvidia.github.io",
      "linkMethod": "copy",
      "verifyMethod": "md5"
    }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
  }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​,
  "S3PublishEndpoints": {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​,
  "SwiftPublishEndpoints": {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
```

この設定内容を保存した上で、以下のコマンドを実行することでスナップショットを公開することができます。この時点で準備作業で作成したキーペアのうち秘密鍵を用いて各パッケージファイルに署名をすることができます。

```
 $ aptly publish snapshot -distribution=ubuntu20.04 libnvidia-container_<yyyymmdd> filesystem:nvidia:libnvidia-container
 $ aptly publish snapshot -distribution=ubuntu20.04 nvidia-container-runtime_<yyyymmdd> filesystem:nvidia:nvidia-container-runtime
 $ aptly publish snapshot -distribution=ubuntu20.04 -architectures=amd64 nvidia-docker_<yyyymmdd> filesystem:nvidia:nvidia-docker
```

### GPG公開鍵の設置
公開したスナップショットと一緒に準備作業で作成したキーペアのうち公開鍵を置いておきましょう。

```
$ cd /mnt/data/aptly/nvidia.github.io
$ gpg1 -a -o gpgkey --export <生成した鍵の名前>
```

あとは、nginx等で /mnt/data を公開しちゃえばOKです。

# ミラーリポジトリの利用
このようにして構築したミラーリポジトリを利用する場合には、上述の準備作業で作成したGPG公開鍵をインポートし明示的にリポジトリの場所を設定しておく必要があります。このセクションでは利用側のOS(Ubuntu 20.04)で行う作業を記述しておきます。

## GPG公開鍵をインポート
```
# curl -s -L http://<リポジトリサーバのIPアドレス>/nvidia.github.io/gpgkey | apt-key add -
```

### ミラーリポジトリの追加
/etc/sources.listに以下の記述を追加するか、/etc/apt/sources.list.d/nvidia-docker.listを新規に作成して記述します。

```
## Nvidia docker
deb http://<リポジトリサーバのIPアドレス>/aptly/nvidia.github.io/libnvidia-container/ ubuntu20.04 main
deb http://<リポジトリサーバのIPアドレス>/aptly/nvidia.github.io/nvidia-container-runtime/ ubuntu20.04 main
deb http://<リポジトリサーバのIPアドレス>/aptly/nvidia.github.io/nvidia-docker/ ubuntu20.04 main
```

## リポジトリ読込
これで準備は完了です。満を持してapt updateしてみましょう！

```
# apt update
```

コマンドが成功すれば完了です。