NVIDIA DockerイメージのGPGキー更新に関する備忘録

R&D チームの徳田(@dakuton)です。
今年のGWあたりにCUDAのGPG更新アナウンス(NVIDIA Technical Blog: Updating the CUDA Linux GPG Repository Key)がありました。記載に従い利用環境の反映作業をしてみたところ、特にDockerイメージ向けの反映については記事に触れられていない範囲でのハマリポイントがいくつかあることがわかったため、対策についてまとめておきます。

参考(GitHub issue)

GPGキー更新アナウンスが出た背景

GPGキー(GNU Privacy Guardにて作成、リポジトリ管理者で共用する秘密鍵にて署名したIndexファイルを、利用者に配布する公開鍵にて検証させることで、配布元の正当性を確認できるようにするためのキー)に関するアップデートの目的

  1. 以前はCUDA以外の機械学習パッケージ(NVIDIA Machine Learning Repository: cuDNN, NCCL, TensorRTなど)を別リポジトリで配布していたが、CUDAリポジトリにこれらのパッケージが集約されたため、複数のリポジトリ(メンテナンス停止リポジトリ含む)で使いまわしている公開鍵を破棄したい
    • Solution: Remove the NVIDIA machine learning repository entry, as it is no longer updated. Newer versions of cuDNN, NCCL, and TensorRT are available in the CUDA repository.に関連
    • 詳細は本記事にて後述します
  2. CUDAで用いるGPGキーの公開鍵をパッケージ経由(cuda-keyring)で取得できるように対応
    • keyringの由来のとおり、複数の公開鍵が配布対象となる場合がありえます

注意したい点

特にDockerイメージにおいては、下記3点に注意してGPGキーを更新することが求められます。

  1. ベースイメージのビルドキャッシュ状況によって、ビルド成功可否が異なる
  2. ベースイメージの種類によって、新しいGPGキーへの移行状況が異なる
  3. ベースイメージに含まれるcuDNNバージョンによって、新しいGPGキーと古いGPGキーの併用が必要な場合がある

1. ベースイメージのビルドキャッシュ状況によって、ビルド成功可否が異なる

前回ビルド日が2022/04/27よりも前(GPGキー更新前のイメージ)の場合において、再ビルド時に過去のイメージキャッシュが利用されることで、新規ビルド環境とは異なりビルドエラーとならない場合があります。
この状態だと、今回のGPGキー更新影響を受けるベースイメージに依存しているか?が不明瞭なため、ローカルキャッシュを破棄した状態で各種パッケージのインストールが可能か?を確認するとよいでしょう。

$ docker run --pull=always nvidia/cuda:<tag> sh -c "\
 apt-get update && apt-get install -y --no-install-recommends <package>"

2. ベースイメージの種類によって、新しいGPGキーへの移行状況が異なる

NVIDIA Docker公式イメージ(nvidia/cudaのバージョンタグが付与されているもの)のなかでも、新しいGPGキーに更新されているものとそうでないものが混在しています。
おおまかな目安として、Docker Hubのnvidia/cuda/tagsにて最新push日が2022/04/27よりも過去のイメージは未移行と考えたほうがよいでしょう。

例えば、Ubuntu かつ CUDA 11 + cuDNN 8 系統のイメージ(name=11.0.3-cudnn8-devel-ubuntu)においては、OSバージョン間で下記のような差分があります。(2022/05/17時点)

  • Ubuntu 20.04, 16.04: GPGキー変更後のイメージがpush済み(ベースイメージを再度pullすることで解決可能)
  • Ubuntu 18.04: GPGキー未更新

また、GPG未更新イメージの場合、cuda-keyringパッケージをwget経由で更新する手順だと、下記のように該当するイメージにはwgetがインストールされていません。

# $distro/$arch = ubuntu1804/x86_64 の場合

$ docker run --pull=always nvidia/cuda:11.0.3-cudnn8-devel-ubuntu18.04 sh -c "\
 wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-keyring_1.0-1_all.deb"

11.0.3-cudnn8-devel-ubuntu18.04: Pulling from nvidia/cuda
sh: 1: wget: not found
# wgetをインストールするためのapt更新が失敗する(curlも同様)
$ docker run --pull=always nvidia/cuda:11.0.3-cudnn8-devel-ubuntu18.04 sh -c "\
 apt-get update && apt-get install -y --no-install-recommends wget"

Get:1 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64  InRelease [1581 B]
Err:1 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64  InRelease
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY A4B469963BF863CC
E: The repository 'https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64  InRelease' is not signed.

この場合は、GPG有効でないパッケージリポジトリを一時的に除外する(方式1)か、wgetを利用しない代替手段(方式2)を用いるとよいでしょう。

# $distro/$arch = ubuntu1804/x86_64 の場合

