bash 如何在 ENTRYPOINT 中等待 postgres 启动?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42206131/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 15:45:12  来源:igfitidea点击:

How to wait for postgres startup in ENTRYPOINT?

bashpostgresqldocker

提问by fredrik

What would be the best approach to wait for postgresto fully start up inside my ENTRYPOINTbefore moving on executing nosetests?

在继续执行之前等待postgres在我的内部完全启动的最佳方法是什么?ENTRYPOINTnosetests

Right now I've timed the startup on my machine to around 50 seconds. So I'm just sleeping for 60 seconds. This does not feel good as this might not work when being run on another machine.

现在我已经将机器上的启动时间设置为大约 50 秒。所以我只是睡了 60 秒。这感觉不太好,因为在另一台机器上运行时这可能不起作用。

ENTRYPOINT \
           runuser -l postgres -c '/usr/lib/postgresql/9.3/bin/postgres -D /var/lib/postgresql/9.3/main -c config_file=/etc/postgresql/9.3/main/postgresql.conf & ' && \
           sleep 60 && \
           nosetests --verbose --cover-erase --with-coverage --cover-package=stalker

This is the output of starting up postgres:

这是启动的输出postgres

2017-02-13 13:46:49.541 UTC [9] LOG:  database system was interrupted; last known up at 2017-02-13 12:53:23 UTC
2017-02-13 13:47:37.951 UTC [9] LOG:  database system was not properly shut down; automatic recovery in progress
2017-02-13 13:47:37.994 UTC [9] LOG:  redo starts at 0/1783EA0
2017-02-13 13:47:37.995 UTC [9] LOG:  record with zero length at 0/17841E8
2017-02-13 13:47:37.995 UTC [9] LOG:  redo done at 0/17841B8
2017-02-13 13:47:37.995 UTC [9] LOG:  last completed transaction was at log time 2017-02-13 12:53:23.731984+00
2017-02-13 13:47:38.384 UTC [9] LOG:  MultiXact member wraparound protections are now enabled
2017-02-13 13:47:38.387 UTC [7] LOG:  database system is ready to accept connections
2017-02-13 13:47:38.387 UTC [13] LOG:  autovacuum launcher started

Please, I do understand that this goes against the convention of running multiple commands in ENTRYPOINT. I have good reasons to do this in this case.

拜托,我明白这违反了在ENTRYPOINT. 在这种情况下,我有充分的理由这样做。

回答by fredrik

Thanks to @zeppelin for suggesting pg_isready. I ended up using this:

感谢@zeppelin 的建议pg_isready。我最终使用了这个:

#!/bin/bash
# wait-for-postgres.sh

set -e

cmd="$@"
timer="5"

until runuser -l postgres -c 'pg_isready' 2>/dev/null; do
  >&2 echo "Postgres is unavailable - sleeping for $timer seconds"
  sleep $timer
done

>&2 echo "Postgres is up - executing command"
exec $cmd

I'm using this in my ENTRYPOINT:

我在我的ENTRYPOINT

ENTRYPOINT \

            # Start PostgreSQL
            runuser -l postgres -c '/usr/lib/postgresql/9.3/bin/postgres -D /var/lib/postgresql/9.3/main -c config_file=/etc/postgresql/9.3/main/postgresql.conf & ' && \

            # Exectute tests when db is up
            ./wait-for-postgres.sh nosetests --verbose --cover-erase --with-coverage --cover-package=stalker

回答by zeppelin

I will normally use a small "tcp-port-wait" script, like this:

我通常会使用一个小的“tcp-port-wait”脚本,如下所示:

#!/bin/bash
set -e 

if [ -z "" -o -z "" ]
then
    echo "tcp-port-wait - block until specified TCP port becomes available"
    echo "Usage: ntcp-port-wait HOST PORT"
    exit 1
fi
echo Waiting for port : to become available...
while ! nc -z   2>/dev/null
do
    let elapsed=elapsed+1
    if [ "$elapsed" -gt 90 ] 
    then
        echo "TIMED OUT !"
        exit 1
    fi  
    sleep 1;
done

echo "READY !"

To wait until a certain service is up and ready.

等待某个服务启动并准备就绪。

In case of Postgresql, the default port it will listen on is 5432, so the command would be:

在 Postgresql 的情况下,它将侦听的默认端口是5432,因此命令将是:

tcp-port-wait localhost 5432

That will block until Postgresql service is ready to serve connections, on :5432 on the loopback interface inside the container (when run in context of the ENTRYPOINT script).

这将阻塞,直到 Postgresql 服务准备好提供连接,在容器内的环回接口上的 :5432(在 ENTRYPOINT 脚本的上下文中运行时)。

You certainly have to copy this script into your container, by adding a line like that to your Dockerfile:

您当然必须将此脚本复制到您的容器中,方法是在Dockerfile 中添加这样的一行

COPY tcp-port-wait /usr/local/bin/

before you can use it.

在你可以使用它之前。

And also install the netcatutility.

并安装netcat实用程序。

You can use this for other types of services, like Tomcat or Mysql, too.

您也可以将其用于其他类型的服务,例如 Tomcat 或 Mysql。

And, if you need, you can also wait "outside the container", like this:

而且,如果您需要,您还可以在“容器外”等待,如下所示:

docker exec my_container tcp-port-wait localhost 5432

Note, there are certainly other ways to do this, e.g. by using some orchestration tool, like docker-composewith healthcheck directive, or some process manager inside the container itself.

请注意,当然还有其他方法可以做到这一点,例如通过使用一些编排工具,如带有healthcheck 指令的docker-compose或容器本身内部的一些进程管理器。

回答by Nanne

It is always better to not run multiple things in one container. The best way would be to have you postgresrun in one container, and have another for your nosetests.

最好不要在一个容器中运行多个东西。最好的方法是让您postgres在一个容器中运行,并为您的nosetests.

You can make a docker-compose file where the nosetest"depends" on the database.

您可以制作一个 docker-compose 文件,其中nosetest“依赖”于数据库。