Dockerを学ぶ際に最低限覚えておけば良いこと

相当今更ですが、最近Dockerを学習してます。
Dockerって結局仮想マシンみたいなことをもっと簡単に実現しようって感じのものだと思うんですが、解説サイトを見ると技術的な難しい話から入ってることが多くて最初なかなか理解出来なくて苦労しました。自分の理解力不足もありますが。。。
なので、最初からこう説明してほしかったなーという内容を自分なりにまとめてみました。

# Dockerとは何か

Dockerは、仮想マシンより起動が簡単で軽量な仮想環境をPC上に起動して操作するためのツールです。
そして、この仮想環境のことをコンテナと呼びます。

ちょっと乱暴な説明になりますが、最初はこれだけの理解で十分な気がしてます。
実際には仮想マシンとコンテナは技術的に別物なんですが、ちょっと使う分にはあまり意識する必要がないかなと思います。

ちなみにコンテナと仮想マシンとの違いをちゃんと説明すると、仮想マシンは、ホストマシンとは別に専用のリソース(CPUやメモリなど)を持ちその上でホストマシンと別のOSが動いていてホストマシンとはほとんど独立したマシンとして動作しているのに対し、コンテナは、ホストマシンとリソースやOSを共有していて表面的には独立したマシン上でOSが動いているような動きをしますがあくまでホストマシン上の１つのプロセスとして動作しているという違いがあります。
そのため、コンテナは高速に起動できたりリソースの消費が少なくて済むなどのメリットがあります。
デメリットとしては、使えるOSが限られていたり仮想マシンほどの自由度が無いというところです。
ただやっぱんりこの辺は最初からちゃんと理解する必要はないと思います。なんとなく、コンテナって仮想マシンみたいなものだけど厳密には違うんだなーくらいで良い気がします。

# Dockerの主な機能

Dockerの主な機能はかなりざっくりまとめるとこの２点かなと思います。

① Docker HubからDockerイメージをダウンロードする
② Dockerイメージからコンテナを生成する

Docker Hub ・・・ Dockerイメージを保管するクラウドサービス
Dockerイメージ ・・・ 仮想マシンで言うところのマシンイメージみたいなもの

図で表すとこんな感じ。

![Dockerの主な機能](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148707/286553df-156d-4efd-cb0d-27df04032e46.png)

具体的にはDockerでは、Dockerイメージの一覧表示・追加・削除、コンテナの一覧表示・追加・削除・起動・停止なんかが行えます。

##### とりあえずコンテナを起動してみる

とりあえずDockerでコンテナ起動してみたいという場合は、以下のコマンドでコンテナの起動を試してみることができます。(もちろん、事前にDockerをインストールしておいて下さい)

```
# docker run centos echo 'Hello world'
```

このコマンドだけで、Docker HubからCentOSのイメージをダウンロードして、そのイメージからコンテナを生成して起動までしてくれます。そして、起動したコンテナで「echo 'Hello world'」が実行され、その後コンテナは停止します。

ちょっと詳しく説明すると、 `docker run` はコンテナを起動して特定のコマンドを実行するためのコマンドで、 `centos` はイメージ名、 `echo 'Hello world'` はコンテナ起動後に実行されるコマンドです。
コマンド実行時に指定したイメージがローカルに存在しない場合は自動的にDocker Hubからイメージをダウンロードしてきてくれます。

まぁそもそもコマンド一個実行して終了するんじゃ意味ないじゃんって感じですが、コンテナを起動しっぱなしにする方法は他の記事で解説されていると思うのでこの記事では割愛します。

# Dockerのコマンド

##### `docker` と `docker-compose`

Dockerで使えるコマンドには、 `docker` コマンドと `docker-compose` コマンドがあります。どっちもやれることはほぼ同じなんですが、微妙に違いがあります。
基本のコマンドがdockerコマンドで、シンプルに単一のコンテナを起動することが出来ます。
そしてdocker-composeコマンドは、 `docker-compose.yml` と言う設定ファイルを利用してコンテナを起動するコマンドで、複数構成のコンテナを扱うのに向いています。でも単一のコンテナに向いてないというわけでは無いです。
個人的には、 docker-composeコマンドなら単一コンテナでも複数コンテナでも扱えるのでこっちを覚えていった方が良い気がします。

使い方としては、メインコマンドとして docker と docker-compose があり、それにサブコマンドを組み合わせて使います。 `docker run` とか `docker ls` みたいな感じです。

# Dockerの設定ファイルについて

##### `Dockerfile` と `docker-compose.yml`

