*本記事は旧TechblogからCOLORSに統合した記事です。

目次

  1. 自己紹介と記事の概要
  2. 前提知識
  3. Dockerコマンドに慣れ親しむ
    3-1. Dockerイメージの取得
    3-2. コンテナの作成方法
    3-3. コンテナを起動・侵入・停止
  4. オリジナルなDockerイメージの作成
    4-1. コンテナからイメージを作成
    4-2. Dockerfileでイメージを作成
    4-3. イメージを.tarファイルとして保存またはロードする方法
  5. コンテナの削除・イメージの削除

1. 自己紹介と記事の概要

こんにちは。株式会社エイアイ・フィールドのS.Tです。 現在大学3年生で、インターンとして働かせてもらっています。社内ではスクレイピングによるデータ収集やツールの調査などの業務を行い、AI開発のサポートを行なっています。私が使っている業務用のPCはWindowsですが、開発をする上で何かと不便なので、Dockerをインストールしてコンテナ内にLinuxの開発環境を構築して作業を行なっています。

本記事は、私が普段Dockerで開発環境を構築するときにどのように行なっているかをまとめたものになります。「Docker?何それおいしいの?」という方はこちらの記事がよくまとまっているのでご覧ください!

Dockerを使ってみよう!

Dockerはイメージからコンテナという仮想環境を作成することができ、その仮想環境の中でいろいろなことができる便利なツールです。本記事では自分好みにカスタマイズしたイメージを作成し、それを.tarファイルとして保存することを目的とします。このファイルが1つあれば、DockerがインストールされているPCならば瞬時にコンテナを作成、つまり自分の開発環境を構築できるようになります。

これができるとどんな良いことがあるのか。 例えば、複数人で同じ環境で作業したい場合、.tarファイルを共有することでまったく同じOS、開発環境を各人のPCに再現できるようになります。ライブラリの依存関係や環境変数などをいちいち各人のPCで設定する必要がなくなり、環境構築にかかっていた時間を大幅に節約できるようになるという利点があります。数時間〜1日かかっていた環境構築を、数分〜数十分で終わらせるということも可能になります!

2. 前提知識

本記事は以下の知識・準備を読者の皆様が持っていることを前提とさせていただきます。ご了承ください。

  • Linuxの基本的なコマンド操作(cd, ls, mkdirなど)ができ、ファイルシステムがどうなっているかの簡単な理解がある
  • Docker (Desktop for Windows, Mac) をインストール済
  • Linux/Unix環境で作業できる(MacやUbuntu、WSL2など)。WindowsのcmdやPowerShell上でもできるとは思うが、私はMacとWSL2上(ubuntu)でしか試したことはない。


特にWindows(HOME)ユーザーの方は、Microsoftが2020年にリリースした WSL2 (Windows Subsystem for Linux 2)という、Linuxを仮想的に動かすWindows標準機能を使用可能にする必要があります。WSL2のインストールは本記事では解説しないので、何とか自力で頑張ってください!まあわかりやすい解説記事がごろごろ転がっているので、多分大丈夫だと思います。参考までに、マイクロソフトの公式ドキュメントのリンクを貼っておきます。

Windows 10 用 Windows Subsystem for Linuxのインストールガイド

3. Dockerコマンドに慣れ親しむ

dockerによる開発環境を作ることができても基本操作がわからなければ使いこなせないので、まずはdockerコマンドに慣れ親しんでおきましょう。dockerの基本コマンドをご存知の方は 4. オリジナルなDockerイメージの作成 のとこまで読み飛ばしてもらってOKですd( ̄  ̄)

3-1. Dockerイメージの取得・確認

Dockerで何かをするときはます基本となるイメージを Docker Hub というところからダウンロードします。今回は ubuntu を使っていくので、それのDockerイメージをダウンロードします。

docker pull ubuntu:latest
# もし18.04が欲しい場合は...
# docker pull ubuntu:18.04

docker pull イメージ名:タグ名 という形でダウンロードします。例えば最新版ではなく18.04のバージョンをダウンロードしたい場合は、タグ名のところを指定の形にします。詳しくは Docker Hub を覗いてみると良いでしょう。

ダウンロードしたイメージを確認するには、以下のコマンドを実行してください。

docker images 
または
docker image ls

3-2. コンテナの作成・確認

コンテナの作成は以下のコマンドでできます。最小限のものと、いろいろ詰め込んだものの2種類を同時に紹介します。

