やろーじだい

ブログと技術メモです。なにかあればより詳細に書こうということで最初は雑に書くようにしています。質問・要望等あれば Twitter かコメントに下さい。

Docker 上の MySQL に外部からアクセス可能な user を作成 (して Emacs で接続するまで)

これまで docker も sql もあまり触っていなかったので使い始めるまでの流れをまとめた。 また Emacs から接続するのにかなり時間がかかったのでこれの流れについても備考としてまとめた。

Docker の MySQL のインストールと接続

https://github.com/docker-library/docs/tree/master/mysql

Docker の mysql 用の image が公開されている。 docker-compose などは利用せず単に起動した docker 内の mysql サーバーコマンドライン等からアクセスすることを想定している。

起動から接続

基本的に README の通り

# dcoker の mysql image を DL
$ docker pull mysql

# docker mysql をベースに mysqld という名前で test_db というデータベースを作成しながらコンテナを起動
# <password> は任意のパスワード
$ docker run --name mysqld -e MYSQL_ROOT_PASSWORD=<password> -e MYSQL_DATABASE=test_db -d mysql

# 上の mysql に接続
$ docker run -it --link mysqld:mysql --rm mysql sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"'

これでコマンドラインからの接続はできた。

外部から接続できる user を追加する

-- 上で mysql に接続した状態で
-- どこからでも接続可能を意味する "%" で test_user をパスワード psword で追加
mysql> create user test_user@"%" identified by 'psword';

-- 権限を追加し確認後終了する
mysql> grant all privileges on *.* to test_user@'%';
mysql> select host, user from mysql.user;
+-----------+------------------+
| host      | user             |
+-----------+------------------+
| %         | root             |
| %         | test_user        |
| localhost | mysql.infoschema |
| localhost | mysql.session    |
| localhost | mysql.sys        |
| localhost | root             |
+-----------+------------------+
mysql> ^Dbye
# docker を再起動
$ docker restart mysqld

# 新しい user で接続
$ docker run -it --link mysqld:mysql --rm mysql sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -utest_user -ppsword'

備考: bind-address

何かエラーがでた時に検索すると大抵 bind-address が云々という記事が出てくるが基本的に docker 経由の場合は別な原因が殆である可能性が高い。 少し待ったり(!) docker を再起動したりすると問題が解決することがあった。

備考: Docker 上の MySQLEmacs から接続する

普段 Emacs を利用しているので Emacs からも接続できるようにしたい。 まず以下のサイトの通りに始めはやってみたのだがうまくいかなかった。

http://rebeja.eu/use-emacs-sql-mode-to-connect-to-database-on-a-docker-image/

そのためいろいろ試した結果以下の流れでできた。

まず Docker で起動する時に -p でポートを指定する必要がある。 この時 -p 3306:3306 とローカル側の port を固定するとうまくいかなかったので -p 3306 としてローカル側のポートは自動的に割り振られるものを利用する。*1

# Docker 側の Port のみを指定して起動
$ docker run --name mysqld -e MYSQL_ROOT_PASSWORD=<password> -e MYSQL_DATABASE=test_db -p 3306 -d mysql

# Port の確認
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
6b098b7aeca6        mysql               "docker-entrypoint.s…"   16 seconds ago      Up 15 seconds       33060/tcp, 0.0.0.0:32771->3306/tcp   mysqld

Emacs では sql-mysql を利用するのだが、Port 指定がそのままではできないので以下を init.el などに追加する。 ただし変数 sql-mysql-login-params が一度 sql-mysql を起動しなければ作られないので use-package:config などで起動後に評価される必要がある。

(use-package sql
  :config
  (setq sql-mysql-login-params (append sql-mysql-login-params '(port))))

その後以下で接続する。

M-x sql-mysql
User: root
Password: <password>
Database: test_db
Server: 0.0.0.0
Port: 32771

おまけ

Docker 内のファイルに tramp 形式で簡単にアクセスできる拡張があり便利だった。

https://github.com/emacs-pe/docker-tramp.el

*1:毎回ポートを確認するのが面倒なので固定してうまくいく方法が知りたいです。