新しい端末を買うたびにDockerを導入しようとして、毎回苦戦する赤ちゃんなので、Docker幼稚園に入ります。
Dockerコンテナって?
- Container
- Images
- Volumes
の関係をまずまとめる。
- Container
-
仮想の動作環境(=ひとつのサーバーみたいな感じ)。
例えばPCのローカル環境にpython2とpython3を同居させてると、パッケージのインストールや動作時にどっちで動かしてるんだ…?ってなるときがある。
このようにひとつの動作環境にいろいろソフトウェアを入れていく(=環境が汚れる)と、お互いが思いもよらぬ形で影響してトラブる可能性がある。
そこで仮想の動作環境(=Container)を作り、それぞれ独立させてやることで無用なトラブルを防止することができる。 - Image
-
Containerの設計図、雛形。
これを共有することで、誰もが同じ仮想環境を構築することができる。
OSの違いや種々のライブラリの導入状況の違いを無視し、環境構築をすっ飛ばしてメインの開発から着手できるのはとてもメリット。
そしてこのImageの共有プラットフォームがDocker Hub。
- Volume
-
複数のコンテナが共有できるデータ領域みたいなもの(まだ使っていないので曖昧)。
後述する各ContainerがマウントするVolumeとは別なのでそこだけ注意。
Containerは使い捨ての環境。
都度、作ったり消したり、起動したり停止したりするもの。
Imageはあくまで設計図なので、そのなかで作業したりはしない、ということだけまず理解する。
Dockerイメージってどこからくるの?
Imageは、Dockerfileというファイルをもとに作られる。
公式Dockerfileリファレンスに記載のサンプルを見てみよう。
FROM ubuntu:18.04
COPY . /app
RUN make /app
CMD python /app/app.py
ひとつひとつ紐解いていく。
FROM句はDockerfileには必須の要素で、これから作るImageのベースとなるImageを指定している。
":"以降はTagと呼ばれ、Imageのバージョンのようなもの。
# FROM <Image名>:<Tag>
FROM ubuntu:18.04
“ubuntu”はDocker Official Imageとして配布されているImage。
このubuntu ImageからContainerを作成すると、まっさらなubuntuの環境が作成される。
その環境をもとにして、少しカスタマイズしたImageを誰かが作る。
それをもとに、また別の誰かが少しカスタマイズしたImageを作る。
このようにImageが数珠つなぎになっているというアイデアは、まさしく「巨人の肩に乗る」発想だと思った。
実際、Docker Desktopで”node” Imageを見てみると、”debian” Imageを出発点として、計4つのImageの上に”node” Imageが成り立っていることが分かる。
余談
ちなみに本当に空っぽの状態からImageを作成したい場合は、次のように指定する。
# 特定のImageを指定せず、
# まっさらな状態からImageを作成する
FROM scratch
残りのコマンドは簡単なので、一気に。
# カレントディレクトリの中身を、コンテナ内の/appディレクトリにコピー
COPY . /app
# コンテナ内で、/appに対してmakeコマンドを実行
RUN make /app
# コンテナ内の/app/app.pyを実行
CMD python /app/app.py
パッと見、RUNとCMDってどちらもシェル形式でコマンド実行しているだけで、何が違うの?ってなると思う。
Dockerfileの書き方, 利用する命令, 作成手順を参考にすると、
- RUN
-
DockerfileからImageを作成する際に実行されるコマンド。
Dockerfile内に複数記載可能。 - CMD
-
ImageからContainerを起動する際に実行されるコマンド。
Dockerfile内に1度しか記載できない。
つまり、作成する環境にパッケージをいろいろインストールしておきたい場合はRUN、
コンテナ立ち上げ時にMySQLを起動しておきたい、というような場合はCMD、
ということになる。
CMDと同じくDockerfile内に一度しか記載できず、コンテナ起動時に実行されるコマンドを指定するENTRYPOINTというものがあるが、ここは幼稚園なのでいったん割愛。
参考になるサイト
(Docker) CMDとENTRYPOINTの「役割」と「違い」を解説
Githubから落としてきたら、docker-compose.ymlがついてきたけどこれは?
docker-compose.ymlはざっくりいうと、ImageからのContainerの起動、あるいはDockerfileからImageのビルドも含めて、自動化するファイル。
メリットは少なくとも2つあって、
- コマンド入力が楽できる
- 複数のContainerを一度に起動できる
docker-compose.ymlに指定するオプションや環境変数を記載しておけば、毎回コマンドでわざわざ指定しなくても、docker-composeファイルを読み込むだけで済むようになる。
またWebサーバーとDBサーバーでそれぞれContainerを起動しようとする際、通常であればそれぞれのContainerに対して起動のコマンド入力をする必要があるが、これもdocker-compose.ymlで一発呼び出しで済む。
# こんなに長いコマンドが
docker run -dp 3000:3000 \
-w /app -v "$(pwd):/app" \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:18-alpine \
sh -c "yarn install && yarn run dev"
docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
mysql:5.7
# これで済むようになる
docker-compose up -d
docker-compose.ymlの中身はこんな感じ
version: "3.7"
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
mysql:
image: mysql:5.7
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data: