GMO DevelopersDay
GMO DevelopersDay
2024.11.29Fri - 11.30Sat YouTube Live
イベント開催まであと6

3ステップで完了!Podmanを使用したコンテナによるセキュリティ強化の実践方法

久々に記事を投稿します。インフラエンジニアの柳です。
直近はGPUのホスティング基盤を担当しています。前回の記事は2022年、機械学習をテーマにした記事でした。2年前はここまでAIが盛り上がるとは想像していませんでした。今回はAIを支える技術としてコンテナを紹介したいと思います。

AI?コンテナ?とすぐには繋がらないと思いますが、AIを支える技術の一つとしてコンテナは非常に重要な役割を担っています。AIは非常に多くの計算を必要とし、その計算はGPUで行われています。GPUはCPUと異なりマルチプロセスには向いていないため、上手くプロセスをスケジュールして実行する必要があります。それぞれのプロセスにコンテナを用いることで、全く異なる実行環境やアプリケーションでも同じGPUにプロセスをスケジュールし処理が実行できるようになります。

1.コンテナについて

コンテナは現在、アプリケーションの開発と配布を効率化するために広く利用されています。しかし、その便利さの背後にはセキュリティリスクも存在します。特に、コンテナをどのように管理し実行するかは、セキュリティリスクを大きく左右します。本ブログでは、コンテナプラットフォームである
DockerとPodmanの違いと、セキュリティ面での取扱いについて解説します。

Dockerの基本とセキュリティ

Docker はコンテナを作成、実行するためのプラットフォームで、多くの開発者に利用されています。Dockerはデーモン(バックグラウンドで実行されるプロセス)として動作し、通常は
ルートユーザー権限で実行されます。ルートユーザーはシステム上で最も強い権限を持つため、Dockerのセキュリティが侵害されると大きなリスクが生じます。

ただし、最近ではRootlessモードを使うことで、通常のユーザー権限でもDockerを動作させることが可能です。このモードでは、管理者権限を持たないユーザーでもコンテナを安全に実行でき、システム全体のセキュリティが向上します。

Podmanの特徴とその利点

一方、Podmanはデーモンレスで動作するコンテナプラットフォームです。つまり、バックグラウンドで常時実行するデーモンプロセスが不要で、それぞれのコンテナが独立して動作します。これにより、システム全体のセキュリティリスクが抑えられます。また、PodmanはDockerのコマンドラインインターフェース(CLI) と互換性があるため、Dockerユーザーも容易に移行が可能です。

特に注目すべきは、ユーザ名前空間の取り扱いです。この機能により、コンテナ内のユーザーとホスト側のユーザーを紐付けまたは隔離することができ、アクセス権を細かく制御することが可能です。Podmanはこの点で非常に使いやすく設計されており、セキュリティ面での利点も大きいです。

2.インストール方法の違い:Docker vs Podman

Ubuntu22.04、Rootlessモードのインストール方法です。GPUもコンテナから利用可能とします。

共通手順

Docker, Podman共通のインストール手順です。
Rootless環境のポイントは、no-cgroups、enable-linger、XDG_RUNTIME_DIRの設定です。

# [1] nvidia-container-toolkitのRepository設定
sudo curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor > /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

sudo curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt update

# [2] パッケージインストール
sudo apt install uidmap dbus-user-session slirp4netns nvidia-container-toolkit fuse-overlayfs

# [3] no-cgroupsをfalseからtrueに変更します。
# ※この変更をしないとRootlessコンテナからGPUが利用できません。
sudo vi /etc/nvidia-container-runtime/config.toml

no-cgroups = true

# [4] Dockerをインストールする一般ユーザーを追加します。
# ※user0001にdockerをインストールする場合の例です。
sudo useradd -m user0001 -s /bin/bash

# [5] enable-lingerでユーザーセッションを有効化します
sudo loginctl enable-linger user0001

