MySQL 是世界知名的關聯式資料庫(RDBMS),相當多應用(Application)背後都是以 MySQL 作為後端資料庫,是除了 PostgreSQL 之外的另一選擇。

MySQL 官方也提供 Docker 映像檔(image)讓人可以輕鬆透過 Docker 運行容器化的 MySQL

本文記錄如何使用 Docker hub 上的 MySQL 。

本文環境

MySQL 版本

目前 MySQL 官方提供 5.5, 5.6, 5.7 以及 8.0 共 4 種版本的資料庫,可以在 pull Docker image 時指定相對應的 tag ,就能夠使用對應版本的 MySQL , tag 列表可以參閱 連結

例如本文使用 MySQL 8.0 版,其對應的 tag 為 8.0 ,因此可用以下指令 pull image:

$ docker pull mysql/mysql-server:8.0

運行 MySQL

下載完成 image 後,可執行以下指令啟動 MySQL:

$ docker run --name=mysql8 -d -p 3306:3306 mysql/mysql-server:8.0

--name=mysql8 將 container 命名為 mysql8
-d 將 container 以背景(background)模式運行
-p 將 host 的 3306 port 導向至 container 的 3306 port, 如此一來,我們連線至 127.0.0.1:3306 便可直接連到 MySQL container

如果上述指令成功,可以用 docker ps 指令看到類似以下的執行結果:

$ docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS                           PORTS                               NAMES
501a59352391        mysql/mysql-server:8.0   "/entrypoint.sh mysq…"   3 seconds ago       Up 1 second (health: starting)   0.0.0.0:3306->3306/tcp, 33060/tcp   mysql8

登入 MySQL

Docker 版本的 MySQL 預設會隨機產生 root 密碼,因此必須查詢 log 才能得知密碼為何。

可用以下指令撈出 root 的密碼:

$ docker logs mysql8 2>&1 | grep GENERATED

執行成功的話可以看到類似以下的訊息:

[Entrypoint] GENERATED ROOT PASSWORD: 7IPAv[UPCURoGMAHujEx$uH8uPr

此時的 root 帳號只接受 container 內的本機(localhost)登入,所以我們以指令試著登入 MySQL:

$ docker exec -it mysql8 mysql -uroot -p

接著輸入以下 SQL 更新 root 的密碼,這是由於 MYSQL_ONETIME_PASSWORD 環境變數預設是 true 導致我們必須變更密碼才能進一步使用:

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';

如果不想這麼麻煩,可以改用以下指令直接設定 root 密碼:

$ docker run --name=mysql8 -d -p 3306:3306 --env MYSQL_ROOT_PASSWORD=myrootpassword mysql/mysql-server:8.0

如果連線到 docker 內的 MySQL 時遇到 Can’t connect to MySQL Server on ‘localhost’ 之類的錯誤的話,多半是因為 root 帳號只開放來自 localhost 的連線,可以使用以下 SQL 改為開放外部連線(p.s. Production 環境請勿如此使用,將造成資安問題):

mysql> UPDATE MYSQL.USER SET HOST='%' WHERE USER = 'root' LIMIT 1;

或者也可以新增 1 個開放外部連線的帳號:

mysql> CREATE USER 'newuser'@'%' IDENTIFIED BY 'password';
mysql> GRANT ALL ON your_database.* TO 'newuser'@'%';

更多可設定的環境變數(例如 MYSQL_DATABASE MYSQL_USER 等)可參閱 Docker Environment Variables 章節。

資料庫資料存在哪裡?

由於 Docker container 預設並不會儲存任何資料,需要掛載 Volume 才有辦法將資料持久化(Persisting Data),而 Docker MySQL 也已經預設幫我們掛載 Volume ,因此資料庫內的資料並不會因為 Docker 重新啟動而消失,如果想知道 MySQL 的 Volume 路徑,可以用 docker inspect container_name 查看 Mounts 的部分,例如:

$ docker inspect mysql8

以下為 Mounts 資訊:

 "Mounts": [
    {
        "Type": "volume",
        "Name": "4f2d463cfc4bdd4baebcb098c97d7da3337195ed2c6572bc0b89f7e845d27652",
        "Source": "/var/lib/docker/volumes/4f2d463cfc4bdd4baebcb098c97d7da3337195ed2c6572bc0b89f7e845d27652/_data",
        "Destination": "/var/lib/mysql",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
]

如果是 macOS 的使用者會發現 /var/lib/docker/ 找不到( no such file or directory: /var/lib/docker ),這是由於 macOS 的 Docker 是用 LinuxKit 模擬的,因此路徑又被包裝過一層,其大致在以下的路徑:

$ cd ~/Library/Containers/com.docker.docker/Data/vms/0/

可於上述資料夾內發現 tty 檔案,可以用 screen tty 指令,就能夠進入 LinuxKit 內,然後就能發現 /var/lib/docker/ 資料夾,然後就能順利找到相對應的 Volume 囉!

References

https://dev.mysql.com/doc/refman/8.0/en/docker-mysql-more-topics.html