超基礎からの 速習 Docker (3)

![Whale, Docker](https://cdn-images-1.medium.com/max/800/1*zzfsCJi6s-79v-4s1AXB1w.jpeg)

本稿は、Christffer Noring さん ([@chris_noring](https://twitter.com/chris_noring)) の [Learn Docker, from the beginning, part III](https://softchris.github.io/pages/docker-three.html) を翻訳し、分かりやすいように少しだけ追記、サンプルコードの実行上の補足等を行ったものです。シリーズ翻訳の意図については [超基礎からの 速習 Docker (1)](https://qiita.com/Gucchiy/items/16045193baabf3dfa176) の冒頭に掲載しています。併せてご参照くださいませ。

#超基礎からの 速習 Docker シリーズ一覧
>TLDR; とても長いけど、誓って、ここにあるのが最小限なんです。中盤で苦痛を伴うけど、きっと僕らは勝利する:smiley:

- **[超基礎からの 速習 Docker (1)](https://qiita.com/Gucchiy/items/16045193baabf3dfa176)** 
    - なぜ Docker なのか、コンテナーやイメージ、Dockerfile の基本コンセプトの解説、もちろん、それらを管理するのに必要なコマンド群もカバーしています。
- **[超基礎からの 速習 Docker (2)](https://qiita.com/Gucchiy/items/18d2ea155084419727c6)** 
    - Volume を用いたデータの永続化や、開発環境の Volume 化を通じて、開発をより手軽なものにします。
- **超基礎からの 速習 Docker (3)**
    - いまここ。
- **[超基礎からの 速習 Docker (4)](https://qiita.com/Gucchiy/items/8a4421dd087a99b44c78)**
    - Docker Compose を用いた複数サービスの管理方法を解説します（その１）
- **[超基礎からの 速習 Docker (5)](https://qiita.com/Gucchiy/items/8d078dde6d890fdd8144)**
    - Docker Compose を用いた複数サービスの管理方法を解説します（その２）

本稿はシリーズ パート3 です。このパートでは、データベースと Docker がどのようにお互い動作するのかについて学ぶことにフォーカスします。また、コンテナ環境のデータベースと強く結びつける Link 機能のコンセプトについても解説しています。

本稿では以下のトピックをカバーしています。

- **MySQL 実行に関する基本についてカバー** データベース一般の基本をカバーすることは常に良いことで、本稿では、その一つとして MySQL を選択しています。
- **なぜ MySQL Docker イメージを使う必要があるのか** どのようにイメージからコンテナーを生成するか、動作させるために必要な環境変数についても説明します。
- **MySQL コンテナーに接続する方法** Link 機能を使ったアプリケーション コンテナーから、二つのコンテナー間の基本的な Link 機能をどのように実現するか、データベースの初期設定を定義する際、どのような利点に使用できるかについてです。
- **Link 機能の知識を広げる** コンテナーを Link する新しい方法をカバーします。Link には 2種類の方法があります。一方の方法がよく使われ、他方は非推奨となっているため、僕らは新しい方法をカバーします。
- **データベースを管理する良い方法を説明** 初期構造や初期データ（シード データ）を与える方法です。

#リソース

Docker を使う事、コンテナー化は、一枚岩をマイクロサービスに分解していくことです。このシリーズのいたるところで僕らは Docker やそのコマンド体系をマスターするために学ぶことになります。そうすれば、きっと君は自作のコンテナーをプロダクション環境で使いたくなるでしょう。その環境は大抵クラウド上にあります。十分な Docker 経験を積んだと思ったなら、次のリンクで Docker をクラウドでどのように活用できるか、ご確認してみると良いと思います。

- [Azure 無料アカウントのサインアップ](https://azure.microsoft.com/ja-jp/free/?wt.mc_id=personal-blog-chnoring) プライベート レジストリのようなクラウドのコンテナーを使うには、無料 Azure アカウントが必要でしょう。
- [クラウドのコンテナー](https://docs.microsoft.com/ja-jp/azure/containers/?wt.mc_id=personal-blog-chnoring) クラウドのコンテナーについて他に知っておくべきことについて網羅する概要ページです。
- [自作コンテナーをクラウドにデプロイ](https://docs.microsoft.com/ja-jp/azure/container-instances/container-instances-tutorial-prepare-app?wt.mc_id=personal-blog-chnoring) 今の Docker スキルをレバレッジしてクラウド上でサービスを動かすことがいかに簡単かを示すチュートリアル。
- [コンテナー レジストリの作成](https://docs.microsoft.com/ja-jp/azure/container-instances/container-instances-tutorial-prepare-acr?wt.mc_id=personal-blog-chnoring) 自作 Docker イメージを Docker Hub に入れられますが、クラウドのコンテナー レジストリも可能です。自作イメージをどこかにストアして、一瞬でレジストリから実際のサービスをできるようにすることは凄くないですか？

#データベース一般、とりわけ MySQL を使うには

データベース一般について、僕らは以下のようなことをやりたくなります：

- **read** 僕らは様々な Query の方法でデータを読みたいと思います。
- **alter/create/delete** 僕らはデータを変更する必要があります。
- **構造を追加する** 僕らは table や collection と言った構造を作成する方法が必要です。それにより、特定フォーマットでデータは保存されます。
- **初期データ（シード データ）の追加** シンプルなデータベースでは全く不要でかも知れませんが、複雑なシナリオの場合、table が基本データで事前入力されている必要があるかも知れません。表示状態を作るためや、既に存在するデータ、またはある状態に入るデータと言った、異なるシナリオのテストを容易にするため、開発フェーズではシード データが重要です。例えば、ショッピング カートにテストしたいアイテムが入っている状態で、会計ページをテストしたい時です。

インデックスの追加や、アクセス権の異なるユーザーの追加などなどなど、データベースで行いたいことは山ほどありますが、僕らが Docker を使う上で知るべきリファレンスとして、上記 4つのポイントにフォーカスしましょう。

##インストールと MySQL への接続

MySQL をインストールする方法はたくさんありますが、全部が全部早いわけではありません:confused:。Linux の場合は以下のようにタイプするのも簡単でしょう：

`sudo apt-get install mysql-server`

>**訳注** 
Linux と言ってもディストリビューションとか環境によって MySQL のインストール方法はマチマチでしょうけど、恐らく Linux ユーザーなら各々 MySQL のインストールはできますよね・・？:sweat_smile:

Mac の場合、brew を使って次のように代わりにタイプするでしょう：

`brew install mysql`

>**訳注**
上記方法で Mac に MySQL をインストールするには、Homebrew をインストールする必要があります。インストール方法などの詳細は以下を参照くださいませ。ターミナルから一行たたくだけです。
https://brew.sh/index_ja

他のシナリオの場合でも、インストーラーをダウンロードして Wizard に従ってください。

>Windows の場合、訳者の環境では [XAMPP](https://www.apachefriends.org/jp/index.html) と言う、Apache + MySQL + PHP を自動でインストールするものを利用してしまいました。もちろん、[MySQL 単体インストールも可能](https://dev.mysql.com/doc/refman/5.6/ja/windows-installation.html)のようです。いずれにしても、PowerShell からインストールする方法はありませんので、各手順にある通り、インストーラーをご利用ください。

一旦、MySQL をインストールし終わると、以下のような情報が出てきます。もちろん、インストール パッケージによって異なるでしょう：

```
==> mysql
We've installed your MySQL database without a root password. To secure it run:
    mysql_secure_installation

MySQL is configured to only allow connections from localhost by default

To connect run:
    mysql -uroot

To have launchd start mysql now and restart at login:
  brew services start mysql
Or, if you don't want/need a background service you can just run:
  mysql.server start
```

上の例では、root パスワードがまだついてないって言ってます・・ギャー！。しかし、mysql-secure-installation を実行することで fix できます。今はとりあえず、提案されている通り  `mysql -uroot` を実行してデータベースに接続しましょう。

```
% mysql -uroot
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
```
NOOO、何が起きたんだ？インストール時に表示された画面でこの情報を得ましたが、`brew services start mysql` を実行して、MySQL を起動する必要があるのでした。OK、さっそく `brew services start mysql` を入力しましょう：

```
% brew services start mysql
==> Tapping homebrew/services
Cloning into '/usr/local/Homebrew/Library/Taps/homebrew/homebrew-services'...
remote: Enumerating objects: 40, done.
remote: Counting objects: 100% (40/40), done.
remote: Compressing objects: 100% (29/29), done.
remote: Total 731 (delta 10), reused 27 (delta 6), pack-reused 691
Receiving objects: 100% (731/731), 201.74 KiB | 470.00 KiB/s, done.
Resolving deltas: 100% (282/282), done.
Tapped 1 command (40 files, 277.3KB).
==> Successfully started `mysql` (label: homebrew.mxcl.mysql)
```

一番最後、Successfully started \`mysql\`：
![Alright, Alright, Alright](https://cdn-images-1.medium.com/max/466/1*-Zi5Ebc6BPSJlH8YvHbsgQ.gif)

Matthew が正しいかどうか見てみよう（訳注：gif が Matthew David McConaughey？）接続できたかな？

>**訳注**
Windows でも MySQL Server を起動しなくてはいけない場合があります。Linux はもちろんですね。Windows で、[MySQL 単体インストール手順](https://dev.mysql.com/doc/refman/5.6/ja/windows-installation.html)に従った場合は、サービスとして自動起動するようなので、特に起動しなくても大丈夫なのではないかと想像します（ごめんなさい、未検証）[XAMPP](https://www.apachefriends.org/jp/index.html)を使っている場合、XAMPP Control Panel を使って MySQL を起動してくださいませ。
![XAMPP Control Panel](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11871/e0e8348d-47a4-666b-6fc6-d8c9bc0c7a74.png)
しかし、MySQL Server を起動しなければならない、ということは使ったことある人なら常識ですよね。全般、この章の MySQL 解説はちょっと丁寧すぎる感じもしてますけど、以降もいろいろハマりながら進めるために、基礎を一度再確認しておくと良い、ということなのでしょう。


```
% mysql -uroot             
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.19 Homebrew

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 
```

プロンプト `mysql>` を得ることができた。僕らは入れた:smile:

OK、パスワードなしで接続していたので、それを Fix しましょう。まだデータベースを持ってなかった。これも Fix しよう:smiley:

僕らがデータベースを持っていないというわけでもなく、自分でデータベースを作っていない、が正くて、僕らがタッチできない実行サポート用データベースはあります：

```
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql> 
```

次に新しいデータベースを作成、選択します。次のように Query を入力します：

```
mysql> CREATE DATABASE Customer;
Query OK, 1 row affected (0.01 sec)

mysql> USE Customer;
Database changed
mysql> 
```

OK、素晴らしい。でも待って。僕らはテーブルを持ってなくないか？そうそう、僕らはテーブルをどうにかして作らないといけない。ターミナルからテーブルを作ることもできるけど、ちょっと痛い。複数のステートメントがたくさん出てきます。ですので、もしできるなら MySQL にファイルでデータベースと作りたい全てのテーブルを入力しましょう。テーブルを追加し続ける最初のファイルを定義しましょう。

```sql:database.sql
/* creates a table `tasks` */
CREATE TABLE IF NOT EXISTS tasks (

task_id INT AUTO_INCREMENT,

title VARCHAR(255) NOT NULL,

start_date DATE,

due_date DATE,

status TINYINT NOT NULL,

priority TINYINT NOT NULL,

description TEXT,

PRIMARY KEY (task_id)

);
/* add more tables below and indeces etc as our solution grows */
```

OK、データベース構造のファイルを作ったので、その内容を取得するため、次のようにして source コマンドを使うことができます：

```
mysql> source /Users/・・・/database.sql
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW TABLES;
+--------------------+
| Tables_in_customer |
+--------------------+
| tasks              |
+--------------------+
1 row in set (0.00 sec)

mysql> 
```

もし、君の database.sql ファイルのあるフルパスを知りたければ、君のファイルのある場所で `pwd` とタイプします。そして、`source [path to sqlfile]/database.sql` とタイプします。先に示した通り、SQL ファイルを実行する前に、データベースを選択する必要があります。テーブルが作成されたかどうかは `SHOW TABLES;` で確認します。同じコマンドを使ってデータベースにシードデータを入れることもできますが、CRWATE TABLE ではなく、INSERT ステートメントになっている sql ファイルを処理することになります・・

OK、では、MySQL はこれで十分。次は Docker の中で動く MySQL について話そう。（訳注：MySQL のコンソールからは、`quit;` などとして抜けてくださいませ）

#なぜ MySQL Docker イメージが必要で、どのようにコンテナーとして起動・実行するのか

OK、それでは、アプリケーション用のコンテナーが欲しいとしましょう。更に、そのソリューションにはデータベースが必要だとしましょう。コンピューターが実行されているホストに MySQL をインストールすることはあまり意味がないでしょう。コンテナーのマントラの一つは、コンテナーが実行されているホスト システムについてケアする必要はない、という意味です（訳注：なぜ[マントラなんていう文教用語](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%B3%E3%83%88%E3%83%A9)が出てきたのか分かりませんが、要はコンテナーで考えている時、ホストを考慮する必要はない、ということのようです）OK、なので、コンテナーに入っている MySQL が必要なのです。アプリがコンテナーを所有するのでしょうか。それとも、コンテナーを分離するのでしょうか。いい質問です。アプリに MySQL をインストールすることもできますし、別のコンテナーで MySQL を実行することもできます。その論拠は：

- **ローリング アップデート** これによって、アプリケーションが個別にリスタートしている間も、データベースは常にオンラインになり、ダウンタイムが発生しません。
- **スケーラビリティ** 疎結合でノードを追加してスケールすることができます。

これに対してはたくさんの議論・意見のあるところなので、どれが良いかは君だけが知ってます・・君のやり方でやるのが良いよ:smiley:

##スタンドアロン イメージとしての MySQL
MySQL のイメージを引っ張ってくるシナリオについて話しましょう。OK、一歩ずつ手順を追って、説明しましょう。最初に行うことは MySQL を実行してみることです。前章で学んだようにイメージを持っていなければイメージを引っ張ってきます。コマンドは次のようになります：

`docker run --name=mysql-db mysql`

OK、アウトプットはどうなっているでしょう？

```
% docker run --name=mysql-db mysql
Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
afb6ec6fdc1c: Pull complete 
0bdc5971ba40: Pull complete 
97ae94a2c729: Pull complete 
f777521d340e: Pull complete 
1393ff7fc871: Pull complete 
a499b89994d9: Pull complete 
7ebe8eefbafe: Pull complete 
597069368ef1: Pull complete 
ce39a5501878: Pull complete 
7d545bca14bf: Pull complete 
211e5bb2ae7b: Pull complete 
5914e537c077: Pull complete 
Digest: sha256:a31a277d8d39450220c722c1302a345c84206e7fd4cdb619e7face046e89031d
Status: Downloaded newer image for mysql:latest
2020-05-24 02:36:17+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.20-1debian10 started.
2020-05-24 02:36:17+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2020-05-24 02:36:17+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.20-1debian10 started.
2020-05-24 02:36:17+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
        You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD
```

イメージを引っ張ってこれましたね（訳注：英語では pull down）アァァァンド、エラー。

僕らは間違ってばかりだ:frowning:

データベースが初期化されていない、パスワード オプションが指定されていない、などなど。これを Fix していきましょう：

`docker run --name mysql-db -e MYSQL_ROOT_PASSWORD=complexpassword -d -p 8001:3306 mysql`

そして勝者は：

```
% docker run --name mysql-db -e MYSQL_ROOT_PASSWORD=complexpassword -d -p 8000:3306 mysql
docker: Error response from daemon: Conflict. The container name "/mysql-db" is already in use by container "3069364970cd5a876976180a89b30a51e41ae003f0ae75165c30d1d183694332". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.
```

うげっ、エラーメッセージを出したにも関わらず、僕らが前に始めたコンテナーが起動・実行されている。OK、コンテナーを落としましょう。

`docker rm mysql-db`

上記のようにデータベース セットを再度実行しましょう。

```
% docker run --name mysql-db -e MYSQL_ROOT_PASSWORD=complexpassword -d -p 8001:3306 mysql
c352b4abe3adcb8af5f3155093d69ae85d8540cbc66cc780b55b0a047288aa73
```

OK、全てのログはターミナルに表示されません。なぜなら、Daemon モード（訳注：[Detached モードが正しい？](https://qiita.com/Gucchiy/items/18d2ea155084419727c6#%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%83%BC%E3%81%AE%E5%AE%9F%E8%A1%8C)）で実行されているからです。`docker ps` を実行して確認しましょう：

```
% docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
c352b4abe3ad        mysql               "docker-entrypoint.s…"   45 seconds ago      Up 44 seconds       33060/tcp, 0.0.0.0:8001->3306/tcp   mysql-db
```

この時点で、外側から接続したくなります。ポート フォワーディングで 0.0.0.0:8001 に接続する必要があります：

`mysql -uroot -pcomplexpassword -h 0.0.0.0 -P 8001`

>**訳注**
Windows では 0.0.0.0 にアクセスすることはできませんでした。そもそも [0.0.0.0 を宛先にするのは誤りだ、という意見もある](https://qiita.com/amuyikam/items/0063df223aed40193ba9)ようです。ここでは単に MySQL が動いていることが分かれば良いので、`docker exec -it mysql-db bash` などとして、コンテナー内にログインし、コンテナー内で `mysql -uroot -pcomplexpassword` すれば良いかな、と思います。実行結果の様子は後述参照。

OK、上記のように、パスワードを設定して -p と書くだけで、次の行で即座にパスワードが入力されます。結果はこんな感じ：

```
% mysql -uroot -pcomplexpassword -h 0.0.0.0 -P 8001
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.20 MySQL Community Server - GPL

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 
```

OK、データベースの接続を管理しました。到達してますね。エライ:smiley:

>**訳注**
前述の通り、Windows では 0.0.0.0 へアクセスできませんので、以下のようにしてコンテナー内から MySQL を実行して確認すると良いでしょう。

```
> docker exec -it mysql-db bash
root@c352b4abe3ad:/# mysql -uroot -pcomplexpassword
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.20 MySQL Community Server - GPL

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 
```

>**訳注**
唐突ですが、MySQL コマンド プロンプトに入ったついでに、下記コマンドをタイプして、データベースを作っておいてくださいませ。次章以降の演習で外側からデータベースを接続する実験になるのですが、この "Customer" データベースがないとエラーとなります。

```
mysql> CREATE DATABASE Customers;
Query OK, 1 row affected (0.01 sec)

mysql> 
```


待って、他のコンテナーからコンテナー内のデータベースに到達できるのしょうか。そこはトリッキーなところです。二つのコンテナーをリンクする必要がある個所です。




##Node.js からデータベースに接続

>**訳注** 
以降の作業は、これまで作成してきたプロジェクトに追加することが想定されています。NPM パッケージのインストール等は作業してきた Node.jsプロジェクトのフォルダで行ってください。また、app.js も同じファイルを編集することが想定されています。

OK、それではデータベースに接続するコードをアプリに追加しましょう。最初に MySQL のための NPM パッケージをインストールする必要があります：

`npm install mysql`

次に、以下のコードを app.js の最初に追加します。

```js:app.js
const mysql = require('mysql');

const con = mysql.createConnection({

host: "localhost",

port: 8001,

user: "root",

password: "complexpassword",

database: 'Customers'

});

con.connect(function (err) {

if (err) throw err;
 console.log("Connected!");
});
```

それではターミナルで試してみましょう：

```
% node app.js      
Example app listening on port undefined!
/Users/・・・・/node_modules/mysql/lib/protocol/Parser.js:437
      throw err; // Rethrow non-MySQL errors
      ^

Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client
```

痛みと苦悩とはこのこと:frowning:
なぜ動かないのだろう？

>caching_sha2_password が MySQL 8.0 で導入されたが、Node.js ではまだ実装されていません。

OK、それがどうした、Postgres か他のデータベースで試すか？いえいえ、以下のようにコネクターに繋いで、Fix できます：

`mysql -uroot -pcomplexpassword -h 0.0.0.0 -P 8001`

>**訳注：**
Windows の場合は、`docker exec -it mysql-db bash` してコンテナーにログイン後、`mysql -uroot -pcomplexpassword` してください。

MySQL のプロンプトに入ったら、次のようにタイプします。

```
mysql> ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'complexpassword';
mysql> FLUSH PRIVILEGES;
```

`node app.js` コマンドを再度実行しましょう。次はこうなりますよ：

```
% node app.js
Connected!
```

ついに！

>**訳注**
この後、ポートエラーとかが出ていると思うのですが、無視していただいて結構です。これは Docker を経由せずに Node.js 単体として、app.js を呼び出しているためです。Dockerfile が設定する環境変数 "PORT" が入っていないんですね。Connected が出たかどうかが実験のすべてなので、"Connected" さえ出ていれば、エラーは気にせず進んでくださいませ。

OK、mysql_native_password の呼び出しはすべてを Fix したようですね。兎穴のより深いところに行きましょう。これって何？

>MySQL はネイティブの認証を実装した mysql_native_password Plug-In を含んでいます。この認証は Plug-In 可能な認証が導入される前から使用されているパスワード ハッシュ方式です。

OK、MySQL 8 は Node.js MySQL ライブラリがまだ追いついていない新しい Plug-In 化された認証にスイッチしているということですね。これは古いバージョンの MySQL を持ってくるか、native 認証に戻せばよいということです:smiley:

>**訳注**
先ほどの謎のコマンドで、MySQL パスワードの認証方式を caching_sha2_password から、mysql_native_password に変更しています。SHA256（"シャーにごろ"とか発音しますね）はダイジェスティングの方式ですが、ここでは暗号化の方法を変えるぐらいにご理解いただければ十分かと思います。コンピューターはあらゆるところでハマりますね・・

##Link 機能

Link 機能のアイディアはコンテナーは実行しているデータベースの IP や Port といった詳細を知る必要はないということに由来します。アプリ コンテナーとデータベース コンテナーがお互いに到達するといったことがちょうど例となります。典型的なシンタックスはこのようになります：

`docker run -d -p 5000:5000 --name product-service --link mypostgres:postgres chrisnoring/node`

少し上記をブレイクダウンしましょう：

- **アプリ コンテナー** product-service と言う名前のアプリ コンテナーを作ります。
- **--link** 既存の mypostgres コンテナーと product-service をリンクするコマンドを読んでいます。
- **link alias** --link mypostgres:postgres は mypostgres をリンクし、 postgres と言う alias を与えています。この alias はデータベースに接続する際、product-service コンテナー内部で利用できます。

OK、 Link 機能をだいたい理解できたと思いますが、既存の my-container にどのように適合し、mysql-db データベース コンテナーにどのように link するか見ていきましょう。my-container を Link 機能なしにスタートしていますので、一旦停止・削除、--link 機能を追加パラメータで再起動する必要があります：

`docker kill my-container && docker rm my-container`

これで、コンテナーは終了します。起動する前に、コードをいくつか変更する必要があります。つまり、データベースに接続する部分です。--link mysql-db:mysql パラメータを使ってデータベース コンテナー と link しようとしています。これは、IP や Port 参照が不要になるという意味で、コードは次のようになります：

```js:app.js
// part of app.js, the rest omitted for brevity

const con = mysql.createConnection({

host: "mysql",  // we changed!

user: "root",

password: "complexpassword",

database: 'Customers'

});

// and the rest of the code below
```

違いは、今やホストは、localhost やリンク先を数値でリンクする原因となっていた Port を 8001 と明示しません。僕らはリンクしたデータベースに与えた alias（e.g mysql）にフォーカスすることが全てです。コードの変更と他のライブラリーの追加から、僕らはイメージを次のようにリビルドする必要があります：

`docker build -t chrisnoring/node .`

今回は link を付けて起動しましょう：

`docker run -d -p 8000:3000 --name my-container --link mysql-db:mysql chrisnoring/node`

アウトプットをみてみましょう：

```
% docker logs my-container                                                             

> nodejs@1.0.0 start /app
> nodemon app.js

[nodemon] 2.0.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node app.js`
Example app listening on port 3000!
Connected!
```

アプリ コンテナーからのログを見る `docker logs my-container` でログを表示させると最後に、MySQL との接続成功を示すコールバック関数からの　Connected! が出ています。
>**訳注**
これは、`console.log("Connected!");` のことを言っていますが、このように書かれたログを `docker logs my-container` で表示できる、ということですね。


今何時か分かる？BOOOM！（訳注：これ、何のジョークか分かる方、教えてください・・）

![BOOOM](https://cdn-images-1.medium.com/max/500/1*PankPb9dXZglAwLMqW1y-Q.gif)

#Link 機能の知識を広げる ―― 他の方法

OK、全部うまくいきました。アプリケーションをコンテナーに配置し、他のコンテナーにデータベースを配置し管理しました。しかし、僕らが見てきた Link 機能はレガシーとされていて、Link 機能に関する他のう方法を学ぶ必要があります。待って・・君が思うほど悪くない。実際、構文的に良くなるように見える。

この新しいやり方は、ネットワークを作る、またはカスタム ブリッジ ネットワークと呼ばれています。実際、僕らが作るネットワークの一つです。ポイントは、コンテナーが所属する特定のグループだということです。コンテナーは一つ以上のグループに横断して関係する、複数のネットワークに存在できます。そりゃまったくすごいことだ、構文を教えてくれないか？

最初に行うことは、アプリ コンテナーとデータベースコンテナーを所属させたいネットワークを作ることです。以下のコマンドでそのネットワークを作ることができます：

`docker network create --driver bridge isolated_network`

新しいネットワークができたので、追加のパラメータとして新しいネットワークと共に各コンテナーを作成する必要があります。

`docker run -d -p 8000:3000 --net isolated_network --name my-container chrisnoring-node`

上記で、--net シンタックスを用いて、isolated_network と呼ぶネットワークを作っています。残りのコンテナーを今まで通り、コンテナーの起動、実行です。簡単でしょう:smiley:

データベース コンテナーはどうでしょうか？

`docker run -p 8000:3306 --net isolated_network --name mysql-db -e MYSQL_ROOT_PASSWORD=complexpassword -d mysql`

--net isolated_network だけを加えて、データベース コンテナーを起動、実行しています。

コンテナーと他のコンテナーを明示的に Link する必要はもはやありません。特定のネットワークに配置するだけです。ネットワークのコンテナーは、お互いをどうコミュニケーションするか知っています。

ネットワークについては更に学ぶことがたくさんあります。たくさんのタイプや、コマンド ホストがあります。レガシー Link 機能との違いと言った要点は理解できたのではないかと思います。更に学ぶ場合は、こちらのリンクを参照してください。→ [docs on networking](https://docs.docker.jp/network/links/)

#コンテナー設定上の一般的なデータベース管理

OK、この章の最初でファイルとしてデータベース構造を作成する方法と、シード データをファイルとして作成する方法、それらを MySQL プロンプトで一括して実行する方法を話しました。つまりこういうことです。そこにどのように構造とシード データを取得するかはあなた次第ですが、大まかなガイドラインや考え方を示そうと思います：

- **構造（Structure）** いくつかの点でこのファイルを実行したくなります。データベースに入れるためには、mysql クライアントを使って接続することと、ホストコンピューターから外部ファイルを参照することとできます。または、アプリのリポジトリとして配置することも、Dockerfile で ファイルを コンテナーの中にコピーして実行することもできます。他の方法は、Knex や Sequelize と言った マイグレーションをサポートするライブラリを確認し、マイグレーションを実行してデータベース構造を特定することです。少し異なるトピックですが、このことを行う他の方法があることをお知らせしたかったのです。
- **シード データ** 構造と同じ方法でシード データを扱うことができます。これは構造を得た後に起きることで、一回限りです。アプリやデータベースのスタート毎に実行したい事ではなく、シードが基本的な構造データなのか、テスト目的で必要なデータなのかに応じて、手動で実行したい場合がほとんどです。e.g クライアントから MySQL に接続して、source コマンドを実行する

#サマリー

OK、この文書では、MySQL の一般的な情報、テーブルと言った構造をどう取得するかの議論、初期/テスト用のシード データについて触れ、それらのスタンドアロンのファイルを使ってデータベースへの入れ方をカバーしました。

次に、なぜ、ホストにインストールするより、Docker コンテナーでデータベースを実行するべきか議論し、続いて、レガシー Link テクニックを使って二つのコンテナーがコミュニケーションする方法を見せました。MySQL 8 の不幸と、MySQL Node.js モジュールが同期していない事実に時間を費やし、それを Fix しました。

レガシー Link 機能をカバーして、それで終わりにするわけにはいかず、コンテナーをネットワーク名を使って Link する新しい方法について話す必要がありました。

最後に、データベースの管理と希望について一般的なガイドラインを共有し、現時点では、データベースをアプリにどのように追加し、アプリの開発を続けていくか理解したところにいます。

[Twitter](https://twitter.com/chris_noring) をフォローして、トピックへのあなたの問い合わせやご質問、提案を頂けるとハッピーです。

***
**[超基礎からの 速習 Docker (4) に進む](https://qiita.com/Gucchiy/items/8a4421dd087a99b44c78)**