【Docker】Docker活用上の基礎


ここではDockerを活用する上で知っておきたい基礎についてまとめています。


# Dockerイメージ


Dockerイメージは、ファイルシステムのようになっており、実行環境とソースコードが含まれているソフトウェアである。コンテナはこれを実行したプロセス。

例えば、イメージにnodeとJavaScriptで書かれたコードがあり、コンテナを立てるとそのJavaScriptプログラムが実行される。

ソフトウェアをPCにインストールして起動するように、コンテナレジストリーからDockerイメージをpullしてきて自分のPC上(Docker上)で起動することができる。




# データの永続化

以下チュートリアルを参考にしています。
（要点が簡潔にまとまっているので、Dockerについて理解したい場合はチュートリアルをやってみるといいと思います。）

https://github.com/docker/getting-started/tree/master

<br>
<br>

データを永続化するためにはボリュームを使います。


>ボリュームを作成し、それをデータが格納されているディレクトリにアタッチ (「マウント」とも呼ばれます) することで、データを永続化できます。

>名前付きボリュームは、単なるデータのバケットと考えてください。 Docker はディスク上の物理的な場所を維持するため、ボリュームの名前だけを覚えておく必要があります。


```
docker volume create todo-db
#「todo-db」というボリュームをホスト上（Docker上）に作る

docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
#作成したボリュームとコンテナ内の/etc/todosをマウントして繋げる
#これでコンテナを削除してもデータを永続化できる
```

>A lot of people frequently ask "Where is Docker actually storing my data when I use a named volume?" If you want to know, you can use the docker volume inspect command.

Dockerは実際にはどこにデータを保存しているかを確認するには`docker volume inspect`コマンドで確認できます。

```
docker volume inspect todo-db

[
    {
        "CreatedAt": "2019-09-26T02:18:36Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
        "Name": "todo-db",
        "Options": {},
        "Scope": "local"
    }
]
```

`Mountpoint`が実際の保存場所になります。



# ソースコードをマウントする


>アプリケーションで作業する場合、バインド マウントを使用してソース コードをコンテナにマウントし、コンテナがコードの変更を確認して応答し、変更をすぐに確認できるようにします。



>バインド マウントと名前付きボリュームは、Docker エンジンに付属する 2 つの主要なボリューム タイプです。ただし、他の使用例 (SFTP、Ceph、NetApp、S3 など) をサポートするために、追加のボリューム ドライバーを使用できます。


```
docker run -dp 3000:3000 -w /app -v "$(pwd):/app" 

# -vでマウントを設定できる。
# カレントディレクトリをコンテナ内の/appにマウントしている。
```


# ネットワーキング

>How do we allow the containers to talk to each other? 

>The answer is networking. Now, you don't have to be a network engineer (hooray!). Simply remember this rule...

>If two containers are on the same network, they can talk to each other. If they aren't, they can't.



コンテナ間で通信を行いたい場合はネットワークを設定します。

以下のルールだけ覚えておきましょうと言われています。
**2つのコンテナが同じネットワーク上にある場合、それらは互いに通信できます。そうでない場合は、できません。**



```
# 「todo-app」というネットワークを作成
docker network create todo-app


# MySQLを「todo-app」ネットワークに所属させて起動
# 「mysql」というネットワークエイリアスをつけている。
# -v todo-mysql-data:/var/lib/mysqlで自動的に「todo-mysql-data」ボリュームを作成してマウントしてくれる。最初にマウントを作成してからrunコマンドを打つ必要はなかったらしい。

docker run -d \
    --network todo-app --network-alias mysql \
    -v todo-mysql-data:/var/lib/mysql \
    -e MYSQL_ROOT_PASSWORD=secret \
    -e MYSQL_DATABASE=todos \
    mysql:8.0
```

>MySQL が稼働していることがわかったので、使用してみましょう。しかし、問題は...どのように？同じネットワーク上で別のコンテナを実行している場合、どのようにしてコンテナを見つけるのでしょうか (各コンテナには独自の IP アドレスがあることに注意してください)。

この場合「mysql」というネットワークエイリアスを使うことによって名前解決してくれるようです。（IPアドレスを指定しなくてもよく、接続時はホスト名に「mysql」を指定してあげればいい。）


```
# Nodeアプリケーションを「todo-app」ネットワークに所属させて起動
# 同じネットワーク上にあるので互いに通信できる

docker run -dp 3000:3000 \
  -w /app -v "$(pwd):/app" \
  --network todo-app \
  -e MYSQL_HOST=mysql \
  -e MYSQL_USER=root \
  -e MYSQL_PASSWORD=secret \
  -e MYSQL_DB=todos \
  node:18-alpine \
  sh -c "yarn install && yarn run dev"
```


# docker-compose

>But, there's a good chance you are starting to feel a little overwhelmed with everything you need to do to start up this application. We have to create a network, start containers, specify all of the environment variables, expose ports, and more! That's a lot to remember and it's certainly making things harder to pass along to someone else.


ということでdocker-composeを使います。


>The big advantage of using Compose is you can define your application stack in a file, keep it at the root of your project repo (it's now version controlled), and easily enable someone else to contribute to your project.


docker-composeのメリットは、コマンド1つで複数コンテナを立ち上げることができることです。
また、docker-compose.ymlを共有することで複数コンテナ環境を簡単に共有することができます。


```yml:docker-compose.yml
services:
  # サービスの名前を自由につけることができる。この名前は自動的にネットワークエイリアスになる。
  service_name:
    # dockerhubで確認して指定する
    image: node:18-alpine
    ports:
      - 5000:5000
    command: sh -c "yarn install && yarn run dev"
    # コンテナ内のワーキングディレクトリ（以下の場合、自動でappというディレクトリを作り、これがカレントディレクトリになる）
    working_dir: /app
    #このファイルが置かれているディレクトリとコンテナ内の/appをマウント
    volumes:
      - ./:/app
    # 環境変数の設定
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: password
      MYSQL_DB: app_name
  mysql:
    image: mysql:8.0
    # ホスト(Docker)内のapp_name_dataとコンテナ内の/var/lib/mysqlをマウント
    volumes:
      - app_name_data:/var/lib/mysql
    # MySQLの環境変数を設定する
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: app_name

# ホスト(Docker)内に「app_name_data」というボリュームを作る
# ボリュームはホストの/var/lib/docker/volumes以下に作られる
volumes:
  app_name_data:
```

docker-composeでコンテナ作成するとデフォルトでネットワークが作成されます。
（`docker-compose.ymlがあるディレクトリ名_default`というネットワーク。複数のdocker-composeで作ったコンテナ同士で通信したい場合は、一方のdocker-compose.ymlで意図的にネットワークを作成して、もう一方のdocker-compose.ymlでネットワークを指定する。）

https://qiita.com/kai_kou/items/d568fe94ee92f837e274

コンテナ起動時は
```
docker-compose up -d
```

コンテナを削除したいときは
```
docker-compose down

# ボリュームも削除したい場合は --volumes をつける
```

簡潔にいうとdocker-composeは、コマンド一つで複数のコンテナを起動でき、同時にネットワーク・環境変数・ポート等の設定ができるものです。

以上です。