我如何知道我的docker mysql容器何时启动并且mysql已准备好接受查询?

har*_*ren 53 mysql bash shell docker

我正在部署一些不同的docker容器,mysql是第一个.我想在数据库启动后立即运行脚本并继续构建其他容器.该脚本一直在失败,因为当设置mysql(来自这个官方的mysql容器)的入口点脚本仍在运行时,它试图运行.

sudo docker run --name mysql -e MYSQL_ROOT_PASSWORD=MY_ROOT_PASS -p 3306:3306 -d mysql
[..] wait for mysql to be ready [..]
mysql -h 127.0.0.1 -P 3306 -u root --password=MY_ROOT_PASS < MY_SQL_SCRIPT.sql
Run Code Online (Sandbox Code Playgroud)

有没有办法等待在docker容器内完成入门的mysql安装脚本的信号?Bash睡眠似乎是次优解决方案.

编辑:去找这样的bash脚本.不是最优雅和善良的蛮力,但工作就像一个魅力.也许有人会觉得有用.

OUTPUT="Can't connect"
while [[ $OUTPUT == *"Can't connect"* ]]
do
    OUTPUT=$(mysql -h $APP_IP -P :$APP_PORT -u yyy --password=xxx <       ./my_script.sql 2>&1)
done
Run Code Online (Sandbox Code Playgroud)

fla*_*yst 49

您可以安装mysql-client软件包并使用mysqladmin来ping目标服务器.使用多个docker容器时很有用.结合sleep并创建一个简单的等待循环:

while ! mysqladmin ping -h"$DB_HOST" --silent; do
    sleep 1
done
Run Code Online (Sandbox Code Playgroud)

  • 这是一件美好的事情.对于Docker健康检查也很有用:`docker run --health-cmd ='mysqladmin ping --silent'-d mysql` (20认同)
  • 为了等待单位容器是健康的我使用脚本`while [$(docker inspect --format"{{json .State.Health.Status}}"<container-name>)!="\"healthy \""]; do printf"."; 睡1; done` (4认同)
  • 这在这里不起作用; 我真的可以使用数据库之前`mysqladmin ping`成功 - 我想容器仍在运行的是初始化`.sql`脚本. (4认同)
  • 我没有在 docker 镜像中安装 mysqladmin,但是,wget 也完成了这项工作:`while !wget mysql:3306; do sleep 1 done` (3认同)
  • 如果您在本地主机上尝试但不起作用,请尝试“127.0.0.1”。当使用“localhost”时,mysqladmin 尝试使用套接字而不是通过默认 TCP 端口 3306 进行连接。 (2认同)

小智 32

这个小的bash循环等待mysql打开,不需要安装任何额外的包:

until nc -z -v -w30 $CFG_MYSQL_HOST 3306
do
  echo "Waiting for database connection..."
  # wait for 5 seconds before check again
  sleep 5
done
Run Code Online (Sandbox Code Playgroud)

  • 仅仅因为端口可用并不意味着服务器已准备好接受连接.`mysqladmin ping`就是这里的正确答案. (5认同)
  • 好一个.我用它作为1个班轮:直到nc -z $ CFG_MYSQL_HOST 3306; 做睡觉1; 回声"等待DB出现......"; DONE (2认同)

And*_*ykh 24

在其他答案的评论中或多或少地提到了这一点,但我认为它应该是它自己的条目.

首先,您可以按以下方式运行容器:

docker run --name mysql --health-cmd='mysqladmin ping --silent' -d mysql
Run Code Online (Sandbox Code Playgroud)

Dockerfile中还有一个等价物.

与该命令你docker ps,并docker inspect会告诉你你的容器的健康状况.特别是对于mysql,此方法具有在容器内mysqladmin可用的优点,因此您无需在docker主机上安装它.

然后你可以简单地循环一个bash脚本来等待状态变得健康.以下bash脚本由Dennis创建.

function getContainerHealth {
  docker inspect --format "{{json .State.Health.Status }}" $1
}

function waitContainer {
  while STATUS=$(getContainerHealth $1); [ $STATUS != "\"healthy\"" ]; do 
    if [ $STATUS == "\"unhealthy\"" ]; then
      echo "Failed!"
      exit -1
    fi
    printf .
    lf=$'\n'
    sleep 1
  done
  printf "$lf"
}
Run Code Online (Sandbox Code Playgroud)

现在您可以在脚本中执行此操作:

waitContainer mysql
Run Code Online (Sandbox Code Playgroud)

