本記事では、ECS GPU-optimized AMI をカスタマイズして Docker のランタイムを変更する方法について紹介しますが、そもそもなぜランタイムを変更しなければならないのかについて説明します。
ECS で GPU を扱うことによる問題点
ECS で GPU を使う場合はタスク定義で GPU 数を設定することができます。
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-057ff763763055073
(amzn2-ami-ecs-gpu-hvm-2.0.20200603-x86_64-ebs
)を使用します。
Docker の設定変更
AMI から EC2 インスタンスを起動します。インスタンスタイプは GPU インスタンス(g4dn.xlarge 等)を選択します。
起動後、EC2 インスタンスにログインして /etc/sysconfig/docker
の OPTIONS
に --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 を作成すれば完了です。