# 最小限のやつ
docker run --name pikachu -t -i ubuntu:latest /bin/bash
# いろいろ詰め込んだやつ
docker run \
    --name pikachu \
    -ti \
    -p 8888:8888 \
    -v C:\Users\JohnSmith\Desktop\pikachu:/root/work/ 
    ubuntu:latest \
    /bin/bash

最小限の方からみていきましょう。docker run イメージ名:タグ名 でコンテナを作成できます。--nameでコンテナに任意の名前をつけられますが、つけなくてもランダムで勝手に名前がつけられます。ですが、後々の管理コストも考えると自分で名前をつけた方が良いでしょう。-t-i (-ti でまとめられる) でそれぞれホスト-コンテナ間の標準入出力を開放でき、/bin/bash でubuntuイメージ内の/bin/bash コマンドが起動します。簡単に言えば、-ti/bin/bash を足すことで、コンテナ内部に侵入できます。実際にこのコマンドを走らせると、コンテナが作成されてroot画面になっているのがわかるでしょう。

次に、いろいろ詰め込んだコマンドの方をみていきましょう。といっても、新要素は2つだけです。1つはポートで、 -p ホスト側のポート番号:コンテナ内のポート番号 という形でポートを開放できます。後で JupyterLab を使う時に役立ちます。2つ目の -v はボリュームと呼ばれるもので、 -v ホスト側の共有ディレクトリ:コンテナ内の共有ディレクトリ という形でディレクトリの共有ができます。ホスト側には予め共有予定のディレクトリを作っておく必要がありますが、コンテナ側の方は自動で作られるので特に何かする必要はありません。コンテナ環境は基本的にGUIがないので、ホスト側のデスクトップに共有ディレクトリを作っておくと、画像の確認などが瞬時に行えて色々便利なのでおすすめです。

コンテナから出るには exit とタイプするか Ctrl + D でOKです。コンテナから脱出したら、コンテナの状態を確認する以下のコマンドを使ってみましょう。

docker ps -a

実行すると様々な情報が出現しますが、注目するのは STATUS と NAMES だけでOKです。先ほど作成したコンテナの名前(私の場合、pikachu)を確認したら、STATUSがExitになっていることを確認してください。これはコンテナが停止中であることを意味します。稼働中の時は、Up ** minutes といった形で表示されます。

3-3. コンテナを起動・侵入・停止

停止したコンテナを起動し、再び侵入、そして停止するには以下のコマンドを実行してください。

# コンテナの起動
docker start pikachu
# コンテナに侵入
docker exec -ti pikachu /bin/bash
# コンテナから出たら以下のコマンドで停止させる
docker stop pikachu

4. オリジナルなDockerイメージの作成

本章ではオリジナルのDockerイメージを作成していくわけですが、それには2つ方法があります。1つはコンテナの情報・状態をそのままイメージに変換する方法、2つ目はDockerfileを用いた方法になります。基本的に後者の方法が推奨されていますが、両方とも覚えておくと便利だと思うのでまとめていきます。

作っていく環境ですが、データサイエンスで使われる基本的なPythonライブラリのpandasやmatplotlib、エディターとしてJupyter Labをインストールしていきます。また、ベースで使うubuntuイメージには最小限のLinuxコマンドしか入っていないので、gitやzipなどのよく使われるものをインストールしていきます。詳しくは後述するDockerfileのRUNを確認してください。

4-1. コンテナの変更をイメージに反映

まずは、先ほど紹介したコンテナの起動・侵入コマンドで再びコンテナ環境に入ってください。次に、 “tree” というlinuxコマンドをインストール、そしてこの「treeコマンドをインストールしたという変化」が反映されたコンテナをもとに、新しいイメージを作成します。
# treeのインストール
sudo apt install tree
tree   # ディレクトリが樹形図のように表される
# Dockerの新しいイメージを作る
exit
docker stop pikachu
docker commit pikachu newimage:v1.0

上記のように、 docker commit 停止中のコンテナ 新しいイメージの名前:タグ名 という形で実行するとイメージ作成が始まります。新しいイメージの名前やタグ名は何でもOKです。イメージが出来上がったらコンテナを立ててみてください。treeコマンドを実行できるようになっているはずです!

同様に、treeの代わりにaptpipコマンドで必要なパッケージをインストールした後にdocker commitでオリジナルイメージを作成できます。しかし、完成後イメージのサイズが重くなる、1個1個のインストールを手動でやらねばならないなど面倒で非効率なので、基本的には次に紹介するDockerfileを用いるやり方でイメージを作成しましょう。