# 方式1(GPGが古いパッケージリポジトリ登録情報を除外してwgetインストール)
RUN rm -f /etc/apt/sources.list.d/cuda.list \
 && apt-get update && apt-get install -y --no-install-recommends \
    wget \
 && wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-keyring_1.0-1_all.deb \
 && dpkg -i cuda-keyring_1.0-1_all.deb \
 && rm -f cuda-keyring_1.0-1_all.deb
# 以降、wgetが不要であれば削除
# && apt-get purge --autoremove -y wget \
# && rm -rf /var/lib/apt/lists/*


# 方式2(Alternate method: Manually Install New Signing Key)
# ref. https://developer.nvidia.com/blog/updating-the-cuda-linux-gpg-repository-key/
RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub

3. ベースイメージに含まれるcuDNNバージョンによって、新しいGPGキーと古いGPGキーの併用が必要な場合がある

今回、NVIDIA Technical Blogにて案内のあった方法は、CUDAやcuDNNが比較的新しいバージョンにおける対応方法となります。
cuDNNなどの利用バージョンによっては別リポジトリ(NVIDIA Machine Learning Repository)のGPG更新状況を考慮する必要があります。
現在のリポジトリ登録状況や動作確認結果をもとにcuDNNバージョンごとの取得元をまとめると、下記のようになります。(cuDNN 8についてはパッチバージョンで若干差があるため、分けて記載しています)

cuDNNバージョン cuDNN取得リポジトリ 2022/04/27 GPG更新対象?
>=8.0.5 /compute/cuda/repos (CUDAと共通) yes
>=8.0.0, <8.0.5 /compute/machine-learning/repos no
<=7.x.x /compute/machine-learning/repos no

以前は/compute/cuda/repos, /compute/machine-learning/reposで同じGPGキーを利用していましたが、2022/04/27のアップデートにより前者のCUDA用GPGキーのみ更新されています。
cuDNN 7以前を利用するイメージでは、更新前のGPGキーが現在も利用されているため、NVIDIA Technical Blogの記載(Remove the outdated signing key)を参考にGPGキー登録を削除すると、下記のようにNVIDIA Machine Learning Repository側でGPGエラーとなります。

# cuda.listで利用していたGPGキーを削除した場合: nvidia-ml.listでGPG verifiedエラーとなる
$ docker run nvidia/cuda:10.2-cudnn7-devel-ubuntu18.04 sh -c "\
 rm -f /etc/apt/sources.list.d/cuda.list\
 && apt-key del 7fa2af80 \
 && apt-get update && apt-get --reinstall install -y --no-install-recommends wget"

OK
Ign:1 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  InRelease
Get:2 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release [564 B]
Get:3 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release.gpg [833 B]
Ign:3 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release.gpg
Get:4 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
︙
Reading package lists...
W: GPG error: https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY F60F4B3D7FA2AF80
E: The repository 'https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release' is not signed.

上記の回避方法としては、NVIDIA Developer Forums(Invalid public key for CUDA apt repository)などで示されているとおりです。

# cuda.list と nvidia-ml.list の両方を削除した場合: GPG verifiedエラーは発生しないが、libcudnn7再インストール失敗
$ docker run nvidia/cuda:10.2-cudnn7-devel-ubuntu18.04 sh -c "\
 rm -f /etc/apt/sources.list.d/cuda.list\
 && rm -f /etc/apt/sources.list.d/nvidia-ml.list\
 && apt-get update && apt-get --reinstall install -y --no-install-recommends libcudnn7"

Get:1 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]
︙
Reinstallation of libcudnn7 is not possible, it cannot be downloaded.
0 upgraded, 0 newly installed, 0 to remove and 10 not upgraded.
# cuda.list のみ削除、かつ古いGPGキーを残す場合: libcudnn7再インストール成功
$ docker run nvidia/cuda:10.2-cudnn7-devel-ubuntu18.04 sh -c "\
 rm -f /etc/apt/sources.list.d/cuda.list\
 && apt-get update && apt-get --reinstall install -y libcudnn7"

Ign:1 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  InRelease
Get:2 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release [564 B]
Get:3 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release.gpg [833 B]
Get:4 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Packages [73.8 kB]
Get:5 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 10 not upgraded.
Need to get 189 MB of archives.
After this operation, 0 B of additional disk space will be used.
Get:1 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  libcudnn7 7.6.5.32-1+cuda10.2 [189 MB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 189 MB in 3s (59.5 MB/s)
(Reading database ... 12313 files and directories currently installed.)
Preparing to unpack .../libcudnn7_7.6.5.32-1+cuda10.2_amd64.deb ...
Unpacking libcudnn7 (7.6.5.32-1+cuda10.2) over (7.6.5.32-1+cuda10.2) ...
Setting up libcudnn7 (7.6.5.32-1+cuda10.2) ...
Processing triggers for libc-bin (2.27-3ubuntu1.5) ...
# GPGキー更新済みベースイメージとの比較: libcudnn8再インストール成功
$ docker run nvidia/cuda:11.0.3-cudnn8-devel-ubuntu20.04 sh -c "\
 apt-get update && apt-get --reinstall install -y libcudnn8"

Get:1 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64  InRelease [1581 B]
Get:2 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64  Packages [540 kB]
Get:3 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB]2 upgraded, 0 newly installed, 0 to remove and 14 not upgraded.

