Google Kubernetes Engine のコンテナGPUで動画エンコード( NVENC )を行い、高速エンコードとスケーラビリティを両立できます。
Container Engine GPU の入門記事は機械学習向けのものが多くて、動画処理のものが見当たらなかったので記事を書きました。
Dockerビルドマシンの側では、GPUはもちろんNVIDIAドライバすら入れる必要がないので楽です。
準備
DockerイメージのビルドマシンはGoogle Compute EngineのVMを使うと手っ取り早く便利です。 今回はCentOS 7を使用しました。 なお、イメージをGoogleクラウドストレージ上にContainer Registryとして保存するので、VMにストレージへの読み取りと書き込み権限が必要です。Dockerイメージをビルド
(1) Dockerをインストール
``` # yum install -y yum-utils # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # yum makecache fast # yum install -y docker-ce # systemctl start docker ```(2) nvidia-docker2をインストール
``` # distribution=$(. /etc/os-release;echo $ID$VERSION_ID) # curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | tee /etc/yum.repos.d/nvidia-docker.repo # yum -y install nvidia-docker2 # pkill -SIGHUP dockerd ```(3) Dockerfileを作成
[こちら](https://hub.docker.com/r/nvidia/cuda/)に基づいてDockerfileを作成しています。 GKEではUbuntuベースが推奨されているようなので、Ubuntu16.04を選択しました。FROM ubuntu:16.04
LABEL maintainer "NVIDIA CORPORATION <cudatools@nvidia.com>"
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates apt-transport-https gnupg-curl && \
rm -rf /var/lib/apt/lists/* && \
NVIDIA_GPGKEY_SUM=d1be581509378368edeec8c1eb2958702feedf3bc3d17011adbf24efacce4ab5 && \
NVIDIA_GPGKEY_FPR=ae09fe4bbd223a84b2ccfce3f60f4b3d7fa2af80 && \
apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub && \
apt-key adv --export --no-emit-version -a $NVIDIA_GPGKEY_FPR | tail -n +5 > cudasign.pub && \
echo "$NVIDIA_GPGKEY_SUM cudasign.pub" | sha256sum -c --strict - && rm cudasign.pub && \
echo "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64 /" > /etc/apt/sources.list.d/cuda.list && \
echo "deb https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64 /" > /etc/apt/sources.list.d/nvidia-ml.list
ENV CUDA_VERSION 9.2.148
ENV CUDA_PKG_VERSION 9-2=$CUDA_VERSION-1
RUN apt-get update && apt-get install -y --no-install-recommends \
cuda-cudart-$CUDA_PKG_VERSION && \
ln -s cuda-9.2 /usr/local/cuda && \
rm -rf /var/lib/apt/lists/*
# nvidia-docker 1.0
LABEL com.nvidia.volumes.needed="nvidia_driver"
LABEL com.nvidia.cuda.version="${CUDA_VERSION}"
RUN echo "/usr/local/nvidia/lib" >> /etc/ld.so.conf.d/nvidia.conf && \
echo "/usr/local/nvidia/lib64" >> /etc/ld.so.conf.d/nvidia.conf
ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:${PATH}
ENV LD_LIBRARY_PATH /usr/local/nvidia/lib:/usr/local/nvidia/lib64
# nvidia-container-runtime
ENV NVIDIA_VISIBLE_DEVICES all
ENV NVIDIA_DRIVER_CAPABILITIES compute,utility
ENV NVIDIA_REQUIRE_CUDA "cuda>=9.2"
# FFMPEG
RUN set -x \
&& apt update \
&& apt install -y gcc git make pkg-config devscripts \
&& apt install -y yasm nasm zlib1g-dev \
&& cd /usr/local/src \
&& curl -L http://sourceforge.net/projects/lame/files/lame/3.99/lame-3.99.5.tar.gz -o lame-3.99.5.tar.gz \
&& tar xvzf lame-3.99.5.tar.gz \
&& cd lame-3.99.5 \
&& ./configure \
&& make \
&& make install \
&& cd /usr/local/src \
&& git clone http://git.videolan.org/git/x264.git \
&& cd x264 \
&& ./configure --enable-shared --disable-asm \
&& make \
&& make install \
&& export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig \
&& echo /usr/local/lib >> /etc/ld.so.conf \
&& ldconfig \
&& cd /usr/local/src \
&& curl -L https://github.com/FFmpeg/nv-codec-headers/releases/download/n8.0.14.6/nv-codec-headers-8.0.14.6.tar.gz -o nv-codec-headers-8.0.14.6.tar.gz \
&& tar xvzf nv-codec-headers-8.0.14.6.tar.gz \
&& cd nv-codec-headers-n8.0.14.6 \
&& make \
&& make install \
&& cd /usr/local/src \
&& git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg \
&& cd ffmpeg \
&& ./configure --enable-nvenc --enable-libx264 --enable-gpl --enable-libmp3lame \
&& make \
&& make install \
&& cd /usr/local/src \
&& rm -rf *
# この辺から下はご自身のプロジェクトに合わせてください。
# Node.js
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - \
&& apt-get install -y nodejs \
&& mkdir /var/video_encode
COPY ./video_encode /var/video_encode
CMD /usr/bin/node /var/video_encode/bin/www
EXPOSE 3000
(4) DockerビルドしてPUSH
下記の「asia.gcr.io」の部分は好きなリージョンに変えてもOK。 Dockerfileのあるディレクトリで、# nvidia-docker build -t asia.gcr.io/自分のGCPプロジェクト名/test-encode .
# gcloud auth configure-docker
# nvidia-docker push asia.gcr.io/自分のGCPプロジェクト名/test-encode
Kubernetes Engine コンソールでの作業
(1) クラスタを作成
コンソールのクラスタメニュー > クラスタを作成 -
ゾーン/リージョンによって提供されるGPUが異なります。
-
GPUを使うノードプールと使わないノードプールを分けて作成することが推奨です。
GPUを要求するPodは nvidia.com/gpu テイントによってGPUノードにスケジュールされる仕組みになっています。
(2) NVIDIAデバイスドライバの用意
クラスタの一覧で新しくクラスタが作成されたことを確認し、右にある「接続」メニューからCloud Shellを開きます。 NVIDIAのデバイスドライバをインストールするデーモンセットを設定します。# kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/stable/nvidia-driver-installer/cos/daemonset-preloaded.yaml
結果:
daemonset.extensions "nvidia-driver-installer" created
(3) 先程のDockerイメージをデプロイ
コンソールのワークロードメニュー > デプロイ デプロイ後、ワークロードのメニューからYAMLを編集し、下記の resources の箇所を書き換えて nvidia.com/gpu でGPU数を指定して保存します。
apiVersion: extensions/v1beta1
kind: Deployment
... 略
spec:
containers:
- name: 〇〇
image: 〇〇
resources:
limits:
nvidia.com/gpu: 1
※ 編集後、"Insufficient nvidia"などのエラーでPodがすぐに起動しない場合がありますが、しばらく待っていれば解消されます。
※ ワークロードのオートスケーラーの設定について
Pod毎にできるだけ同じGPUを使わないようにすることが望ましい場合、CPUターゲット値を低めにしたほうが良いです。CPUターゲット値が高いと、CPUをあまり消費しないアプリケーションの場合、同じノード内にPodが次々と作られていき、GPUを共有します。
(4) NVENCができるか確認
Podにexecして確認しましょう。 稼働中のPod名はワークロードのメニューで確認できます。# kubectl exec -it Pod名 /bin/bash
Pod内に入ったら、h264_nvenc でエンコードしてみる。
# ffmpeg -i test.mov -vcodec h264_nvenc -b:v 2000k -acodec libmp3lame -b:a 128k output.mp4
(5) アプリケーションを公開(必要に応じて)
以上