并且您的脚本将一直等到容器启动并运行.如果容器变得不健康,脚本将退出,这是可能的,如果例如docker host内存不足,那么mysql无法为自己分配足够的内容.

  • 我发现这是最好的方法,因为它只依赖于Docker,因此应该有更少的跨平台问题.我遇到的唯一问题是图像入口点将mysqlserver旋转两次 - 一旦裸露,并且一旦初始化.`mysqladmin ping`也抓住了第一个旋转,这很可能是你不想要的.在我的例子中,使用您希望在那里运行的模式运行虚拟查询最好,即将health命令更改为`mysql -u root -e"使用your_schema;"`. (3认同)

Mih*_*iță 12

在所有 Linux 发行版上都可以找到使用curl 的一种衬垫:

while ! curl -o - db-host:3306; do sleep 1; done
Run Code Online (Sandbox Code Playgroud)

  • 这是迄今为止最好的解决方案。我想补充一点,容器需要具有卷曲的权限。`运行 apt-get update &amp;&amp; apt-get update -y &amp;&amp; apt-get install curl -y` (2认同)

ale*_*opg 8

有时端口的问题是端口可能是打开的,但数据库还没有准备好.

其他解决方案要求你在主机上安装了mysql oa mysql客户端,但实际上你已经在Docker容器中安装了它,所以我更喜欢使用这样的东西:

while ! docker exec mysql mysqladmin --user=root --password=root --host "127.0.0.1" ping --silent &> /dev/null ; do
    echo "Waiting for database connection..."
    sleep 2
done
Run Code Online (Sandbox Code Playgroud)

  • 这似乎是最好和最短的选择,但只是ping不适合我,它仍然没有准备好所以我使用命令:`mysql -u root -proot -e'status'&gt;/dev/null`代替of mysqladmin ping` (4认同)

dev*_*214 6

以下运行状况检查适用于我的所有 mysql 容器:

db:
    image: mysql:5.7.16
    healthcheck:
      test: ["CMD-SHELL", 'mysql --database=$$MYSQL_DATABASE --password=$$MYSQL_ROOT_PASSWORD --execute="SELECT count(table_name) > 0 FROM information_schema.tables;" --skip-column-names -B']
      interval: 30s
      timeout: 10s
      retries: 4
    extends:
        file: docker-compose-common-config.yml
        service: common_service
Run Code Online (Sandbox Code Playgroud)


cta*_*o85 6

所以我不确定是否有人发布过这个。它看起来不像任何人,所以...... mysqladmin 中有一个命令具有等待功能,它处理连接测试,然后在内部重试并在完成后返回成功。

sudo docker run --name mysql -e MYSQL_ROOT_PASSWORD=MY_ROOT_PASS -p 3306:3306 -d mysql
mysqladmin ping -h 127.0.0.1 -u root --password=MY_ROOT_PASS --wait=30 && mysql -h 127.0.0.1 -P 3306 -u root --password=MY_ROOT_PASS < MY_SQL_SCRIPT.sql
Run Code Online (Sandbox Code Playgroud)

的重要的部分是mysqladmin ping -h 127.0.0.1 -u root --password=MY_ROOT_PASS --wait=30 -v--wait作为标记等到连接成功和数为尝试重试的量。

理想情况下,您应该从 docker 容器内部运行该命令,但我不想过多地修改原始海报命令。

在我的 make 文件中用于初始化时

db.initialize: db.wait db.initialize


db.wait:
  docker-compose exec -T db mysqladmin ping -u $(DATABASE_USERNAME) -p$(DATABASE_PASSWORD) --wait=30 --silent

db.initialize:
  docker-compose exec -T db mysql -u $(DATABASE_USERNAME) -p$(DATABASE_PASSWORD) $(DATABASE_NAME) < dev/sql/base_instance.sql
Run Code Online (Sandbox Code Playgroud)


Mat*_*mer 5

我发现使用这种mysqladmin ping方法并不总是可靠的,尤其是当您要建立一个新的数据库时。在这种情况下,即使您能够ping通服务器,但如果仍在初始化用户/特权表,则可能无法连接。相反,我会执行以下操作:

while ! docker exec db-container mysql --user=foo --password=bar -e "SELECT 1" >/dev/null 2>&1; do
    sleep 1
done
Run Code Online (Sandbox Code Playgroud)

到目前为止,我还没有遇到这种方法的任何问题。我看到VinGarcia在对其中一个mysqladmin ping答案的评论中提出了类似的建议。


kms*_*eng 0

https://github.com/docker-library/mysql/blob/master/5.7/docker-entrypoint.sh docker-entrypoint.sh 尚不支持合并自定义.sql。

我认为你可以修改 docker-entrypoint.sh 来合并你的sql,这样一旦mysql实例准备好它就可以执行。