Dockerのイメージ/コンテナのライフサイクルと基本操作【初心者OK！Docker入門＋応用シリーズ】

# はじめに
本記事は **[「初心者OK！Docker入門＋応用：ゼロからでも実務で使えるスキルが身に付ける」](https://qiita.com/kenny_J_7/items/5fa59d4238058c1060e8)** のシリーズ記事の１つです。
「初心者OK！Docker入門＋応用：ゼロからでも実務で使えるスキルが身に付ける」のシリーズについては、以下の元記事をご覧ください。

https://qiita.com/kenny_J_7/items/5fa59d4238058c1060e8

# 本記事の内容
今回は「Dockerの基本操作」を体験してもらえる記事にしました。
Dockerイメージの基礎からコンテナのライフサイクルとそれを制御するコマンドまで説明します。

あと、いいねくれると喜びます🙇‍♂️

# Docker講義動画を Udemy で配信中（クーポンあり）
今回の内容を含むUdemyの動画コースを配信しています。
ぜひ興味のある方はご覧ください。
動画版では、**完全ゼロ知識を想定して説明しています。**
また、**動画版にしかないコンテンツも多数あります。**
たとえば、動画版ではDockerの基礎部分だけでなく実際の業務に即したアプリ開発を体験するセクションも用意してあります。


以下リンクからだと割引で買えます🙇‍♂️

https://dockercourse.page.link/coupon-qiita

では、以下本題です。

# Docker イメージとは？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181439/eba24c0d-6fd7-f080-bd96-ac517ebde1bf.png)
Dockerを学ぶ上で、「イメージ」は非常に重要なキーワードです。

イメージはコンテナとは若干違った存在です。

では、イメージっていうのは何なのか？
**「コンテナに必要なソフトウェアや環境変数などの情報がパッケージ化されて入っているもの」** になります。

コンテナっていうのは隔離されて分離された非常に安定した環境です。

そして、そのコンテナ環境っていうのがどういったものなのか、例えば、Pythonが動くのか、Node.jsが動くのか、Rubyが動くのか、コンテナがどういった環境のものなのかというのを定義しないといけません。

その定義に使われるのが「イメージ」です。

ですので、コンテナはイメージをもとにして起動します。

**イメージ　＝　コンテナの形**

という理解ができます。

「イメージ」と「コンテナ」はよく出てくるキーワードで混合しがちなんですが、イメージからコンテナを作り出すことを、しっかり頭の中で理解しましょう。

# イメージとコンテナのライフサイクル
Dockerのイメージとコンテナのライフサイクルをまとめてみようと思います。

Dockerを学ぶ時に、すぐさまコマンドを実行してみたい気持ちになりますが、まずは全体像を把握するのが近道です。

そうすることで、自分がコンテナとイメージどちらに対して何を命令しているのかで迷子になりにくくなるはずです。

## イメージの入手
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181439/37615e1b-29fe-0b5b-62f9-df3c19c3130a.png)
まずはイメージの入手から始まります。

イメージの取得方法は主に２つあります。

一つが、DockerHubなどのイメージレジストリと呼ばれるイメージを溜めている倉庫のような場所からダウンロードする方法。
最初に実行した、HelloWorldもこのやり方でイメージを入手しています。

もう一つが、Dockerfileと呼ばれるファイルから作成する方法です。
このやり方についてはまた別途説明します。

そして、イメージはもちろん破棄することも可能です。。

## コンテナの起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181439/4dab624c-387d-bc81-38bb-eaa2cc1b5040.png)
次にコンテナのライフサイクルも追加しました。

コンテナはイメージから作成されるんでしたね。
コンテナはSTATUSと呼ばれる状態を持っています。

イメージから作成された直後は、**「Created」** の状態になっている。
ここではまだコンテナは起動していない状態です。

そして、起動すると **「Up」** になり、実行内容が終了すると **「Exited」** になる。

コンテナはExitedでもまだ存在はしています。なので、そこからUPに再起動することも可能です。
また、コンテナは破棄することも当然可能です。

以上が、Dockerイメージとコンテナのライフサイクルの概要になります。

# Dockerコマンドを実行してみる
以降ではこれらのライフサイクルを実際のDockerコマンドを使いながら説明していきます。

## イメージをダウンロード・破棄する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181439/0237e8a7-fac0-e487-23bd-5f9e2533f4dc.png)
まず、ライフサイクルの最初である、Dockerイメージのダウンロードする部分を実行してみます。
そして、ダウンロードしたイメージを確認して、それを破棄するのも試してみます。

