LoginSignup
5
3

More than 1 year has passed since last update.

yamlで保存してあるconda仮想環境をDocker上で構築(multistage-build)

Last updated at Posted at 2022-11-04

昔書いた記事: yamlで保存してあるconda仮想環境をDocker上で構築をふと見返してみると、色々と微妙というか「個人的には今ならこうは書かないな。。。」と思ったのでアップデート版を書いてみる。

概要

前提知識:

  • conda cliの基本と概念
    • 特にAnacondaやminicondaで仮想環境を作ることができ、yamlファイルの形でexport出来ること
    • 逆に、yamlファイルを取り込むことでAnacondaやminicondaなどで仮想環境を作成出来ること
  • docker周りの基本
  • linux周りの基本

やること:

前回からの主な改善点

  • multistage-buildを使う
    • ツールのビルドなど下準備用のLayerを実際に動かすイメージから分離出来るため、余計なものをインストールしなくて良くなったり、キャッシュファイルの削除を頑張らなくても良くなったりする。すなわち、イメージサイズの削減につながるし、余計なものが無い方がセキュリティ的にも良いと思われる。
  • conda環境の生成にmambaを使っている
    • condaのC++による再実装(githubのREADMEより)であり、conda互換でかつ高速(ビルド時間の削減)
  • conda環境の生成にmambaforgeイメージを利用している
    • Anacondaリポジトリの商用利用が有償化されており、minicondaを使っているとdefault channel(=Anaconda公式リポジトリ)からパッケージを取得してしまう可能性があった気がするので、商用利用にあたる場合、使うyamlファイルで全パッケージリポジトリレベルまで指定されていない場合はminicondaを使わないほうが無難と思われる
    • miniforgeはやや不正確ながらざっくりいうとdefault channelがconda-forgeになっているminicondaのようなもの。mambaforgeはそれのmambaコマンド(先述)が使えるバージョン
    • あと、前回はminicondaのインストールから始めていたので、今回は最初からmambaが使えるイメージを使うことで記述内容をかなり簡略化できた
  • (本質では無いが)docker内で使うユーザーの権限見直し
    • 以前の記事ではrootへの昇格を許していたが、通常はやらない方が良いので改めている

改善後の環境生成方法

今回は以下のyamlファイル:

conda_env.yaml
name: example_env
channels:
  - conda-forge
dependencies:
  - python==3.10.*
  - pandas
  - jupyterlab
  - pip
  - pip:
    - python-language-server[all]

を使ってconda環境を作る。
内容は割とナンセンスで本質的では無いので注意。

使うDockerfileは例えば以下のような感じにする。

Dockerfile
FROM condaforge/mambaforge:latest as builder
COPY conda_env.yaml .

RUN mkdir -p /usr/local/conda && \
    mamba env create -f ./conda_env.yaml -p /usr/local/conda

# 今回の例ではベースイメージにubuntuを使う。(mambaforgeイメージのベースも執筆時点でubuntuだったりする)
FROM ubuntu:latest as main

# NOTE: 環境によって設定すべき値は変わるので、必要があれば編集する
# または、ARGとしているのでbuild時に値を与えて変更する
ARG USERNAME=user
ARG GROUPNAME=user
ARG UIDVALUE=1000
ARG GIDVALUE=1000

# NOTE: 使いたいパッケージがあれば適宜追加する
RUN apt-get update && \
    apt-get install --no-install-recommends --yes \
    tini && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# rootユーザーで動かすのは避けたいのでユーザーを作成する
# 設定するユーザー名やUIDなどは必要に応じて上記のARGの値で変更する
RUN groupadd --gid  ${GIDVALUE} ${GROUPNAME} && \
    useradd --uid ${UIDVALUE} --gid ${GROUPNAME} --shell /bin/bash --create-home ${USERNAME}

# この例では/usr/local/condaディレクトリ上にconda環境を格納する
RUN mkdir -p /usr/local/conda
# builderイメージからそっくりそのままコピーする(所有権は変えておく)
COPY --from=builder --chown=${UIDVALUE}:${UIDVALUE} /usr/local/conda/ /usr/local/conda

# 実行ユーザーをrootから先程作成したものに切り替え
USER ${UIDVALUE}

# 作成したconda環境にPATHを追加する
ENV PATH=/usr/local/conda/bin:${PATH}

# ----------------------------------------------------------------------------------------------- #

# ここから下は特にユースケース次第で完全に変わる部分なので適当に編集すること。
# 今回はそこそこ実用的な例?としてjupyterlabを起動している
# なお、例なのでjupyterの起動オプションでtoken=''(ログイン認証無し)としているが、むやみにやるのは良くない
WORKDIR /home/${USERNAME}
EXPOSE 8888
ENTRYPOINT ["tini", "--"]
CMD ["jupyter", "lab", "--ip=0.0.0.0", "--NotebookApp.token=''"]

multi-stage buildを使ったことなどにより、前回記事よりも簡潔に記述できている。(トリッキーな部分を大幅に少なくできている)

なお、作成するconda環境内のbinディレクトリだが、一部のコマンドは絶対パスの参照をもつシンボリックがある?ようで、
builderとmainとでconda環境の置き場所の絶対パスを同じにしないと動かなかったので、編集して使う際は注意。

これで、上記のDockerfileconda_env.yamlを置いてあるディレクトリで

docker build . -t <タグ名>

などとすればイメージが作れる。

なお、厳密に条件を揃えた訳では無いが、同一のconda_env.yamlを使って作成したDockerイメージのサイズを比較したところ、執筆時点(2022/11/4)では前回記事の方法で850MB、今回の方法では753MBとなった。
思ったよりもイメージサイズを削減できていることがわかった。ちゃんと調べていないが、前回記事はminicondaをインストールして動かしたりするためにapt-getなどで入れないといけないパッケージが若干あったため、主にその分で差が出ている?と思われる。(正直どちらも割と大きいが)
(↑今回の例ではなんとなくtiniを入れているが必須のものではなく、aptなどでマストで追加しないといけないパッケージは実質存在しない)

感想

  • multi-stage buildは便利
  • (正直ここ最近ほぼ全くPythonとかcondaとか触っていないので、知識のアップデート漏れがあったら申し訳ないです)
5
3
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
5
3