目的
NVIDIA GPU による高速なハードウェアエンコードを Docker コンテナで動かしたい。
前提条件
- Docker コンテナで NVIDIA GPU を使用するには、ホストマシンに NVIDIA GPU が搭載されている必要がある。
- 今回はホストマシンとして NVIDIA Tesla M60 を搭載した Amazon EC2 G3 インスタンス を使用した。
- ホスト OS は Amazon Linux 2 を選択、NVIDIA GPU のドライバは執筆当時の最新版を使用した。
ホストマシンの準備
まずは Docker コンテナを動作させるホストマシンとなる Amazon EC2 インスタンスを用意する。
-
Amazon EC2 G3 インスタンスを起動
- AMI (Amazon Machine Image) は Amazon Linux 2 AMI
ami-0a2de1c3b415889d2
を選択 - インスタンスタイプは G3 インスタンスの中では比較的安価な
g3.4xlarge
やg3s.xlarge
を推奨 - EBS ルートボリュームは 8 GB だと空き容量が不足する可能性があるため注意
- AMI (Amazon Machine Image) は Amazon Linux 2 AMI
-
起動した EC2 インスタンスに SSH 接続
-
最初にタイムゾーンを設定
sudo timedatectl set-timezone Asia/Tokyo
-
Docker のインストール
Amazon Linux 2 では Extras Library を使用することで Docker を簡単にインストールすることができる。sudo amazon-linux-extras install docker
-
NVIDIA Graphics Driver のインストール
最新のドライバは https://www.nvidia.com/Download/index.aspx で Tesla M60 を検索することで取得可能。
なお、NVIDIA Graphics Driver の使用には NVIDIA Software License Agreement への同意が必要である。sudo yum install gcc kernel-devel-$(uname -r) wget http://us.download.nvidia.com/tesla/410.72/NVIDIA-Linux-x86_64-410.72.run sudo bash NVIDIA-Linux-x86_64-410.72.run --ui=none --no-questions --accept-license
-
nvidia-docker2
のインストール
nvidia-docker2 は Docker コンテナで NVIDIA GPU を使用するために必要なランタイムである。distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | sudo tee /etc/yum.repos.d/nvidia-docker.repo sudo yum install nvidia-docker2
-
Docker コンテナの起動確認
先にインストールしたランタイムを指定してnvidia/cuda
コンテナを起動する。
コンテナ内部で実行するnvidia-smi
は NVIDIA GPU の情報を取得するためのコマンドである。sudo systemctl start docker sudo docker run --runtime=nvidia nvidia/cuda nvidia-smi
以下のように NVIDIA GPU の情報が表示されれば成功。
+-----------------------------------------------------------------------------+ | NVIDIA-SMI 410.72 Driver Version: 410.72 CUDA Version: 10.0 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 Tesla M60 Off | 00000000:00:1E.0 Off | N/A | | N/A 29C P0 40W / 150W | 0MiB / 7618MiB | 97% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+
FFmpeg のビルド
次に Docker コンテナで動かす FFmpeg のビルドを行う。ビルドも Docker コンテナ内部で行う。
-
作業用コンテナの起動
nvidia/cuda:10.0-devel-centos7
コンテナを起動しシェルに接続する。sudo docker run --runtime=nvidia -it nvidia/cuda:10.0-devel-centos7 /bin/bash
-
必要なパッケージのインストール
yum install autoconf bzip2 git make
-
nasm
のインストールcurl -fsSLO https://www.nasm.us/pub/nasm/releasebuilds/2.14/nasm-2.14.tar.bz2 tar xjvf nasm-2.14.tar.bz2 cd nasm-2.14 ./autogen.sh ./configure make -j$(nproc) make install
-
ffnvcodec
のインストール
FFmpeg 4.0 以降 NVIDIA Video Codec SDK のヘッダファイルが FFmpeg 本体に付属されなくなった。git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers cd nv-codec-headers make install
-
FFmpeg 本体のビルド
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig curl -fsSLO https://ffmpeg.org/releases/ffmpeg-4.1.tar.bz2 tar xjvf ffmpeg-4.1.tar.bz2 cd ffmpeg-4.1 ./configure --enable-nvenc make -j$(nproc) make install
ハードウェアエンコードの実行
ビルドした FFmpeg を使ってハードウェアエンコードを行う。エンコードはより軽量な新しいコンテナで行う。
-
エンコード実行用コンテナの起動
環境変数NVIDIA_DRIVER_CAPABILITIES=video
を設定することで、ホストマシンにインストールされた NVIDIA GPU ドライバを構成するライブラリのうち NVENC に関連するものをコンテナ内部から使用できるようになる。
nvidia/cuda:10.0-runtime
イメージはnvidia/cuda:10.0-devel
に比べて含まれるライブラリの種類が少ない代わりにイメージサイズが小さい。ビルド済みの CUDA アプリケーションを実行する場合はこちらを使用する。sudo docker run --runtime=nvidia -it -e 'NVIDIA_DRIVER_CAPABILITIES=video' nvidia/cuda:10.0-runtime-centos7 /bin/bash
-
前節でビルドした FFmpeg 本体
/usr/local/bin/ffmpeg
を新しいコンテナにもコピーする。
いったんコンテナからexit
してからdocker cp
コマンドによりコンテナ内部のファイルを操作できる。sudo docker cp <source-container-id>:/usr/local/bin/ffmpeg <target-container-id>:/usr/local/bin/ffmpeg
-
FFmpeg コマンドの実行
再び新しいコンテナにdocker attach
してから、適当な動画ファイル input.mp4 を用意する。
これに対し NVENC によるハードウェアエンコードを行うには、以下のffmpeg
コマンドを実行する。/usr/local/bin/ffmpeg -i input.mp4 -vcodec h264_nvenc -acodec aac output.mp4
Docker コンテナイメージの作成
NVENC に対応した FFmpeg が最初から使用可能な新しい Docker コンテナイメージ example/nvenc
を作成する。完成したコンテナイメージを Docker Hub に公開すれば、誰でも docker pull
できるようになる。
-
Dockerfile の作成
Dockerfile はコンテナイメージのレシピを記述したものである。
以下の内容をDockerfile
という名前で作成する。Dockerfile
の記法についてはここでは割愛する。FROM nvidia/cuda:10.0-devel-centos7 as builder ENV NASM_VERSION 2.14 ENV NVCODEC_VERSION 8.2.15.6 ENV FFMPEG_VERSION 4.1 RUN yum install -y autoconf bzip2 git make RUN curl -fsSLO https://www.nasm.us/pub/nasm/releasebuilds/$NASM_VERSION/nasm-$NASM_VERSION.tar.bz2 \ && tar -xjf nasm-$NASM_VERSION.tar.bz2 \ && cd nasm-$NASM_VERSION \ && ./autogen.sh \ && ./configure \ && make -j$(nproc) \ && make install RUN git clone -b n$NVCODEC_VERSION --depth 1 https://git.videolan.org/git/ffmpeg/nv-codec-headers \ && cd nv-codec-headers \ && make install ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig RUN curl -fsSLO https://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2 \ && tar -xjf ffmpeg-$FFMPEG_VERSION.tar.bz2 \ && cd ffmpeg-$FFMPEG_VERSION \ && ./configure --enable-nvenc \ && make -j$(nproc) \ && make install FROM nvidia/cuda:10.0-runtime-centos7 ENV NVIDIA_VISIBLE_DEVICES all ENV NVIDIA_DRIVER_CAPABILITIES compute,video,utility COPY --from=builder /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg COPY --from=builder /usr/local/bin/ffprobe /usr/local/bin/ffprobe
-
Docker コンテナイメージのビルド
Dockerfile
と同じディレクトリで以下のコマンドを実行するとコンテナイメージのビルドが開始される。sudo docker build -t example/nvenc .
-
Docker コンテナの起動確認
作成したexample/nvenc
コンテナを起動し、ffmpeg
コマンドが使用可能であることを確認する。sudo docker run --runtime=nvidia -it example/nvenc /bin/bash /usr/local/bin/ffmpeg
-
コンテナイメージを Docker Hub に公開
あらかじめ Docker Hub のアカウントを作成し Create Repository からリポジトリを作成しておく必要がある。sudo docker login sudo docker push example/nvenc
なお、今回作成した Docker コンテナイメージは https://hub.docker.com/r/clerk67/nvenc/ にて公開している。