-
Notifications
You must be signed in to change notification settings - Fork 1.2k
How to determine when new container is truly "ready" #146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I have done this:
and it seems to work, but I am still learning... |
Hi @spmacdonald, Here's the first time:
Then it runs its entrypoints, e.g. here is an example if adding postgis:
And then the restart:
And only now is it truly ready. If you kicked off a seeding/provisioning script once you saw PG "ready" the first time, you're likely to hit a failure when it restarts. I think all containers need to have a deterministic way to indicate when they're actually-truly "won't restart on you" ready without resorting to sleep timers. |
@rarkins What is the |
@md5 sorry, $PSQL is just an alias defined earlier in my file:
I am using host networking in docker, which might explain the difference? |
@rarkins You're going to have a hard time with a lot of assumptions in various Docker images if you're using host networking. |
The way the container is designed is that when it is listening on the network port via its non-loopback interface, it is ready to accept connections. Accepting connections on the loopback connection is for the scripts in |
The best way to wait for your container to be up and ready is this:
That's what we're using at Gemnasium, it avoid the "double start" issue. |
We do
|
improved version of @gravis's solution
it works even if password is required Update as noted by @enumag if you use network, then you need to add
|
@gravis @yelizariev Thank you for your solutions! |
Is the
|
As @rarkins I've struggled with the server restart too.
|
The simplest solution for me was watching the logs for |
thanks for the solution @gravis |
I tried to use the solution posted by @gravis and later improved by @yelizariev. In my case there was one more problem:
I found a fix here. I just had to add Here is the final version:
|
This should be solved if #282 is implemented, right? |
The problem is that you can't use healthcheck when using docker-compose.yml version 3 since |
As explained in this comment, solutions that merely check for connectivity (using psql or pg_isready or anything else) will not work in the general case with this image since it does a postgres restart after the initial setup (if you are mounting an existing database you're fine though).
|
@mausch Unfortunately your solution is can't be used it from inside of another container - which is what you want most of the time. Any tips for that situation? |
For future google hits: I'm using |
If using docker version 2.1
and then
|
@enumag The other solutions aren't effective because my docker image, the For those of us whose Postgres image needs to start Have not tested this on platform besides Linux, or with a goal other than 2.
|
Use this: |
As noted back in #146 (comment), the best way to test if the container is "ready" is to connect to it using its external IP address (it does not listen externally until the initialization process is fully complete). In the future, these sorts of questions/requests would be more appropriately posted to the Docker Community Forums, the Docker Community Slack, or Stack Overflow. |
Need some hints for monitoring image from: docker-library/postgres#146 (comment)
This PR fixes an issue with our Docker Postgres connection where we sometimes connect before Postgres is fully up, see [1] for more details. [1] docker-library/postgres#146
This PR fixes an issue with our Docker Postgres connection where we sometimes connect before Postgres is fully up, see [1] for more details. [1] docker-library/postgres#146
I came across this while building a devtool that starts a postgres database inside a Docker container. Some of these solutions don't deal with the "first start" "second start" issue. process_ids=()
kill_processes() {
# send kill signal to each process
for process_id in "${process_ids[@]}"; do
kill "$process_id" > /dev/null 2>&1
done
# wait for each process to exit
for process_id in "${process_ids[@]}"; do
wait "$process_id" 2>/dev/null
done
}
trap kill_processes EXIT
# start database process
database_log_file="$(mktemp)"
"$START_DATABASE" 2>&1 | tee "$database_log_file" & process_ids+=($!)
database_process_id="${process_ids[-1]}"
# wait for the database to initialize and be ready to accept connections
until \
grep -q "^.*\[1\].*database system is ready to accept connections" "$database_log_file"
do
# check that the database process still exists
if ! ps -p "$database_process_id" > /dev/null; then
echo_error "The database failed to start"
exit 1
fi
sleep 0.1
done
# check that the database is accessible at port 5432
if ! netstat -tulpn 2>&1 | grep ":5432 " > /dev/null 2>&1; then
echo_error "The database did not bind to port 5432"
exit 1
fi
# TODO: start the server that connects to the database
In my case, it is |
It's the PID -- so, if you use |
Tested this works, you can thank me later if it works for you too ✌🏼 I only tested for def wait_for_psql_container(timeout: int = 30):
"""A blocking function that runs until a polled, executed command against the container
to check that the postgresql instance is ready to accept connections succeeds. Otherwise
raises a :py:class:`TimeoutError` when the set :param:`timeout` elapses without a positive
result from the executed command.
:param timeout: The timeout in seconds after which the waiting cancels and fails, defaults to 30
:raises TimeoutError: When :param:`timeout` is elapsed before the postgresql instance is ready
:return: `None`
"""
logger.info("[+] Waiting for PostgreSQL to be ready...")
commands = [
[
"docker",
"exec",
PSQL_CONTAINER_NAME,
"pg_isready",
"-U",
"postgres",
],
[
"docker",
"exec",
PSQL_CONTAINER_NAME,
"psql",
"-U",
"postgres",
"-d",
"postgres",
"-c",
"SELECT PostGIS_version();",
],
]
command = commands[0]
times_ready = 0
while (timeout := timeout - 1) > -1:
result = subprocess.run(command, capture_output=True)
logger.info("%s", result.stdout.decode())
if result.returncode == 0 and "accepting connection" in result.stdout.decode():
# Postgres restarts after PostGIS is loaded, and causes ConnectionDoesNotExistError:
# "connection was closed in the middle of operation"
# https://github.com/docker-library/postgres/issues/146#issuecomment-215619771
#
# ============================================================================
command = commands[1]
if (times_ready := times_ready + 1) < 2:
logger.info("[+] Checking PostGIS is loaded...")
continue
time.sleep(1)
return logger.info("[✓] PostgreSQL is ready.")
elif result.returncode == 0 and "postgis_version" in result.stdout.decode():
logger.info("[+] Checking PostgreSQL is accepting connections...")
command = commands[0]
time.sleep(1)
continue
time.sleep(1)
raise TimeoutError("PostgreSQL container could not start up in time.") |
I think this won't work for the case where there is only 1 start. So when database initialization is skipped (let's say you persist your PG_DATA directory), your script will timeout. |
I believe it would work! It only checks In fact it would work for an already running container and a stopped container just as it would for a newly created container. I've used it in all those listed situations. The only difference I've made so far is move the script into a bash script rather than a python script. |
To wait for a postgres container to be "ready", I've been using a script like this:
But it seems even this is too early. Is there any unequivocal way that another container can tell once the postgres container is ready to be provisioned, without resorting to more arbitrary wait timers?
The text was updated successfully, but these errors were encountered: