【入門】Docker とは?基本コマンドや Dockerfile の使い方

Docker

Docker とは、指定した OS やソフトウェアを持つ環境(=コンテナ)で、指定したコマンドの実行結果を再現するソフトウェアです。

左: 「指定した環境 = CentOS」・「実行するコマンド = ls」
右: 「指定した環境 = ubuntu」・「実行するコマンド = Nginx (Web サーバー) を起動するコマンド」
スポンサーリンク

初めに

本記事はコンテナ環境構築シリーズの Docker 編となります。

他のシリーズについては、以下の記事をご覧ください。

スポンサーリンク

Docker の利点・使いどころ

Docker を利用する利点は主に次の4つです。

環境の移行が容易

Docker では、次の2つを Dockerfile と呼ばれるファイル形式で保存することができます。

  • 「OS やインストールしているパッケージなどを指定した環境(=コンテナ)」
  • 「実行するコマンド」

そのため、Dockerfile ファイルを渡すだけで、他のコンピュータに環境を移行できます。
「A さんの PC では動くが、 B さんの PC では動かない」という状況を回避できます。

複数のホストを用意するのが容易

ロードバランサーやクラスターの検証をする場合、複数のサーバー必要です。

一方で、1つのサーバーに複数のコンテナを作成することで、この問題を解決できます。

以下の記事では、「ロードバランサー」+「Web サーバー3台」の合計4つのコンテナを1つのサーバーで稼働させる方法を紹介しています。

パッケージの競合を回避

次の依存関係がある場合、どちらかのパッケージがインストールできません。

しかし Docker では、OS やインストールしているパッケージなどを指定した環境(=コンテナ)を分けることでパッケージの競合を回避可能です。

スポンサーリンク

Docker をインストール

Docker を利用するために、まずはインストールをします。

  1. Docker をインストール
    1. sudo amazon-linux-extras install docker -y
    2. Install Docker Engine
      Lists the installation methods
  2. sudo systemctl start docker
  3. docker --version
    Docker version 19.03.13-ce, build 4484c46
  4. sudo usermod -a -G docker `whoami`
    exit

Docker の使い方

Docker イメージの取得 pull

Docker コンテナは、Docker イメージと呼ばれるものから作成します。

リポジトリから Docker イメージを取得する方法は以下のとおりです。

docker pull <コンテナリポジトリ>:<コンテナタグ>

例えば、リポジトリから CentOS8 の Docker イメージを取得する場合は以下のコマンドとなります。

docker pull centos:centos8

Docker イメージの一覧 images

Docker イメージの一覧を表示します。

docker images
REPOSITORY                            TAG                 IMAGE ID            CREATED             SIZE
centos                                centos8             300e315adb2f        4 weeks ago         209MB

コンテナでコマンドを実行 run

docker run <コンテナリポジトリ>:<コンテナタグ> <実行するコマンド>
docker run centos:centos8 ls
bin
dev
etc
home
lib
(中略)
var

ls コマンドが実行できたことがわかります。

コンテナの一覧 ps

docker ps -a
CONTAINER ID        IMAGE                                       COMMAND                  CREATED             STATUS                     PORTS                  NAMES
ff53e74d2aec        centos:centos8                              "ls"                     3 minutes ago       Exited (0) 3 minutes ago                          upbeat_bardeen

ls コマンドの実行が完了し、終了(Exited)したコンテナを確認できます。

コンテナを削除 rm

終了している Docker コンテナを削除します。

docker rm <CONTAINER ID もしくは NAMES>

コンテナ終了時に自動削除 --rm

終了したコンテナを毎回削除するのは手間なので、コンテナ起動時 (docker run) のオプションで、コンテナ終了時に自動削除するように設定します。

docker run --rm centos:centos8 ls
bin
dev
etc
home
lib
(中略)
var
docker ps -a

停止したコンテナが削除されていることが確認できます。

コンテナの中に入る -it bash

bash コマンドの標準入力と標準出力をホスト側に変更することで、ホストから Docker コンテナに入ったかのように操作できます。

