webman容器 启动等待数据库启动后在启动

lsmir2

docker编排文件

services:
  1panel-php:
    build:
      context: ${DOCKER_PHP_DIR}
      args:
        PHP_IMAGE: php:${PHP_VERSION}-cli-alpine3.21
        CONTAINER_PACKAGE_URL: ${CONTAINER_PACKAGE_URL}
        PHP_EXTENSIONS: ${PHP_EXTENSIONS}
        TZ: ${TZ}
    privileged: true
    image: ${IMAGE_NAME}
    container_name: ${CONTAINER_NAME}
    command: sh -c "php /app/wait_db_ready.php && sh /usr/local/bin/docker-init.sh"
    labels:
      - "com.centurylinklabs.watchtower.enable=false"
    networks:
      - 1panel-network
    ports:
      - "127.0.0.1:8787:8787"
    volumes:
      - ${SOURCE_DIR}:/app
      - ${DOCKER_PHP_DIR}/docker-init.sh:/usr/local/bin/docker-init.sh
      - ${DOCKER_PHP_DIR}/php.ini:/usr/local/etc/php/php.ini
      - ${DOCKER_PHP_DIR}/docker-php-ext-apcu.ini:/usr/local/etc/php/conf.d/docker-php-ext-apcu.ini
    restart: always

command: sh -c "php /app/wait_db_ready.php && sh /usr/local/bin/docker-init.sh" 容器启动后执行的2条命令
php /app/wait_db_ready.php 执行数据库准备的代码 见下方

挂载docker-init.sh 内容是

php start.php start -e APP_ENV=production

在写一个 wait_db_ready.php 丢到 /app 挂载的目录下

wait_db_ready.php

<?php
/**
 *  数据库 Redis 容器就绪检测
 */
require_once __DIR__ . '/vendor/autoload.php';
app\common\Env::init(); // 配置文件加载类
//DB配置
$dbHost = envs('DB_HOST_ADDR') ?: '1panel-mariadb';
$dbPort = envs('DB_HOST_PORT', 3306);
$dbUser = envs('DB_USERNAME', 'root');
$dbPassword = envs('DB_PASSWORD', '');

// Redis配置
$redisHost = envs('REDIS_HOST') ?: '1panel-redis';
$redisPort = envs('REDIS_PORT') ?: 6379;
$redisPassword = envs('REDIS_PASSWORD') ?: '';
$redisDatabase = envs('REDIS_DATABASE') ?: 0;

// 超时时间
$timeout = 300; // 5分钟
$interval = 5; // 每5秒检查一次

$endTime = time() + $timeout;
echo "等待MariaDB({$dbHost}:{$dbPort})就绪...\n";

// 检查MariaDB连接
while (time() < $endTime) {
    try {
        // 尝试建立连接
        $conn = new PDO(
            "mysql:host=$dbHost;port=$dbPort;charset=utf8",
            $dbUser,
            $dbPassword,
            [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
        );
        echo "MariaDB已就绪!\n";
        break;
    } catch (Exception $e) {
        echo "等待中...(" . $e->getMessage() . ")\n";
        sleep($interval);
    }
}

if (time() >= $endTime) {
    echo "错误:等待MariaDB超时!\n";
    exit(1);
}

// 检查Redis连接
echo "\n等待Redis就绪...\n";

$endTime = time() + $timeout;
echo "等待Redis({$redisHost}:{$redisPort})就绪...\n";

while (time() < $endTime) {
    try {
        $redis = new Redis();
        $redis->connect($redisHost, $redisPort, 5);

        if (!empty($redisPassword)) {
            if (!$redis->auth($redisPassword)) {
                throw new Exception('Redis认证失败');
            }
        }

        $redis->select($redisDatabase);
        $redis->ping();

        echo "Redis已就绪!\n";
        exit(0);
    } catch (Exception $e) {
        echo "等待中...(" . $e->getMessage() . ")\n";
        sleep($interval);
    }
}

echo "错误:等待Redis超时!\n";
exit(1);

Env.php

<?php
namespace app\common;
class Env
{
    public static function init(): void
    {
        global $argv;
        $env = false;
        $base_path = base_path() . '/.env.';
        // 从环境变量获取 APP_ENV
        foreach ($argv as $key => $value) {
            if ($value == '-e' && isset($argv[$key + 1]) && str_contains($argv[$key + 1], '=')) {
                list($name, $value) = explode('=', $argv[$key + 1]);
                $envFilePath = $base_path . $value;
                if ($name == 'APP_ENV' && file_exists($envFilePath)) {
                    $env = self::parseEnvFile($envFilePath);
                    if ($env) {
                        self::initEnv($env, $value);
                        return;
                    }
                }
            }
        }
        // 如果没有环境变量,则从 .env.development 或 .env.production 中获取
        $file = 'development';
        if (!file_exists($base_path . $file)) $file = 'production';
        $env = self::parseEnvFile($base_path . $file);
        if (!$env) {
            error_log("Error: .env.development or .env.production file not found.");
            exit('Error LINE:' . __LINE__);
        }
        self::initEnv($env, $file);
    }

    private static function parseEnvFile($file): false|array
    {
        if (!file_exists($file)) return false;
        return parse_ini_file($file, true) ?? false;
    }

    /**
     * @param array $env
     * @param string $envFilePath
     * @return void
     */
    protected static function initEnv(array $env, string $envFilePath): void
    {
        self::printEnv($envFilePath);
        //初始化ENV 配置
        foreach ($env as $key => $val) {
            //过滤首字母#或者'//'开头的注释
            if (str_starts_with($key, '#') || str_starts_with($key, '//')) continue;
            if (is_array($val)) {
                foreach ($val as $k => $v) { //如果是二维数组 item = PHP_KEY_KEY
                    $item = $key . '_' . $k;
                    putenv("$item=$v");
                }
            } else {
                putenv("$key=$val");
            }
        }

    }

    /**
     * 多进程下只输出一次 env 名字
     * @param string $envFilePath .env 名字
     * @return void
     */
    private static function printEnv(string $envFilePath): void
    {
        $lockFilePath = runtime_path() . '/env_printed.lock';
        $timeout = 3;

        $lockFile = fopen($lockFilePath, 'a+');
        if ($lockFile === false) {
            error_log("Could not open lock file: " . $lockFilePath);
            return;
        }
        if (!flock($lockFile, LOCK_EX)) {
            error_log("Could not acquire lock on file: " . $lockFilePath);
            fclose($lockFile);
            return;
        }
        try {
            if (file_exists($lockFilePath)) {
                $modifiedTime = filemtime($lockFilePath);
                if (time() - $modifiedTime > $timeout) {
                    // 锁失效,输出语句并更新时间
                    echo "Load env file: " . $envFilePath . PHP_EOL;
                    touch($lockFilePath); // 更新修改时间为当前时间
                }
                // 如果锁未失效,不输出
            } else {
                // 文件不存在,输出语句并创建文件
                echo "Load env file: " . $envFilePath . PHP_EOL;
                touch($lockFilePath); // 创建文件并设置修改时间为当前时间
            }
        } finally {
            flock($lockFile, LOCK_UN);
            fclose($lockFile);
        }
    }
}
47 0 1
0个评论

lsmir2

2180
积分
0
获赞数
0
粉丝数
2024-01-29 加入
🔝