Docker初学者がやるべきこと3選

この記事は[Nuco Advent Calendar 2022](https://qiita.com/advent-calendar/2022/nuco)の22日目の記事です
![スクリーンショット 2022-12-19 19.23.33.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/19cbcc37-c6e5-f526-7220-44e3fb45f8ae.jpeg)

# はじめに
### 対象読者
この記事では
- Docker初学者の方
- これからDockerを学ぼうとしている方

を対象にやるべきことして以下の3つを紹介します。
  1. Dockerの全体像を把握する
  2. チュートリアルで基本操作を学ぶ
  3. Docker Hubを散策する
 
自身が初学者だった頃の経験を基になるべく早く効率的にDockerを学ぶためにやるべきことを紹介するので参考にしてもらえれば幸いです。
![スクリーンショット 2022-12-07 9.37.23.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/f54ccd43-d7f8-285d-4906-231753fcfd23.jpeg)

### できるようになること
- Dockerが何なのか理解できるようになります
- Dockerを使ったアプリケーション開発に必要な基礎知識が身につきます
- 記事TOPのクリスマスツリーをターミナルに表示できるようになります
# 1. Dockerの全体像を把握する
まずはDockerが何者であるかを把握しましょう。実際にコマンドで操作する前にざっくりイメージを膨らませておくことで理解のスピードが上がります。
### Dockerはコンテナ型の仮想環境を提供するもの
Dockerは、Docker社が開発している、**コンテナ型の仮想環境を作成、配布、実行するためのオープンソースソフトウェア**です。
さて**コンテナ型の仮想環境**とはなんでしょうか？この用語を理解するために仮想環境とコンテナについて説明します。
### 仮想環境とは
仮想環境の仮想とは**疑似的な**という意味で使われています。仮想環境は**コンピュータの中に疑似的に作った環境**のことです。ここでの環境とは**開発したり、テストしたり、実際にプログラムを動かしたりするために必要なコンピュータやソフトウェアなどが揃った場所**と思ってください。仮想環境を構築することを**仮想化**といいます。
仮想環境を構築することで、Windows環境の中で仮想的に作られたLinux OS環境を用意したり、Windoiws環境の中にAndroid環境を用意してAndoroidアプリ開発を行ったりすることができます。
![スクリーンショット 2022-12-13 1.26.51.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/ded42334-89b5-0a82-c61b-c1c5e46ea0ce.jpeg)



### コンテナ技術とは
コンテナとは仮想環境を構築する技術の１つです。物流業界で使われるコンテナは中に輸送するものを入れていますが、ここでいうコンテナの場合は**アプリケーションが動くのに必要なものがまとまって入っている箱**というイメージです。様々な環境においてコンテナで同じ仮想環境を作ることができ、環境ごとの違いによって発生する問題を減らすことができます。

![スクリーンショット 2022-12-07 9.41.46.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/cc8d0224-975d-8e24-8a12-7d3fad4b16b0.jpeg)

### 従来の仮想化とコンテナの違い
![スクリーンショット 2022-12-13 2.51.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/1a7fa4d3-f8e3-3e97-2bfa-bc5667a11ed3.jpeg)

従来の仮想化はアプリケーションが各々の仮想サーバの中で動作します。アプリケーションを起動するためには物理サーバにインストールされているホストOSとは別に仮想サーバ内でのゲストOSの起動が必要になります。
コンテナによる仮想化では仮想サーバとゲストOSが不要になります。**コンテナエンジンがアプリケーションの起動に必要な環境(従来の仮想化のゲストOS)をそれっぽく再現**しています。コンテナエンジンがコンテナにゲストOSがあるように見せているとも言えます。そのコンテナエンジンの中で最も有名なのがDockerです。
![スクリーンショット 2022-12-13 3.22.32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/aae72d42-0c8c-55b5-64ec-2e0ea0f41d2f.jpeg)





### Dockerを使うメリット
#### Dockerイメージで簡単に環境構築
初学者にとってはDockerコンテナとDockerイメージの違いがわかりにくいと思います。まずは**DockerイメージとはDockerコンテナのテンプレート**、**DockerコンテナはDockerイメージ(テンプレート)から起動したアプリケーションの動作環境**くらいの理解で十分です。
Dockerイメージを共有することで誰でも簡単に同じ環境を用意することができます。

#### Dockerfileでイメージ構築手順をファイル化できる
DockerfileとはDockerイメージを作成するための手順が記されたテキストファイルです。**Dockerイメージの設計図**と説明されたりします。仮想環境を構築する手順をテキストで管理できます。
後述する基本コマンドの説明でDockerfileからDockerイメージを作成し、Dockerコンテナを起動するまでの流れを説明します。実際にコマンドを実行してみるとDockerfile、Dockerイメージ、Dockerコンテナそれぞれの役割と関係性が理解できると思います。
![スクリーンショット 2022-12-19 19.51.35.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/82f49906-11b0-72ac-701f-e5ea16ffbd85.jpeg)


#### 軽量で早い
従来の仮想化と異なり、**仮想サーバの立ち上げが不要なのでアプリケーションの起動が早い**というメリットがあります。これにより開発作業をスムーズに行うことができます。
　
# 2. チュートリアルで基本操作を学ぶ
Dockerが何者であるかおおよそのイメージができたら、次はチュートリアルで実際の操作方法を学びます。公式のチュートリアルを終えるとDockerの基本操作はひととおり自信を持って行えるはずです。
また、本章の後半ではチュートリアルの復習も兼ねてよく使うコマンドを紹介するので、ぜひターミナルを開いて操作しながら読み進めてみてください。
### やるべきは公式のチュートリアル
Dockerについて調べると、様々なブログや記事が見つかりますが、まずはじめにやるべきは公式のチュートリアルです。
Dockerのインストールが済んでいない方は[こちら](https://docs.docker.com/get-docker/)からインストールしましょう。
こちらの[リポジトリ](https://github.com/docker/getting-started/tree/master)に従ってチュートリアルを進めます。

まずはターミナルで次のコマンドを実行します。
```
$ docker run -d -p 80:80 docker/getting-started
```
この時点でコマンドの意味はわからなくても大丈夫です。チュートリアルを終える頃には理解できるようになっています。
コマンドを実行すると次のような出力が出てきます。
![スクリーンショット 2022-12-08 8.05.24.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/69e51452-63dc-84c2-5a39-bcbff78bc196.jpeg)
ブラウザでhttp://localhost/ を開くと次のような画面が開きます。
![スクリーンショット 2022-12-08 8.08.40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/02717248-e510-5311-c507-42f925452598.jpeg)
チュートリアルがとても丁寧に簡単な英語で説明されているので、英語のドキュメントに慣れていない方も頑張って読み進めてほしいです。Dockerを使ったアプリケーション開発をハンズオン形式で学ぶことができます。

和訳している方の記事がありましたので、どうしても英語が無理という方のためにリンクを貼らせていただきます。
[Dockerを体系的に学べる公式チュートリアル和訳](https://qiita.com/Michinosuke/items/5778e0d9e9c04038903c)


### まず覚えるべき基本コマンド
チュートリアルでも基本的なコマンドを学べますが、こちらでもおさえておくべきDockerコマンドを紹介します。
コマンドを実行しながら読み進めてみてください。
#### コンテナ一覧 docker ps
コンテナの一覧を確認するコマンドです。
前述したチュートリアルのコンテナが起動している状態で実行すると次のような出力が確認できます。
```
$ docker ps
CONTAINER ID   IMAGE                    COMMAND                 CREATED          STATUS         PORTS                              NAMES
1c064f6d6e88   docker/getting-started   "/docker-entrypoint.…" 26 minutes ago   Up 26 minutes  0.0.0.0:80->80/tcp, :::80->80/tcp  infallible_lewin
```

#### イメージ一覧 docker images
イメージの一覧を確認するコマンドです。
前述したチュートリアルのイメージがあると次のような出力が確認できます。
```
$ docker images
REPOSITORY                  TAG             IMAGE ID            CREATED             SIZE
docker/getting-started      latest          e5be50c31cd9        12 days ago         29.8 MB
```

#### コンテナ停止 docker stop
`docker stop <CONTAINER IDまたはNAME>`で起動中のコンテナを停止することができます。
CONTAINER IDが`1c064f6d6e88`のコンテナを停止する場合は
```
$ docker stop 1c064f6d6e88
```

NAME(ここでは`infallible_lewin`)を指定してコンテナを停止する場合は
```
$ docker stop infallible_lewin
```
停止したことを確認してみます。`docker ps`は起動中のコンテナだけ表示するので、実行すると停止したコンテナは表示されなくなります。
```
$ docker ps
CONTAINER ID   IMAGE                    COMMAND                 CREATED          STATUS         PORTS                              NAMES
```

`docker ps -a`または`docker ps --all`で停止中のコンテナを含めたすべてのコンテナを表示できます。
STATUSがExitedになっていることからコンテナが停止中であることが確認できます。
```
$ docker ps -a
CONTAINER ID   IMAGE                    COMMAND                 CREATED          STATUS                   PORTS        NAMES
1c064f6d6e88   docker/getting-started   "/docker-entrypoint.…" 26 minutes ago   Exited (0) 8 minutes ago              infallible_lewin
```


#### コンテナ起動 docker start
`docker start <CONTAINER IDまたはNAME>`でコンテナを起動することができます。
CONTAINER IDが`1c064f6d6e88`のコンテナを起動する場合は
```
$ docker start 1c064f6d6e88
```
NAME(ここでは`infallible_lewin`)を指定してコンテナを起動する場合は次のとおりです。
```
$ docker start infallible_lewin
```

#### イメージ作成 docker build
まず作成するDockerイメージの基となるDockerfileを作成します。
```
$ cat << EOS > Dockerfile
FROM nginx
EOS
```

エディターソフトでDockerfileという名前のファイルを作成し、`FROM nginx`とだけ入力して作成しても構いません。
Visual Studio Codeで作成するとこんな感じです。
![スクリーンショット 2022-12-14 22.45.03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/6bedfaf0-2604-6e9c-ebe7-92f2ebe5b6e0.jpeg)
イメージを作成してみます。
```
$ docker build -t test:qiita .
```
`-t test:qiita`はオプションでDockerイメージに名前とタグをつけています。ここではtestが名前、qiitaがタグです。
最後のピリオド`.`はDockerfileのある場所(カレントディレクトリ)を指定しています。
実行すると次のような出力が出てきます。
![スクリーンショット 2022-12-14 22.52.12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/5abbd931-ebf4-e6bd-d96f-a99a25aa70ad.jpeg)
ここで何が起こっているかというと、Dockerfileに`FROM`で指定したnginxのイメージをDocker Hubから取得(pullといいます)してローカルPC上にDockerイメージを構築しています。
Docker HubとはDockerイメージを検索・共有するためにDocker社が提供しているサービスです。平たく言うとGitHubのDockerイメージ版です。

`docker images`でDockerイメージが作成されていることが確認できます。
```
$ docker images
REPOSITORY          TAG         IMAGE ID       CREATED        SIZE
test                qiita       7f7b4ac1ce1f   13 hours ago   142MB
```
#### コンテナを起動状態で作成 docker run
作成したDockerイメージからDockerコンテナを作成し、起動してみます。
ここではコンテナを起動した状態で作成する`docker run`を使用します。
```
$ docker run -d -p 8080:80 --name test-container test
```
`-d`はコンテナをバックグラウンドで動作させるオプションです。
`-p 8080:80`はローカルPCのポート8080をコンテナのポート80を結びつけます。
`--name test-container`は起動するコンテナに`test-container`という名前をつけています。ここでつけた名前はdockerコマンドでコンテナの指定に使えます。
最後の`test`は基となるDockerイメージの名前です。

`docker ps`でDockerコンテナが作成されているか確認します。
```
$ docker ps
CONTAINER ID   IMAGE     COMMAND                 CREATED         STATUS         PORTS                                  NAMES
09015830f07d   test      "/docker-entrypoint.…" 3 minutes ago   Up 3 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp  test-container
```
コンテナの起動が確認できました。
ブラウザでhttp://localhost:8080 を開くと次のような画面が表示されます。`docker run`の`-p`オプションでローカルPCのポート8080とコンテナのポート80がマッピングされているので、nginxのWebページが表示されます。

:::note info
<b>80番ポート</b>
インターネットでWeb閲覧をしているとき、ユーザーのPCとサーバと呼ばれるコンピュータが「TCP/IP」と呼ばれるプロトコル群を使って一対一の通信を行なっています。しかし、IPアドレスだけでは利用したいサービスを識別できないため、サーバ側ではアプリケーションプロトコルごとに固定的に割り当てられたポート番号が用意されています。
ポート番号は0から65535まで存在しますが、そのなかでも0~1023までを<b>ウェルノウンポート番号</b>といい、IANAという団体により管理されています。TCP/IPにおいて通信で利用されるポート番号のうち、メジャーなサービスやプロトコルが利用するために予約されているポート番号がウェルノウンポート番号です。
80番ポートはHTTPでWebサーバがクライアントサーバと通信する際に利用されます。
:::

![スクリーンショット 2022-12-14 23.51.38.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/61b47879-e4cb-1a60-c4ff-b687f3ff1b1f.jpeg)


### コンテナを削除 docker rm
Dockerを使って開発をしていると使わなくなったコンテナを削除することがあります。初心者の場合はコンテナを削除することをためらうかもしれませんので、ここでしっかり削除する流れを学んでおきましょう。
まず`docker ps`でコンテナを確認します。
```
$ docker ps
CONTAINER ID   IMAGE     COMMAND                 CREATED         STATUS         PORTS                                  NAMES
09015830f07d   test      "/docker-entrypoint.…" 15 minutes ago   Up 15 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp  test-container
```
`docker stop`でコンテナを停止します。
ここではNAMEを指定して停止します。IDを指定しても構いません。
```
$ docker stop test-container
```
`docker ps -a`でコンテナの停止を確認します。
```
$ docker ps -a
CONTAINER ID   IMAGE    COMMAND                 CREATED          STATUS                    PORTS        NAMES
09015830f07d   test     "/docker-entrypoint.…" 16 minutes ago   Exited (0) 15 seconds ago              test-container
```
コンテナの停止を確認したら削除してみましょう。
`docker rm <CONTAINER IDまたはNAME>`でコンテナを削除することができます。
ここではNAMEを指定して削除します。
```
$ docker rm test-container
```
`docker ps -a`でコンテナが削除されていることが確認できます。
```
$ docker ps -a
CONTAINER ID      IMAGE      COMMAND      CREATED      STATUS       PORTS        NAMES
```
#### コンテナを停止状態で作成　docker create
再びDockerイメージからDockerコンテナを作成してみます。先程は`docker run`で作成しましたが、ここでは`docker create`を使用します。
`docker run`と`docker create`はどちらもコンテナを作成するコマンドですが、作成されるコンテナが起動状態か停止状態かという違いがあります。`docker run`はコンテナを起動状態で作成し、`docker create`はコンテナを停止状態で作成します。
`docker run = docker create(コンテナ作成) + docker start(コンテナ起動)`と覚えておきましょう。
実際にコマンドを実行してみます。
```
$ docker create -p 8080:80 --name test-create test
```
停止状態でコンテナを作成したので`docker ps -a`(停止中も含めたすべてのコンテナを表示)で確認します。
```
$ docker ps -a
CONTAINER ID   IMAGE    COMMAND                  CREATED          STATUS        PORTS       NAMES
b5f4e819a872   test     "/docker-entrypoint.…"  2 minutes ago    Created                   test-create
```
`docker rm`でコンテナを削除しておきます。ここではCONTAINER IDを指定して削除します。
```
$ docker rm b5f4e819a872
```

### イメージを削除 docker rmi
`docker rmi`はイメージを削除するコマンドです。
まず`docker images`でイメージ一覧を確認します。
```
$ docker images
REPOSITORY          TAG         IMAGE ID       CREATED        SIZE
test                qiita       7f7b4ac1ce1f   13 hours ago   142MB
```
`docker rmi <REPOSITORY:TAGまたはIMAGE ID>`で削除することができます。
ここではREPOSITORY:TAGでイメージを指定して削除してみます。
```
$ docker rmi test:qiita
```
最後に`docker images`で削除されていることを確認しましょう。
```
$ docker images
REPOSITORY          TAG         IMAGE ID       CREATED        SIZE
```
使用していないDockerイメージを放置しておくと、いつの間にかディスク容量を圧迫していることになりかねないので、使わないイメージは削除しておきましょう。

### イメージを取得 docker pull
DokckerHubからイメージをpull(取得)するコマンドです。Docker Hubにある多くの構築済みのイメージから特定のイメージをダウンロードして使うことができます。
```
$ docker pull lukaszlach/merry-christmas
```
例でpullされるイメージ`lukaszlach/merry-christmas`でコンテナを実行すると記事TOPのクリスマスツリーが現れるので試してみてください。
クリスマスツリーのイメージのDocker Hubは[こちら](https://hub.docker.com/r/lukaszlach/merry-christmas)

### コンテナ内でコマンド実行　docker exec
`docker exec`は起動中のコンテナ内で指定したコマンドを実行します。
いくつか例を試してみます。準備としてexecコマンドを試すためのコンテナを起動します。
```
$ docker run -d -p 8080:80 --name test-exec nginx
```
`docker ps`で起動を確認します。
```
$ docker ps
CONTAINER ID  IMAGE  COMMAND                CREATED        STATUS         PORTS                                   NAMES
bc20a5650fe5  nginx  "/docker-entrypoint.…" 4 seconds ago  Up 3 seconds   0.0.0.0:8080->80/tcp, :::8080->80/tcp  test-exec
```
まずは`exec`コマンドを使ってコンテナ内で`ls`コマンドを実行してみます。
```
$ docker exec test-exec ls -l /usr
```
`test-exec`はコンテナ名、`ls -l /usr`がコンテナ内で実行するコマンドです。
以下のようにコンテナ内の`/usr`ディレクトリ下のファイル一覧が出力されます。
```
total 36
drwxr-xr-x 1 root root 4096 Dec 14 01:20 bin
drwxr-xr-x 2 root root 4096 Sep  3 12:10 games
drwxr-xr-x 2 root root 4096 Sep  3 12:10 include
drwxr-xr-x 1 root root 4096 Dec 14 01:20 lib
drwxr-xr-x 3 root root 4096 Sep 24  2020 libexec
drwxr-xr-x 1 root root 4096 Dec  5 00:00 local
drwxr-xr-x 1 root root 4096 Dec 14 01:20 sbin
drwxr-xr-x 1 root root 4096 Dec 14 01:20 share
drwxr-xr-x 2 root root 4096 Sep  3 12:10 src
```
次はよく利用するコンテナ内でシェルを起動する場合を試してみます。
```
$ docker exec -it test-exec bash
```
`-it`は`-i -t`と同じで`-i`は標準入力を開き続けるオプション、`-t`は疑似ttyを割り当てるオプションです。
とりあえずは`-it`で **手元の環境でdocker内コマンド入力ができるようになる**と覚えておけばよいでしょう。

コマンドを実行すると以下のようにプロンプトが`#`に変わるはずです。このプロンプトは`docker exec`で実行したコンテナ内の`bash`が出力しているプロンプトです。
`@`のあとの文字列`bc20a5650fe5`はコンテナIDです。先程`docker ps`で確認したコンテナIDと同じです。
```
root@bc20a5650fe5:/#
```
このプロンプトで実行するコマンドはコンテナ内で実行することになります。`ls`や`cd`など色々なコマンドを実行みてください。
コンテナ内のシェルを終了するときは`exit`を実行します。
```
root@bc20a5650fe5:/# exit
```
最後にコンテナとイメージを削除しておきます。
`docker rm`についている`-f`オプションは起動中のコンテナを強制的に削除します。
```
$ docker rm -f test-exec
$ docker rmi nginx
```

# 3. Docker Hubを散策する
やるべきこと3つ目はDocker Hub散策です。様々なイメージのDockerfileを見て勉強しましょう。
### Docker Hubとは
前の章でも簡単に触れましたが、Docker HubとはDocker社が運営しているDockerイメージをアップロードして公開・共有できるサービスで、ここで公開されているイメージは自由にダウンロードして使うことができます。公開されているコンテナのベースになっているDockerfileを見ることができるので、Dockerfileの作成に慣れていない方はとても参考になると思います。
[Docker Hub](https://hub.docker.com/)

### 公式イメージのDockerfileを見てみる
試しに[pythonの公式イメージ](https://hub.docker.com/_/python)を見てみます。Simple Tagsの一番上のリンクを踏んでみます。
![スクリーンショット 2022-12-08 9.17.29.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/5fd92b73-01d8-b788-e2db-bdc5a5ed5dd3.jpeg)
GitHubでDockerfileを見ることができます。公式イメージは無駄がなくベストプラクティスにしたがって書かれているので、是非参考にしてみてください。
![スクリーンショット 2022-12-08 9.20.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957616/5e8feafe-aec5-b5c8-6fc6-05e70530d83b.jpeg)


# さらに理解を深めたいあなたへ
### Dockerfileのベストプラクティス
最後にDockerfileのベストプラクティスを紹介させていただきます。
- [英語版](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
- [日本語版](https://docs.docker.jp/develop/develop-images/dockerfile_best-practices.html)

保守性が高く軽量で効率的なイメージを作成するためにDocker社が推奨しているものです。
**.dockerignoreの使い方**や**ADDとCOPYの違い**などを学ぶことができます。公式チュートリアルを終えたあとはこちらを学ぶことでより実践的な力が身につくでしょう。

# おわりに
最後まで読んでいただきありがとうございます。
弊社では、経験の有無を問わず、社員やインターン生の採用を行っています。

興味のある方は[こちら](https://www.recruit.nuco.co.jp/)をご覧ください。