[SadServers] 解説 "Bern": Docker web container can't connect
"Bern": Docker web container can't connect to db container.
SadServersの "Bern": Docker web container can't connect to db container. の解説です。
SadServers って何? って人は、 SadServers解説 を見てください。
一言でいうと、LeetCode (コーディング問題集) の Linuxサーバ設定版のようなものです。
問題
では、問題を見ていきます。
Scenario: "Bern": Docker web container can't connect to db container.
Level: Hard
Description: There are two Docker containers running, a web application (Wordpress or WP) and a database (MariaDB) as back-end, but if we look at the web page, we see that it cannot connect to the database. curl -s localhost:80 |tail -4 returns:
<body id="error-page"> <div class="wp-die-message"><h1>Error establishing a database connection</h1></div></body> </html>
This is not a Wordpress code issue (the image is :latest with some network utilities added). What you need to know is that WP uses "WORDPRESS_DB_" environment variables to create the MySQL connection string. See the ./html/wp-config.php WP config file for example (from /home/admin).
2つのDockerコンテナが動作し、Webアプリケーション(WordpressまたはWP)とバックエンドとしてデータベース(MariaDB)がありますが、Webページを見ると、データベースに接続できないことがわかります。 curl -s localhost:80 |tail -4 が返されます。
<body id="error-page"> <div class="wp-die-message"><h1>Error establishing a database connection</h1></div></body> </html>
これはWordpressのコードの問題ではありません(画像はネットワークユーティリティを追加した:latestです)。知っておくべきことは、WPはMySQL接続文字列を作成するために「WORDPRESS_DB_」環境変数を使用することです。例として、./html/wp-config.php WP設定ファイル(/home/adminから)をご覧ください。
Test: sudo docker exec wordpress mysqladmin -h mysql -u root -ppassword ping . The wordpress container is able to connect to the database in the mariadb container and returns mysqld is alive.
sudo docker exec wordpress mysqladmin -h mysql -u root -ppassword ping .wordpressコンテナはmariadbコンテナ内のデータベースに接続でき、mysqldが生きていることを返します。
Time to Solve: 20 minutes.
OS: Debian 11
解説
まず、 curl -s localhost:80 |tail -4
の動作確認をします。
admin@ip-172-31-19-232:/$ curl -s localhost:80 |tail -4
<body id="error-page">
<div class="wp-die-message"><h1>Error establishing a database connection</h1></div></body>
</html>
問題の通りの結果が返ってきています。
次に、Testの sudo docker exec wordpress mysqladmin -h mysql -u root -ppassword ping
を実行してみます。
admin@ip-172-31-19-232:/$ sudo docker exec wordpress mysqladmin -h mysql -u root -ppassword ping
mysqladmin: connect to server at 'mysql' failed
error: 'Unknown MySQL server host 'mysql' (-2)'
Check that mysqld is running on mysql and that the port is 3306.
You can check this by doing 'telnet mysql 3306'
当然ながら、エラーとなっています。
このコマンドは wordpress
コンテナから、mysqladmin -h mysql -u root -ppassword ping
を実行しています。エラーは、mysql
というサーバに接続できないことを示しています。
docker ps
コマンドで、動作中のコンテナを確認します。
sudo
をつけないと、permissionエラーとなるので、注意してください。sudoをしたくない場合は、dockerという名のグループを作ってユーザを登録すればいいのですが、ここではsudo
で回避します。
admin@ip-172-31-19-232:/$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6ffb084b515c wordpress:sad "docker-entrypoint.s…" 4 months ago Up 2 minutes 0.0.0.0:80->80/tcp wordpress
0eef97284c44 mariadb:latest "docker-entrypoint.s…" 4 months ago Up 2 minutes 0.0.0.0:3306->3306/tcp mariadb
wordpress
と mariadb
という2つのコンテナが動作していることがわかります。
wordpress
コンテナのイメージは、wordpress:sadでポート80をオープンしています。
mariadb
コンテナのイメージは、mariadb:latestでポート3306をオープンしています。
これらのコンテナについて調べていきます。
まず、docker inspect
で、mariadb
コンテナの詳細情報を確認します。
sudo docker inspect mariadb
"Env": [
"MYSQL_ROOT_PASSWORD=password",
"MYSQL_DATABASE=wordpress",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.14",
"MARIADB_MAJOR=10.8",
"MARIADB_VERSION=1:10.8.3+maria~jammy"
],
Env
に示される環境変数から、MYSQL_ROOT_PASSWORD=password
とMYSQL_DATABASE=wordpress
が設定されていることがわかります。
同様に、`wordpress コンテナの詳細情報を確認します。
sudo docker inspect wordpress
"Env": [
"WORDPRESS_DB_PASSWORD=password",
"WORDPRESS_DB_USER=root",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"PHPIZE_DEPS=autoconf \t\tdpkg-dev \t\tfile \t\tg++ \t\tgcc \t\tlibc-dev \t\tmake \t\tpkg-config \t\tre2c",
"PHP_INI_DIR=/usr/local/etc/php",
"APACHE_CONFDIR=/etc/apache2",
"APACHE_ENVVARS=/etc/apache2/envvars",
"PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64",
"PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64",
"PHP_LDFLAGS=-Wl,-O1 -pie",
"GPG_KEYS=42670A7FE4D0441C8E4632349E4FDC074A4EF02D 5A52880781F755608BF815FC910DEB46F53EA312",
"PHP_VERSION=7.4.30",
"PHP_URL=https://www.php.net/distributions/php-7.4.30.tar.xz",
"PHP_ASC_URL=https://www.php.net/distributions/php-7.4.30.tar.xz.asc",
"PHP_SHA256=ea72a34f32c67e79ac2da7dfe96177f3c451c3eefae5810ba13312ed398ba70d"
],
Env
に示される環境変数から、MYSQL_ROOT_PASSWORD=password
とWORDPRESS_DB_USER=root
が設定されていることがわかります。
問題にあるように、wordpressの設定は、/home/admin/html/wp-config.php
の WORDPRESS_DB_ 変数にて設定されるということなので、wp-config.php
の WORDPRESS_DB_
を確認します。
admin@ip-172-31-19-232:~/html$ grep WORDPRESS_DB_ wp-config.php
define( 'DB_NAME', getenv_docker('WORDPRESS_DB_NAME', 'wordpress') );
define( 'DB_USER', getenv_docker('WORDPRESS_DB_USER', 'example username') );
define( 'DB_PASSWORD', getenv_docker('WORDPRESS_DB_PASSWORD', 'example password') );
define( 'DB_HOST', getenv_docker('WORDPRESS_DB_HOST', 'mysql') );
define( 'DB_CHARSET', getenv_docker('WORDPRESS_DB_CHARSET', 'utf8') );
define( 'DB_COLLATE', getenv_docker('WORDPRESS_DB_COLLATE', '') );
phpはわからないですが、ググって調べると getenv_docker()
は、第1引数で環境変数を指定して、第2引数で環境変数が無いときのデフォルト値のようです。
MYSQL_ROOT_PASSWORD
とWORDPRESS_DB_USER
は環境変数が設定されているので、それぞれ環境変数の値password
と root
が使われ、それ以外は、デフォルト値が使われます。
が、これらの設定には特に問題はなさそうです。
wordpress
コンテナから、 mariadb
コンテナにアクセスできないことが問題なので、これを解決しましょう。
アクセスするだけなら、IPアドレスでアクセスするとかいろいろな手段があるのですが、テストが sudo docker exec wordpress mysqladmin -h mysql -u root -ppassword ping
と ホスト名mysql
でアクセスできないといけないので、wordpress
コンテナから、mariadb
コンテナに、ホスト名mysql
でアクセスできるようにする必要があります。
コンテナ間の通信は、docker compose
を使うと簡単なので、docker-compose.yml
ファイルを作ります。
version: "3"
services:
mysql:
image: mariadb:latest
# コンテナ名を指定
container_name: mysql
# hostnameをmysqlとする。 wordpressコンテナから、mysqlでアクセスできる。
hostname: mysql
ports:
- 3306:3306
environment:
# 元のmariadbコンテナの環境変数を設定
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: wordpress
wordpress:
depends_on:
- mysql
image: wordpress:sad
container_name: wordpress
hostname: wordpress
ports:
- 80:80
environment:
# 元のwordpressコンテナの環境変数を設定
WORDPRESS_DB_PASSWORD: password
WORDPRESS_DB_USER: root
既存のコンテナを停止してから、docker-compose
で起動します。
# 停止
admin@ip-172-31-19-232:~$ sudo docker stop wordpress mariadb
wordpress
mariadb
admin@ip-172-31-19-232:~$ cd /home/admin
# /home/admin/ で、 docker-composeを実行。
admin@ip-172-31-19-232:~$ sudo docker-compose up
Recreating admin_mysql_1 ... done
Recreating admin_wordpress_1 ... done
Attaching to mysql, wordpress
テストを実行します。
admin@ip-172-31-19-232:/$ sudo docker exec wordpress mysqladmin -h mysql -u root -ppassword ping
mysqld is alive
mysqld is alive
が出力されました。成功です。
curl
も試してみます。
admin@ip-172-31-19-232:/$ curl -v -s localhost:80
* Trying 127.0.0.1:80...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Date: Thu, 29 Dec 2022 11:15:14 GMT
< Server: Apache/2.4.54 (Debian)
< X-Powered-By: PHP/7.4.30
< Expires: Wed, 11 Jan 1984 05:00:00 GMT
< Cache-Control: no-cache, must-revalidate, max-age=0
< X-Redirect-By: WordPress
< Location: http://localhost/wp-admin/install.php
< Content-Length: 0
< Content-Type: text/html; charset=UTF-8
<
* Connection #0 to host localhost left intact
先ほどとは違う結果で、302
です。 リダイレクト先のデータを取得するために、-L
オプションを付けて再度実行してみます。
admin@ip-172-31-19-232:/$ curl -v -L localhost:80
* Trying 127.0.0.1:80...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Date: Thu, 29 Dec 2022 14:54:01 GMT
< Server: Apache/2.4.54 (Debian)
< X-Powered-By: PHP/7.4.30
< Expires: Wed, 11 Jan 1984 05:00:00 GMT
< Cache-Control: no-cache, must-revalidate, max-age=0
< X-Redirect-By: WordPress
< Location: http://localhost/wp-admin/install.php
< Content-Length: 0
< Content-Type: text/html; charset=UTF-8
<
* Connection #0 to host localhost left intact
* Issue another request to this URL: 'http://localhost/wp-admin/install.php'
* Found bundle for host localhost: 0x560f9bba12f0 [serially]
* Can not multiplex, even if we wanted to!
* Re-using existing connection! (#0) with host localhost
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /wp-admin/install.php HTTP/1.1
> Host: localhost
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 29 Dec 2022 14:54:01 GMT
< Server: Apache/2.4.54 (Debian)
< X-Powered-By: PHP/7.4.30
< Expires: Wed, 11 Jan 1984 05:00:00 GMT
< Cache-Control: no-cache, must-revalidate, max-age=0
< Vary: Accept-Encoding
< Content-Length: 6960
< Content-Type: text/html; charset=utf-8
<
<!DOCTYPE html>
正しく、取得できているようです。
Check My Solution
を実行して、問題ないことを確認します。
Discussion