4-2. Dockerfileでイメージを作成

先ほどは docker commit でオリジナルのイメージを作成しました。少しの変更を加えるだけならそれでも良いのですが、1から環境構築をする場合や大きな変更を加える場合はDockerfileを作成してイメージを作成した方がベターです。ではイメージ作成にとりかかりましょう。最初に以下のコマンドを実行してください。

mkdir devenv # ディレクトリの名前は何でもOK
cd devenv
touch Dockerfile .dockerignore

まずは空のディレクトリを作成してその中に移動、Dockerfile という名前の空ファイルを作成します。Dockerではこのディレクトリを build context と呼んでおり、イメージをビルド(作成)する際には build context にある情報がすべてDockerデーモンに伝達されます。平たく言えば、ビルドに必要なファイルはすべてこのディレクトリに放り込んでおけばOKということです。.dockerignoreというファイルは、gitにおける.gitignoreと同じような役割を果たします。.dockerignore の中にはbuild contextに読み込んでほしくないファイルを、1ファイルごとに改行して書き込んでいきます。例えば以下のような感じです。

.dockerignore
.DS_Store
.ipynb_checkpoints/

それではDockerfileに以下の内容を書き込んでください。

FROM ubuntu:latest
# LABEL version=‘1.0’ location=‘Tokyo’ type=‘laptop’ role=‘general development’
SHELL [“/bin/bash”, “-c”]
ENV SHELL=/bin/bash
# ubuntuという名前の一般ユーザーを作成。ここはsatoshiでもtakeshiでも何でもいい。 
RUN useradd -ms /bin/bash ubuntu
# ADD . .
# -yを入れないと途中で止まってエラーなるので必ず入れる
RUN apt update && apt full-upgrade -y && \ 
  apt install -y sudo vim less zip unzip curl git python3 python3-pip && \
  pip3 install --upgrade pip && \
  pip3 install virtualenv numpy pandas matplotlib jupyterlab && \
  passwd -d root && passwd -d ubuntu && \
  usermod -aG sudo ubuntu && \
  echo ‘alias python=“python3”’ >> /home/ubuntu/.bashrc && \ 
  echo ‘alias pip=“pip3"’ >> /home/ubuntu/.bashrc && \
  # jupy というコマンドでjupyter labが開けるようにするための処理
  echo ‘alias jupy=“jupyter lab --no-browser --ip=0.0.0.0 --port=8888”’ >> /home/ubuntu/.bashrc