Dockerfile追記方法(Debian, Ubuntu)

1,2,3を踏まえ、ローカルキャッシュ削除で対処できない場合のDockerfile追記方法をまとめておきます。(方式1,方式2についてはどちらでも可)
cuDNN 7までの環境のほうがDockerfile追記が必要なケースが多いです。CUDA 11+cuDNN 8の組み合わせのイメージについては、多くはローカルキャッシュ削除で対応可能(ベースイメージ最新版のpullでOK、Dockerfile追記不要)となるものの、一部イメージについては利用側でDockerfile追記が必要となるケースも残っています。
NVIDIA Machine Learning Repository なし版/あり版がどちらを使うとよいか?迷う場合は、リポジトリ登録情報を確認するとよいでしょう。

  • cuda.listのみ: NVIDIA Machine Learning Repository なし版
  • cuda.list,nvidia-ml.listどちらも含まれる: NVIDIA Machine Learning Repository あり版
# cuda.list のみ含まれるイメージ例
$ docker run nvidia/cuda:11.0.3-cudnn8-devel-ubuntu20.04 sh -c "\
 find /etc/apt/sources.list.d/ -type f | xargs -i sh -c 'echo path:{} && cat {}'"

path:/etc/apt/sources.list.d/cuda.list
deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64 /
# cuda.list と nvidia-ml.list どちらも含まれる例
$ docker run nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04 sh -c "\
 find /etc/apt/sources.list.d/ -type f | xargs -i sh -c 'echo path:{} && cat {}'"

path:/etc/apt/sources.list.d/nvidia-ml.list
deb https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 /
path:/etc/apt/sources.list.d/cuda.list
deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 /

NVIDIA Machine Learning Repository なし版(おもにcuDNN 8向け)

こちらのケースにおいては、古いGPGキーを残す必要はないため、NVIDIA Technical Blogの記載(Remove the outdated signing key)に従い削除しています。

# 方式1(GPGが古いパッケージリポジトリ登録情報を除外してwgetインストール)
RUN rm -f /etc/apt/sources.list.d/cuda.list \
 && apt-key del 7fa2af80 \
 && apt-get update && apt-get install -y --no-install-recommends \
    wget \
 && distro=$(. /usr/lib/os-release; echo $ID$VERSION_ID | tr -d ".") \
 && arch=$(/usr/bin/arch) \
 && wget https://developer.download.nvidia.com/compute/cuda/repos/$distro/$arch/cuda-keyring_1.0-1_all.deb \
 && dpkg -i cuda-keyring_1.0-1_all.deb \
 && rm -f cuda-keyring_1.0-1_all.deb
# 方式2(Alternate method: Manually Install New Signing Key)
RUN distro=$(. /usr/lib/os-release; echo $ID$VERSION_ID | tr -d ".") \
 && arch=$(/usr/bin/arch) \
 && apt-key del 7fa2af80 \
 && apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/$distro/$arch/3bf863cc.pub

NVIDIA Machine Learning Repository あり版(おもにcuDNN 7まで向け)

新旧2つのGPGキー併用が必要なケースです。

# 方式1(GPGが古いパッケージリポジトリ登録情報を除外してwgetインストール)
RUN rm -f /etc/apt/sources.list.d/cuda.list \
 && apt-get update && apt-get install -y --no-install-recommends \
    wget \
 && distro=$(. /usr/lib/os-release; echo $ID$VERSION_ID | tr -d ".") \
 && arch=$(/usr/bin/arch) \
 && wget https://developer.download.nvidia.com/compute/cuda/repos/$distro/$arch/cuda-keyring_1.0-1_all.deb \
 && dpkg -i cuda-keyring_1.0-1_all.deb \
 && rm -f cuda-keyring_1.0-1_all.deb
# 方式2(Alternate method: Manually Install New Signing Key)
RUN distro=$(. /usr/lib/os-release; echo $ID$VERSION_ID | tr -d ".") \
 && arch=$(/usr/bin/arch) \
 && apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/$distro/$arch/3bf863cc.pub \
 && apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/$distro/$arch/7fa2af80.pub

Dockerfile追記方法(Fedora, RHEL, openSUSE, SLES)

未検証(後日追記するかもしれません)

所感

しばらくはGPG key errorに関するissueの乱立が続くように思いました。

オプティムでは技術をいい感じに使ってデジタライゼーションに貢献できるエンジニアを募集しています。

www.optim.co.jp