本日も乙

ただの自己満足な備忘録。

ECS GPU-optimized AMI で Docker ランタイムを変更する

本記事では、ECS GPU-optimized AMI をカスタマイズして Docker のランタイムを変更する方法について紹介しますが、そもそもなぜランタイムを変更しなければならないのかについて説明します。

ECS で GPU を扱うことによる問題点

ECS で GPU を使う場合はタスク定義で GPU 数を設定することができます。

aws.amazon.com

1つの GPU を複数の ECS タスクで共有することができない問題が起こります。例えば、g4dn.xlarge は GPU 搭載数が1なので GPU を扱う ECS タスクは EC2 インスタンスにつき1つしか置くことができません。機械学習や推論などで GPU のリソースを専有するのであればあまり問題ではないかもしれませんが、別タスクとして GPU のメトリクスを収集・送信したいときに困ります。

GPU 使用率などのメトリクスを取得する方法として NVIDIA Management Library (NVML) を使うことになりますが、これを動かすためにはタスク定義で GPU の設定が必要になります。上で書いたように搭載する GPU 数により EC2 インスタンスで実行できる ECS タスク数が決まっているため、g4dn.xlarge の場合は機械学習・推論などを行うタスクかメトリクスを収集するタスクのどちらかしか置けないことになります。2つ以上搭載している EC2 インスタンスタイプに変更すればいいのですが、g4dn ファミリーの場合、g4dn.12xlarge(GPU 数:4)と、かなり大きいインスタンスタイプになってしまいます。メトリクスを収集するためだけに貴重な GPU を専有したくない、かといってスケールアップして余計なコストはかけたくありません。

Docker のランタイムを変更することで回避する

Docker 19.03 以降の場合は --gpus=all をつけることでコンテナで GPU を使うことができます(19.03以前は nvidia-docker で --runtime=nvidia)。

$ docker run -d --gpus=all --rm nvidia/cuda nvidia-smi

ECS タスク定義で --gpus=all を渡せればそれで解決するのですが、Issue として上がってはいるが進まなそうです。
[ECS] How to share a single GPU with multiple containers · Issue #327 · aws/containers-roadmap

現実的な回避策としては、ECS GPU-optimized AMI をカスタマイズしてそれを使うしかありません。

最新の ECS GPU-optimized AMI を探す

SSM Parameter Store に最新の AMI ID が格納されているので以下のコマンドで取得します。

$ aws ssm get-parameters \
    --names /aws/service/ecs/optimized-ami/amazon-linux-2/gpu/recommended \
    --output text --query 'Parameters[].Value[]' | jq -r '.image_id'

今回は ami-057ff763763055073amzn2-ami-ecs-gpu-hvm-2.0.20200603-x86_64-ebs)を使用します。

Docker の設定変更

AMI から EC2 インスタンスを起動します。インスタンスタイプは GPU インスタンス(g4dn.xlarge 等)を選択します。

起動後、EC2 インスタンスにログインして /etc/sysconfig/dockerOPTIONS--default-runtime nvidia を追加します。

% sed -i"" -e 's/OPTIONS="--default-ulimit nofile=1024:4096"/OPTIONS="--default-runtime nvidia --default-ulimit nofile=1024:4096"/' /etc/sysconfig/docker

変更点

 # Additional startup options for the Docker daemon, for example:
 # OPTIONS="--ip-forward=true --iptables=true"
 # By default we limit the number of open files per container
-OPTIONS="--default-ulimit nofile=1024:4096"
+OPTIONS="--default-runtime nvidia --default-ulimit nofile=1024:4096"

 # How many seconds the sysvinit script waits for the pidfile to appear
 # when starting the daemon.

Docker を再起動して、プロセスに --default-runtime nvidia がついていることを確認します。

% systemctl restart docker.service
% ps -ef | grep [d]ocker | grep 'default-runtime nvidia'
root      7147     1  0 01:20 ?        00:00:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --default-runtime nvidia --default-ulimit nofile=1024:4096 --add-runtime nvidia=/etc/docker-runtimes.d/nvidia

この状態で AMI を作成すれば完了です。

参考 URL