docker run --rm -it centos:centos8 bash
ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
exit

バックグラウンドで実行 -d

docker run --rm -dit centos:centos8 bash
docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
03e96e9e13a8        centos:centos8      "bash"              55 seconds ago      Up 54 seconds                           nifty_kilby

コンテナの実行中のプロセスを表示 container top

docker container top <CONTAINER ID もしくは NAMES>
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                5564                5521                0                   12:18               pts/0               00:00:00            bash

実行中のコンテナで新しくコマンドを実行 exec

実行中のコンテナに対して、bash コマンドを実行してみます。

docker exec -it <CONTAINER ID もしくは NAMES> bash
exit

コンテナを終了する stop

docker stop <CONTAINER ID もしくは NAMES>

コンテナに名前をつける --name

そろそろ毎回 CONTAINER ID を調べるのがめんどくさくなってきた頃でしょうか。

そんな時はコンテナに名前をつけましょう。

docker run --name centos --rm -dit centos:centos8 bash
docker ps -a
CONTAINER ID   IMAGE            COMMAND   CREATED         STATUS     NAMES
0f1d8d7f52b9   centos:centos8   "bash"    3 seconds ago   Up 2 seconds     centos

NAMES が centos になっていることがわかります。

docker stop centos

コンテナのポートをホスト側に公開 -p

「ホスト側の 8080 ポート」と「コンテナの 80 ポート」を紐付けます。

docker run --name nginx --rm -d -p 8080:80 nginx
curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

無事、ホスト側の 8080 ポートを利用して、nginx コンテナの 80 ポートにアクセスできました。

docker stop nginx

Docker イメージを削除 rmi

docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    12766a6745ee   5 days ago     142MB
centos       centos8   5d0da3dc9764   6 months ago   231MB
docker rmi nginx
docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
centos       centos8   5d0da3dc9764   6 months ago   231MB

コンテナにデータ・ボリュームを追加 -v

データ・ボリュームは主に以下の用途で利用します。

  • コンテナ自身を削除しても、データ・ボリュームは残り続けます。(永続化)
  • データ・ボリュームはコンテナ間で共有・再利用できます。
  • データ・ボリュームとしてホストのボリュームをコンテナにマウントできます。

データ・ボリュームのマウントには以下の3つが存在します。

https://matsuand.github.io/docs.docker.jp.onthefly/storage/

「名前付きボリューム」をデータ・ボリュームとしてマウント

名前付きボリュームは、オプション v の値をアルファベット文字「a-z0-9, "_", "." , "-"」で開始します。

名前 を指定する場合は、Docker は、その 名前 を持つボリュームを作成します。

名前 は英数字で始まる必要があり、以降は a-z0-9 、_ (アンダースコア)、 . (ピリオド)、 - (ハイフン)が使えます

https://docs.docker.jp/engine/reference/run.html#run-volume

以下に、名前付きボリューム「volume」をデータ・ボリュームとしてマウントする例を示します。

docker run --name test1 --rm -v volume:/hoge centos:centos8 touch /hoge/test.txt
docker run --name test2 --rm -v volume:/hoge centos:centos8 ls /hoge/test.txt
test.txt

test1 コンテナの /hoge が永続化されていたり、test2 コンテナで共有・再利用しています。

なお、名前付きボリュームは、Docker が管理するストレージエリアに保存されます。
(ホスト側の /var/lib/docker/volumes/)

sudo ls /var/lib/docker/volumes/volume/_data
test.txt

「ホスト側のパス」をデータ・ボリュームとしてバインドマウント

ホスト側のパスは、オプション v の値を「/」で開始します。

ホスト側ディレクトリ に絶対パスを指定すると、 Docker は指定したパスをバインド・マウントします。

絶対パスは / (フォアワード・スラッシュ)で始める必要があります。

https://docs.docker.jp/engine/reference/run.html#run-volume

以下に、ホスト側のパス「/tmp」をデータ・ボリュームとしてマウントする例を示します。

echo host_side > /tmp/test.txt
docker run --rm -v /tmp:/hoge centos:centos8 cat /hoge/test.txt
host_side

