This commit is contained in:
wanghai
2026-02-06 20:38:12 +08:00
parent 3dfafe0b83
commit 903506c6fd
216 changed files with 28040 additions and 6204 deletions

281
docker-dev/docker-entrypoint.sh Executable file
View File

@@ -0,0 +1,281 @@
#!/bin/sh
# ECShopX API Docker 容器启动脚本
# 负责初始化服务、配置环境和启动 Supervisor
# 注意:某些非关键步骤允许失败(使用 || true关键步骤失败会退出
# 设置时区
if [ -z "$TZ" ]; then
export TZ="Asia/Shanghai"
fi
if ! ln -snf /usr/share/zoneinfo/$TZ /etc/localtime || ! echo "$TZ" > /etc/timezone; then
echo "警告: 无法设置时区,使用默认值"
fi
# 配置 PHP-FPM根据基础镜像的实际路径
PHP_FPM_CONF_DIR=""
if [ -d "/usr/local/etc/php-fpm.d" ]; then
PHP_FPM_CONF_DIR="/usr/local/etc/php-fpm.d"
elif [ -d "/etc/php7/php-fpm.d" ]; then
PHP_FPM_CONF_DIR="/etc/php7/php-fpm.d"
elif [ -d "/etc/php-fpm.d" ]; then
PHP_FPM_CONF_DIR="/etc/php-fpm.d"
fi
if [ -n "$PHP_FPM_CONF_DIR" ] && [ -f "/tmp/php-fpm-custom.conf" ]; then
if cp /tmp/php-fpm-custom.conf "$PHP_FPM_CONF_DIR/www.conf"; then
echo "✓ PHP-FPM 配置已复制到: $PHP_FPM_CONF_DIR/www.conf"
else
echo "✗ 错误: 无法复制 PHP-FPM 配置文件"
exit 1
fi
fi
# 检测 PHP-FPM 可执行文件路径(用于 supervisor 配置)
PHP_FPM_BIN=""
if [ -f "/usr/local/sbin/php-fpm" ]; then
PHP_FPM_BIN="/usr/local/sbin/php-fpm"
elif [ -f "/usr/sbin/php-fpm7" ]; then
PHP_FPM_BIN="/usr/sbin/php-fpm7"
elif [ -f "/usr/sbin/php-fpm" ]; then
PHP_FPM_BIN="/usr/sbin/php-fpm"
elif command -v php-fpm &> /dev/null; then
PHP_FPM_BIN=$(command -v php-fpm)
fi
if [ -n "$PHP_FPM_BIN" ]; then
# 更新 supervisor 配置中的 PHP-FPM 路径
SUPERVISOR_CONF="/etc/supervisor/conf.d/supervisord.conf"
if [ -f "$SUPERVISOR_CONF" ]; then
# 使用 sed 更新配置Alpine Linux 兼容语法)
if sed -i "s|^command=.*php-fpm.*|command=$PHP_FPM_BIN -F|" "$SUPERVISOR_CONF"; then
echo "✓ PHP-FPM 路径已设置为: $PHP_FPM_BIN -F"
else
echo "警告: 无法更新 supervisord.conf 中的 PHP-FPM 路径,使用默认配置"
fi
else
echo "✗ 错误: $SUPERVISOR_CONF 文件不存在"
echo "检查文件位置..."
find /etc -name "supervisord.conf" 2>/dev/null || echo "未找到 supervisord.conf"
exit 1
fi
else
echo "警告: 未找到 PHP-FPM 可执行文件supervisor 配置将使用默认路径"
fi
# 设置环境变量默认值(使用更简洁的语法)
export FPM_LISTEN="${FPM_LISTEN:-127.0.0.1:9000}"
export FPM_PM="${FPM_PM:-dynamic}"
export FPM_PM_MAX_CHILDREN="${FPM_PM_MAX_CHILDREN:-40}"
export FPM_PM_MIN_SPARE_SERVERS="${FPM_PM_MIN_SPARE_SERVERS:-1}"
export FPM_PM_MAX_SPARE_SERVERS="${FPM_PM_MAX_SPARE_SERVERS:-3}"
export FPM_PHP_ADMIN_VALUE_MEMORY_LIMIT="${FPM_PHP_ADMIN_VALUE_MEMORY_LIMIT:-64M}"
export MYSQL_ROOT_PASSWORD="${MYSQL_ROOT_PASSWORD:-rootpassword}"
export MYSQL_DATABASE="${MYSQL_DATABASE:-ecshopx}"
export MYSQL_USER="${MYSQL_USER:-ecshopx}"
export MYSQL_PASSWORD="${MYSQL_PASSWORD:-ecshopx}"
export REDIS_PASSWORD="${REDIS_PASSWORD:-redispassword}"
# 初始化 MySQL如果数据目录为空或没有系统表
if [ ! -d "/var/lib/mysql/mysql" ] && [ ! -d "/var/lib/mysql/mariadb" ]; then
echo "=========================================="
echo "初始化 MySQL 数据目录..."
echo "=========================================="
if ! mysql_install_db --user=mysql --datadir=/var/lib/mysql --skip-test-db --auth-root-authentication-method=normal >/dev/null 2>&1; then
echo "✗ 错误: MySQL 数据目录初始化失败"
exit 1
fi
# 启动 MySQL 以创建数据库和用户
echo "启动临时 MySQL 进程..."
mysqld_safe --defaults-file=/etc/my.cnf --user=mysql --datadir=/var/lib/mysql --skip-networking --socket=/var/run/mysqld/mysqld.sock >/dev/null 2>&1 &
MYSQL_PID=$!
# 等待 MySQL 启动(最多等待 30 秒)
echo "等待 MySQL 启动..."
MYSQL_READY=false
for i in $(seq 1 30); do
if mysqladmin ping --socket=/var/run/mysqld/mysqld.sock --silent 2>/dev/null; then
MYSQL_READY=true
break
fi
sleep 1
done
if [ "$MYSQL_READY" = false ]; then
echo "✗ 错误: MySQL 启动超时"
kill $MYSQL_PID 2>/dev/null || true
exit 1
fi
echo "✓ MySQL 已启动,创建数据库和用户..."
# 创建数据库和用户
if ! mysql --socket=/var/run/mysqld/mysqld.sock -uroot <<EOF
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';
CREATE DATABASE IF NOT EXISTS ${MYSQL_DATABASE};
CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'localhost' IDENTIFIED BY '${MYSQL_PASSWORD}';
CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';
GRANT ALL PRIVILEGES ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'localhost';
GRANT ALL PRIVILEGES ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'%';
FLUSH PRIVILEGES;
EOF
then
echo "✗ 错误: 无法创建数据库和用户"
kill $MYSQL_PID 2>/dev/null || true
exit 1
fi
# 停止 MySQLsupervisor 会重新启动)
echo "停止临时 MySQL 进程..."
mysqladmin --socket=/var/run/mysqld/mysqld.sock -uroot -p${MYSQL_ROOT_PASSWORD} shutdown 2>/dev/null || kill $MYSQL_PID 2>/dev/null || true
wait $MYSQL_PID 2>/dev/null || true
sleep 2
echo "✓ MySQL 初始化完成"
fi
# 配置 Redis
# 确保 Redis 用户和目录存在Dockerfile 中已创建,这里只是确保)
if ! id -u redis >/dev/null 2>&1; then
echo "警告: Redis 用户不存在,尝试创建..."
adduser -D -s /sbin/nologin redis || {
echo "✗ 错误: 无法创建 Redis 用户"
exit 1
}
fi
mkdir -p /var/lib/redis /var/log/redis /var/run/redis
chown -R redis:redis /var/lib/redis /var/log/redis /var/run/redis || {
echo "✗ 错误: 无法设置 Redis 目录权限"
exit 1
}
# 确保 Nginx 临时目录存在且有正确权限
mkdir -p /var/lib/nginx/tmp/client_body \
/var/lib/nginx/tmp/proxy \
/var/lib/nginx/tmp/fastcgi \
/var/lib/nginx/tmp/uwsgi \
/var/lib/nginx/tmp/scgi \
/var/log/nginx
chown -R www-data:www-data /var/lib/nginx /var/log/nginx || {
echo "警告: 无法设置 Nginx 目录权限,可能影响文件上传"
}
# 配置 Redis 密码
if [ -n "$REDIS_PASSWORD" ]; then
# 检查 Redis 配置文件是否存在
if [ -f "/etc/redis.conf" ]; then
# 如果已有 requirepass 配置,替换它;否则添加
if grep -q "^requirepass" /etc/redis.conf 2>/dev/null; then
sed -i "s/^requirepass.*/requirepass ${REDIS_PASSWORD}/" /etc/redis.conf
else
echo "requirepass ${REDIS_PASSWORD}" >> /etc/redis.conf
fi
else
# 如果配置文件不存在,创建基本配置
cat > /etc/redis.conf <<EOF
bind 0.0.0.0
port 6379
requirepass ${REDIS_PASSWORD}
dir /var/lib/redis
logfile /var/log/redis/redis.log
daemonize no
EOF
fi
fi
# 处理许可证文件
if [ -n "$LICENSEZL" ]; then
if echo "$LICENSEZL" | base64 -d > /data/httpd/ECShopX/license.zl 2>/dev/null; then
echo "✓ 许可证文件已写入"
else
echo "警告: 许可证文件解码失败"
fi
fi
# 如果提供了命令参数,直接执行(用于 docker exec 等场景)
if [ -n "$1" ]; then
exec "$@"
fi
# 先启动 supervisord 在后台(临时修改配置为 daemon 模式)
echo "=========================================="
echo "启动 Supervisor 管理所有服务..."
echo "=========================================="
# 创建临时配置文件daemon 模式)
TEMP_SUPERVISOR_CONF="/tmp/supervisord-daemon.conf"
cp /etc/supervisor/conf.d/supervisord.conf "$TEMP_SUPERVISOR_CONF"
# 修改为 daemon 模式
sed -i 's/nodaemon=true/nodaemon=false/' "$TEMP_SUPERVISOR_CONF" 2>/dev/null || \
sed -i 's/nodaemon = true/nodaemon = false/' "$TEMP_SUPERVISOR_CONF" 2>/dev/null || true
# 启动 supervisord 在后台
echo "启动后台 supervisord..."
if ! /usr/bin/supervisord -c "$TEMP_SUPERVISOR_CONF"; then
echo "✗ 错误: 无法启动 supervisord"
exit 1
fi
echo "✓ 后台 supervisord 已启动"
# 等待服务启动
echo "等待服务启动..."
sleep 5
# 检查 supervisord 是否运行(使用临时配置文件启动的进程)
# 等待一下让 supervisord 完全启动
sleep 2
if ! supervisorctl -c "$TEMP_SUPERVISOR_CONF" status >/dev/null 2>&1; then
echo "警告: 无法连接到后台 supervisord尝试继续执行..."
# 不退出继续执行composer 和迁移由 dev-setup.sh 处理)
fi
# 等待 MySQL 和 Redis 就绪
echo "等待 MySQL 和 Redis 服务就绪..."
MYSQL_READY=false
for i in $(seq 1 60); do
if mysqladmin ping --socket=/var/run/mysqld/mysqld.sock --silent 2>/dev/null || \
mysqladmin ping -h 127.0.0.1 -u root -p${MYSQL_ROOT_PASSWORD} --silent 2>/dev/null; then
MYSQL_READY=true
echo "✓ MySQL 已就绪"
break
fi
if [ $((i % 5)) -eq 0 ]; then
echo " 等待 MySQL... ($i/60)"
fi
sleep 1
done
if [ "$MYSQL_READY" = false ]; then
echo "警告: MySQL 启动超时,继续执行..."
fi
REDIS_READY=false
for i in $(seq 1 30); do
if redis-cli -a ${REDIS_PASSWORD} ping 2>/dev/null | grep -q "PONG"; then
REDIS_READY=true
echo "✓ Redis 已就绪"
break
fi
if [ $((i % 5)) -eq 0 ]; then
echo " 等待 Redis... ($i/30)"
fi
sleep 1
done
if [ "$REDIS_READY" = false ]; then
echo "警告: Redis 启动超时,继续执行..."
fi
# 注意Composer 安装和数据库迁移已移到 dev-setup.sh 脚本中执行
# 这样可以更好地控制执行时机和错误处理
# 停止后台 supervisord然后在前台启动成为 PID 1
echo "=========================================="
echo "切换到前台模式运行 Supervisor..."
echo "=========================================="
supervisorctl -c "$TEMP_SUPERVISOR_CONF" shutdown 2>/dev/null || pkill supervisord 2>/dev/null || true
sleep 2
# 使用原始配置文件在前台启动(成为 PID 1
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf -n