LoginSignup
16
17

More than 1 year has passed since last update.

yamlで保存してあるconda仮想環境をDocker上で構築

Last updated at Posted at 2020-07-24

(追記 2022-11-05)

本記事の内容(オリジナルは2020年の7月頃)ですが、
2年以上経って久々に見返してみると我ながら色々とよろしくない点もあったように思うので、
可能な範囲で直した改善版: yamlで保存してあるconda仮想環境をDocker上で構築(multistage-build)を本記事の続きとして書いています。

本記事だとdocker内で作成しているユーザーの権限が大き過ぎたり、minicondaを使っている関係で商用利用が有償化されているAnacondaリポジトリから意図せずにパッケージを取得してしまう可能性があったりと、そのまま実行すると懸念点があるので注意してください。


Docker上でPython環境を作るときにpipPipenvなども使うのだが、使うライブラリやパッケージの関係でconda環境を使えると便利なことがある。
思った通りのconda環境をDocker上で作るための方法の自分用メモ。

1. 動機

Pythonの開発やデータ分析などでMinicondaやAnacondaを使うことがある。
(依存ライブラリも割と一緒にインストールしてくれるので自分で入れなくて良いなど環境構築が楽だったり、バイナリ互換性の問題でcondaの特定チャンネルからのインストールを推奨されるパッケージがあったりする)
その際、やっている作業毎にパッケージやバージョンを変えたかったり、環境を後で再現しやすくするなどの目的で基本はconda仮想環境を使うようにしている。
が、Python以外のところから環境設定・構築が必要になることがあったり、仮想環境と言えどもPCの環境を汚して他と干渉したりの問題が起きるなどで、結局Dockerで対応することが多いため。(で、そのDockerへの移植時に結構苦戦したため)

yamlファイルを使う理由

詳細は次章として、

  • PC上の既存のconda仮想環境を容易にDocker上に移植出来る
  • 逆に、Docker上で開発したconda環境を手元のAnacondaやMinicondaですぐに再現出来る

など

2. conda環境の保存と再構築

2-1. yamlファイルからのconda環境生成

(公式ドキュメント)

conda env create -f environment.yml

を実行すると、environment.ymlに記載した情報の通りにconda環境が生成される。
例えばenvironment.ymlに対応するものをgit上などで管理しておくと、可搬性や再現性の点で便利。

environment.ymlの中身は以降の記述を参考
conda env create以降のオプションの詳細ははっきり覚えていない。。。発見出来てかつ気が向いたら後で追記。ちなみにconda createのオプションはこんな感じ

2-2. yamlファイルの生成

(公式ドキュメント)

対象のconda仮想環境に入って、例えば以下のようにする

conda env export > environment.yml

すると、該当のconda環境でインストールされていた全パッケージとそのバージョン(ビルド情報含む)がenvironment.ymlに書き出される。(pip freezeするような感覚)

ちなみに、仮想環境に入らなくとも

conda env export  -n <仮想環境名> > environment.yml

のようにして、明示的に書き出す仮想環境名を指定することも出来る。

また、上記の2つは完全にバージョン情報が固定されるが、そこまではせずに最低限の条件だけ指定したい場合がある。
(公式ドキュメント)を参考にして、パッケージと使うチャンネルなどを書いたyamlファイルを自分で作ることが出来る。(以下、適当な例)

create_env_sample.yml
name: hoge
channels:
  - conda-forge
  - default
dependencies:
  - python==3.7.*
  - pandas<1.0
  - flask
  - pip
  - pip:
    - pynvim
  • 依存ライブラリなどは(conflictが起きなければ)自動でインストールされる。
  • pipでインストールされるものも書ける。(pip:の下のところ)
    • 先にcondaでのインストールが実行され、最後にpipでのインストールが実行される
    • condaでインストールするパッケージ内で明示的にpipをインストールしておくと無難かもしれない
      • 「conda仮想環境のものでないpipを使う可能性がある」的な趣旨のwarningが出る

なお、上記の例のyamlファイルだと、

# condaでパッケージをインストール
conda create -n hoge python=3.7 pandas\<1.0 flask pip -c conda-forge
# 作った仮想環境に入る
conda activate hoge
# 最後にpipで必要なパッケージをインストール
python -m pip install pynvim

みたいな感じで環境構築するのと大体同じ。(※厳密に本当に同じかまでは未検証)

3. Docker上でconda仮想環境を作る

(方針)

  • 前章を踏まえて用意してあるyamlファイルをDockerイメージ内にCOPYなどしておく
  • yamlファイルからの環境作成はMinicondaを利用して行う
    • Miniconda自体のインストールは公式などを参照
    • continiuum公式のDockerfileなども参考になる
  • 上記のMinicondaはyamlファイルから仮想環境を作ること「のみ」に使い、作り終わったら元のMinicondaはキャッシュ毎全部消す(←容量の無駄なので)
    • 代わりにyamlから作られた仮想環境の方をbaseにする
    • (もっと良いやり方があるかもしれない)

Dockerfile作成例(抜粋)

ディレクトリ構成:

tree . 
# .
# ├── Dockerfile
# └── environment.yml

のような感じ。

docker build --tag=hoge .

または

# Dockerfile内のARG部分を制御する場合
docker build \
    --tag=hoge \
    --build-arg VAL1=FOO \
    --build-arg VAL2=BAR \
     . 

のようにすると、ビルドが通ればhogeというイメージが出来る

Dockerfile
ARG BASE_IMAGE=ubuntu:latest
FROM ${BASE_IMAGE}

# system update & package install
RUN apt-get clean && \
    apt-get -y update && \
    apt-get install -y --no-install-recommends \
    unzip bzip2 \
    openssl libssl-dev \
    curl wget \
    ca-certificates \
    locales \
    bash \
    sudo \
    git \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*


# ローカルuser作成
ARG USER_NAME=user
ARG USER_UID=1000
ARG PASSWD=password
RUN useradd -m -s /bin/bash -u ${USER_UID} ${USER_NAME} && \
    gpasswd -a ${USER_NAME} sudo && \
    echo "${USER_NAME}:${PASSWD}" | chpasswd && \
    echo "${USER_NAME} ALL=(ALL) ALL" >> /etc/sudoers && \
    chmod g+w /etc/passwd


# conda用準備
ENV CONDA_DIR=/opt/conda \
    CONDA_TMP_DIR=/tmp/conda \
    HOME=/home/$USER_NAME \
    SHELL=/bin/bash
RUN mkdir -p $CONDA_DIR && \
    mkdir -p $CONDA_TMP_DIR && \
    chown $USER_NAME:$USER_UID $CONDA_DIR && \
    chown $USER_NAME:$USER_UID $CONDA_TMP_DIR
# yamlファイルの取り込み
ARG CONDA_YAML="./environment.yml"
COPY $CONDA_YAML /tmp/conda_packages.yml

USER ${USER_NAME}

WORKDIR $HOME
# miniconda
ARG MINICONDA_VERSION=py37_4.8.3-Linux-x86_64
ARG MINICONDA_MD5=751786b92c00b1aeae3f017b781018df
ENV PATH=${CONDA_DIR}/bin:$PATH

RUN cd /tmp && \
    wget --quiet https://repo.anaconda.com/miniconda/Miniconda3-${MINICONDA_VERSION}.sh && \
    echo "${MINICONDA_MD5} *Miniconda3-${MINICONDA_VERSION}.sh" | md5sum -c - && \
    /bin/bash Miniconda3-${MINICONDA_VERSION}.sh -f -b -p $CONDA_TMP_DIR && \
    rm Miniconda3-${MINICONDA_VERSION}.sh && \
    $CONDA_TMP_DIR/bin/conda env create -f /tmp/conda_packages.yml -p $CONDA_DIR && \
    rm -rf $HOME/.cache/* && \
    rm -rf $CONDA_TMP_DIR/*

# (以下省略)
  • はじめにMinicondaは/tmp/conda/下にインストールする
    • 先述の通り、conda env createをするためだけに使うので、後で/tmp/conda/下をまるっと消す
    • インストール先は-pオプションで指定している
  • 所望のconda環境は/opt/conda/下にインストールされ、ここにPATHを通すことで作成ユーザーにとってのデフォルトPython環境にしている
    • conda環境を/opt/conda/にするために、-p--prefixオプションでインストール先を指定
  • イメージサイズが肥大化しないように、Minicondaのダウンロード・インストールから不要なファイル・キャッシュの削除まで1つのRUNの中で全てをやり切る必要

(補足)

  • 使っているMinicondaは執筆時点(2020-07-24)での最新版なので、ここなどを参考に適宜アップデートする
  • ユーザー作成を行っているが別に必須ではないので、そこを省けばもっとすっきりするはず
  • yamlファイルにおけるprefix:部分があればそれはインストール場所を示すが、conda env create-pないし--prefixオプションでの指定が優先される様子
  • yamlファイルに書くインストールパッケージの中にcondaを書いておくと、/opt/conda/にインストールされる仮想環境が新しいbase環境になる
    • コンテナ使用中に追加で入れたいパッケージが出てきたときにその場でconda install ***を実行出来たり、その後conda env export -n base | tee environment.ymlなどと叩いてインストールパッケージの再確認や新しいyamlファイルの生成が出来る
(更に細かい補足)

たまにconda env exportで生成したyamlファイルをそのままconda env createに渡せないときがある(あった)ので、その例と対処。

  • pipgraphvizをインストールさせたものをconda env exportしてyamlを生成すると、python-graphvizの名前になっている
  • しかし、pip install python-graphvizはエラーになるため、したがってこのyamlファイルをそのまま使うとインストールエラーになってしまう
  • そこで、例えば以下の部分を挿入してyamlファイルを少しだけ書き換えるなどした
RUN sed -i -e 's/python-graphviz/graphviz/' /tmp/conda_packages.yml

sedでyamlファイル内のpython-graphvizgraphvizに置換している

参考

conda環境の保存・構築:
https://qiita.com/nshinya/items/cb1cffabc3305c907bc5
https://qiita.com/yubessy/items/2dd43551aa8308dc7eca

Docker上でのconda環境の構築
https://hub.docker.com/r/continuumio/miniconda/dockerfile
https://github.com/jupyter/docker-stacks/tree/master (←リポジトリ内の各Dockerfileを参照)

16
17
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
16
17