■ Rootless Dockerのインストール方法

下記作業は全て一般ユーザーで実行します。

# [1] systemd busの設定
cat<<EOS>> ~/.bashrc
# systemd bus
export XDG_RUNTIME_DIR=/run/user/$(id -u user0001)
# Docker config
export PATH=${HOME}/bin:$PATH
export DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/docker.sock
EOS

# [2] bashrc変更設定を反映
source ~/.bashrc

# [3] Rootless Dockerのダウンロード
curl -fsSL https://get.docker.com/rootless | sh

# [4] Rootless Dockerのインストール
dockerd-rootless-setuptool.sh install

# [5] 実行確認
systemctl --user status docker

docker-composeのインストール

docker composeコマンドも一般ユーザーにインストールします。

[1] ディレクトリ作成
$ mkdir .docker/cli-plugins

[2] インストール(v2.21.0の場合)
curl -L "https://github.com/docker/compose/releases/download/v2.21.0/dockercompose-$(uname -s)-$(uname -m)" -o ~/.docker/cli-plugins/docker-compose

[3] 実行権限付与
chmod +x ~/.docker/cli-plugins/docker-compose

■ Podmanのインストール方法

# [1] Repository設定
sudo curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/Release.key | gpg --dearmor | tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null

sudo echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg] https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/ /" | tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null

# [2] Install
sudo apt update
sudo apt -y install podman

# [3] sticky付け権限調整
sudo chmod u+s $(which newuidmap)
sudo chmod u+s $(which newgidmap) 

# [4] CDI(Container Device Interface)生成
sudo mkdir /etc/cdi
sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml

# [5] 確認
sudo nvidia-ctk cdi list

以下表示がでればOK

INFO[0000] Found 2 CDI devices
nvidia.com/gpu=0
nvidia.com/gpu=all

podman.socketの設定

下記作業は全て一般ユーザーで実行します。

# [1] systemd busの設定
cat<<EOS>> ~/.bashrc
# systemd bus
export XDG_RUNTIME_DIR=/run/user/$(id -u user0001)
# Docker config
export PATH=${HOME}/bin:$PATH
export DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/podman/podman.sock
EOS

# [2] bashrc変更設定を反映
source ~/.bashrc

# [3] podman起動
systemctl --user start podman.socket

# [4] podmanのソケット確認
podman info --format '{{.Host.RemoteSocket.Path}}'

# [5] gpuが読み込めるか検証
podman run --rm --device nvidia.com/gpu=0 ubuntu nvidia-smi -L

podman-composeのインストール

sudo apt install python3-pip
sudo pip3 install podman-compose

3.YAMLファイルの違い: Docker vs Podman

DockerとPodmanではGPUの指定方法が異なります。
Podmanではuserns_mode: keep-idの指定が可能となります。

Dockerでのコンテナ起動

docker-compose.yml

version: '3.9'
name: webui-docker
services:
  auto:
    ports:
      - "${WEBUI_PORT:-7860}:7860"
    volumes:
      - ./data:/data
      - ./output:/output
    stop_signal: SIGKILL
    tty: true
    image: ##IMAGE_ID##
    deploy:
      resources:
        reservations:
          devices:
              - driver: nvidia
                device_ids: ['0']
                capabilities: [compute, utility]
    command: ###
docker-compose up --build -d

Podmanでのコンテナ起動

docker-compose.yml

version: '3.9'
name: webui-podman
services:
  auto:
    ports:
      - "${WEBUI_PORT:-7860}:7860"
    volumes:
      - ./data:/data
      - ./output:/output
    stop_signal: SIGKILL
    tty: true
    image: ##IMAGE_ID##
    userns_mode: keep-id
    devices:
      - nvidia.com/gpu=0
    command: ###
podman-compose up --build -d

4.userns_mode: keep-idについて