USER 1000
# 必ずUSERより後にWORKDIRを指定する
WORKDIR /home/ubuntu/
CMD [“jupyter-lab”, “--no-browser”, “--ip=0.0.0.0", “--port=8888”]

順番にみていきましょう。まず、FROMでベースとなるイメージを選択します。0から何もベースにせずイメージを作ることも可能ではありますが、通常はubuntuやcentosなどをベースにしてその上に色々インストールし、オリジナルのイメージを作ります。

LABELは話を簡単にするため今回はコメントアウトしましたが、これを入れておくと後で作成後のイメージの情報を調べる際に便利なので、慣れてきたら入れてみましょう。

イメージをビルドする際にパッケージのインストールなど様々なコマンドが実行されます。その際に使われるシェルを指定するのがSHELLで、デフォルトでは /bin/sh になっています。

ENVでイメージ内部、そしてコンテナ立ち上げ後のOSに環境変数を設定することができます。後で使うJupyter Lab内部のターミナルは SHELL という環境変数を読んで実行するので、bashシェルを明示しておきましょう。

RUNの後に実行したいコマンドを書くことで、ビルド中に実行され、イメージに反映されます。詳しい理屈は省略しますが、RUNコマンドは可能な限り少なく、各コマンドは && で繋げることで完成後のイメージのファイルサイズを小さくすることができます。パッケージはデータサイエンスでよく使われる基本的なものを入れてみましたが、この部分は自分の用途に合わせてうまく変更して使ってください。

WORKDIR でビルド中にどのディレクトリで作業するかを指定できます。また、ここで指定したディレクトリが、コンテナ作成時に最初に入る場所になります。rootユーザーで WORKDIR を指定した場合、一般ユーザーはそのディレクト
リでファイルの作成や書き込み等ができなくなってしまうので、今回のように開発環境イメージを作成する場合は一般ユーザーに変更した後にWORKDIRを指定しましょう。

ADDも今回はコメントアウトしています。最初の" . "は build context を指定しており、2つ目の" . "WORKDIRで指定したディレクトリを指しています。ここで使われている" . "はLinuxコマンドのカレントディレクトリと同じ意味であり、ホスト側のカレントディレクトリ(build context)にある全ファイルを、イメージ側のカレントディレクトリに加えるという意味です。なので、.bashrcや.jupyter/などの設定ファイルを加えたい場合、それらを build context の中に置いてADDをDockerfileに書き加えることで、作成中イメージにそれらを取り込むことができます。

USERでユーザーIDまたはユーザー名を指定することで、(ユーザーが存在していれば)どのユーザーで作業をするかを指定できます。コンテナ作成時のユーザーもこれで指定したものと同じになります。デフォルトではrootユーザーになっていますが、安全運用の面から今回は一般ユーザーでコンテナが立ち上がるようにしました。

最後にCMDですが、これはコンテナ作成時に自動的に走らせるコマンドを指定するもので、1つのDockerfileに1回だけ指定できます。コマンドや引数はリスト形式で囲ってください。今回作成するイメージではコンテナ起動時に JupyterLab が起動するようにしていますが、後述するように docker run のときに上書きできます。

イメージのビルドを行うために、以下のコマンドを実行してください。-tで作成予定のイメージの名前とタグを指定します。つける名前は何でもOKです。”.”は、カレントディレクトリからockerfileを探してイメージを作っていくよという意味です。

docker build -t devenv:latest .

ビルドが終わったら、出来上がったイメージからコンテナを作成してみましょう。今回作ったイメージでは2種類の立ち上げ方があるのでみていきましょう。

1. コンテナ作成時にJupyter Lab を自動で立ち上げる方法

docker run \
    --rm
    --name pikachu
    -p 8888:8888 \
    -v <strong>$(</strong>pwd<strong>)</strong>:/home/ubuntu/work/ \
    devenv:latest

3-2章でやったのとほぼ同じですが、2つ変更点を加えています。

1つ目は最後の部分の/bin/bashは省いています。ここの部分はコンテナ作成時に実行されるコマンドを指定する場所で、何も指定しなければ Dockerfile で指定した Jupyter Lab が開くことになっています。今までbashを指定していたのはシェルを操作するためだったのですが、それがなくなった今標準入出力を開放する必要もないので、-t -i フラグも省いています。

2つ目は--rmで、これを入れるとコンテナ脱出(または停止)とともに自動的にコンテナが削除されます。使い捨ての即興的な開発環境を作りたい場合などに向いています。

さて、上記のコマンドを実行するとJupyter Labのサーバーが立ち上がります。下図のようにtokenをコピペし、ホスト側のブラウザに以下のコマンドをタイプすることでエディターが開くようになります。

localhost:8888

2. Jupyter Labを立ち上げずにシェルに入る方法

docker run \
    --name pikachu
    -t -i \
    -p 8888:8888 \
    -v <strong>$(</strong>pwd<strong>)</strong>:/home/ubuntu/work/ \
    devenv:latest \
    /bin/bash

3-2章で見たやり方とほぼ同じ方法です。/bin/bashを加えることで、DockerfileのCMDで指定されていた Jupyter Lab の自動立ち上げが上書きされ、 bashシェルが開くようになっています。本イメージではjupyというエイリアスを作ったので、任意のディレクトリでjupyとタイプすることで Jupyter Lab サーバーが立ち上がり、先ほどと同様のやり方でエディターが開きます。

1点だけ注意。ボリュームのマウント先が違います。3-2章ではrootユーザーで作業していましたが、今回は一般ユーザー:ubuntuくんで作業をしているため、ubuntuのホームディレクトリ直下に共有ディレクトリを作成してマウントしています。

4-3. イメージを.tarファイルとして保存またはロードする方法

# イメージを.tarファイルにして保存
docker save devenv:latest -o devenv.tar
または
docker save devenv:latest > devenv.tar
# .tarファイルをロードする方法
docker load -i devenv.tar
または
docker load < devenv.tar

これでイメージの保存や読み込みも自由自在ですね!

5. コンテナの削除・イメージの削除

コンテナの削除方法

docker stop pikachu
docker rm pikachu

イメージの削除方法

docker rmi newimage:v1.0
または
docker images <em># ここで IMAGE ID を確認して
docker rmi 1c28a1589115 # 今回はIMAGE ID が1c28a1589115

記事は以上になります。最後までお読みいただきありがとうございます!