1人で0からWebアプリを作成できるようになる入門記事(1) Docker入門

この記事は[1人で0からWebアプリを作成できるようになる入門記事](https://qiita.com/minoruishihara/items/63fd9d4f5d737aed0765)の第一回です

### 結論から

1.プロジェクトに以下のファイルを作成

![docker-intro-directory.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263665/f4553f6b-3b0b-fa2b-704a-8ac90f49376f.png)

```yaml:docker-compose .yaml
version: '3.8'
services:
    nginx:
        build:
            context: .
            dockerfile: Dockerfile
        image: nginx:latest
        container_name: nginx
        ports:
            - 8080:80
        volumes:
            - ./source:/var/www/html/localhost
        tty: true
        stdin_open: true
        environment:
            - NGINX_HOST=localhost
            - NGINX_PORT=80
```

```Dockerfile:Dockerfile
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
RUN apt update && \
    apt install vim -y
RUN mkdir -p /var/logs/nginx
EXPOSE 80
```

```nginx:nginx.conf
events {
    worker_connections  4096;
}
http{
    include mime.types;
    default_type application/octet-stream;
    server{
        listen 80;
        server_name localhost;
        root /var/www/html/localhost;
        charset UTF-8;
    }
    log_format formatA '[$time_local]$connection - $status';
    access_log /var/logs/nginx/access_log formatA;
}
```

```html:source/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Docker Test</title>
    <link href="index.css" rel="stylesheet" type="text/css" media="all" />
  </head>
  <body>
    <h1>Docker is running!</h1>
    <h2>Dockerfile</h2>
    <div class="code-block">
      FROM nginx:latest <br />
      COPY index.html /var/www/html/localhost/ <br />
      COPY index.css /var/www/html/localhost/ <br />
      RUN apt update && \ <br />
      apt install vim
    </div>
    <h2>docker-compose.yaml</h2>
    <div class="code-block">
      version: '3.8'<br />
      services:<br />
      &nbsp;&nbsp;nginx:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;build:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;context: .<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dockerfile: Dockerfile<br />
      &nbsp;&nbsp;&nbsp;&nbsp;image: nginx:latest<br />
      &nbsp;&nbsp;&nbsp;&nbsp;container_name: nginx<br />
      &nbsp;&nbsp;&nbsp;&nbsp;ports:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- 8080:80<br />
      &nbsp;&nbsp;&nbsp;&nbsp;volumes:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- ./source:/var/www/html/localhost<br />
      &nbsp;&nbsp;&nbsp;&nbsp;tty: true<br />
      &nbsp;&nbsp;&nbsp;&nbsp;stdin_open: true<br />
      &nbsp;&nbsp;&nbsp;&nbsp;environment:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- NGINX_HOST=localhost<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- NGINX_PORT=80
    </div>
  </body>
</html>
```

```css:source/index.css
div.code-block {
    color: aqua;
    background: black;
    margin: 1rem;
    padding: 1rem;
    width: 70%;
}
```

2.以下のコマンドでイメージ作成・コンテナ/作成・起動/停止・削除
```bash:イメージの作成
docker-compose build
```

```bash:コンテナの作成・起動
docker-compose up
```

```bash:コンテナの停止・破棄
docker-compose down
```

```bash:コンテナでコマンド実行
docker-compose run [サービス名] [コマンド]
```

```bash:コンテナでコマンド実行(起動中のコンテナ)
docker-compose exec [サービス名] [コマンド]
```

### 目次
- [1.1-Dockerとは何か？](#11-dockerとは何か)
- [1.2-Dockerの基本的な概念](#12-dockerの基本的な概念)
- [1.3-Dockerのインストール](#13-dockerのインストール)
- [1.4-Dockerfileの作成とイメージのビルド](#14-dockerfileの作成とイメージのビルド)
- [1.5-コンテナの作成・起動と停止](#15-コンテナの作成起動と停止)
- [1.6-コンテナ上でのコマンドの実行](#16-コンテナ上でのコマンドの実行)
- [1.7-Docker-Composeによる複数コンテナの管理](#17-docker-composeによる複数コンテナの管理)
- [1.8-DockerHubからイメージを取得](#18-dockerhubからイメージを取得)

### 1.1 Dockerとは何か？
> Docker はアプリケーションを開発（developing）、移動（shipping）、実行（running）するためのオープンなプラットフォームです。Docker はインフラストラクチャ 1 とアプリケーションを切り離すため、ソフトウェアを短時間で提供できます。Docker があれば、アプリケーションを管理するのと同じ方法で、あなたのインフラも管理できます。Docker 的な手法を最大限活用しますと、テストやコードのデプロイを素早くできますので、コードを書いてから、プロダクション（実行環境）で動かすまでにかかる時間を著しく軽減できます。
> 
> Docker ドキュメント日本語化プロジェクト「Docker 概要」
> <https://docs.docker.jp/get-started/overview.html>

何言ってるのかわかない人向けの要約・補足：
 - アプリを作るにはアプリの本体(ソースコード)に加えて、アプリを動かすための**環境**(ハードウェアやOS)が必要
 - アプリを作る際に、そのアプリが特定の環境でしか動かないと不便
 - Dockerは1つのコンピュータの中に、アプリを動かすための複数の環境を再現できる
 - また、Dockerは環境の詳細をアプリのソースコードのように記述できる

### 1.2 Dockerの基本的な概念
#### コンテナ (Container)
Dockerはコンテナと呼ばれる環境の上でアプリケーションを実行します。コンテナには、アプリケーションの実行に必要なものがすべて詰まっています。

![docker-abst.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263665/307a226a-307c-8772-725c-ba47cfa7e7e4.png)

#### イメージ (Image)
イメージはコンテナの元となるテンプレートファイルです。イメージはDockerfileというファイルを用いて記述され、DockerfileにはOSの情報や環境変数、コンテナを作成するために実行するコマンドなどを記述します。

#### Dockerファイル(Dockerfile)
Dockerファイルはイメージを作成する方法(レシピ)が書かれたファイルです。Dockerファイルからイメージをbuildし、イメージからコンテナをcreateします。

![docker-abst-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263665/0d5a32db-d1e9-ea66-43e4-4dff1ed2cec2.png)


### 1.3 Dockerのインストール
- [Mac](https://qiita.com/R_R/items/a09fab09ce9fa9e905c5#docker-desktop-for-mac-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%89%8B%E9%A0%86)
- [Windows](https://qiita.com/R_R/items/a09fab09ce9fa9e905c5#docker-desktop-for-windows-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%89%8B%E9%A0%86)
- [Linux](https://qiita.com/yoshiyasu1111/items/f2cab116d68ed1a0ce13)

### 1.4 Dockerfileの作成とイメージのビルド
どこかに適当なフォルダを作り、その中に以下のようなファイルを作成してください。

```html:index.html
<h1>Hello Docker!</h1>
```

```Dockerfile:Dockerfile
FROM nginx:latest
COPY index.html /var/www/html/localhost/index.html
RUN service nginx start
ENV NGINX_HOST=localhost
ENV NGINX_PORT=80
EXPOSE 80
```

Docker Desktopが起動した状態で、先ほど作成したディレクトリに移動して以下のコマンドを実行。

```bash:イメージの作成
docker build -t nginx:latest .
```

以下のコマンドで作成したイメージの一覧が確認できます。

```bash:イメージ一覧
docker image ls
```
```bash:結果
REPOSITORY               TAG       IMAGE ID       CREATED             SIZE
nginx                    latest    25957b75ef68   1 minutes ago      253MB
```

### 1.5 コンテナの作成・起動と停止
1.4で作成したイメージからコンテナを作成して起動します
以下のコマンドでイメージ名を指定してコンテナを作成できます

```bash:コンテナの作成
docker create [オプション] [イメージ名:タグ]
```

```bash:コンテナの作成
docker create --name nginx -p 8080:80 nginx:latest
```

コンテナが作成されているか確認します

```bash:コンテナの確認
docker container ls -a
```

```bash:結果
CONTAINER ID   IMAGE          COMMAND                   CREATED              STATUS    PORTS     NAMES
e5ad83bf5621   nginx:latest   "/docker-entrypoint.…"   About a minute ago   Created             nginx
```

コンテナに割り振られたID `CONTAINER ID` 、作成元のイメージ名 `IMAGE` 、コンテナの名前 `NAMES` 、状態 `STATUS` が確認できます

次に、以下のコマンドでコンテナを起動します

```bash:コンテナの起動
docker start [コンテナ名:タグもしくはコンテナID]
```

```bash:コンテナの起動
docker start nginx
```

コンテナが起動できているか確認します。

```bash:コンテナの確認
docker container ls
```

```bash:結果
CONTAINER ID   IMAGE          COMMAND                   CREATED         STATUS         PORTS     NAMES
e5ad83bf5621   nginx:latest   "/docker-entrypoint.…"   5 minutes ago   Up 4 seconds   80/tcp    nginx
```

`-a` オプションですべてのコンテナを表示し、ない場合は起動中のコンテナのみを表示します。

[http://localhost:8080/index.html](http://localhost:8080/index.html)にアクセスすると以下のような画面が表示されます

![nginx_hello_docker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263665/324cce18-23ce-6008-619a-6b04133289e1.png)

以下のコマンドでコンテナを停止できます。

```bash:コンテナの停止
docker container stop [コンテナ名]
```

```bash:コンテナの停止
docker container stop nginx
```

コンテナの `status` がstoppedになっているか確認します

```bash:コンテナ確認
docker container ls -a
```

```bash:結果
CONTAINER ID   IMAGE          COMMAND                   CREATED         STATUS                      PORTS     NAMES
e5ad83bf5621   nginx:latest   "/docker-entrypoint.…"   6 minutes ago   Exited (0) 19 seconds ago             nginx
```
また、以下のコマンドでコンテナを削除できます。

```bash:コンテナの停止
docker container rm [コンテナ名]
```

```bash:コンテナの停止
docker container rm nginx
```

```bash:コンテナ確認
docker container ls -a
```

```bash:結果
CONTAINER ID   IMAGE          COMMAND                   CREATED         STATUS                      PORTS     NAMES
```


`docker run` はコンテナの作成`docker create`とコンテナの起動`docker start`を両方実行してくれます。通常はこちらを使う場合が多いです。

```bash:コンテナの作成・起動
docker run [オプション] [イメージ名]
```

```
docker run --name nginx -p 8080:80 nginx:latest
```

### 1.6 コンテナ上でのコマンドの実行

以下の方法で実行中のコンテナでコマンドを実行することができます
```bash:コマンド実行(起動中のコンテナ)
docker exec [コンテナ名] [コマンド]
```
試しに、以下のコマンドでフォルダの中身を表示してみます。
```bash:lsコマンド実行
docker exec nginx ls /var/www/html/localhost
```
```bash:結果
index.html
```

また、`-it`オプションをつけてbashコマンドを実行するとコンテナのシェルに入ることができます
```bash:コマンド実行
docker exec -it nginx bash
```

このコマンド実行の方法は`docker run`コマンドでも使えます
```bash:コマンド実行
docker run -it nginx:latest bash
```

### 1.7 Docker Composeによる複数コンテナの管理

Docker Compose を使うと、複数のコンテナをまとめて起動することができます
Docker Compose では、[yamlファイル](https://wa3.i-3-i.info/word13801.html)を用いて記述を行います
複数のコンテナをまとめて管理できるメリットだけでなく、yamlで簡単に記述でき、見通しがいいというメリットもあります。

ディレクトリに以下のファイルを作成してください

![docker-intro-directory.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263665/f4553f6b-3b0b-fa2b-704a-8ac90f49376f.png)

```html:source/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Docker Test</title>
    <link href="index.css" rel="stylesheet" type="text/css" media="all" />
  </head>
  <body>
    <h1>Docker is running!</h1>
    <h2>Dockerfile</h2>
    <div class="code-block">
      FROM nginx:latest <br />
      COPY index.html /var/www/html/localhost/ <br />
      COPY index.css /var/www/html/localhost/ <br />
      RUN apt update && \ <br />
      apt install vim
    </div>
    <h2>docker-compose.yaml</h2>
    <div class="code-block">
      version: '3.8'<br />
      services:<br />
      &nbsp;&nbsp;nginx:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;build:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;context: .<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dockerfile: Dockerfile<br />
      &nbsp;&nbsp;&nbsp;&nbsp;image: nginx:latest<br />
      &nbsp;&nbsp;&nbsp;&nbsp;container_name: nginx<br />
      &nbsp;&nbsp;&nbsp;&nbsp;ports:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- 8080:80<br />
      &nbsp;&nbsp;&nbsp;&nbsp;volumes:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- ./source:/var/www/html/localhost<br />
      &nbsp;&nbsp;&nbsp;&nbsp;tty: true<br />
      &nbsp;&nbsp;&nbsp;&nbsp;stdin_open: true<br />
      &nbsp;&nbsp;&nbsp;&nbsp;environment:<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- NGINX_HOST=localhost<br />
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- NGINX_PORT=80
    </div>
    <a href="http://localhost:8090">localhost:8090</a>
  </body>
</html>
```

```css:index.css
div.code-block {
    color: aqua;
    background: black;
    margin: 1rem;
    padding: 1rem;
    width: 70%;
}
```

```nginx:nginx.conf
events {
    worker_connections  4096;
}
http{
    include mime.types;
    default_type application/octet-stream;
    server{
        listen 80;
        server_name localhost;
        root /var/www/html/localhost;
        charset UTF-8;
    }
    log_format formatA '[$time_local]$connection - $status';
    access_log /var/logs/nginx/access_log formatA;
}
```

```docker:Dockerfile
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
RUN mkdir -p /var/logs/nginx
ENV NGINX_HOST=localhost
ENV NGINX_PORT=80
EXPOSE 80
```

```yaml:docker-compose .yaml
version: '3.8'
services:
    nginx-1:
        build:
            context: .
            dockerfile: Dockerfile
        image: nginx-1:latest
        container_name: nginx-1
        ports:
            - 8080:80
        volumes:
            - ./source:/var/www/html/localhost
        tty: true
        stdin_open: true
        environment:
            - NGINX_HOST=localhost
            - NGINX_PORT=80
    nginx-2:
        image: nginx:latest
        container_name: nginx-2
        ports:
            - 8090:80
        tty: true
        stdin_open: true
```
各項目の解説
- version
    Composeファイル形式のバージョン指定(2024/6現在3.8が最新)
- services
    サービス(Dockerのイメージ、コンテナ、設定などのまとまり)の一覧
- build
    ビルド`docker-compose build`時の設定
    - context
        DockerfileなどDockerのビルドに必要なファイルの場所を指定する
    - dockerfile
        context内のDockerfileを指定する
- image
    イメージを指定する。指定されたイメージが無ければbuildを元にイメージを作成する
- container_name
    コンテナ名を指定する
- ports
    ポート転送設定。ホスト側のポート:コンテナ側のポート
- volumes
    ホスト側のディレクトリとコンテナ側のディレクトリを同期する
- tty
    コンテナに入出力デバイスを割り当てる
- stdin_open
    標準入出力とエラー出力をコンテナに結びつける

次に、ディレクトリ上で以下のコマンドを実行してイメージを作成します。
```bash:イメージの作成
docker-compose build
```
以下のコマンドでコンテナを作成・起動します
```bash:コンテナの作成・起動
docker-compose up
```
[localhost:8080/index.html](http://localhost:8080/index.html)
にアクセスして確認します

このような画面が表示されます
![nginx_index_html.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263665/e49d9bf7-1d2b-4e0a-0231-ebc7d3f0f58e.png)

[localhost:8090](http://localhost:8090)
にアクセスして確認します

こちらはNginxのデフォルトの画面になっています
![welcome_to_nginx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263665/f5fa9a20-1c49-e128-47dc-dde73fa85e5d.png)


```bash:コンテナの停止・破棄
docker-compose down
```
で終了・コンテナを破棄します。

また、
```bash:デタッチモードでの起動
docker-compose up -d
```
でデタッチモードとして起動できます


コマンドを実行するときは
```bash:コマンド実行
docker-compose run [サービス名] [コマンド]
```

```bash:コマンド実行(起動中のコンテナ)
docker-compose exec [サービス名] [コマンド]
```

で実行できます

### 1.8 DockerHubからイメージを取得

[Dockerhub](https://hub.docker.com)には、様々なイメージが公開されています。
これらのイメージを利用すれば、自分で環境を構築しなくても、最初から使える環境が入手できます。

Ubuntu
https://hub.docker.com/_/ubuntu

Python
https://hub.docker.com/_/python

PyTorch
https://hub.docker.com/r/pytorch/pytorch

NodeJS
https://hub.docker.com/_/node

OpenJDK
https://hub.docker.com/_/openjdk

Go
https://hub.docker.com/_/golang

なんでもあります