はじめに
ずっと Docker 使ってみたいなと思いつつ使う機会がないまま・・・ついに今年1月に使う機会がやってきました!
その時に書いたメモなどを元に、「こんな記事があったら嬉しかった」と思える記事にまとめてみました。
この記事の対象読者は
- コマンドライン操作が行える
- Linuxを扱ったことがある
- ファイルシステムやポート番号が何のことか分かる
- 仮想マシンが何だか分かる
を想定しています。
記事は以下に分けて投稿する予定です。
- dockerコマンド編(この記事)
- Dockerfile編
- Dockerの仕組み編
- docker-compose編
Docker の利点を活かした使い方は3つ目以降で説明します。
筆者は Docker for Mac を使って試しています。
Windows の場合も基本的な考え方や docker コマンドの使い方は同じですが、Docker for Windows を利用していてコマンドプロンプトで操作する場合は、記事中の Unix コマンドは適宜 DOS コマンドに置き換えてください(それかコマンドを使わずに GUI で作業してください)。
この記事の目標
シリーズ最初のこの記事では Docker を単なる「軽量な Linux 仮想マシン」を動かす環境と捉えて説明します。
- サーバーと同じような開発環境を用意したい
- ちょっと試したいサーバーアプリがあるけど、システムに直接インストールしたくない
- Mac や Windows じゃ動作しない Linux プログラムを動かしたい
などなど、Linux 仮想マシンを使いたい場合に Docker を利用できるようになることを目指します。
そのために基本的な docker
コマンドの使い方を覚えます。
Dockerのインストール
Download Docker Community Editionからダウンロードしましょう。
Mac の場合は Docker for Mac をインストールするだけです。
Windows の場合も Windows 10 以上かつ Home でなければ Docker for Windows をインストールするだけです。
もし Windows 10 Home などで Docker for Windows を利用できない場合は、
- 64bit
- Windows 7以降
- 仮想化支援技術(IntelならVT-x, AMDならAMD-v)がCPUでサポートされている
- BIOSで上記仮想化支援機能(Virtualization)を有効にしている
の条件が満たされていれば Docker Toolbox が利用できます。"docker toolbox インストール" でググれば情報が色々出てくるかと思います。
Linux の場合もディストリビューションごとに用意されています。公式でなくともコミュニティによってパッケージが提供されているはずです。
Docker for Mac は起動するとメニューバー右上のステータスメニューに鯨のアイコンが表示されます。
これの Preferences で設定を行えます。Windowsも同様の設定があると思います。Linuxでは必要ありません(理由は後の記事で分かります)。
CPU数やメモリ使用量を最低限にして、使う時だけ起動する場合は以下のようにします。
- General - Start Docker when you log in を OFF
- Advanced - CPUs を 1 に
- Advanced - Memory を 1.0 GB に
Docker をしっかり活用するようになったら適宜変更してください。
以下のコマンドで docker のバージョンを確認できます。--version
だと簡易確認、version
だと詳細確認。
注: docker
コマンドは Docker が起動していないと動作しません。
$ docker --version
Docker version 18.03.1-ce, build 9ee9f40
$ docker version
Client:
Version: 18.03.1-ce
API version: 1.37
Go version: go1.9.5
Git commit: 9ee9f40
Built: Thu Apr 26 07:13:02 2018
OS/Arch: darwin/amd64
Experimental: false
Orchestrator: swarm
Server:
Engine:
Version: 18.03.1-ce
API version: 1.37 (minimum version 1.12)
Go version: go1.9.5
Git commit: 9ee9f40
Built: Thu Apr 26 07:22:38 2018
OS/Arch: linux/amd64
Experimental: true
docker info
で動作状況を確認できます。試してみてください。
用語の理解
とりあえず現時点での理解はこんな感じで。
ホスト
Docker を動かしている環境のことです。あなたがこの記事の内容を試すために使っている自分の PC であり、その上で動いている macOS や Windows などのことですね。
Docker
とりあえずこの記事を読んで作業するには、どうやって実現されているかは置いておいて、「CPUやメモリのオーバーヘッドが少ない、超軽量な仮想マシンを作って動かせるもの」と理解しておけばオッケー。
ただし 仮想マシンの OS には Linux しか利用できません 。
コンテナ
1つの Linux 仮想マシンと思っておけばいいです。
イメージ
コンテナを生成する元になるもの。
同じイメージを使えば、同じ Linux ディストリビューションで同じアプリケーションがインストールされた全く同じ環境を複製することができます。
「OS丸ごとディスク全体をバックアップしたもの」と思ってください。
Docker Hub
あらかじめよく使われる便利なイメージが登録されています。
ここからイメージを取得して、それをベースに改造する形を取るのが一般的な利用方法になります。
取得可能なイメージは Explore Official Repositories で検索できます。
利用の流れ
必ずしも毎回この通りじゃないけど、大雑把に利用の流れを掴むために以下の順に解説します。
- Docker Hub のイメージを検索 (search)
- Docker Hub から使いたいイメージを取得する (pull)
- イメージからコンテナを生成して起動 (run)
- コンテナ内でコマンド実行 (exec)
- コンテナを停止 (stop)
- コンテナをイメージ化 (commit)
- いらなくなったらコンテナを削除 (rm)
- いらなくなったらイメージを削除 (rmi)
その他に以下のコマンドもよく利用します。
- 取得済みイメージ一覧 (images)
- 実行中コンテナ一覧 (ps)
- 停止中も含めた全てのコンテナ一覧 (ps -a)
- 停止中のコンテナを起動 (start)
- ホストとコンテナ間でのファイルコピー (cp)
run は 生成して起動 だということに注意。色々作業して改変した後の状態で起動したいなら、
- start を使う
- commit してイメージ化したものから run
のどちらかを使います。
今はよく分からなくても、これから手を動かして作業しながら理解していきましょう。
また Docker Hub のアカウントを持っていると、自分の作成したイメージを Docker Hub に push
することもできます。
今回の記事では push
は対象外です。
チュートリアル
nginx のイメージを利用して Web サーバーを立ててみます。
イメージを取得する
公式が提供している nginx イメージ(何らかの Linux ディストリビューションをベースにして nginx が動作する設定にしてあるもの)があるのでそれを利用しましょう。
search コマンドで Docker Hub にあるイメージを検索してみると・・・
$ docker search nginx
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 7722 [OK]
jwilder/nginx-proxy Automated Nginx reverse proxy for docker con… 1233 [OK]
richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable of… 500 [OK]
jrcs/letsencrypt-nginx-proxy-companion LetsEncrypt container to use with nginx as p… 288 [OK]
kong Open-source Microservice & API Management la… 150 [OK]
webdevops/php-nginx Nginx with PHP-FPM 94 [OK]
(略)
一番上にある Official build of nginx というのを使います。名前は nginx です。
なお search の使い方は docker searchコマンドの使い方(実例付) が参考になります。
イメージを Docker Hub から取得してみます。
$ docker pull nginx
取得済みイメージの一覧は以下で確認できます。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 3f8a4339aadd 2 weeks ago 108MB
コンテナを生成して起動する
nginx のログを出力する nginx/log
ディレクトリをホスト側に作成しておきましょう。
$ mkdir -p nginx/log
生成と起動を一度に行う run コマンドを利用します。
$ docker run -d -p 80:80 -v $(pwd)/nginx/log:/var/log/nginx --name webserver nginx
-d
はバックグラウンド実行することを指定しています。コマンド実行後にコンテナIDが表示されます。
-d
を付け忘れて実行するとコマンド入力が行えなくなります。その場合は慌てずに別ターミナルを立ち上げて作業しましょう。後述するコンテナの停止を行えば元のターミナルもまた入力できるようになります。
-p 80:80
はホスト側の80番ポートをコンテナ側の80番ポートに転送するように指定しています。-p 8080:80
と指定すれば http://localhost:8080 でアクセスできるようになります。
-v $(pwd)/nginx/log:/var/log/nginx
はホストのディレクトリ($(pwd)/nginx/log
)をコンテナのディレクトリ(/var/log/nginx
)としてマウントします。
ホスト側のディレクトリも絶対パスで指定する 必要があります。
$(pwd)
の部分はカレントディレクトリに置き換えられます(これは Unix シェルの機能です)。
このような -v
でマウントするものを ボリューム と言います。v は volume の頭文字です。
--name webserver
は生成するコンテナに名前をつけます。名前をつけずにコンテナIDを利用することもできますが、指定するのが面倒なので名前をつけた方が作業しやすいです。
最後に指定している nginx
が生成に利用するイメージの名前です。
本当は最後(イメージ名の後)に実行するコマンドを指定する のですが、nginx のイメージはデフォルトで nginx を起動するコマンドが実行されるようになっているため必要ありません。
以下に概念図を示します(カレントディレクトリが /Users/myname/Documents と仮定しています)。
これでホスト側でブラウザを立ち上げて
にアクセスすれば、"Welcome to nginx!" のページが表示されるはずです。
nginx はアクセスログを /var/log/nginx/access.log
に出力する設定になっています。
ホスト側の ~/nginx/log
をコンテナ側の /var/log/nginx
にマウントしましたので、以下でアクセスログを確認できます。
$ cat nginx/log/access.log
Docker ではコンテナを毎回削除するような使い方が好まれます(run の時に指定した内容は後から変更できないし・・・)。
コンテナを削除すると起動後に作成されたコンテナ内のファイルは消えてしまう (PC捨てたらバックアップ取っとかない限り搭載されてるHDDの内容ごと捨てられるのは当たり前ですよね?)ので、データの保存場所は -v
で別に指定しておくのがよくやる使い方になります。
ホスト側のディレクトリをマウントしてもいいし、名前付きボリュームを指定する方法もありますがそれは後述。
コンテナ内で作業する
このコンテナのコマンドラインで作業してみましょう。
$ docker exec -it webserver /bin/bash
root@1f99d8d3072d:/#
exec
は指定したコンテナで指定したコマンドを実行します。
-it
はコンテナ側のコマンドの入出力を手元のターミナルに接続します。
webserver
がコンテナの名前です。
/bin/bash
が実行するコマンドです。
root でログインした状態でコマンドプロンプトが表示されます。
apt コマンドが使えるので nginx イメージは debian 系みたいですね。
Docker は CPU とメモリのオーバーヘッドは小さいけれど、ディスクサイズは増えるので、目的のプロセスを動作させるのに最低限のシステムにするのが好ましいです。最近は Alpine Linux がよく使われます。
Alpine Linux ベースだと bash が入っていなかったりするので、その場合は /bin/sh を指定 します。
これで設定ファイルを変更したりといった様々な作業を行うことができます。
exec
で接続した場合は、exit
してもコンテナは起動したまま になります。
え?当たり前じゃんって思いますか? ところが run
の時にシェルを実行して exit
した場合は、コンテナは停止します。
root@1f99d8d3072d:/# exit
実行中のコンテナ一覧を表示すると、ちゃんと実行されているのが確認できます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f99d8d3072d nginx "nginx -g 'daemon of…" 17 minutes ago Up 17 minutes 0.0.0.0:80->80/tcp webserver
-it
は手元のシェルに入出力を繋ぐために指定していますが、単に何かコマンドを実行するだけで結果表示すらいらないなら指定しなくてもいいです。
$ docker exec webserver ls /etc/nginx
conf.d
fastcgi_params
koi-utf
koi-win
mime.types
modules
nginx.conf
scgi_params
uwsgi_params
win-utf
docker cp
を使ってホスト側にファイルをコピーしてみましょう。
$ docker cp webserver:/etc/nginx/nginx.conf .
webserver:/etc/nginx/nginx.conf
が「どのコンテナの」「どのファイルか」を指定しています。
その後にホスト側のどこにコピーするかを指定します。上記では .
でカレントディレクトリを指定してます。
コンテナを停止する
停止するには stop
を使います。シャットダウンして電源を切ると思ってもらえればいいかと。
$ docker stop webserver
ps
で実行中のコンテナを確認してみると、表示されなくなっています。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ps -a
で停止中のものも含めて全て表示すれば見つかります。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f99d8d3072d nginx "nginx -g 'daemon of…" 44 minutes ago Exited (0) 20 seconds ago webserver
コンテナをイメージ化
何か色々設定した後のものをイメージ化するには commit
コマンドを使います。
イメージの命名規則は以下です。
<Docker Hubのユーザ名>/イメージ名:[タグ名]
タグ名は自分が分かりやすい名前を付ければいいです。公開されているものは大抵はバージョン番号になっています。
今回は Docker Hub に push
しないので、ユーザー名は省略します。
なお一応コンテナを停止していなくても作成できます。
$ docker commit webserver webserver:0.0
イメージが作成されたか確認してみましょう。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver 0.0 943dcf35eaf4 7 seconds ago 108MB
nginx latest 3f8a4339aadd 2 weeks ago 108MB
注意点としては -v
で指定したボリュームは commit
でのイメージ化の対象外 になります。
ボリュームは外付けハードディスクやネットワークドライブ的なもので、commit
は内臓ハードディスクしかバックアップしないと考えると分かりやすいかと思います。
コンテナを起動する
run
を実行してしまうと新しくコンテナを作成してしまいます。
停止している既存のコンテナを起動するには start
を使います。
$ docker start webserver
実行中のコンテナを確認してみましょう。ちゃんと起動していますね。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f99d8d3072d nginx "nginx -g 'daemon of…" 2 hours ago Up 4 seconds 0.0.0.0:80->80/tcp webserver
コンテナを削除する
起動しているコンテナを停止します(シャットダウン)。
停止しないでいきなり削除もできますが・・・。
$ docker stop webserver
コンテナを削除します(マシンを廃棄)。
$ docker rm webserver
全てのコンテナを表示して削除されたか確認してみます。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
イメージを削除する
いらなくなったイメージを削除してみましょう。
コンテナの削除が rm
に対してイメージの削除は rmi
を利用します。混同しやすいので注意してください。
タグを省略すると latest
指定と同じになります。
$ docker rmi webserver:0.0
$ docker rmi nginx
削除されたか確認してみます。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
おまけ
privileged モード
CentoOS でサーバーと同じ開発環境を整えようとして躓いたので previleged モードについて書いておきます。
systemd を利用するディストリビューションでは、privileged モードを指定して run
しないと sytemctl
コマンドが実行できません。
参考: Docker privileged オプションについて
参考: Dockerで立ち上げたCentOSでsystemctlを使うとFailed to get D-Bus connection: Operation not permittedと出る
また centos のイメージからコンテナを作った場合、/sbin/init
を実行すると普通に起動したのと同じような感じに扱えます。
(nginx イメージは nginx を起動するコマンドが実行されるように設定されているため、コマンドを指定する必要はありませんでした)
$ docker run -d --name mycentos --privileged centos /sbin/init
この記事では「軽量な Linux 仮想マシン」として扱う想定ですので、このような使い方を紹介しておきます。
続編の記事で解説しますが、実際には Docker の文化(利点を活かした使い方)では、1つのコンテナで1つのアプリケーションしか実行しないため、systemd を使わずに(nginx イメージのように)直接目的のサービスを実行する設定にするのが普通です。
名前付きボリューム
run
の時に -v で指定するものを ボリューム と呼ぶと前述しました。
ホスト側のディレクトリと同期する方法が良く用いられますが、Docker が管理する 名前付きボリューム を使う方法もあります。
$ docker run -d -p 80:80 -v webserver_log:/var/log/nginx --name webserver nginx
これで webserver_log
という名前付きボリュームがコンテナ側の /var/log/nginx
にマウントされ、そこにログが出力されます。
名前付きボリュームはコンテナを削除しても残ります。
仮想外付けハードディスクと思ってもらえばいいです。ただしコンテナ作成時にしか接続できないので「リムーバブル」じゃないですけど。
以下に名前付きボリュームも加えた Docker の概念図を示します。
名前付きボリュームの一覧は
$ docker volume ls
DRIVER VOLUME NAME
local webserver_log
で見ることができます。
削除するのは以下で。
$ docker volume rm webserver_log
実は今までのコマンドは省略形?
docker --help
で用意されているコマンドをみると、Management Commands というのがあります。
$ docker --help
(略)
Management Commands:
checkpoint Manage checkpoints
config Manage Docker configs
container Manage containers
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes
Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
(略)
実は既に docker volume ls
や docker volume rm
で Management Commands は利用しています。
自分は基本的に Commands: に記載されているコマンドを使って作業していますが(楽なので)、もっと複雑なことをやる人や、どんなコマンドがあるのか --help
をつけて確認する場合は、これらの Management Commands を使うと良いのではないでしょうか。
Docker 本家の Get Started でも Management Commands を使って解説されています。
Commands利用 | Management Commands利用 |
---|---|
docker pull | docker image pull |
docker images | docker image ls |
docker rmi | docker image rm |
docker ps | docker container ls |
docker ps -a | docker container ls --all |
docker rm | docker container rm |
docker commit | docker container commit |
docker run | docker container run |
docker start | docker container start |
docker stop | docker container stop |
このように「何に対する操作なのか」が体系的にまとまっていて、コマンド入力は面倒ですが分かりやすいです。
docker image --help
で表示してみると、イメージに対する操作コマンドは以下があるようです。
使ってないイメージを削除してくれる prune
とか便利そうです。
$ docker image --help
Usage: docker image COMMAND
Manage images
Options:
Commands:
build Build an image from a Dockerfile
history Show the history of an image
import Import the contents from a tarball to create a filesystem image
inspect Display detailed information on one or more images
load Load an image from a tar archive or STDIN
ls List images
prune Remove unused images
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rm Remove one or more images
save Save one or more images to a tar archive (streamed to STDOUT by default)
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
Run 'docker image COMMAND --help' for more information on a command.
まとめ
Docker を「Linuxしか使えない軽量な仮想マシン」を動作させる環境として捉え、そのための docker
コマンドの使い方を学びました。
この記事の内容だけでも、Linux仮想マシンが欲しくなった時に Docker を利用できると思います。
この次は?
コンテナを作ったらあれこれインストールしたり設定を変更したりするかと思います。
作業後に commit
してイメージとして保存してもいいんですが、それらの作業内容を Dockerfile に記載してテキスト化しておくと管理しやすいです。
次は Dockerfile の記述方法と、Dockerfile からイメージをビルドする方法について説明する予定です。