userns_mode: keep-idを設定すると、コンテナ内のユーザーID (UID) とグループID (GID) が、コンテナを
起動したホストのユーザーIDとグループIDと一致するようになります。

keep-idを指定しない場合

ホストの一般ユーザー(1012)が、コンテナ内のルートユーザーに名前空間で紐づけされます。

podman top -l user huser
USER        HUSER
root        1012

keep-idを指定した場合

ホスト側の一般ユーザー(1012)が、コンテナ内でも一般ユーザー(1012)に名前空間で紐づけされます。

podman top -l user huser
USER        HUSER
1012        1012

keep-idを利用する利点

セキュリティの向上

デフォルトではコンテナ環境で使用されるユーザーはrootユーザー(UID 0)ですが、userns_mode: keepid を使用することで、コンテナ内の作業を非rootユーザーで実行できるため、セキュリティリスクを低減できます。

ファイルの所有権管理の簡素化

コンテナ内のユーザーIDとホストのユーザーIDが一致すると、ホストとコンテナ間でファイルを共有する際の所有権やパーミッションの管理が容易になります。コンテナから作成されたファイルは、ホスト上でも同じユーザーIDによって所有されます。これにより、ファイルの所有権やパーミッションに関する問題を避けることができます。

5.パフォーマンス

コンテナ環境での Stable Diffusion Web UI を利用した画像生成のパフォーマンスについて紹介させていただきます。

結果

  • コールドブート時間はL4とH100で差異はなかった
  • H100はL4の倍以上の画像生成速度でバッチ数が増えるほど差が広がる
  • バッチ数が増えてもリニアに生成時間が増えるわけではない
GPU種別Nvidia H100(PCIE)Nvidia L4
コールドブート*18.7秒8.6秒
GPU種別Nvidia H100(PCIE)Nvidia L4
512 x 512 画像生成 – バッチ数:1 *22.26秒*33.54秒
512 x 512 画像生成 – バッチ数:43.22秒8.53秒
512 x 512 画像生成 – バッチ数:85.2秒17.6秒
1024 x 1024 画像生成 – バッチ数:14.42秒11.7秒
1024 x 1024 画像生成 – バッチ数:414.45秒55.6秒
1024 x 1024 画像生成 – バッチ数:828.07秒115.7秒
*1 コールドブートにはコンテナ起動時間とモデルロード時間が含まれます。
*2 バッチ数は同時に生成する画像枚数です。
*3 画像生成時間にはコールドブートの時間は含まれていません

画像生成条件

設定項目
チェックポイントmeinamix_meinaV11
チェックポイントサイズ1.99GB
LoRAAsuka Langley Souryuu/Shikinami (Evangelion)
sampling step28

検証結果

pkgversion
CUDA12.2
Stable Diffusion WebUIv1.5.2
Python3.10.9
Pytorch2.01+cu118
xformers0.0.21.dev544
gradio3.32.0
Docker20.10LTS
ContainerToolKit1.13.5

6.まとめ

コンテナからGPUを利用することで、推論や学習環境を簡単に切り替えられることは非常に便利だと感じます。また、DockerとPodmanは似たような機能を持ちながらも、その実行構造と安全性においては大きな違いがあります。特にセキュリティを重視する場合には、Podmanの方が優れた選択肢かもしれません。GPU+Podmanの組み合わせにより、セキュリティとコンテナによる柔軟性の両立が可能だと考えます。

ブログの著者欄

柳 匡哉

GMOインターネットグループ株式会社

2008年GMOインターネットグループ株式会社にアルバイトとして入社。データセンターでの監視・運用業務の傍らshell, perl, javaを勉強。社員登用後ベトナム、タイのホスティングサービス立ち上げやOpen Stackでのクラウド基盤開発に従事。現在はマイニング事業を担当しつつ機械学習を勉強中。

採用情報

関連記事

KEYWORD

採用情報

SNS FOLLOW

GMOインターネットグループのSNSをフォローして最新情報をチェック