Dockerでは、コンテナの設定を記述するための設定ファイルに `Dockerfile` と `docker-compose.yml` があります。
docker-compose.ymlは前述したように、docker-composeコマンドを使う際に利用する設定ファイルです。そして Dockerfileは、dockerコマンドでもdocker-composeコマンドでも使える設定ファイルです。
Dockerfileが基本の設定ファイルで、docker-compose.ymlはdocker-composeコマンド専用の設定ファイルといった感じです。

この２つのファイルはどっちもコンテナの設定を記述するためのファイルなんですが、書き方が違っていて、設定できる内容も微妙に違います。
どう違うかはとりあえず置いといて、使い分けとしては、dockerコマンドを使うならDockerfile、docker-composeコマンド使うなら基本はdocker-compose.ymlで場合によってはDockerfileを一緒に使う感じで良いみたいです。

[参考記事]
[今更だけどdocker composeのベストプラクティス](http://innossh.hatenablog.com/entry/2017/04/22/192743)

##### とりあえずDockerfileを使ってコンテナ起動してみる

[Dockerfile]

```
FROM centos
```

[コマンド]

```
# docker build . -t image1
# docker run web echo 'Hello world'
```

これで、コンテナを起動して `echo 'Hello world'` を実行することができます。
「とりあえずDockerを起動してみる」の項目でやっていることと同じです。

説明すると、まずDockerfileに `FROM centos` と書いておくことで `centos` のDockerイメージを使うことを指定しています。
次にコマンドの説明ですが、 `docker build` コマンドでDockerfileを元に `image1` という名前のDockerイメージを作成(ビルド)しています。 この場合、Dockerfileには元となるDockerイメージの指定しか書いてないので `centos` のDockerイメージと同じものが `image1` という名前で再作成されたような感じになります。
そして２つ目の `docker run` コマンドで `image1` からコンテナを作成しています。

この例から分かるようにDockerfileを使ってコンテナを作成する場合はビルドという工程が必要になります。

##### とりあえずdocker-compose.ymlを使ってコンテナ起動してみる

[docker-compose.yml]

```
version: '3'
services:
  container1:
    image: centos
```

[コマンド]

```
# docker-compose run container1 echo 'Hello world'
```

これも、「とりあえずDockerを起動してみる」の項目と同じことをやっています。

説明すると、まずdocker-compose.ymlには `centos` のDockerイメージを元に `container1` という名前のコンテナを作成するという設定を記述しています。
具体的には、 `version: '3'` の部分がDockerComposeのバージョンを指定で、 `services:` の部分はこれから下にコンテナの設定を書いていくことを表しています。そして、 `container1:` の部分がコンテナの名前、 `image: centos` の部分が `centos` のDockerイメージを使うことを表しています。
次にコマンドの説明ですが、 `docker-compose run` コマンドでdocker-compose.ymlで記述した `container1` のコンテナを起動して `echo 'Hello world'` を実行しています。

Dockerfileの時と違ってこっちはビルドは必要ありません。
これは、Dockerfileの場合はDockerfileに書かれた設定を元に新たなDockerイメージを作成(ビルド)するのに対して、docker-compose.ymlの場合はdocker-compose.ymlに書かれた設定を加えたコンテナをそのまま起動するからです。
こういう微妙な違いが分かりにくさを煽るんですよね。。。難しいです。

# 番外: Dockerのバージョンによるサブコマンドの違い

Dockerのバージョン1.13からdockerコマンドのサブコマンドが新しいコマンド体系になったようで、Docker関連の記事には古いコマンドで書かれている記事と、新しいコマンドで書かれている記事が混在しています。
例でいうと、古いコマンドで `docker ps` と書いていたのが、新しいコマンドでは `docker container ls` になっています。見た目全然違うコマンドに見えますが、コマンドの意味は全く同じです。
Docker関連の記事を読むときに混乱しやすいので、頭に入れておくと良いかもしれません。
ちなみに最新バージョン(v19.03.2)でも古いコマンドは動きます。

あと、docker-composeコマンドのサブコマンドの方は変わってないみたいで、 `docker-compose container ls` とかは存在しないのでご注意を。

[参考記事]
[docker container / image コマンド新旧比較](https://qiita.com/zembutsu/items/6e1ad18f0d548ce6c266)

# 最後に

ちゃんとDockerを使おうと思ったらもうちょっと理解を深める必要があるとは思いますが、前提知識としてこの内容を覚えておけば他の解説サイトを読むときも余計なところで混乱せずに読める気がします。
とは言え、自分もまだ覚えたてなので理解が間違っているところがあれば指摘いただけるとありがたいです。