### イメージをダウンロードする
```sh
# イメージをダウンロードする
$ docker image pull {イメージ名/イメージID}
```
このコマンドでイメージをDockerHubからダウンロードすることができます。

たとえば、Ubuntu Linux環境のコンテナが作れるイメージをダウンロードする場合、
```sh
$ docker image pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
2ab09b027e7f: Pull complete 
Digest: sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
```

このようになります。
出力されるメッセージを見ると、ダウンロードが行われているのがわかると思います。


### ローカルマシンに存在するイメージ一覧を表示する
```sh
# ローカルマシンに存在するイメージ一覧を表示する
$ docker image ls
```
このコマンドによって、現在存在するイメージの一覧を表示できます。
```sh
$ docker image ls
REPOSITORY                             TAG        IMAGE ID       CREATED         SIZE
ubuntu                                 latest     08d22c0ceb15   2 weeks ago     77.8MB
```
`TAG`として、`latest`となっていますが、これは `image pull` するときに `ubuntu:TAG` のように指定することができるのですが、TAGを省略すると最新のイメージである `latest` を指定したことになるためです。
たとえば、Ubuntuの20.04のイメージを使いたい場合には、
```sh
$ docker image pull ubuntu:20.04
```
とすることでバージョンを指定したイメージをダウンロード可能です。

### イメージを削除する
```sh
# イメージを削除する
$ docker image rm {イメージ名/イメージID}
```
このコマンドによってイメージを削除できます。
実際にUbuntuのイメージを削除してみましょう。
```sh
docker image rm ubuntu
Untagged: ubuntu:latest
Untagged: ubuntu@sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21
Deleted: sha256:08d22c0ceb150ddeb2237c5fa3129c0183f3cc6f5eeb2e7aa4016da3ad02140a
Deleted: sha256:b93c1bd012ab8fda60f5b4f5906bf244586e0e3292d84571d3abb56472248466
```
ここもPullの時と同じで、TAGを未指定にすると、勝手に `ubuntu:latest` が指定されたことになります。

## イメージからコンテナを作成・実行する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181439/90430656-67ca-80e0-a836-5a9329665867.png)
次に、ダウンロードしたイメージからコンテナを作成し、さらにそれを実行するところを解説します。

### イメージからコンテナを作成し起動する
```sh
# イメージからコンテナを作成し起動する
$ docker container run {イメージ名/イメージID}
```
このコマンドによって、指定したイメージからコンテナを作成して起動できます。
つまり、 STATUSが `Created` なコンテナを作り、 `Up` にまでさせるということです。

試しに、`hello-world` という名前のイメージがDockerHubに存在しますので、そちらを使ってコンテナを作成・起動してみます。
```sh
$ docker container run hello-world  

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```

これは、`hello-world` イメージのコンテナが作成された上で、このイメージに事前に設定されていたデフォルトコマンドが実行された状態です。
`Hello from Docker!...`の文言がその結果出力されたということですね。

`docker container run` にはさまざまなオプションが存在しますが、それはおいおい説明します。

### ローカルマシンに存在するコンテナ一覧を表示する
```sh
# ローカルマシンに存在するコンテナ一覧を表示する
$ docker container ls
```
このコマンドで、現在存在するコンテナ一覧を表示できます。
実際にやってみます。
```sh
$ docker container ls -a
CONTAINER ID   IMAGE         COMMAND    CREATED         STATUS                     PORTS     NAMES
0f117760b45c   hello-world   "/hello"   5 minutes ago   Exited (0) 5 minutes ago             jolly_heisenberg
```
`-a` (`--all`の省略形) というコマンドをつけることで、STATUSが `Exited` なコンテナも表示されるようになります。
結果を見ると、`hello-world` イメージから作成されたコンテナがなぜか `Up` ではなく、 `Exited` になっているのがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181439/f557498e-4ec2-35b2-2507-b6dded54f1b6.png)
なぜかというと、上図のように、`hello-world`コンテナは `Up` になりデフォルトで設定されていたコマンドを実行し終わるとプロセスを終了するため `Exited` の状態になるからです。

ですから、 `nginx` のようなHTTP Serverを実行するイメージを使えば、実行されたコマンドが終わることはありませんから、プロセスも終了せずに `Up` の状態でコンテナが生き続けることになります。

## コンテナを停止・再起動する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181439/fb693a2a-9db6-23e8-caa2-69a06f43bd15.png)

