使用 docker 搭建 hyperf 项目框架遇到 MySQL 连接失败的问题

问题描述:在使用 dockercompose 构建项目时候启动 hyperf 容器无法链接 MySQL

这是我的 docker-compose.yml 配置:


services:
  hyperf:
    build:
      context: .
#    image: hyperf/hyperf:7.4-alpine-v3.11-swoole
    #容器的重启策略
    #no: 默认策略,不自动重启容器。
    #on-failure: 只在容器异常退出(退出状态码非0)时重启容器。
    #unless-stopped: 在容器退出时总是重启容器,但如果容器被手动停止(如使用 docker stop 命令),则不会在 Docker 守护进程重启时自动启动容器。
    #always: 在容器退出时总是重启容器,并且在 Docker 守护进程重启时也会自动启动容器。
    restart: always
    environment:
      - TIMEZONE='${TIMEZONE}'
    ports:
      - 9501:9501
      - 9502:9502
      - 9503:9503
    volumes:
      - ./:/opt/www
    depends_on:
      - mysql
    entrypoint: ["php", "/opt/www/bin/hyperf.php", "start"]
  mysql:
    environment:
      MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
      #允许 root 用户从任意主机连接到 MySQL 服务器。这里的 % 是一个通配符,表示任意主机。
      #'root'@'localhost' 表示 root 用户只能从 localhost 连接
      MYSQL_ROOT_HOST: '%'
      MYSQL_DATABASE: '${DB_DATABASE}'
      MYSQL_USER: '${DB_USERNAME}'
      MYSQL_PASSWORD: '${DB_PASSWORD}'
    image: mysql:8.0
    ports:
      - '${DB_PORT:-3306}:3306'
    volumes:
      #数据库持久化
      - mysql_data:/var/lib/mysql
      #初始化数据库
      - './docker/mysql/db_dump.sql:/docker-entrypoint-initdb.d/db_dump.sql'
      # 挂载数据库日志目录
      - ./docker/mysql/log:/var/log
#      - ./docker/mysql/my.cnf:/etc/my.cnf
      # 挂载自定义配置文件目录
      - ./docker/mysql/slow-query-log.cnf:/etc/mysql/conf.d/slow-query-log.cnf
#    command: "--default-authentication-plugin=mysql_native_password"
  redis:
    image: redis
    restart: no
  # rabbitmq:
  #   image: rabbitmq:management
  #   restart: always
  #   ports:
  #     - "4369:4369"
  #     - "5672:5672"
  #     - "15672:15672"
  #     - "25672:25672"
  #   environment:
  #     - RABBITMQ_DEFAULT_USER=mineadmin
  #     - RABBITMQ_DEFAULT_PASS=123456

volumes:
    mysql_data:

dockerfile:

# Default Dockerfile
#
# @link     https://www.hyperf.io
# @document https://hyperf.wiki
# @contact  group@hyperf.io
# @license  https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE

FROM hyperf/hyperf:7.4-alpine-v3.11-swoole
LABEL maintainer="Hyperf Developers <group@hyperf.io>" version="1.0" license="MIT" app.name="Hyperf"

##
# ---------- env settings ----------
##
# --build-arg timezone=Asia/Shanghai
ARG timezone

ENV TIMEZONE=${timezone:-"Asia/Shanghai"} \
    APP_ENV=prod \
    SCAN_CACHEABLE=(true)

# update
RUN set -ex \
    # show php version and extensions
    && php -v \
    && php -m \
    && php --ri swoole \
    #  ---------- some config ----------
    && cd /etc/php7 \
    # - config PHP
    && { \
        echo "upload_max_filesize=128M"; \
        echo "post_max_size=128M"; \
        echo "memory_limit=1G"; \
        echo "date.timezone=${TIMEZONE}"; \
    } | tee conf.d/99_overrides.ini \
    # - config timezone
    && ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \
    && echo "${TIMEZONE}" > /etc/timezone \
    # ---------- clear works ----------
    && rm -rf /var/cache/apk/* /tmp/* /usr/share/man \
    && echo -e "\033[42;37m Build Completed :).\033[0m\n"

WORKDIR /opt/www

# Composer Cache
# COPY ./composer.* /opt/www/
# RUN composer install --no-dev --no-scripts

COPY . /opt/www
RUN composer install --no-dev -o && php bin/hyperf.php

EXPOSE 9501

#CMD ["tail", "-f", "/dev/null"]
ENTRYPOINT ["php", "/opt/www/bin/hyperf.php", "start"]

hyperf 框架中的 .env 文件:

APP_NAME=skeleton
APP_ENV=dev
#守护进程
DAEMONIZE=1

DB_DRIVER=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=u7cloud
DB_USERNAME=u7cloud
DB_PASSWORD=u7cloud@MySQL!
DB_CHARSET=utf8mb4
#DB_COLLATION=utf8mb4_unicode_ci
DB_COLLATION=utf8mb4_general_ci
DB_PREFIX=

REDIS_HOST=redis
REDIS_AUTH=
REDIS_PORT=6379
REDIS_DB=0

启动:

 docker-compose up --build
[+] Building 16.4s (10/10) FINISHED docker:default
 => [hyperf internal] load build definition from Dockerfile
 => => transferring dockerfile: 1.53kB
 => [hyperf internal] load metadata for docker.io/hyperf/hyperf:7.4-alpine-v3.11-swoole
 => [hyperf internal] load .dockerignore
 => => transferring context: 2B 
 => [hyperf 1/5] FROM docker.io/hyperf/hyperf:7.4-alpine-v3.11-swoole
 => [hyperf internal] load build context
 => => transferring context: 1.00MB
 => CACHED [hyperf 2/5] RUN set -ex     && php -v     && php -m     && php --ri swoole     && cd /etc/php7     && {         echo "upload_max_filesize=128M";         echo "post_max_size=128M";         echo "memory_limit=1G";         echo "date.timezone=Asia/Sha  0.0s
 => CACHED [hyperf 3/5] WORKDIR /opt/www 
 => [hyperf 4/5] COPY . /opt/www  
 => [hyperf 5/5] RUN composer install --no-dev -o && php bin/hyperf.php  
 => [hyperf] exporting to image    
 => => exporting layers   
 => => writing image sha256:217be6c8e5e126a55ff2111af14061846460ef29247832dce98ca9ecb5e95104 
 => => naming to docker.io/library/yunque_admin-hyperf 
[+] Running 3/3
 ✔ Container yunque_admin-redis-1   Created   
 ✔ Container yunque_admin-mysql-1   Created  
 ✔ Container yunque_admin-hyperf-1  Recreated  
Attaching to hyperf-1, mysql-1, redis-1
redis-1   | 1:C 31 May 2024 02:25:29.503 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis-1   | 1:C 31 May 2024 02:25:29.503 * Redis version=7.2.5, bits=64, commit=00000000, modified=0, pid=1, just started
redis-1   | 1:C 31 May 2024 02:25:29.503 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis-1   | 1:M 31 May 2024 02:25:29.503 * monotonic clock: POSIX clock_gettime
redis-1   | 1:M 31 May 2024 02:25:29.503 * Running mode=standalone, port=6379.
redis-1   | 1:M 31 May 2024 02:25:29.504 * Server initialized
redis-1   | 1:M 31 May 2024 02:25:29.504 * Loading RDB produced by version 7.2.5
redis-1   | 1:M 31 May 2024 02:25:29.504 * RDB age 23 seconds
redis-1   | 1:M 31 May 2024 02:25:29.504 * RDB memory usage when created 0.83 Mb
redis-1   | 1:M 31 May 2024 02:25:29.504 * Done loading RDB, keys loaded: 0, keys expired: 0.
redis-1   | 1:M 31 May 2024 02:25:29.504 * DB loaded from disk: 0.001 seconds
redis-1   | 1:M 31 May 2024 02:25:29.504 * Ready to accept connections tcp
mysql-1   | 2024-05-31 02:25:29+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.37-1.el9 started.
mysql-1   | 2024-05-31 02:25:29+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
mysql-1   | 2024-05-31 02:25:29+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.37-1.el9 started.
mysql-1   | '/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
mysql-1   | 2024-05-31T02:25:30.112759Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead.
mysql-1   | 2024-05-31T02:25:30.113403Z 0 [Warning] [MY-011068] [Server] The syntax 'log_slow_slave_statements' is deprecated and will be removed in a future release. Please use log_slow_replica_statements instead.
mysql-1   | 2024-05-31T02:25:30.113423Z 0 [Warning] [MY-011068] [Server] The syntax 'expire-logs-days' is deprecated and will be removed in a future release. Please use binlog_expire_logs_seconds instead.
mysql-1   | 2024-05-31T02:25:30.115781Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.37) starting as process 1
mysql-1   | 2024-05-31T02:25:30.126707Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
hyperf-1  |
hyperf-1  | In Connection.php line 1082:
hyperf-1  |
hyperf-1  |   SQLSTATE[HY000] [2002] Connection refused (SQL: select `id`, `from_id`, `fr
hyperf-1  |   om_type`, `crontab_time` from `crontab_task` where `from_type` = system)
hyperf-1  |
hyperf-1  |
hyperf-1  | In Connector.php line 106:
hyperf-1  |
hyperf-1  |   SQLSTATE[HY000] [2002] Connection refused
hyperf-1  |
hyperf-1  |
hyperf-1  | start
hyperf-1  |
hyperf-1  | Connection failed: SQLSTATE[HY000] [2002] Connection refused

排查问题

  1. 从输出来看 hyperf 容器好像无法连接 mysql,为了防止 docker-compose up 启动 hyperf 容器的时候 MySQL 容器还没有启动导致 SQLSTATE[HY000] [2002] Connection refused所以我在 docker-compose.yml 文件中配置了重启策略:restart: always

  2. 然后在 hyperf 容器尝试手动连接到 mysql,于是在 bin/hyperf.php 启动文件尝试连接数据库:

#!/usr/bin/env php
<?php

ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');

error_reporting(E_ALL);
date_default_timezone_set('Asia/Shanghai');

! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);

require BASE_PATH . '/vendor/autoload.php';

$host = 'mysql';
$dbname = 'u7cloud';
$user = 'u7cloud';
$pass = 'u7cloud@MySQL!';

try {
    $conn = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
    echo "Connected successfully";
} catch (PDOException $e) {
    echo "Connection failed: " . $e->getMessage();
}

// Self-called anonymous function that creates its own scope and keep the global namespace clean.
try {
    (function () {
        Hyperf\Di\ClassLoader::init();
        /** @var \Psr\Container\ContainerInterface $container */
  $container = require BASE_PATH . '/config/container.php';

        $application = $container->get(\Hyperf\Contract\ApplicationInterface::class);
        $application->run();
    })();
} catch (Exception|Throwable $e) {

    var_dump($e);
}

这里的数据库配置和 config/autoload/database.php 的配置是一致的

  1. 重启项目:
    docker-compose up --build
    [+] Building 16.2s (10/10) FINISHED                                                                                                                                                                                                                         docker:default
    => [hyperf internal] load build definition from Dockerfile 
    => => transferring dockerfile: 1.53kB  
    => [hyperf internal] load metadata for docker.io/hyperf/hyperf:7.4-alpine-v3.11-swoole  
    => [hyperf internal] load .dockerignore      
    => => transferring context: 2B          
    => [hyperf 1/5] FROM docker.io/hyperf/hyperf:7.4-alpine-v3.11-swoole      
    => [hyperf internal] load build context             
    => => transferring context: 1.01MB              
    => CACHED [hyperf 2/5] RUN set -ex     && php -v     && php -m     && php --ri swoole     && cd /etc/php7     && {         echo "upload_max_filesize=128M";         echo "post_max_size=128M";         echo "memory_limit=1G";         echo "date.timezone=Asia/Sha  0.0s
    => CACHED [hyperf 3/5] WORKDIR /opt/www    
    => [hyperf 4/5] COPY . /opt/www           
    => [hyperf 5/5] RUN composer install --no-dev -o && php bin/hyperf.php 
    => [hyperf] exporting to image
    => => exporting layers   
    => => writing image sha256:b66f8604b419674225cdcfe0a7f40cb35e02304133724236b7cd8f276322477f 
    => => naming to docker.io/library/yunque_admin-hyperf  
    [+] Running 3/3
    ✔ Container yunque_admin-redis-1   Created    
    ✔ Container yunque_admin-mysql-1   Created     
    ✔ Container yunque_admin-hyperf-1  Recreated   
    Attaching to hyperf-1, mysql-1, redis-1
    redis-1   | 1:C 31 May 2024 02:53:07.958 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    redis-1   | 1:C 31 May 2024 02:53:07.958 * Redis version=7.2.5, bits=64, commit=00000000, modified=0, pid=1, just started
    redis-1   | 1:C 31 May 2024 02:53:07.958 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
    redis-1   | 1:M 31 May 2024 02:53:07.958 * monotonic clock: POSIX clock_gettime
    redis-1   | 1:M 31 May 2024 02:53:07.958 * Running mode=standalone, port=6379.
    redis-1   | 1:M 31 May 2024 02:53:07.959 * Server initialized
    redis-1   | 1:M 31 May 2024 02:53:07.959 * Loading RDB produced by version 7.2.5
    redis-1   | 1:M 31 May 2024 02:53:07.959 * RDB age 24 seconds
    redis-1   | 1:M 31 May 2024 02:53:07.959 * RDB memory usage when created 0.83 Mb
    redis-1   | 1:M 31 May 2024 02:53:07.959 * Done loading RDB, keys loaded: 0, keys expired: 0.
    redis-1   | 1:M 31 May 2024 02:53:07.959 * DB loaded from disk: 0.000 seconds
    redis-1   | 1:M 31 May 2024 02:53:07.959 * Ready to accept connections tcp
    mysql-1   | 2024-05-31 02:53:08+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.37-1.el9 started.
    mysql-1   | 2024-05-31 02:53:08+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
    mysql-1   | 2024-05-31 02:53:08+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.37-1.el9 started.
    mysql-1   | '/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
    mysql-1   | 2024-05-31T02:53:08.621464Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead.
    mysql-1   | 2024-05-31T02:53:08.621498Z 0 [Warning] [MY-011068] [Server] The syntax 'log_slow_slave_statements' is deprecated and will be removed in a future release. Please use log_slow_replica_statements instead.
    mysql-1   | 2024-05-31T02:53:08.621505Z 0 [Warning] [MY-011068] [Server] The syntax 'expire-logs-days' is deprecated and will be removed in a future release. Please use binlog_expire_logs_seconds instead.
    mysql-1   | 2024-05-31T02:53:08.622443Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.37) starting as process 1
    mysql-1   | 2024-05-31T02:53:08.628274Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
    hyperf-1  |
    hyperf-1  | In Connection.php line 1082:
    hyperf-1  |
    hyperf-1  |   SQLSTATE[HY000] [2002] Connection refused (SQL: select `id`, `from_id`, `fr
    hyperf-1  |   om_type`, `crontab_time` from `crontab_task` where `from_type` = system)
    hyperf-1  |
    hyperf-1  |
    hyperf-1  | In Connector.php line 106:
    hyperf-1  |
    hyperf-1  |   SQLSTATE[HY000] [2002] Connection refused
    hyperf-1  |
    hyperf-1  |
    hyperf-1  | start
    hyperf-1  |
    hyperf-1  | Connection failed: SQLSTATE[HY000] [2002] Connection refused
    mysql-1   | 2024-05-31T02:53:08.853962Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
    mysql-1   | 2024-05-31T02:53:09.040485Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
    mysql-1   | 2024-05-31T02:53:09.040528Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
    mysql-1   | 2024-05-31T02:53:09.045163Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
    mysql-1   | 2024-05-31T02:53:09.066378Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
    mysql-1   | 2024-05-31T02:53:09.066467Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.37'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.
    hyperf-1  | Connected successfully
    hyperf-1 exited with code 0
    hyperf-1  | Connected successfully
    hyperf-1 exited with code 0
    hyperf-1  | Connected successfully
    hyperf-1 exited with code 0
    ^Bhyperf-1  | Connected successfully
    从输出来看第一次启动 hyperf 报错:SQLSTATE[HY000] [2002] Connection refused
    因为配置了重启策略,然后 hyperf 容器重启输出:Connected successfully,说明 MySQL 是连接成功了,但是后面却异常退出了

解决方法

暂时还没有找到什么原因

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 1

感谢李铭昕大佬的指点

因为我在 .env 配置了 #守护进程 DAEMONIZE=1,配置了守护进程,hyperf 启动进程就自己退出了,docker 看到你进程退出了,就认为你没有启动成功,所以 docker一直重启

.env 文件中设置 DAEMONIZE=1 会导致 Hyperf 在后台运行,这意味着 Hyperf 的主进程会在启动后立即退出,而不是保持前台运行。 当 Docker 运行一个容器时,它会监视容器的主进程(PID 1)。如果这个进程退出,Docker 会认为容器已经完成了它的工作并退出。如果配置了 restart: always,Docker 会不断地重启容器,因为它认为容器没有成功运行。 这是使用 Docker 运行后台进程时的一个常见问题。Docker 的设计理念是一个容器运行一个前台进程。

最简单的解决方案可能就是设置 DAEMONIZE=0,让 Hyperf 在前台运行

2周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!