2017-02-13 29 views
6

在繼續執行nosetests之前,等待postgres在我的ENTRYPOINT內完全啓動的最佳方法是什麼?如何在入口點等待postgres的啓動?

現在我已經在我的機器上啓動了大約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 

這是啓動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 

請,我不明白,這不利於在ENTRYPOINT運行多個命令的約定。在這種情況下,我有很好的理由這樣做。

+1

您可以運行['pg_isready'](https://www.postgresql.org/docs/current /static/app-pg-isready.html),而返回代碼爲1. –

回答

0

最好不要在一個容器中運行多個東西。最好的辦法是讓你postgres運行在一個容器中,並有另一個爲你的nosetests

您可以創建一個docker-compose文件,其中nosetest「依賴於」數據庫。

+0

_depends_只是強制啓動容器的順序,但postgress容器已啓動的事實並不意味着它已準備就緒接受連接(即準備測試),因此您還必須使用正確的[healthcheck](https://docs.docker.com/compose/compose-file/#/healthcheck)來驗證_postgress_進程containe r真的準備好了。 – zeppelin

+0

這是一個非常好的觀點,我不知道如何讓它走。另外,雖然我支持我的觀點100%,但這並不是一個完全的答案,因爲它實際上並沒有解決問題。 – Nanne

1

我通常會用一個小的「TCP端口,等待」的劇本,是這樣的:

#!/bin/bash 
set -e 

if [ -z "$1" -o -z "$2" ] 
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 $1:$2 to become available... 
while ! nc -z $1 $2 2>/dev/null 
do 
    let elapsed=elapsed+1 
    if [ "$elapsed" -gt 90 ] 
    then 
     echo "TIMED OUT !" 
     exit 1 
    fi 
    sleep 1; 
done 

echo "READY !" 

要等到一定的服務和準備。

在PostgreSQL的情況下,它會監聽的默認端口是,所以命令爲:

tcp-port-wait localhost 5432 

這將阻塞,直到PostgreSQL服務已準備好爲連接上:5432上容器內部的回送接口(當在ENTRYPOINT腳本的上下文中運行時)。

你肯定有通過添加這樣的一條線,你Dockerfile這個腳本複製到你的容器, :

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

,然後才能使用它。

並且還安裝netcat實用程序。

您也可以將其用於其他類型的服務,如Tomcat或Mysql。

而且,如果你需要,你也可以等待「容器外」,類似這樣的:

docker exec my_container tcp-port-wait localhost 5432 

注意,也肯定有其他方法可以做到這一點,例如通過使用一些編排工具,如碼頭組成healthcheck directive,或一些流程管理器內的容器本身。

+0

這看起來不錯,但對我來說,這個腳本立即認爲數據庫已啓動:http://pastebin.com/x8UwhHQD – fredrik

+0

嗯,這很奇怪,顯然它正在接受連接,同時恢復正在進行中,嘗試更換'nc - z $ 1 $ 2'與'pg_isready'(這是一個PostgreSQL特定的工具來檢查它的狀態),看看它是否有幫助。 – zeppelin

+0

謝謝,使用'pg_isready'工作!另外,我必須刪除參數的檢查。如果您想修改答案,我會將其標記爲已接受。 – fredrik

7

感謝@zeppelin建議pg_isready。最後我用這樣的:在我的ENTRYPOINT

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

set -e 

cmd="[email protected]" 
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 

我使用這個:

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