使用Docker时,我遇到了错误:“SQLSTATE[HY000] [2002] 没有这样的文件或目录”。

59
我使用Docker在Mac上创建一个容器来测试我基于PHP和MySQL构建的Web应用程序。我的PHP应用程序使用Fat-Free框架进行MVC和路由构建。我有两个Dockerfile,一个用于MySQL,一个用于PHP。我已经成功地使用过测试Docker应用程序,因此我认为我的映像安装正确。 错误的主要部分:
Internal Server Error

SQLSTATE[HY000] [2002] No such file or directory

[fatfree/lib/DB/SQL.php:466] PDO->__construct('mysql:host=127.0.0.1;port=3306;dbname=robohome','root','password',array(1002=>'SET NAMES utf8;'))
[fatfree/app/Controllers/Controller.php:24] DB\SQL->__construct('mysql:host=127.0.0.1;port=3306;dbname=robohome','root','password')

请注意,如果我使用 127.0.0.1 而不是 localhost 进行连接,那么我会收到一个略微不同的错误消息,其内容为:SQLSTATE[HY000] [2002] Connection refused

我的 PHP Dockerfile:

FROM php:5.6-apache

RUN docker-php-ext-install mysqli pdo pdo_mysql
RUN a2enmod rewrite

我的MySQL Dockerfile:

FROM mysql:5.7

ENV MYSQL_ROOT_PASSWORD password
ENV MYSQL_DATABASE robohome

COPY ./schema.sql /docker-entrypoint-initdb.d/

错误提到了第24行的Controller.php文件:

<?php

namespace Controllers;

class Controller
{
    protected $f3;
    protected $db;

    public function __construct()
    {
        $f3 = \Base::instance();
        $this->f3 = $f3;

        $mysqlServerName = $f3->get("MYSQL_SERVERNAME");
        $mysqlDatabseName = $f3->get("MYSQL_DBNAME");

        //$container = \DI\ContainerBuilder::buildDevContainer(); <-Not used currently

        //Below is line 24 referred to in the error
        $db = new \DB\SQL(
            "mysql:host={$mysqlServerName};port=3306;dbname={$mysqlDatabseName}",
            $f3->get("MYSQL_USERNAME"),
            $f3->get("MYSQL_PASSWORD")
        );

        $this->db = $db;
    }

那些MYSQL_*的值是从一个.ini文件中获取的:

MYSQL_SERVERNAME = "localhost" <-This is what I've tried changing to 127.0.0.1
MYSQL_USERNAME = "root"
MYSQL_PASSWORD = "password"
MYSQL_DBNAME = "robohome"
我的Docker Compose文件:
version: '2'

services:
  web:
    build: ./docker/php
    ports:
      - 80:80
    volumes:
      - .:/var/www/html/
    links:
      - db
  db:
    build: ./docker/mysql
    ports:
      - 3306

我运行了以下命令docker-compose up --build -d。然后,我可以从docker ps获取输出:

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
f35066a16586        robohomeweb_mysql   "docker-entrypoint.sh"   3 minutes ago       Up 2 seconds        0.0.0.0:32777->3306/tcp   robohomeweb_mysql_1
86d34eb34583        robohomeweb_php     "apache2-foreground"     3 minutes ago       Up 2 seconds        0.0.0.0:80->80/tcp        robohomeweb_php_1
如果我在前台运行,将会得到以下输出:
Building php
Step 1 : FROM php:5.6-apache
 ---> 8f9b7e57129a
Step 2 : RUN docker-php-ext-install mysqli pdo pdo_mysql
 ---> Using cache
 ---> fadd8f9e7207
Step 3 : RUN a2enmod rewrite
 ---> Using cache
 ---> 9dfed7fdc60f
Successfully built 9dfed7fdc60f
Building mysql
Step 1 : FROM mysql:5.7
 ---> eda6a4884645
Step 2 : ENV MYSQL_ROOT_PASSWORD password
 ---> Using cache
 ---> 759895ac5772
Step 3 : ENV MYSQL_DATABASE robohome
 ---> Using cache
 ---> e926c5ecc088
Step 4 : COPY ./schema.sql /docker-entrypoint-initdb.d/
 ---> Using cache
 ---> cf5d00aa8020
Successfully built cf5d00aa8020
Starting robohomeweb_php_1
Starting robohomeweb_mysql_1
Attaching to robohomeweb_mysql_1, robohomeweb_php_1
php_1    | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.18.0.3. Set the 'ServerName' directive globally to suppress this message
php_1    | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.18.0.3. Set the 'ServerName' directive globally to suppress this message
php_1    | [Sun Oct 16 20:21:17.944575 2016] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.10 (Debian) PHP/5.6.26 configured -- resuming normal operations
php_1    | [Sun Oct 16 20:21:17.946919 2016] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
mysql_1  | 2016-10-16T20:21:18.036272Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
mysql_1  | 2016-10-16T20:21:18.038330Z 0 [Note] mysqld (mysqld 5.7.16) starting as process 1 ...
mysql_1  | 2016-10-16T20:21:18.043331Z 0 [Note] InnoDB: PUNCH HOLE support available
mysql_1  | 2016-10-16T20:21:18.043603Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
mysql_1  | 2016-10-16T20:21:18.043951Z 0 [Note] InnoDB: Uses event mutexes
mysql_1  | 2016-10-16T20:21:18.044077Z 0 [Note] InnoDB: GCC builtin __atomic_thread_fence() is used for memory barrier
mysql_1  | 2016-10-16T20:21:18.044260Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.3
mysql_1  | 2016-10-16T20:21:18.044414Z 0 [Note] InnoDB: Using Linux native AIO
mysql_1  | 2016-10-16T20:21:18.045150Z 0 [Note] InnoDB: Number of pools: 1
mysql_1  | 2016-10-16T20:21:18.045620Z 0 [Note] InnoDB: Using CPU crc32 instructions
mysql_1  | 2016-10-16T20:21:18.047629Z 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M
mysql_1  | 2016-10-16T20:21:18.057705Z 0 [Note] InnoDB: Completed initialization of buffer pool
mysql_1  | 2016-10-16T20:21:18.059988Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
mysql_1  | 2016-10-16T20:21:18.074670Z 0 [Note] InnoDB: Highest supported file format is Barracuda.
mysql_1  | 2016-10-16T20:21:18.101209Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables
mysql_1  | 2016-10-16T20:21:18.101433Z 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
mysql_1  | 2016-10-16T20:21:18.354806Z 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB.
mysql_1  | 2016-10-16T20:21:18.356928Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active.
mysql_1  | 2016-10-16T20:21:18.357158Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active.
mysql_1  | 2016-10-16T20:21:18.358049Z 0 [Note] InnoDB: Waiting for purge to start
mysql_1  | 2016-10-16T20:21:18.412987Z 0 [Note] InnoDB: 5.7.16 started; log sequence number 12179647
mysql_1  | 2016-10-16T20:21:18.414470Z 0 [Note] Plugin 'FEDERATED' is disabled.
mysql_1  | 2016-10-16T20:21:18.421833Z 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
mysql_1  | 2016-10-16T20:21:18.424144Z 0 [Note] InnoDB: Buffer pool(s) load completed at 161016 20:21:18
mysql_1  | 2016-10-16T20:21:18.425607Z 0 [Warning] Failed to set up SSL because of the following SSL library error: SSL context is not usable without certificate and private key
mysql_1  | 2016-10-16T20:21:18.427018Z 0 [Note] Server hostname (bind-address): '*'; port: 3306
mysql_1  | 2016-10-16T20:21:18.427581Z 0 [Note] IPv6 is available.
mysql_1  | 2016-10-16T20:21:18.427749Z 0 [Note]   - '::' resolves to '::';
mysql_1  | 2016-10-16T20:21:18.428019Z 0 [Note] Server socket created on IP: '::'.
mysql_1  | 2016-10-16T20:21:18.456023Z 0 [Warning] 'db' entry 'sys mysql.sys@localhost' ignored in --skip-name-resolve mode.
mysql_1  | 2016-10-16T20:21:18.456354Z 0 [Warning] 'proxies_priv' entry '@ root@localhost' ignored in --skip-name-resolve mode.
mysql_1  | 2016-10-16T20:21:18.480237Z 0 [Warning] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode.
mysql_1  | 2016-10-16T20:21:18.488758Z 0 [Note] Event Scheduler: Loaded 0 events
mysql_1  | 2016-10-16T20:21:18.490880Z 0 [Note] mysqld: ready for connections.
mysql_1  | Version: '5.7.16'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
根据我的研究,我尝试使用localhost127.0.0.1进行连接,因为它们在技术上被视为不同。这可能也与尝试通过套接字而不是TCP进行通信有关。理想情况下,我希望有一个解决方案,可以将其添加到我的Dockerfile中,这样我就不必担心记住命令或者如何完成某件事。

1
MySQL 配置的监听方式是什么?是端口 3306(TCP 默认端口)还是一个套接字文件? - Devon
根据我上面的评论(您需要向右滚动才能看到它)0.0.0.0:32777->3306/tcp - roundtheworld
已编辑以包括我的Docker compose文件。 - roundtheworld
5个回答

168

正如评论中某人指出的那样,您提供的docker-compose文件与您的问题非常相关。

Docker Compose文件中links的文档表示:

链接服务的容器将在主机名与别名相同的情况下可达,如果没有指定别名,则为服务名称。

在您的情况下,数据库容器命名为db,因此从PHP容器解析db主机应该指向MySQL容器。 将配置文件中的localhost替换为db应允许PHP容器连接到MySQL。


4
那就是我之前缺失/没理解的那个信息:我的数据库位置需要与docker-compose文件中的名称匹配。现在,我终于搞定了! - roundtheworld
4
我还想补充一点,我不需要“链接”部分。我的问题完全是因为我的配置文件中数据库的位置是“localhost”,而应该是我的yml文件中服务的名称“db”。 - roundtheworld
2
@roundtheworld 这是真的,最近 Docker 支持基本 DNS,使得容器可以通过名称相互发现。 - Roman
2
将 'dsn' => 'mysql:host=localhost;dbname=yourdb' 更改为 'dsn' => 'mysql:host=db;dbname=yourdb'。 - haiflive
1
链接已经过时,现在应该使用用户定义的网络。 - Alexander Kim
显示剩余4条评论

16
你可以使用以下命令:

docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)

容器将通过它们的 IP 地址相互连接。例如,我的 IP 列表如下:

/nginx - 172.23.0.4

/php - 172.23.0.3

/mysql - 172.23.0.2

请将这些 IP 地址放入你的配置文件中,替换掉 127.0.0.1。希望这能够帮到你!

4

PHP运行在与MySQL不同的Docker镜像上。因此,来自PHP的localhost和127.0.0.1不指向MySQL。您应该连接到MySQL Docker实例的IP。

还要确保MySQL正在监听所有接口。在mysql.ini文件中,您需要将listen 0.0.0.0放置在所有可用接口上进行监听。默认情况下,它仅允许从localhost进行连接(而php Docker容器是一个不同的主机)。


1
不要发布,除非你在其他地方需要它,这只是另一个需要保护的端点。将它们链接在一起。https://docs.docker.com/compose/compose-file/#links - user2105103
我知道php和mysql存在于不同的Docker镜像中,但是在我找到的样例中,我没有看到任何这样做的内容。我成功地运行了一个非常类似于我的示例:https://github.com/mikesir87/docker-compose-demo - roundtheworld
我更新了响应。将容器链接在一起是您想要的,然后通过链接名称引用。 - user2105103
是的,我只玩了大约一周的Docker,所以我经验不足。如果我正确理解了你在我的.yml文件中添加links: - mysql的评论,但它没有起作用。我也尝试将php链接到mysql,结果相同。我认为在.yml文件中链接东西是不必要的。 - roundtheworld
docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq) - mohammad nazari
显示剩余2条评论

3

我在使用PHP/MariaDB/PhpMyAdmin的组合文件时,遇到了同样的问题。经过一些研究,我降级了PhpMyAdmin。我强制将phpMyAdmin镜像降至5.1.1版本。

  image: phpmyadmin/phpmyadmin:5.1.1

重建后没有问题。

查看您的版本:

  • 首先获取 PhpMyAdmin 的镜像 ID:

docker images

  • 然后获取版本信息:

docker image inspect --format '{{json .}}' $IMAGE_ID | jq -r '. | {Id: .Id, Digest: .Digest, RepoDigests: .RepoDigests, Labels: .Config.Labels}'


0

文档中提到:

链接服务的容器将可通过与别名相同的主机名或服务名称(如果未指定别名)进行访问。

在您的情况下,数据库容器的名称为db,因此从PHP容器解析db主机应该指向MySQL容器。在配置文件中用db替换localhost应该允许PHP容器连接到MySQL。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接