0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CLAMリポジトリにDocker+VSCode環境を実装してみた

Last updated at Posted at 2024-12-03

概要

共同での研究や開発において、環境の違いによる問題を回避するために
統一された便利なDockerコンテナ環境を持つことには利点があると思われます。
 
また、VSCodeを用いて作業を行うことで、
コードの変更や動作確認、デバッグなどが行いやすくなると考えられます。

本記事では、githubから取得できるCLAMリポジトリについて、
Dockerコンテナ構築手順を用意し、
コンソールまたはVSCodeから扱えるような手順を紹介しております。

CLAMは2020年にハーバード大学医学部ブリガム・アンド・ウイメンズ病院 病理部のMing Y.Lu氏らが発表した、スライド画像から特徴量を抽出し、スライド単位のラベルを用いて弱教師あり学習でクラス分類を行うスクリプトです。

今回の例はCLAMですが、CLAM以外でも、DockerとVSCodeを連携させた
環境が用意されていないリポジトリを、共同で使ってみたい場合などの参考になればと思います。
 
なお、GPUを用いない場合と用いる場合の両方に対応できるよう記載しております。
(DockerGPUをサポートするためには、
事前にnvidia-container-toolkitをインストールしている必要があります)

環境構築用ファイル作成手順

手順1

CLAMのリポジトリをクローン

git clone https://github.com/mahmoodlab/CLAM.git

手順2

取得したCLAMリポジトリに移動し、dockerディレクトリを作成

cd CLAM
mkdir docker

手順3

dockerディレクトリに、Dockerfiledocker-compose.yml等で参照する環境変数を設定するシェルファイルinit_env.shを作成

init_env.sh
#!/bin/bash
set -euo pipefail

# 本ファイルのあるディレクトリの1つ上のディレクトリに移動
cd $(dirname $0)/..

REPLACE_USERNAME=$(echo $USER |sed 's/\./_/g')

# ホストのユーザー名がrootの場合、REPLACE_USERNAME="developer"に指定
if [ "$USER" = "root" ]; then
  REPLACE_USERNAME="developer"
fi

# .envファイルがない場合、下記内容の環境変数ファイルを作成
if [ ! -f .env ]; then
    cat <<EOT > .env

COMPOSE_PROJECT_NAME=clam_${REPLACE_USERNAME}
USERNAME=$REPLACE_USERNAME
HOST_UID=`id -u`
HOST_GID=`id -g`
EOT
fi

手順4

dockerディレクトリにDockerfileを作成

apt-get installpip installなどの項目はCLAMenv.ymlをベースに作成します。

Dockerfile
# ベースイメージ (CPUの場合)
FROM ubuntu:22.04 AS base
# ベースイメージ (GPUの場合[Nvidia])
# FROM nvidia/cuda:12.1.0-devel-ubuntu22.04 AS base

# 時刻設定(東京)
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

# システムパッケージ更新とbuild-essential, python3.10関連パッケージ
# 及び、OpenSlide, OpenCV関連パッケージのインストール
RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y build-essential python3.10 python3.10-distutils python3-pip libopenslide-dev libgl1 git

## GPUの場合に下記を設定 (CUDA関連追加設定)
# CUDAホームディレクトリを環境変数CUDA_HOMEに設定
# ENV CUDA_HOME=/usr/local/cuda
# CUDAの実行可能ファイル(例: nvcc)ディレクトリを環境変数PATHに追加。これにより、nvccなどをコマンドとして直接実行可能に
# ENV PATH=$CUDA_HOME/bin:$PATH
# CUDAライブラリ(例:cuDNN)があるディレクトリを動的ライブラリの検索パスに追加。これにより、アプリケーションがCUDAライブラリをロード可能。
# ENV LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH
# Pytorchで使用するGPUアーキテクチャを指定
# ENV TORCH_CUDA_ARCH_LIST="6.0;6.1;7.0;7.5;8.0;8.6"

# CLAMのenv.ymlに合わせてpipパッケージをインストール
RUN pip install --upgrade pip &&\
    pip install ipykernel &&\
    pip install pandas pyyaml opencv-python matplotlib scikit-learn scipy tqdm &&\
    pip install timm==0.9.8 torch torchvision tensorboardx &&\
    pip install openslide-python &&\
    pip install h5py &&\
    pip install git+https://github.com/oval-group/smooth-topk.git

