コンテナ上のMariaDBに外部から接続する方法まとめ

未だにHyper-V+DockerのPHP開発環境が落ち着かない。
今度はDockerコンテナ化したMariaDBに、諸々のアプリからアクセス出来ない問題が勃発したので、その試行錯誤工程をまとめました。

追記2018/02/03
PCが変わったのを機にもう一度やってみたら **あっさり出来ました。**
改めてやった時の備忘録はこちら。
ベストプラクティスかは分かりませんが、当記事のよりは洗練されたかと。
[DockerのMySQLコンテナに外部からアクセスする方法まとめ改 - Qiita](https://qiita.com/saken649/items/00e752d89f2a6c5a82f6)

# 環境

- Windows10 Proffesional
- Hyper-V
- Docker for Windows

# 何がMariaDBに繋がらない？

- A5:SQL mk-2
- CakePHP2

やってみると対処法が違いました。

# 現状の構成

現状docker-compose.ymlに記載している内容は以下の通りです。

```docker-compose.yml
version: '2'
services:
  mariadb:
    container_name: mariadb
    image: mariadb:user
    ports:
      - '3306:3306'
    volumes:
      - db:/var/lib/mysql
    privileged: true
    command: /sbin/init
  php_app:
    container_name: php_app
    image: php7:user
    expose:
      - '9000'
    ports:
      - '8080:80'
    volumes:
      - ../app_dir/:/var/www/html
    depends_on:
      - mariadb
    privileged: true
    command: /sbin/init
volumes:
  db:
```


```bash:docker_ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                            NAMES
2814f7b46798        php7:user           "/sbin/init"        5 days ago          Up 3 hours          9000/tcp, 0.0.0.0:8080->80/tcp   php_app
c376bb48006c        mariadb:user        "/sbin/init"        5 days ago          Up 3 hours          0.0.0.0:3306->3306/tcp           mariadb
```

- mariadb:user  
公式のcentosコンテナ(CentOS7)にMariaDBを手動インストールしたもの。  
単純にUbuntuに慣れていないのと、クエリログの設定を予めしておきたかったので自作。
- php7:user  
これも公式centosコンテナにPHP7.1とXDebugを手動インストールしたもの。  
同じくUbuntuに慣れていないのと、XDebugの設定を予めしておきたかったので自作。

# A5:SQLが繋がらない！
### エラー内容

```
「#28000Access denied for user 'root'@'gateway' (using password: NO)」
```

ホスト名: `localhost` (ポート: 3306)
ユーザー名: `root`
パスワード無し。
docker execしたコンソール上からのログインは可能。

### 試行錯誤

どうやら外部アクセス関連の設定が怪しい。

```MariaDB:MariaDB
MariaDB [mysql]> SELECT `Host`, `User`, `Password` FROM user;
+--------------+------+-------------------------------------------+
| Host         | User | Password                                  |
+--------------+------+-------------------------------------------+
| localhost    | root |                                           |
| 2814f7b46798 | root |                                           |
| 127.0.0.1    | root |                                           |
| ::1          | root |                                           |
| localhost    |      |                                           |
| 2814f7b46798 |      |                                           |
+--------------+------+-------------------------------------------+
6 rows in set (0.00 sec)
```

※「2814f7b46798」はphp_appコンテナのコンテナIDです。

ここから読み取る限り、このMariaDBにアクセス出来るホストは「localhost」「127.0.0.1」「php_app」コンテナの3つ。
「::1」は、

```bash:/etc/hosts
sh-4.2# cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
```

とのことで、恐らく「localhost」と同義。

エラーメッセージ見る限り、「gateway」からのアクセス扱いになっているようで、それじゃあアクセス出来ませんね。

### ユーザー作成
というわけでアクセス出来るユーザーを作ります。

```MariaDB:MariaDB
MariaDB [(none)]> USE mysql;
Database changed

-- a5m2ユーザーを、gatewayからのアクセス用ユーザーとして作成
MariaDB [mysql]> CREATE USER a5m2@gateway IDENTIFIED BY 'a5m2';
Query OK, 0 rows affected (0.00 sec)

MariaDB [mysql]> SELECT `Host`, `User`, `Password` FROM user;
+--------------+------+-------------------------------------------+
| Host         | User | Password                                  |
+--------------+------+-------------------------------------------+
| localhost    | root |                                           |
| 2814f7b46798 | root |                                           |
| 127.0.0.1    | root |                                           |
| ::1          | root |                                           |
| localhost    |      |                                           |
| 2814f7b46798 |      |                                           |
| gateway      | a5m2 | *7367A95690040CB321E09B233CC56FCCB6AB2E0A |
+--------------+------+-------------------------------------------+
7 rows in set (0.00 sec)

-- a5m2ユーザーに全権限を設定
MariaDB [mysql]> GRANT ALL PRIVILEGES ON *.* TO a5m2@gateway WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)
```

Hostは「%」(Hostが何でも可)でも良いのですが、つまりは誰でもアクセス可になってしまいます。
いくらローカル環境とはいえ、ちょっと良くない上、今回はHostがちゃんと分かっているので指定しました。

改めてA5:SQLの設定をします。
ホスト名: `localhost` (ポート: 3306)
ユーザー名: `a5m2`
パスワード: `a5m2`

これでA5SQLから繋がりました。一件落着。

### 原因

Windowsからのアクセスはlocalhostではなく外部ホスト扱いになるらしく、そのホストからの接続設定がされていなかった。
よって、Windowsからのアクセス用ユーザーを作って解決。

# CakePHP2からも繋がらない！

ヘーイ！今度は何デスカー！？

### エラー内容

```
Database connection "Mysql" is missing, or could not be created.
SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
```

```php:app/Config/database.php
public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => 'localhost',
    'login' => 'root',
    'password' => '',
    'database' => 'database',
    'prefix' => '',
    'encoding' => 'utf8',
);
```

A5:SQLが繋がったと思ったら今度はCakePHP2からエラーが。
まーたlocalhostじゃ繋がらないのか。。

### 試行錯誤

一旦「host」をループバックアドレスである`127.0.0.1`にしてみます。

```
Database connection "Mysql" is missing, or could not be created.
SQLSTATE[HY000] [2003] Can't connect to MySQL server on '127.0.0.1' (111)
```

状況変わらず。
Dockerで別コンテナにする＝別ホストでDBが動いている、ということなのでしょうか。

```MariaDB:MariaDB
MariaDB [mysql]> SELECT `Host`, `User`, `Password` FROM user;
+--------------+------+-------------------------------------------+
| Host         | User | Password                                  |
+--------------+------+-------------------------------------------+
| localhost    | root |                                           |
| 2814f7b46798 | root |                                           |
| 127.0.0.1    | root |                                           |
| ::1          | root |                                           |
| localhost    |      |                                           |
| 2814f7b46798 |      |                                           |
| gateway      | a5m2 | *7367A95690040CB321E09B233CC56FCCB6AB2E0A |
+--------------+------+-------------------------------------------+
7 rows in set (0.00 sec)
```

とはいえ、コンテナIDがちゃんとmysql.userテーブルにもあるので、繋がりそうなものですが、繋がらないのは何故なんでしょうね。

### 接続先の変更
釈然としませんが、今度はIP直指定してみます。
まずはMariaDBコンテナのIPを調べます。

```bash:/etc/hosts
sh-4.2# cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3      c376bb48006c
```

```bash:docker_ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                            NAMES
2814f7b46798        php7:user           "/sbin/init"        5 days ago          Up 3 hours          9000/tcp, 0.0.0.0:8080->80/tcp   php_app
c376bb48006c        mariadb:user        "/sbin/init"        5 days ago          Up 3 hours          0.0.0.0:3306->3306/tcp           mariadb
```

MariaDBコンテナのコンテナIDが「c376bb48006c」なので、恐らく「172.10.0.3」というのがこのコンテナのIPでしょう。

```php:app/Config/database.php
public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => '172.10.0.3',
    'login' => 'root',
    'password' => '',
    'database' => 'database',
    'prefix' => '',
    'encoding' => 'utf8',
);
```

さて。

```
Database connection "Mysql" is missing, or could not be created.
SQLSTATE[28000] [1045] Access denied for user 'root'@'ic_v3.dockercompose_default' (using password: NO)
```

ホスト名がおかしいですね…？
試しに先程作ったa5m2ユーザーで試してみます。

```php:app/Config/database.php
public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => '172.10.0.3',
    'login' => 'a5m2',
    'password' => 'a5m2',
    'database' => 'database',
    'prefix' => '',
    'encoding' => 'utf8',
);
```

```
CakePHP is able to connect to the database.
```

無事繋がりはしたのですが、何か釈然としない。。
これも「gateway」ホストからのアクセスと見なされているのでしょうか。。

### 原因

別コンテナ＝別ホストらしいので、DBコンテナのIPを調べて直に指定する。
その際は、ホストPCからのアクセスとなるらしい？ので、ホストからアクセスするのと同等の権限を持ったユーザーを設定する必要がある。

# まとめ
とりあえず、外部ホストからアクセス出来てroot同様の権限を持つユーザーをMariaDB上に作らないといけない。
そして、基本そのユーザーを使ってアレコレする。

# おまけ
公式のMariaDBコンテナを使わずに、自作したから随所でハマっているような気がしなくもないです。
Ubuntuを避けてきましたが、ここらでUbuntuにも慣れないといけませんね。。

探し方が悪いのか、コンテナ連携や実際のアプリでの運用について説明しているサイトが意外と少なくて、割と手当たり次第やってる感が強いです。
Hyper-V+DockerでのPHP開発環境構築は、まだまだ前途多難なようです。。