ホスト側のボリューム /tmp/test.txt を、コンテナ側にデータ・ボリューム /hoge/test.txt としてバインドマウントできていることが確認できます。

ボリューム一覧を確認 volume ls

ホスト側で Docker が管理するストレージエリア /var/lib/docker/volumes/ に保存されたボリューム一覧を表示します。

docker volume ls
DRIVER    VOLUME NAME
local     volume

先ほど作成した volume という名前のボリュームが確認できます。

一括削除 system prune

以下のオブジェクトを一括削除します。

  • 終了したコンテナ
  • タグ無しイメージ (オプション -a で使われてないイメージも削除)
  • 未使用ボリューム (オプション --volumes が必要)
  • 未使用ネットワーク
docker system prune -a
Are you sure you want to continue? [y/N] y # y を押すと一括削除されます。
docker volume ls
DRIVER    VOLUME NAME

先ほど確認したボリュームは全て削除されていることが確認できます。

コンテナ、イメージ、ボリューム、ネットワークを別々に一括削除する場合は以下のとおりです。

終了したコンテナの一括削除

docker container prune

タグ無しイメージの一括削除

docker image prune

未使用ボリュームの一括削除

docker volume prune

未使用ネットワークの一括削除

docker network prune

Dockerfile: Dockerイメージを作成

Dockerfile は ベースとなる Docker イメージから、新しい Docker イメージを作成する命令を記載したファイルです。

1回だけ環境構築する場合は docker exec *** でも良いですが、同じ環境を何度も構築する場合は Dockerfile に命令を書いてしまいましょう。2回目以降は Dockerfile を使いまわして環境構築できます。

Dockerfile で利用可能な命令一覧

Dockerfile で利用可能な命令の一覧は以下のとおりです。

命令説明
FROMベースイメージを設定
RUNベースイメージで実行するコマンドを指定(新しいDocker イメージの作成)
CMDコンテナの実行時のデフォルトで実行するコマンドを設定
LABELイメージにラベル(メタデータ)を追加
EXPOSEコンテナ実行時にリッスンするポートを指定
ENV環境変数を設定
ADDローカルホストからイメージへファイルを追加
COPYローカルホストからイメージへファイルをコピー
ENTRYPOINTコンテナを実行モジュールとして実行するように設定
VOLUMEマウントポイントを生成
USERRUN, CMD, ENTRYPOINT を実行するユーザーを指定
WORKDIRワークディレクトリを指定
ARGビルド時の引数を指定
ONBUILDイメージに対してトリガーを追加
STOPSIGNALコンテナが終了する時に送信するシステムコールシグナルを追加
HEALTHCHECKコンテナのヘルスチェック方法を指定
SHELLデフォルトのシェルを指定

ADD と COPY の違い

基本的に COPY を使っておきましょう。COPY でやりたいことが出来ない場合は ADD の利用を検討します。

Although ADD and COPY are functionally similar, generally speaking, COPY is preferred. That’s because it’s more transparent than ADD. COPY only supports the basic copying of local files into the container, while ADD has some features (like local-only tar extraction and remote URL support) that are not immediately obvious. Consequently, the best use for ADD is local tar file auto-extraction into the image, as in ADD rootfs.tar.xz /.

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#add-or-copy

CMD と ENTRYPOINT の違い

CMDENTRYPOINT
目的コンテナ実行時のデフォルトのコマンドを指定コンテナ実行時のコマンドを固定
docker run <コマンド>コマンドの上書き可能コマンドの上書き可能

例: Dockerfile で nginx の Docker イメージを作成

Dockerfile を理解するために、CentOS8 の Docker イメージから以下のような nginx の Docker イメージを作成してみます。

nginx の Docker イメージ

Dockerfile を作成

vim Dockerfile
FROM centos:centos8
RUN yum install nginx -y

EXPOSE 80
CMD /usr/sbin/nginx -g 'daemon off;'

Dockerfile から Docker イメージを作成

docker build -t test:1.0 -f Dockerfile .

Nginx の Docker イメージから Docker コンテナを作成し、アクセス

