この記事は、Udemy のコース「米シリコンバレーDevOps監修!超Docker完全入門【優しい図解説とハンズオンLab付き】」で学習した内容を記録したものだ。
このコースでは Linux の基礎的なコマンドや docker の基礎を丁寧に説明してくれ、初心者でも短期間で docker の基礎を身に付けることができる楽しいコースになっている。
米シリコンバレーDevOps監修!超Docker完全入門【優しい図解説とハンズオンLab付き】
- Docker のインストール
- Linux の基本
- シェルの基本コマンド
- Docker のコマンド
- イメージの操作
- コンテナの操作
- イメージからコンテナを起動(docker run)
- 起動中のコンテナの一覧を表示(docker ps)
- 停止中のコンテナも含めて全ての一覧を表示(docker ps –all)
- コンテナを停止する(docker stop)
- 停止中のコンテナを削除(docker rm)
- コンテナをバックグランドで起動(docker run –detach)
- コンテナのログを表示(docker logs)
- 起動中のコンテナの中にシェルで入る(docker exec -it)
- ホストのデータをコンテナにコピー(マウント)(docker run –volume)
- コンテナの環境変数を設定(docker run –env)
- コンテナのメタデータ(様々な情報)を見る(docker inspect)
- コンテナにつなげるホストのポートを変える(docker run -p)
- コンテナが停止したら自動でコンテナを削除させる(docker run –rm)
- 起動中のコンテナからイメージを作成する(docker commit)
- Dockerfile からイメージを作成する(docker build)
- コンテナとイメージの削除
- Docker の作業の流れ
- Dockerfile
- Docker-Compose
Docker のインストール
Windows の場合
- Install Docker Desktop on Windows の「Download from Docker Hub」をクリック。
- Docker Desktop for Windows ページの「Get Docker」ボタンでインストーラ-をダウンロードする。
Mac の場合
- Install Docker Desktop on Mac の「Download from Docker Hub」をクリック。
- Docker Desktop for Mac ページの「Get Docker」ボタンでインストーラ-をダウンロードする。
Linux の基本
Linux のカーネル(kernel)とは
カーネルは、CPU やメモリ、入出力装置(マウス、キーボードなど)、ネットワークなどのハードウェア資源を管理して抽象化し、アプリケーション側がハードウェアの違いを意識せずに利用できる手段を提供する。また、実行中のプログラムの状態を管理する。
Linux のシェル(shell)とは
シェルは、ユーザーが OS と対話するためのインターフェースを提供するプログラムのこと。ユーザーがコマンドを入力すると、シェルはそのコマンドを理解してカーネルのプログラムを実行する。
ユーザー
↑ ↑ ↑ ↑
↓ ↓ ↓ ↓
シェル
↑ ↑ ↑ ↑
↓ ↓ ↓ ↓
カーネル
↑ ↑ ↑ ↑
↓ ↓ ↓ ↓
ハードウェア(CPU やメモリ、マウス、キーボードなど)
また、シェルには sh, tcsh, bash, zsh, … など、いくつかの種類がある。
フォアグランドプロセスとバックグランドプロセス
フォアグランドプロセス(Foreground process)
フォアグランドプロセスとは、実行する処理(プロセス)の完了を待ち、完了するまで次のプロセスが実行できないものをいう。
フォアグランドプロセスを実行したシェルは、完了するまでコマンドの入力を受け付けない。
バックグランドプロセス(Background process)
バックグランドプロセスとは、実行する処理(プロセス)の完了を待たずに次のプロセスが実行できる。
バックグランドプロセスを実行したシェルは、完了を待たないので、すぐに次のコマンドの入力を受け付ける。
シェルの STDIN、STDOUT、STDERR とは
シェルからフォアグランドでプロセスを実行させると、インプット(入力したコマンド)とアウトプット(プロセスの結果の表示)をターミナルで見ることができる。
シェルに対してコマンドを入力するとき、標準として(暗黙的に)使用される入力元のことを STDIN と呼ぶ。
また、シェルが返すプロセスの結果を、標準として(暗黙的に)吐き出す出力先のこと STDOUT と呼ぶ。プロセスがエラーのときの標準出力先は STDERR と呼ばれる。
TTY
シェルの STDIN と STDOUT をターミナルに繋げること、つまりシェルに対してコマンドの入力やその実行結果の出力をできるようにすることを、TTY(Tele Typewiter) をターミナルにアタッチする、と表現する。
docker の中にシェルで入るときには
$ docker exec --interactive --tty
というコマンドを使用する。
シェルの基本コマンド
ディレクトリ用操作コマンド
ディレクトリ情報の表示(ls)
ls は list の略。
$ ls
#隠しファイルも含めてすべてを表示
$ ls -a
ディレクトリの移動(cd)
cd は change directory の略。
cd home/
現在のディレクトリを表示(pwd)
pwd は print working directory の略。
$ pwd
ディレクトリの作成(mkdir)
mkdir は make directory の略。
$ mkdir sample_dir
ファイル操作用コマンド
ファイルの作成(touch)
$ touch test_file
ファイルにテキストを付け足す(echo >>)
$ echo "この文章がファイルに追加されます。" >> test_file
ファイルの内容を表示する(cat)
cat は concatenate の略。concatenate は「追加する、連結する」といった意味がある。ファイルの内容を STDOUT に追加して出力するという意味でコマンド名が cat になっている。
$ cat test_file
ファイルを削除(rm)
rm は remove の略。
$ rm test_file
プロセス操作用コマンド
プロセスの表示(ps)
ps は process status の略。
$ ps
プロセスをバックグランドで起動(&)
プロセスをバックグランドで起動するためには、コマンドの末尾に & を付けて実行させる。
$ sleep 50 &
プロセスをフォアグランドに戻す(fg)
fg は foreground の略。
$ fg
コマンド補助用コマンド
コマンドのヘルプ(–help)(help の前にハイフン2つ)
ps コマンドの使い方が知りたいなら「ps –help」を入力する。(help の前にハイフン2つ)
$ ps --help
Usage: ps [-aefls] [-u UID] [-p PID]
Report process status
-a, --all show processes of all users
-e, --everyone show processes of all users
-f, --full show process uids, ppids
-h, --help output usage information and exit
-l, --long show process uids, ppids, pgids, winpids
-p, --process show information for specified PID
-s, --summary show process summary
-u, --user list processes owned by UID
-V, --version output version information and exit
-W, --windows show windows as well as cygwin processes
With no options, ps outputs the long format by default
コマンドの保存先を表示(which)
ps コマンドの保存先を知りたいなら「which ps」とする。
$ which ps
/usr/bin/ps
コマンドのマニュアルを表示(man)
man は manual の略。ps コマンドのマニュアルが見たいときは、「man ps」とする。
サーチ用コマンド
ファイル・ディレクトリを探す(find)
find 検索パス 検索する条件 [アクション]
という形式で使用する。例えば、
- 検索するパスが「/」ならルートから、「./」ならカレントディレクトリから検索する。
- 検索する条件が「-type d」ならディレクトリを探し、「-type f」ならファイルを探す。
検索する条件が「-name hoge」なら hoge という名前のファイル・ディレクトリを探す。
$ find / -type f -name mkdir.exe
/bin/mkdir.exe
/usr/bin/mkdir.exe
ファイルの中の文字列を検索する(grep)
grep [オプション...] 検索文字列 [ファイル名1] [ファイル名2] ...
という形式で使用する。
$ cat test_file
abcde
fghij
abcxyz
123456789
$ grep abc test_file
abcde
abcxyz
$ grep -n abc test_file
1:abcde
3:abcxyz
また、ディレクトリを指定して、その中の全てのファイルを検索したい場合は次のようにする。
grep 検索文字列 ディレクトリ/*
サブディレクトリも含めて検索したい場合は、-r オプション(–recursive)を付けて次のようにする。
grep -r 検索文字列 ディレクトリ
コマンドの入出力を切り替える
コマンドの標準出力を切り替える(リダイレクト >, >>)
「コマンド > ファイル」とした場合、コマンドの標準出力をファイルに書き込む。ファイルが既に存在する場合は、上書きされる。
$ cat test_file
hello world!
$ echo "hello" > test_file
$ cat test_file
hello
また、「コマンド >> ファイル」とした場合、コマンドの標準出力をファイルに追記する。
$ cat test_file
hello
$ echo "hello world" >> test_file
$ cat test_file
hello
hello world
コマンドの標準出力を別のコマンドの標準入力に渡す(パイプ | )
「コマンド1 | コマンド2」とした場合、コマンド1の標準出力がコマンド2の標準入力に渡される。
$ cat test_file
hello
hello world
$ cat test_file | grep -n world
2:hello world
標準入力に対してコマンドを実行する(xargs)
xargs コマンドを実行すると、標準入力から受け取ったデータを、任意のコマンドに引数として渡すことができる。パイプで他のコマンドの出力を受け取って、次のコマンドを実行させる、といった使い方をすることが多い。
$ ls
test_file
$ cat test_file
hello
hello world
$ ls | xargs echo >> test_file
$ cat test_file
hello
hello world
test_file
その他のコマンド
現在のユーザー名を表示(whoami)
現在ログインしている自分の名前を表示するには「whoami」と入力する。
$ whoami
コマンドの出力結果を文字列の中に展開する($(…))
$() を使用すると、あるコマンドの出力結果を別のコマンドの引数の文字列に組み込むことができる。
$ echo "現在のディレクトリ:$(pwd)"
コマンドを一定間隔で繰り返し実行する
watch コマンドを使用すると、一定間隔(デフォルト2秒毎)で指定のコマンドの実行を繰り返させることができる。
$ watch コマンド
コマンドを連続して実行する
「コマンド1が成功したら、コマンド2を実行する」というようなことを行いたい場合は、&& でコマンドをつなぐ。
$ コマンド1 && コマンド2
例えば、次のコマンドは、Linux のパッケージマネージャー apt をアップデートしたら、curl コマンドをインストールするという意味になる。(-y は何か聞かれたら全て yes にするという意味のオプション)
$ apt update && apt install -y curl
Docker のコマンド
イメージの操作
イメージを取得する(docker pull)
public あるいは private の Docker Registry からイメージをダウンロードするには、つぎのコマンドを実行する。
$ docker pull イメージ名
例えば、Webサーバーの Nginx の docker イメージを取得する場合
$ docker pull nginx
この際にターミナルをもう一つ開いて、
$ watch -t "docker ps"
を実行しておくと、docker ps コマンドを2秒毎に実行してくれるので便利。
イメージの一覧を表示する(docker images)
ダウンロードした docker イメージの一覧を表示するには次のコマンドを入力する。
$ docker images
イメージの履歴を表示する(docker history)
$ docker history イメージ名
例えば、nginx の履歴を表示するなら、
$ docker history nginx
イメージを削除する(docker rmi)
$ docker rmi イメージ名
例えば、nginx のイメージを削除するなら、
$ docker rmi nginx
コンテナの操作
イメージからコンテナを起動(docker run)
$ docker run -p 80:80 --name nginx nginx
-p は –publish の略であり、「-p 80:80」により、host 側のポートを 80、コンテナ側のポートを 80 という形に、host とコンテナのポートをマッピングする。
nginx ではデフォルトでポート 80 をオープンにしているため、コンテナ側は 80 にする。host 側をポート 1000 としてマッピングするなら「-p 1000:80」とすればよい。
–naem オプションで起動するコンテナに名前を付けることができる。
起動中のコンテナの一覧を表示(docker ps)
ps は process status の略。
$ docker ps
停止中のコンテナも含めて全ての一覧を表示(docker ps –all)
$ docker ps --all
あるいは -a でもよい。
$ docker ps -a
コンテナを停止する(docker stop)
$ docker stop コンテナID
$ docker stop nginx
停止中のコンテナを削除(docker rm)
$ docker rm コンテナID
コンテナをバックグランドで起動(docker run –detach)
–detach オプション(-d でもよい)を使用することでバックグランドで起動することができる。
$ docker run --detach -p 80:80 --name nginx nginx
コンテナのログを表示(docker logs)
$ docker logs コンテナID
このコマンドを実行すると、コンテナ内のログが STDOUT に出力される。つまりターミナルに表示される。コンテナをバックグランドで起動しているときにログを見ることができる。
起動中のコンテナの中にシェルで入る(docker exec -it)
-it オプションは「–interactive」と「–tty」を兼ねたもの。バックグランドで起動しているコンテナと対話できるようになる。
$ docker exec -it コンテナ名 シェルの種類
$ docker exec -it nginx sh
$ docker exec --interactive --tty nginx bash
コンテナから出るには「exit」を入力する。
ホストのデータをコンテナにコピー(マウント)(docker run –volume)
正確にはコピーするわけではなく、マウントなので、コンテナ内で書き換えられたデータは、ホスト側に保存される。コンテナ内には保存されない。
$ docker run --volume ホスト側パス:コンテナ側パス
現在のディレクトリをコンテナ内の /home にマウントして、nginx イメージからコンテナをバックグランドで起動するには次のようにする。
$ docker run -d --volume $(pwd):/home nginx
その他の例
$ docker run --volume index.html:/home nginx
メモ:Windows ではホスト側のパスの表記上の問題により、この書き方では上手く行かなかった。
コンテナの環境変数を設定(docker run –env)
$ docker run --env キー=値
とすることで、コンテナ内に環境変数を追加することができる。
$ docker run -d --env TEST_ENV=hello_world --name nginx nginx
また、コンテナ内では「$env」を入力することで、設定された環境変数を確認することができる。
コンテナのメタデータ(様々な情報)を見る(docker inspect)
$ docker inspect コンテナID
$ docker inspect nginx
コンテナにつなげるホストのポートを変える(docker run -p)
-p は –publish の略。
docker run -p 8080:80 -d --name nginx nginx
コンテナが停止したら自動でコンテナを削除させる(docker run –rm)
docker stop でコンテナを停止させたときに、自動でそのコンテナを削除させたい場合は、次のように docker run コマンド時に –rm オプションを指定する。
docker run -d -p 80:80 --rm --name nginx nginx
起動中のコンテナからイメージを作成する(docker commit)
docker commit コンテナ名 イメージ名
例えば、起動中のコンテナ nginx から、sample_image という名前の新しいイメージを作成する場合は、次のようにする。
docker commit nginx sample_image
イメージを作成する場合の注意点
volume マウントしたデータはあくまでもホスト側で保存されていて、コンテナ内には保存されていない。そのため、volume マウントしてある起動中のコンテナからイメージを作成しても、作成されたイメージには volume マウントしたデータは反映されない。
Dockerfile からイメージを作成する(docker build)
–tag で新しく作られるイメージの名前を指定する。
$ docker build --tag イメージ名 Dockerfileがあるディレクトリパス
$ docker build --tag my_image .
コンテナとイメージの削除
停止中のコンテナと無名のイメージを削除
$ docker system prune
起動中のコンテナも含むすべてのコンテナを削除
docker rm -v -f $(docker ps -a -q)
$(docker ps -a -q) により、() 内のコマンドをバックグランドで実行して、その結果を用いて rm コマンドを実行する。
全てのイメージを削除する(起動中のコンテナも削除される)
docker rmi -f $(docker images -a -q)
Docker の作業の流れ
イメージにパッケージを加えて新しいイメージを作成する
Dockerfile でレシピを作成する
# FROM で基になるイメージを指定(latest は最新のもの)
FROM nginx:latest
# WORKDIR でコンテナが起動したときのコマンドを開始する位置を指定
WORKDIR /usr/share/nginx/html
# COPY でホストからコンテナにファイルをコピー(--volume と同じ)。
# 左側がホスト、右側がコンテナ
# ホストはカレントディレクトリに対する相対パス、コンテナは WORKDIR に対する相対パスを指定
COPY index.html index.html
# RUN で、docker イメージを作っている最中に実行するシェルコマンド
# 次のコマンドで、Linux のパッケージマネージャー apt をアップデートしたら、curl コマンドをインストール
RUN apt update && apt install -y curl
Dockerfile からイメージを作成する(docker build)
–tag で新しく作られるイメージの名前を指定する。
$ docker build --tag イメージ名 Dockerfileがあるディレクトリパス
$ docker build --tag my_image .
作成したイメージからコンテナを起動
$ docker run -d -p 8080:80 --name my_container my_image
Dockerfile
Dockerfile とは
Dockerfile は docker イメージの設計書。ダウンロードした docker イメージをそのまま使うのではなく、ライブラリなどのパッケージを追加して自分専用のイメージを作成したい場合にこのファイルを使用する。作成の元になる docker イメージを指定し、それに対して追加する内容を記述する。
Dockerfile の書き方
# FROM で基になるイメージを指定(latest は最新のもの)
FROM nginx:latest
# WORKDIR でコンテナが起動したときのコマンドを開始する位置を指定
WORKDIR /usr/share/nginx/html
# COPY でホストからコンテナにファイルをコピー(--volume と同じ)。
# 左側がホスト、右側がコンテナ
# ホストはカレントディレクトリに対する相対パス、コンテナは WORKDIR に対する相対パスを指定
COPY index.html index.html
# RUN で、docker イメージを作っている最中に実行するシェルコマンド
# 次のコマンドで、Linux のパッケージマネージャー apt をアップデートしたら、curl コマンドをインストール
RUN apt update && apt install -y curl
その他に、環境変数を設定する ENV
ENV env_key env_value
コンテナが起動したときに最初に実行するコマンドを指定する CMD
CMD ["nginx", "-g", "daemon", "off"]
などがある。
Docker-Compose
Docker-Compose とは
Nginx コンテナの他に Node コンテナも起動したい場合など、複数のコンテナを起動する場合は、それぞれ Docker run するのは煩わしい。
そのような場合は、Docker-Compose を使用すると複数のコンテナを一括で管理できる。Docker-Compose による複数コンテナの管理には、YAML 形式のファイルを使用する。
Docker-Compose は複数のコンテナを管理するためのものだが、単独の docker コンテナを管理するためにも使用することができる。コンテナの操作を YAML に記述しておけば、Git にコミットできるという利点もある。
YAML とは
YAML は、JSON と同様に、構造化されたデータを表すためのフォーマットのこと。インデント(字下げ)を使って、データの階層構造を表す。
YAML は基本的には Key-Value ペアのマップになっていて、行頭が「-(ハイフン」で始まるものだけがリスト(配列)を表す。
Docker run を Docker-Compose の YAML ファイルに記述する
$ docker run -d --name nginx\
--env env_key=env_value \
-p 80:80 \
--volume $(pwd):/usr/share/nginx/html \
nginx
という docker run コマンドは次のような YAML で記述できる。
version: 3.7
services:
nginx:
image: nginx:latest
container_name: nginx
environment:
- env_key=env_value
ports:
- "80:80"
volumes:
- $(pwd):/usr/share/nginx/html
Docker-compose コマンド
YAML に定義されたコンテナサービスを起動する(up)
$ docker-compose --file docker-compose.yaml up
–file オプションは -f でもよい。また -d(–detach)を付けるとコンテナがバックグランドで起動する。
YAML に定義されたコンテナサービスを停止し、削除する(down)
$ docker-compose -f docker-compose.yaml down
複数のコンテナのログをまとめて表示する(logs)
–follow オプション(-f)を付けるとリアルタイムで表示する。付けないとその時点のログを出力する。
$ docker-compose -f docker-compose.yaml logs --follow
Docker-Compose でコンテナのレプリカ(複製)を複数起動する
YAML を変更する(複数のレプリカで重複を避ける)
YAML の次の点を変更する。
- コンテナ名が重複するのを防ぐために、container_name を削除する。これにより自動で名前が付けられるようになる。
- ポート番号が重複するのを防ぐため、ホスト側のポートをレンジ(幅を持たせて)で指定する。
変更前
version: 3.7
services:
nginx:
image: nginx:latest
container_name: nginx
environment:
- env_key=env_value
ports:
- "80:80"
volumes:
- $(pwd):/usr/share/nginx/html:ro
変更後
version: 3.7
services:
nginx:
image: nginx:latest
environment:
- env_key=env_value
ports:
- "80-85:80"
volumes:
- $(pwd):/usr/share/nginx/html
レプリカ数を指定してコンテナサービスを起動する(up –scale)
up コマンド実行時に、–scale オプションでレプリカ数を指定する。
$ docker-compose -f docker-compose.yaml up --scale nginx=3
このようにすると、nginx コンテナが3つ起動される。
Docker-Compose で起動されたコンテナ同士で通信する
Docker-Compose で起動されたコンテナ同士はデフォルトで通信ができるようになっている。また Docker-Compose で起動されていない(つまり YAML 外の)コンテナとは通信できない。
docker-compose.yaml
version: "3.7"
services:
nginx:
image: nginx:latest
container_name: docker_compose_nginx
environment:
- env_key=env_value
ports:
- "80:80"
volumes:
- ${PWD}:/usr/share/nginx/html:ro
ubuntu:
image: ubuntu
container_name: docker_compose_ubuntu
command: ["sleep", "1500"]
ports:
- "8080:8080"
docker-compose up で起動する。
$ docker-compose -f docker-compose.yaml up -d
ubuntu コンテナに入って、nginx コンテナに curl してみる。docker-compose で起動されたコンテナ同士は名前で通信できる。
$ docker exec -it docker_compose_ubuntu bash
$ apt update && apt install -y curl
$ curl docker_compose_nginx:80
これで nginx の /usr/share/nginx/html/index.html が取得できれば通信成功。