Rails容器无法使用gitlab ci连接到mysql容器

时间:2018-11-11 11:19:01

标签: ruby-on-rails docker gitlab-ci

我正在为具有构建,测试和发布阶段的Rails应用设置一个简单的gitlab ci:

build:
  stage: build
  script:
    - docker build --pull -t $TEST_IMAGE .
    - docker push $TEST_IMAGE

test:
  stage: test
  services:
    - docker:dind
  script:
    - docker pull $TEST_IMAGE
    - docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=mysql_strong_password mysql:5.7
    - docker run -e RAILS_ENV=test --link mysql:db $TEST_IMAGE bundle exec rake db:setup

build成功构建了docker映像并推送到注册表

test启动另一个我用作主机数据库的mysql容器,但是在建立与mysql的连接时失败。

Couldn't create database for {"host"=>"db", "adapter"=>"mysql2", "pool"=>5, "username"=>"root", "encoding"=>"utf8", "timeout"=>5000, "password"=>"mysql_strong_password", "database"=>"my_tests"}, {:charset=>"utf8"}
(If you set the charset manually, make sure you have a matching collation)
rails aborted!
Mysql2::Error: Can't connect to MySQL server on 'db' (111 "Connection refused") 

我还尝试使用--network而非link方法创建单独的docker网络,但没有帮助。

这仅在Gitlab运行器实例上发生。当我在本地计算机上执行这些步骤时,效果很好。

大量阅读后,我认为这是docker executor的错误。我想念什么吗?

1 个答案:

答案 0 :(得分:1)

拒绝连接表示容器知道如何相互访问,但是目标容器在所选端口上没有任何接受连接的内容。这很可能意味着您在数据库完成初始化之前就启动了应用程序。我的建议是更新/创建您的应用程序,或在应用程序容器中创建一个入口点,以轮询数据库以使其启动并运行,如果它没有启动,则在几分钟后失败。我也建议您使用网络而不是链接,因为不赞成使用链接,并且不能优雅地处理正在重新创建的容器。

您看到的行为是documented in the mysql image

  

在MySQL初始化完成之前没有连接

     

如果在容器启动时没有初始化数据库,则将创建一个默认数据库。尽管这是预期的行为,但这意味着在初始化完成之前它将不接受传入的连接。在使用自动化工具(例如docker-compose)时,这可能会引起问题,该工具会同时启动多个容器。

     

如果您尝试连接到MySQL的应用程序无法处理MySQL停机时间或等待MySQL正常启动,则可能有必要在服务启动之前放置connect-retry循环。有关官方图像中此类实现的示例,请参阅WordPress或Bonita。

从链接的wordpress示例中,您可以看到其重试代码:

$maxTries = 10;
do {
    $mysql = new mysqli($host, $user, $pass, '', $port, $socket);
    if ($mysql->connect_error) {
        fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n");
        --$maxTries;
        if ($maxTries <= 0) {
            exit(1);
        }
        sleep(3);
    }
} while ($mysql->connect_error);

一个用于等待mysql而无需更改应用程序本身的示例入口点脚本可能如下所示:

#!/bin/sh
wait-for-it.sh mysql:3306 -t 300
exec "$@"

wait-for-it.sh来自vishnubob/wait-for-it,最后的exec "$@"将pid 1替换为您传递的命令(例如bundle exec rake db:setup)。这种方法的缺点是数据库可能在真正准备好接受连接之前就正在侦听端口,因此我仍然建议您在重试循环中使用您的应用程序进行完全登录。