docker run --rm -d -p 8080:80 test:1.0
curl localhost:8080
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
        <title>Test Page for the Nginx HTTP Server on Red Hat Enterprise Linux</title>

無事に Dockerfile から Nginx をインストールした Docker イメージを作成可能なことを確認できました。

docker-compose: 複数のコンテナを実行

docker-compose は、複数のコンテナを一気に起動するためのファイルです。

docker-compose で利用可能な命令一覧は以下のとおりです。

Compose ファイル version 3 リファレンス — Docker-docs-ja 20.10 ドキュメント

docker-compose: インストール

Linux 系で docker-compose をインストール

sudo curl -L https://github.com/docker/compose/releases/download/v2.4.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
docker-compose version 2.4.1, build 6d1ac21

Linux 系以外で docker-compose をインストール

以下のドキュメントに従ってインストールしてください。

Docker Compose のインストール — Docker-docs-ja 19.03 ドキュメント

docker-compose: 使い方

先程自作した Nginx と、公式の Nginx の2つの Docker イメージを利用して、2つのコンテナを起動する docker-compose を作成します。

docker-compose.yml ファイルの作成

vim docker-compose.yml
version: '3'

services:
  my_nginx:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:80"
 
  official_nginx:
    image: nginx
    ports:
      - "8081:80"

Compose ファイル (docker-compose.yml) の書き方は以下のとおりです。

Compose ファイル version 3 リファレンス — Docker-docs-ja 20.10 ドキュメント

docker-compose で複数コンテナを一括起動

docker-compose up -d
docker ps -a
CONTAINER ID        IMAGE                                       COMMAND                  CREATED             STATUS                    PORTS                  NAMES
a2acd90e276f nginx "nginx -g 'daemon of…" 6 minutes ago Up 6 minutes 0.0.0.0:8081->80/tcp http_official_nginx_1 f7cc5a4d0c56 http_my_nginx "/bin/sh -c '/usr/sb…" 6 minutes ago Up 6 minutes 0.0.0.0:8080->80/tcp http_my_nginx_1

自作した Nginx と、公式の Nginx の2つのコンテナが起動していることが確認できます。

また、それぞれのコンテナにアクセス可能なことも確認できます。

curl localhost:8080
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
        <title>Test Page for the Nginx HTTP Server on Red Hat Enterprise Linux</title>
curl localhost:8081
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

docker-compose でコンテナ群を一括終了

docker-compose down
docker ps -a

補足事項:名前付きボリューム

個人的にハマったのでメモ書きとして置いておきます。

名前付きボリュームを使うには、以下にあるようにトップレベルの volumes キーに記述する必要があります。

https://docs.docker.jp/compose/compose-file/compose-file-v3.html#volumes

つまり、以下のような記載をすると次のようなエラーが発生します。

version: "3"
services:
  web:
    image: nginx:alpine
    volumes:
      - html:/usr/share/nginx/html/
    ports:
      - "80:80"
ERROR: Named volume "html:/usr/share/nginx/html:rw" is used in service "web" but no declaration was found in the volumes section.

正しい記載は以下です。(docker run -v の名前付きボリュームの作成方法と異なります。)

version: "3"
services:
  web:
    image: nginx:alpine
    volumes:
      - html:/usr/share/nginx/html/
    ports:
      - "80:80"

volumes:
  html:

関連記事

コンテナ環境構築シリーズの記事は以下のとおりです。


参考記事

公式ドキュメント

Docker Documentation
Home page for Docker's documentation

Docker 日本語ドキュメント(有志による翻訳)

Docker ドキュメント日本語化プロジェクト — Docker-docs-ja 19.03 ドキュメント

Docker で検索すると一番上に出てくる Qiita の記事

いまさらだけどDockerに入門したので分かりやすくまとめてみた - Qiita
はじめに 今更ながらDockerに入門したのでまとめます。 全てのコマンドの細かいオプションとかまではやりません。 Dockerコマンド体系はv1.13以降の新系です。 ここではクラスタ管理(KubernetesやSwarm)に...