diff --git a/docs/faq.md b/docs/faq.md index 73596c18b..201549f18 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -15,7 +15,77 @@ weight=90 If you don’t see your question here, feel free to drop by `#docker-compose` on freenode IRC and ask the community. -## Why do my services take 10 seconds to stop? + +## How do I control the order of service startup? I need my database to be ready before my application starts. + +You can control the order of service startup with the +[depends_on](compose-file.md#depends-on) option. Compose always starts +containers in dependency order, where dependencies are determined by +`depends_on`, `links`, `volumes_from` and `network_mode: "service:..."`. + +However, Compose will not wait until a container is "ready" (whatever that means +for your particular application) - only until it's running. There's a good +reason for this. + +The problem of waiting for a database to be ready is really just a subset of a +much larger problem of distributed systems. In production, your database could +become unavailable or move hosts at any time. Your application needs to be +resilient to these types of failures. + +To handle this, your application should attempt to re-establish a connection to +the database after a failure. If the application retries the connection, +it should eventually be able to connect to the database. + +The best solution is to perform this check in your application code, both at +startup and whenever a connection is lost for any reason. However, if you don't +need this level of resilience, you can work around the problem with a wrapper +script: + +- Use a tool such as [wait-for-it](https://github.com/vishnubob/wait-for-it) + or [dockerize](https://github.com/jwilder/dockerize). These are small + wrapper scripts which you can include in your application's image and will + poll a given host and port until it's accepting TCP connections. + + Supposing your application's image has a `CMD` set in its Dockerfile, you + can wrap it by setting the entrypoint in `docker-compose.yml`: + + version: "2" + services: + web: + build: . + ports: + - "80:8000" + depends_on: + - "db" + entrypoint: ./wait-for-it.sh db:5432 + db: + image: postgres + +- Write your own wrapper script to perform a more application-specific health + check. For example, you might want to wait until Postgres is definitely + ready to accept commands: + + #!/bin/bash + + set -e + + host="$1" + shift + cmd="$@" + + until psql -h "$host" -U "postgres" -c '\l'; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 + done + + >&2 echo "Postgres is up - executing command" + exec $cmd + + You can use this as a wrapper script as in the previous example, by setting + `entrypoint: ./wait-for-postgres.sh db`. + + +## Why do my services take 10 seconds to recreate or stop? Compose stop attempts to stop a container by sending a `SIGTERM`. It then waits for a [default timeout of 10 seconds](./reference/stop.md). After the timeout, @@ -40,6 +110,12 @@ in your Dockerfile. * If you are able, modify the application that you're running to add an explicit signal handler for `SIGTERM`. +* Set the `stop_signal` to a signal which the application knows how to handle: + + web: + build: . + stop_signal: SIGINT + * If you can't modify the application, wrap the application in a lightweight init system (like [s6](http://skarnet.org/software/s6/)) or a signal proxy (like [dumb-init](https://github.com/Yelp/dumb-init) or @@ -84,30 +160,6 @@ specify the filename to use, for example: docker-compose -f docker-compose.json up ``` -## How do I get Compose to wait for my database to be ready before starting my application? - -Unfortunately, Compose won't do that for you but for a good reason. - -The problem of waiting for a database to be ready is really just a subset of a -much larger problem of distributed systems. In production, your database could -become unavailable or move hosts at any time. The application needs to be -resilient to these types of failures. - -To handle this, the application would attempt to re-establish a connection to -the database after a failure. If the application retries the connection, -it should eventually be able to connect to the database. - -To wait for the application to be in a good state, you can implement a -healthcheck. A healthcheck makes a request to the application and checks -the response for a success status code. If it is not successful it waits -for a short period of time, and tries again. After some timeout value, the check -stops trying and report a failure. - -If you need to run tests against your application, you can start by running a -healthcheck. Once the healthcheck gets a successful response, you can start -running your tests. - - ## Should I include my code with `COPY`/`ADD` or a volume? You can add your code to the image using `COPY` or `ADD` directive in a