# 言語設定(日本語)
RUN apt update && apt install -y language-pack-ja && update-locale LANG=ja_JP.UTF-8
RUN apt install -y fonts-takao fonts-takao-gothic fonts-takao-pgothic fonts-takao-mincho
ENV LANG jp_JP.UTF-8
ENV XMODIFIERS @im=fcitx
ENV GTK_IM_MODULE fcitx
ENV QT_IM_MODULE fcitx
ENV LC_CTYPE ja_JP.UTF-8

# dev(開発用)
FROM base AS dev

# 開発などで良く用いられるLinuxツール+nodejs(markdownlintインストール用)
RUN apt update && apt install -y \
    curl \
    gnupg \
    sudo \
    nano \
    vim \
    wget \
    && apt purge -y nodejs \
    && curl -sL https://deb.nodesource.com/setup_22.x | bash - \
    && apt install -y nodejs \
    && apt clean && rm -rf /var/lib/apt/lists/*

# コードの書式等チェック用linter, formatter, testerインストール
RUN pip install \
    codespell==2.3.0 \
    pytest==8.2.1 \
    ruff

# マークダウンファイル(README.mdなど)の書式チェック用
RUN npm install -g --save-dev markdownlint-cli2@0.13.0

# シンボリックリンク作成("python OOO.py"でコマンド実行できるようにするため)
RUN ln -s /usr/bin/python3 /usr/bin/python

# ipykernelの設定(jupyter notebook等を用いる場合、別途インストールが必要)
RUN python -m ipykernel install --user --name=sysmtem-python --display-name "Python(system)"

# 開発用ユーザー追加
ARG USERNAME=developer
ARG USER_UID
ARG USER_GID

# ホストのユーザーID,グループIDをコンテナ内のIDに割り当てるが、
# コンテナ環境で既存のグループID、ユーザーIDの場合は、
# ユーザーID=1000, グループID=1000を割り当て
RUN USER_GID=$(getent group $USER_GID >/dev/null && echo 1000 || echo $USER_GID) \
    && USER_UID=$(getent passwd $USER_UID >/dev/null && echo 1000 || echo $USER_UID) \
    && groupadd --gid $USER_GID $USERNAME \
    && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
    && echo "$USERNAME ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME

# 指定したユーザー名でコンテナをビルド
USER $USERNAME

CMD ["usr/bin/bash"]

手順5

CLAMのトップディレクトリに移動し、docker-compose.ymlを作成

docker-compose.yml
# プロジェクト名。コンテナ名等のprefixとして付与される
name: clam
# コンテナ全体の設定
services:
  # service内の1つのサービス名(任意名)
  dev:
    # コンテナにホストと同等の特権を持たせる
    privileged: true
    # Dockerのimage名
    image: clam:dev-${USERNAME}
    # docker build条件
    build:
      # コンテナビルドの基準になるディレクトリ
      # `docker-compose.yml`から見て`Dockerfile`が格納されたディレクトリパス
      # `docker-compose.yml`が`clam/`にあり、`Dockerfile`は`clam/docker`にあるため、
      # `docker`を指定
      context: docker
      # Dockerfileの指定
      dockerfile: Dockerfile
      # ビルドの際のステージを指定(開発用の部分が不要の場合はbase)
      # 他のステージをDockerfileに追加しtargetに指定してもOK
      target: dev
      args:
        - USER_UID=${HOST_UID}
        - USER_GID=${HOST_GID}
    # nvidiaのGPU(id=0を指定)を用いる場合
    # deploy:
      # resources:
        # reservations:
          # devices:
            # - driver: "nvidia"
              # capabilities: ["gpu"]
              # nvidia-smiで確認できるGPU IDを指定
              # device_ids: ["0"]
    user: "${HOST_UID}:${HOST_GID}"
    # ホスト側のネットワークを指定
    # 別途ポートを指定する場合、`network_mode:`は記載せず、
    # 代わりに`ports:`を記載し`- "8888:8888"`(ホストのポート:コンテナのポート)
    # のようにポート番号を指定する
    network_mode: "host"
    # ボリューム設定
    volumes:
      # ホストのカレントディレクトリをコンテナ内の/workspaces/clamにマウント
      # (ホストでの変更を動的にコンテナに反映)
      - .:/workspaces/clam
      # ホストのデバイスディレクトリをコンテナ内の/devにマウント
      # (GPUやUSBデバイスへのアクセス用)
      - /dev:/dev
    # コンテナ内の作業ディレクトリ
    working_dir: /workspaces/clam
    # 対話型操作用
    stdin_open: true
    # docker execでアクセス用
    tty: true
    # bash -c "tail -f /dev/null"はコンテナをバックグラウンドで起動し続けるため
    # コンテナ内で常にJupyter等の他のプロセスを起動する場合は必要なし
    command: >
      bash -c "tail -f /dev/null"

手順6

開発に用いるVSCodeDev Container機能用に.devcontainerディレクトリを用意し、
ホストと同様にsshgitを使用するための補足用docker-compose.ymlを作成

docker-compose.yml
services:
  dev:
    user: developer
    # コンテナ内のdeveloperユーザーがsshやgitを使用できるように指定
    volumes:
      - ~/.ssh:/home/developer/.ssh:ro
      - ~/.gitconfig:/home/developer/.gitconfig

手順7

.devcontainerディレクトリに、
VSCodeDev Container機能用のdevcontainer.jsonを用意

devcontainer.json
{
    "name": "clam",
    "dockerComposeFile": [
        "../docker-compose.yml",
        "docker-compose.yml"
    ],
    "service": "dev",
    "workspaceFolder": "/workspaces/clam",
    "containerEnv": {
        "SHELL": "/bin/bash"
    },
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
                "ms-python.vscode-pylance",
                "ms-python.mypy-type-checker",
                "charliermarsh.ruff",
                "DavidAnson.vscode-markdownlint"
            ]
        }
    }
}

devcontainer.jsonについて補足

dockerComposeFileには.devcontainerにある
 docker-compose.ymlCLAMディレクトリの直下にあるdocker-compose.ymlを指定  
serviceにはdocker-compose.ymlで指定してあるdevを指定
workspaceFolderには、コンテナ内の作業ディレクトリのパスを指定
containerEnvでは、コンテナ内の環境変数を設定

"customizations": {
        "vscode": {
            "extensions": [

には、VSCodeにインストールする拡張機能を指定
(python系に加え、今回は書式をチェックするもの等指定)

手順8

トップディレクトリにREADME.mdを作成し、
環境構築手順が分かるようにする。

README.md例

CLAM

環境構築

Dockerコンテナでの使用を想定した手順です

1. リポジトリを取得

git clone https://github.com/mahmoodlab/CLAM.git

2. .envファイルの作成

ホストのUID及びGIDを使用するために、.envファイルを作成します

./docker/init_env.sh

3. Dockerイメージのビルド及びコンテナの起動

下記2つの方法があります。(VSCode推奨)

[VSCodeの拡張機能(Dev Container)を用いた方法]

下記を実施することで、VSCodeのDev Containerを使用し環境構築を行うことができます

VSCodeでプロジェクトのルートディレクトリを開く

CtrlShiftを押しながらPを押してコマンドパレットを開く

・コマンドパレットからReopen in Container(コンテナーで再度開く)を選択する

・コンテナ内の環境が開く

[Docker composeを用いた方法]

docker compose build dev
docker compose run dev

上記実行後に、別のウインドウ又はタブからコンテナに入ります

docker exec -it コンテナ名 /bin/bash

環境構築手順

作成したファイルを用いて環境の構築を実施します

方法1 (VSCode)

  1. VSCodeCLAMリポジトリを開く
     
  2. Ctrl & Shift + Pで開くメニューから、
    Dev Containers: Reopen in Container(コンテナで再度開く)を選択
     
  3. 新たにコンテナ内の処理ウインドウが開きます
    このウインドウのコンソールから、
    create_patches_fp.pyなどのCLAMのプログラムを実行します
     
  4. コンテナ外のコンソールから、コンテナの稼働状況を確認
PS D:\OOO\CLAM> docker ps
CONTAINER ID   IMAGE            COMMAND                   CREATED       STATUS       PORTS     NAMES
3b8e557ab872   clam:dev-OOO   "/bin/sh -c 'echo Co…"   3 hours ago   Up 3 hours             clam_developer-dev-1 

方法2 (docker composeコマンド)

  1. コンソールにて、CLAMディレクトリから、docker compose build devを実行
root@OOOOO:/mnt/d/OOOOO/CLAM# docker compose build dev
[+] Building 1014.2s (16/16) FINISHED                                                                                      docker:default
 => [dev internal] load build definition from Dockerfile                                                                             0.1s
 => => transferring dockerfile: 2.39kB                                                                                               0.0s
 => [dev internal] load metadata for docker.io/library/ubuntu:22.04                                                                  2.5s
 => [dev internal] load .dockerignore                                                                                                0.1s
 => => transferring context: 2B                                                                                                      0.0s
 => [dev base 1/6] FROM docker.io/library/ubuntu:22.04@sha256:0e5e4a57c2499249aafc3b40fcd541e9a456aab7296681a3994d631587203f97       4.4s
 => => resolve docker.io/library/ubuntu:22.04@sha256:0e5e4a57c2499249aafc3b40fcd541e9a456aab7296681a3994d631587203f97                0.0s
 => => sha256:0e5e4a57c2499249aafc3b40fcd541e9a456aab7296681a3994d631587203f97 6.69kB / 6.69kB                                       0.0s
 => => sha256:3d1556a8a18cf5307b121e0a98e93f1ddf1f3f8e092f1fddfd941254785b95d7 424B / 424B                                           0.0s
 => => sha256:97271d29cb7956f0908cfb1449610a2cd9cb46b004ac8af25f0255663eb364ba 2.30kB / 2.30kB                                       0.0s
 => => sha256:6414378b647780fee8fd903ddb9541d134a1947ce092d08bdeb23a54cb3684ac 29.54MB / 29.54MB                                     3.0s
 => => extracting sha256:6414378b647780fee8fd903ddb9541d134a1947ce092d08bdeb23a54cb3684ac                                            1.1s
 => [dev base 2/6] RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime                                                          3.5s
 => [dev base 3/6] RUN apt-get update &&     apt-get upgrade -y &&     apt-get install -y build-essential python3.10 python3.10-d  148.8s
 => [dev base 4/6] RUN pip install --upgrade pip &&    pip install ipykernel &&    pip install pandas pyyaml opencv-python matplo  775.2s
 => [dev base 5/6] RUN apt update && apt install -y language-pack-ja && update-locale LANG=ja_JP.UTF-8                               9.8s
 => [dev base 6/6] RUN apt install -y fonts-takao fonts-takao-gothic fonts-takao-pgothic fonts-takao-mincho                          7.8s
 => [dev dev 1/6] RUN apt update && apt install -y     curl     gnupg     sudo     nano     vim     wget     && apt purge -y nodej  27.7s
 => [dev dev 2/6] RUN pip install     codespell==2.3.0     pytest==8.2.1     ruff                                                    4.6s
 => [dev dev 3/6] RUN npm install -g --save-dev markdownlint-cli2@0.13.0                                                            10.7s
 => [dev dev 4/6] RUN ln -s /usr/bin/python3 /usr/bin/python                                                                         0.5s
 => [dev dev 5/6] RUN python -m ipykernel install --user --name=sysmtem-python --display-name "Python(system)"                       0.9s
 => [dev dev 6/6] RUN USER_GID=$(getent group 0 >/dev/null && echo 1000 || echo 0)     && USER_UID=$(getent passwd 0 >/dev/null &&   0.5s
 => [dev] exporting to image                                                                                                        17.0s
 => => exporting layers                                                                                                             17.0s
 => => writing image sha256:75c16e5d90aaafc5ccf569ca8f55ec640f939a6f56a08b3bfaf7c03eafcec396                                         0.0s
 => => naming to docker.io/library/clam:dev-developer   

 
2. docker imagesでイメージが作成されていることを確認

root@AlzaPC:/mnt/d/OOO/CLAM# docker images
REPOSITORY                 TAG         IMAGE ID       CREATED         SIZE
clam                       dev-OOO   ceb4480de052   4 hours ago     10.3GB
ubuntu                     22.04       97271d29cb79   2 months ago    77.9MB
continuumio/anaconda3      latest      de606c8c8d2d   9 months ago    4.45GB
docker/welcome-to-docker   latest      c1f619b6477e   12 months ago   18.6MB

3.docker compose run devでコンテナを起動

root@AlzaPC:/mnt/d/OOO/CLAM# docker compose run dev

4.コンテナに入る際は、別のタブなどからコンソールを開き、下記を実行

docker exec -it コンテナ名(clam-OOO) /bin/bash

5.下記のようにdocker内の作業環境が開きます
 ここから、create_patches_fp.pyなどのCLAMのプログラムを実行します

developer@docker-desktop:/workspaces/clam$ 

環境構築方法は以上になります。
構築した環境でCLAMのコードを実行することができます。

実際に構築した例について、githubに公開しておりますので、ご参考にしていただけましたら幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?