最近在研究容器化使用 typecho,经常反复删除和重建容器,于是想到开启环境变量里自动安装的功能,但是尝试多次发现都没有效果。看到有朋友也遇到了一样的问题 #21。一番摸索后找到了原因,分享给大家供参考。
遇到问题:
开启自动安装需要在 docker-compose.yml 中设置环境变量 TYPECHO_INSTALL: 1
,但我发现即便是启用了,首次登录时还是会出现安装数据库的初始化页面,之后一切使用如常。初始配置文件 config.inc.php 也没有自动生成,但手动配置后会生成(如果你的问题是根本连不上数据库或者打不开页面什么的,应该是其他原因)。所以我考虑不是程序出错,而是配置不到位。
原 docker-compose 配置文件:
version: "3.9"
services:
nginx:
container_name: nginx
image: cym1102/nginxwebui
restart: unless-stopped
environment:
TZ: Asia/Shanghai
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- $PWD/typecho:/var/lib/nginx/html
- nginx:/home/nginxWebUI
depends_on:
- typecho
typecho:
container_name: typecho
image: joyqi/typecho:nightly-php8.0-fpm-alpine
restart: unless-stopped
environment:
TIMEZONE: Asia/Shanghai
TYPECHO_INSTALL: 1
TYPECHO_DB_HOST: mysql
TYPECHO_DB_USER: zurica
TYPECHO_DB_PASSWORD: 123456
TYPECHO_DB_DATABASE: typecho
TYPECHO_SITE_URL: http://my.web.site
TYPECHO_USER_NAME: zurica
TYPECHO_USER_PASSWORD: password
TYPECHO_USER_MAIL: [email protected]
volumes:
- $PWD/typecho:/app
depends_on:
- mysql
mysql:
container_name: mysql
image: mysql
restart: unless-stopped
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: typecho
MYSQL_USER: zurica
MYSQL_PASSWORD: 123456
volumes:
nginx:
name: nginx
networks:
default:
name: blog
探究原因:
查看 docker-compose 的日志会发现以下内容:
typecho | Typecho 1.2.0
typecho | PHP 8.0.22
typecho | 对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装
typecho | [23-Aug-2022 06:04:36] NOTICE: fpm is running, pid 33
typecho | [23-Aug-2022 06:04:36] NOTICE: ready to handle connections
......
mysql | 2022-08-23 14:04:38+08:00 [Note] [Entrypoint]: Creating database typecho
mysql | 2022-08-23 14:04:38+08:00 [Note] [Entrypoint]: Creating user zurica
mysql | 2022-08-23 14:04:38+08:00 [Note] [Entrypoint]: Giving user zurica access to schema typecho
......
已知 typecho 在访问 Mysql 时如果不存在相应数据库,会显示无法连接;而这里 Mysql 明明已经按照预设环境变量成功创建了 typecho 数据库。其实秘密在时间戳上:Mysql 创建 typecho 数据库的时间,比 typecho 尝试访问它的时间晚了2秒,typecho 自然访问了个寂寞 😓
解决方法:
那么问题又来了,我在 docker-compose 的 typecho 段落里已经写了
不起作用吗?
答案是确实不起作用(果然不能乱抄配置),因为按照官方文档的解释,depends_on 只是让被配置的容器比被依赖的容器后启动,并不是等被依赖的容器完全准备好了才启动。但是这个参数也是有作用的,就是通过长语法再补充一些细节:
service_healthy
service_completed_successfully
你可能以为要选第二个?错了 😅,因为名称已经写的很清楚了,这个服务不但要成功,还要完成(exits with 0 code)。如果只是毫无差错地处于待命状态,依赖它的容器就只能一直等下去也不能启动~~
使用 service_healthy 的话,就到要对容器进行健康检查,关于如何写判断条件我也查了很多:
- 检查数据库的目录是否已经生成
test: ["CMD", "test -f var/lib/mysql/typecho"]
- 检查运行的 mysql 版本
test: ["CMD", "echo 'SELECT version();'| mysql"]
- 检查容器是否能连接
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
实践证明以上三种都不管用,具体原因我也不清楚(尤其是第一种看似最可行的条件)
最后找到一个亲测可用的配置:
Docker-compose with MySQL/MariaDB and healthcheck
这个命令在 Mysql 容器里直接运行的结果:
bash-4.4# mysql --user=zurica --password=123456 --execute "SHOW DATABASES;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| performance_schema |
| typecho |
+--------------------+
其实也就是去判断目标数据库有没有建好
修改后的 docker-compose.yml
version: "3.9"
services:
nginx:
container_name: nginx
image: cym1102/nginxwebui
restart: unless-stopped
environment:
TZ: Asia/Shanghai
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- $PWD/typecho:/var/lib/nginx/html
- nginx:/home/nginxWebUI
depends_on:
- typecho
typecho:
container_name: typecho
image: joyqi/typecho:nightly-php8.0-fpm-alpine
restart: unless-stopped
environment:
TIMEZONE: Asia/Shanghai
TYPECHO_INSTALL: 1
TYPECHO_DB_HOST: mysql
TYPECHO_DB_USER: zurica
TYPECHO_DB_PASSWORD: 123456
TYPECHO_DB_DATABASE: typecho
TYPECHO_SITE_URL: http://my.web.site
TYPECHO_USER_NAME: zurica
TYPECHO_USER_PASSWORD: password
TYPECHO_USER_MAIL: [email protected]
volumes:
- $PWD/typecho:/app
depends_on:
mysql:
condition: service_healthy
mysql:
container_name: mysql
image: mysql
restart: unless-stopped
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: typecho
MYSQL_USER: zurica
MYSQL_PASSWORD: 123456
healthcheck:
test: "mysql --user=zurica --password=123456 --execute \"SHOW DATABASES;\""
interval: 2s
timeout: 1s
retries: 10
volumes:
nginx:
name: nginx
networks:
default:
name: blog
有几点要注意:
- depends_on 的长语法只对 2.x 和 3.9 的 docker-compose 配置文件有效,常规短语法没有限制;
- 关于健康检查的间隔和频次,可以酌情设定。我观察到从 Mysql 容器启动到创建 typecho 数据库需要15秒时间,那么设定的 Interval*retries 至少要能完全覆盖这段时间,不然健康检查会失败;
- 健康检查的条件不能写成 test: ["CMD“, ”XX", "XX"] 这种格式,也不能用 "-u" "-p" 等短参数。倒是没有报错,但也不会生效。
容器成功启动后的日志:
typecho | Typecho 1.2.0
typecho | PHP 8.0.22
typecho | 安装成功
typecho | 您的用户名是 zurica
typecho | 您的密码是 password
typecho | [23-Aug-2022 07:23:55] NOTICE: fpm is running, pid 32
typecho | [23-Aug-2022 07:23:55] NOTICE: ready to handle connections
......
mysql | 2022-08-23 15:23:49+08:00 [Note] [Entrypoint]: Creating database typecho
mysql | 2022-08-23 15:23:49+08:00 [Note] [Entrypoint]: Creating user zurica
mysql | 2022-08-23 15:23:49+08:00 [Note] [Entrypoint]: Giving user zurica access to schema typecho
......
数据库比访问请求早了6秒创建,自然就没有问题了
最后说一句,手动初始配置比这个省事多了,自动安装反而折腾 🤣