### コンテナを停止する
```sh
# 起動状態のコンテナを止める
$ docker container stop {コンテナ名/コンテナID}
```
このコマンドでコンテナを止める（`Exited`）にできます。
ですが、`hello-world` コンテナだとRunしても直ちにExitedになってしまっていたので、nginxコンテナを使って実験してみます。
```sh
# nginx コンテナを起動する
$ docker container run -d nginx 
49f65a25d0a9c4afb67cef945ab63580bf35328ee93f7a5b26db3d53f2263788

$ docker container ls
CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS     NAMES
49f65a25d0a9   nginx     "/docker-entrypoint.…"   About a minute ago   Up About a minute   80/tcp    objective_allen
```
`nginx`コンテナが`Up`になっているのが見えます。
ちなみに、runするところでやっている `-d`オプションは、デタッチドモードでの起動を指定しています。
こうすることで、バックグラウンドでコンテナを起動させ続けることが可能です。

では、このコンテナを止めてみましょう。
```sh
$ docker container stop 49f65a25d0a9
49f65a25d0a9

$ docker container ls -a
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                      PORTS     NAMES
49f65a25d0a9   nginx         "/docker-entrypoint.…"   4 minutes ago    Exited (0) 26 seconds ago             objective_allen
```
Stop時に指定したのは、`container ls` で確認した `CONTAINER ID` です。
そして、STATUSを確認すると、`Exited`になっています。ちゃんと止まりました！


### コンテナを再起動する
```sh
$ docker container restart {コンテナ名/コンテナID}
```
では、今度は再起動してみます。
```sh
$ docker container restart 49f65a25d0a9
49f65a25d0a9

$ docker container ls                  
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
49f65a25d0a9   nginx     "/docker-entrypoint.…"   7 minutes ago   Up 8 seconds   80/tcp    objective_allen
```
はい、このように再度 STATUSが`Up`になりました。

## コンテナを破棄する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181439/fc0f5a0f-a86d-64e1-e09c-fceb013d5c04.png)
では最後にコンテナを破棄してみます。
```sh
# コンテナを破棄する
$ docker container rm {コンテナ名/コンテナID}
```
まずは、先ほど`Up`にしたコンテナを破棄してみます。
```sh
$ docker container rm 49f65a25d0a9
Error response from daemon: You cannot remove a running container 49f65a25d0a9c4afb67cef945ab63580bf35328ee93f7a5b26db3d53f2263788. Stop the container before attempting removal or force remove
```
するとこのようにエラーになってできません。
コンテナは`Exited`の状態でないと破棄できません。
ですのでまずはStopする必要があります。
```sh
$ docker container stop 49f65a25d0a9
49f65a25d0a9

$ docker container rm 49f65a25d0a9  
49f65a25d0a9

$ docker container ls -a
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS    PORTS     NAMES
```
今度はうまく行きました。コンテナは跡形もなく削除されました。

# 新旧Dockerコマンドについて
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181439/6fee5be2-b76a-14b1-bbf1-875f104506e4.png)
Docker に関する資料を読んでいる中で、`docker pull`や`docker images` といったコマンドを目にしたことがある方も多いかも。
Docker は、version 1.13時にDockerコマンドが一新されました。

新コマンドでは、`docker` というコマンドの後に、何に対して操作をするのかを明示的に示すことになりました。
たとえば、イメージのダウンロードをする場合、旧コマンドでは単にpull だったが、新コマンドでは image pull とイメージをPull（＝ダウンロード）するという書き方になります。

旧コマンドは引き続きサポートされていて実行可能です。
旧コマンドの方がコマンドが短くて楽に入力できるメリットがありますが、今後のDockerのアップデートの方針にそわせるためにも新コマンドをなるべく使うことを推奨します。

# Docker講義動画を Udemy で配信中（クーポンあり）
今回の内容を含むUdemyの動画コースを配信しています。
ぜひ興味のある方はご覧ください。
動画版では、**完全ゼロ知識を想定して説明しています。**
また、**動画版にしかないコンテンツも多数あります。**
たとえば、動画版ではDockerの基礎部分だけでなく実際の業務に即したアプリ開発を体験するセクションも用意してあります。


以下リンクからだと割引で買えます🙇‍♂️

https://dockercourse.page.link/coupon-qiita

# 次に読むのにおすすめ
https://qiita.com/kenny_J_7/items/7e2e3300e5b8ff7d7571