docker-compose-wait
A simple script to wait for other docker images to be started while using docker-compose (or Kubernetes or docker stack or whatever)
Top Related Projects
Pure bash script to test and wait on the availability of a TCP host and port
./wait-for is a script to wait for another service to become available.
Utility to simplify running applications in docker containers
Quick Overview
The ufoscout/docker-compose-wait
project is a simple utility that helps you wait for specific services to be available before starting your Docker Compose application. It can be used to ensure that dependent services (e.g., databases, message queues) are ready before your application starts, reducing the risk of startup failures.
Pros
- Simplicity: The project is lightweight and easy to use, with a straightforward command-line interface.
- Flexibility: It supports waiting for various types of services, including TCP, HTTP, and command-based checks.
- Reliability: The utility uses a robust polling mechanism to ensure that services are truly available before proceeding.
- Cross-platform: The tool can be used on Windows, macOS, and Linux platforms.
Cons
- Limited Functionality: The project is focused on a specific use case (waiting for services) and may not provide advanced features or customization options.
- Dependency on Docker Compose: The utility is designed to work within the context of a Docker Compose environment, which may limit its usefulness in other deployment scenarios.
- Potential Performance Impact: Depending on the number of services and the time required for them to become available, the waiting process may add some overhead to the application startup.
- Lack of Extensive Documentation: While the project has a README file, the documentation could be more comprehensive, especially for more advanced use cases.
Code Examples
The ufoscout/docker-compose-wait
project is a command-line utility, so there are no code examples to provide. However, here are a few examples of how you can use the tool in your Docker Compose setup:
- Waiting for a TCP service:
version: '3'
services:
my-app:
image: my-app:latest
depends_on:
- database
command: ["./wait-for-it.sh", "database:5432", "--", "python", "app.py"]
database:
image: postgres:12
- Waiting for an HTTP service:
version: '3'
services:
my-app:
image: my-app:latest
depends_on:
- api
command: ["./wait-for-it.sh", "http://api:8080/healthz", "--", "python", "app.py"]
api:
image: my-api:latest
- Waiting for a command-based check:
version: '3'
services:
my-app:
image: my-app:latest
depends_on:
- message-queue
command: ["./wait-for-it.sh", "message-queue", "--timeout=60", "--", "python", "app.py"]
message-queue:
image: rabbitmq:3
Getting Started
To use the ufoscout/docker-compose-wait
utility in your Docker Compose setup, follow these steps:
-
Add the
wait-for-it.sh
script to your project's root directory. You can download the script from the project's GitHub repository: https://raw.githubusercontent.com/ufoscout/docker-compose-wait/master/wait-for-it.sh -
Make the script executable:
chmod +x wait-for-it.sh
-
In your Docker Compose file, add the
depends_on
andcommand
directives to the services that need to wait for other services to be available. Use thewait-for-it.sh
script to specify the service(s) to wait for, as shown in the code examples above. -
Run your Docker Compose application as usual:
docker-compose up
The wait-for-it.sh
script will automatically wait for the specified services to be available before starting your application.
Competitor Comparisons
Pure bash script to test and wait on the availability of a TCP host and port
Pros of wait-for-it
- Written in pure Bash, making it more portable and easier to integrate into existing scripts
- Supports both TCP and HTTP checks, offering more flexibility
- Provides more detailed output and debugging options
Cons of wait-for-it
- May have slower performance compared to compiled languages
- Requires Bash to be available in the container
- Limited to checking single host:port combinations at a time
Code Comparison
wait-for-it:
#!/usr/bin/env bash
wait_for() {
if [[ $TIMEOUT -gt 0 ]]; then
echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT"
else
echoerr "$cmdname: waiting for $HOST:$PORT without a timeout"
fi
# ... (additional code)
}
docker-compose-wait:
fn main() {
let args: Vec<String> = env::args().collect();
let hosts = parse_hosts(&args);
let timeout = parse_timeout(&args);
let start = Instant::now();
// ... (additional code)
}
The main difference in the code is the language used. wait-for-it is written in Bash, while docker-compose-wait is implemented in Rust. This affects performance, portability, and integration capabilities. wait-for-it's script is more human-readable and easier to modify, while docker-compose-wait's compiled binary offers better performance and resource efficiency.
./wait-for is a script to wait for another service to become available.
Pros of wait-for
- Lightweight shell script, easy to understand and modify
- Supports multiple protocols (TCP, HTTP, etc.) and custom commands
- More flexible in terms of customization and usage scenarios
Cons of wait-for
- Requires manual integration into Docker images or Compose files
- May need additional dependencies installed in the container (e.g., netcat)
- Less automated approach compared to docker-compose-wait
Code Comparison
wait-for:
#!/bin/sh
TIMEOUT=15
QUIET=0
usage() {
echo "Usage: $0 [OPTIONS] HOST:PORT [-t TIMEOUT] [-- COMMAND [ARG...]]"
exit 1
}
docker-compose-wait:
use std::env;
use std::net::TcpStream;
use std::time::Duration;
fn main() {
let hosts = env::var("WAIT_HOSTS").unwrap_or_default();
let timeout = env::var("WAIT_HOSTS_TIMEOUT").unwrap_or_else(|_| "30".to_string());
Summary
wait-for is a more flexible and customizable solution, suitable for various scenarios beyond Docker Compose. It supports multiple protocols and custom commands but requires manual integration and potential additional dependencies. docker-compose-wait is more automated and specifically designed for Docker Compose environments, offering a simpler setup but with less flexibility. The choice between the two depends on the specific requirements of the project and the desired level of customization.
Utility to simplify running applications in docker containers
Pros of dockerize
- More versatile: Can generate configuration files, handle SSL certificates, and perform other tasks beyond waiting
- Supports complex dependency chains with multiple services
- Actively maintained with regular updates and improvements
Cons of dockerize
- Larger image size due to additional features
- Steeper learning curve for basic wait functionality
- May be overkill for simple use cases where only waiting is required
Code comparison
docker-compose-wait:
/wait && your_command
dockerize:
dockerize -wait tcp://db:5432 -wait http://web:80 your_command
Key differences
docker-compose-wait is a lightweight tool focused solely on waiting for services to be ready before starting a container. It's simple to use and has a small footprint.
dockerize is a more comprehensive tool that offers additional functionality beyond waiting, such as template rendering and log output. It's better suited for complex scenarios but may be excessive for basic wait requirements.
Both tools serve the purpose of managing container startup dependencies, but dockerize provides a broader range of features at the cost of increased complexity and image size.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
docker-compose-wait
A small command-line utility to wait for other docker images to be started while using docker-compose (or Kubernetes or docker stack or whatever).
It permits waiting for:
- a fixed amount of seconds
- until a TCP port is open on a target image
- until a file or directory is present on the local filesystem
Usage
This utility should be used in the docker build process and launched before your application starts.
For example, your application "MySuperApp" uses MongoDB, Postgres and MySql (wow!) and you want to be sure that, when it starts, all other systems are available, then simply customize your dockerfile this way:
## Use whatever base image
FROM alpine
## Add the wait script to the image
COPY --from=ghcr.io/ufoscout/docker-compose-wait:latest /wait /wait
## Otherwise you can directly download the executable from github releases. E.g.:
# ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.11.0/wait /wait
# RUN chmod +x /wait
## Add your application to the docker image
ADD MySuperApp.sh /MySuperApp.sh
## Launch the wait tool and then your application
CMD /wait && /MySuperApp.sh
Done! the image is ready.
Now let's modify the docker-compose.yml file:
version: "3"
services:
mongo:
image: mongo:3.4
hostname: mongo
ports:
- "27017:27017"
postgres:
image: "postgres:9.4"
hostname: postgres
ports:
- "5432:5432"
mysql:
image: "mysql:5.7"
hostname: mysql
ports:
- "3306:3306"
mySuperApp:
image: "mySuperApp:latest"
hostname: mySuperApp
environment:
WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017
When docker-compose is started (or Kubernetes or docker stack or whatever), your application will be started only when all the pairs host:port in the WAIT_HOSTS variable are available. The WAIT_HOSTS environment variable is not mandatory, if not declared, the script executes without waiting.
If you want to use the script directly in docker-compose.yml instead of the Dockerfile, please note that the command:
configuration option is limited to a single command so you should wrap in a sh
call. For example:
command: sh -c "/wait && /MySuperApp.sh"
This is discussed further here and here.
Usage in images that do not have a shell
When using distroless or building images FROM scratch
, it is common to not have sh
available. In this case, it is necessary to specify the command for wait to run explicitly. The invoked command will be invoked with any arguments configured for it and will completely replace the wait
process in your container via a syscall to exec
. Because there is no shell to expand arguments in this case, wait
must be the ENTRYPOINT
for the container and has to be specified in the exec form. Note that because there is no shell to perform expansion, arguments like *
must be interpreted by the program that receives them.
FROM golang
COPY myApp /app
WORKDIR /app
RUN go build -o /myApp -ldflags '-s -w -extldflags -static' ./...
## ----------------
FROM scratch
COPY --from=ghcr.io/ufoscout/docker-compose-wait:latest /wait /wait
COPY --from=0 /myApp /myApp
ENV WAIT_COMMAND="/myApp arg1 argN..."
ENTRYPOINT ["/wait"]
Additional configuration options
The behaviour of the wait utility can be configured with the following environment variables:
- WAIT_LOGGER_LEVEL : the output logger level. Valid values are: debug, info, error, off. the default is debug.
- WAIT_HOSTS: comma-separated list of pairs host:port for which you want to wait.
- WAIT_PATHS: comma-separated list of paths (i.e. files or directories) on the local filesystem for which you want to wait until they exist.
- WAIT_COMMAND: command and arguments to run once waiting completes. The invoked command will completely replace the
wait
process. The default is none. - WAIT_TIMEOUT: max number of seconds to wait for all the hosts/paths to be available before failure. The default is 30 seconds.
- WAIT_HOST_CONNECT_TIMEOUT: The timeout of a single TCP connection to a remote host before attempting a new connection. The default is 5 seconds.
- WAIT_BEFORE: number of seconds to wait (sleep) before start checking for the hosts/paths availability
- WAIT_AFTER: number of seconds to wait (sleep) once all the hosts/paths are available
- WAIT_SLEEP_INTERVAL: number of seconds to sleep between retries. The default is 1 second.
Supported architectures
From release 2.11.0, the following executables are available for download:
- wait: This is the executable intended for Linux x64 systems
- wait_x86_64: This is the very same executable than wait
- wait_aarch64: This is the executable to be used for aarch64 architectures
- wait_arm7: This is the executable to be used for arm7 architectures
All executables are built with MUSL for maximum portability.
To use any of these executables, simply replace the executable name in the download link: https://github.com/ufoscout/docker-compose-wait/releases/download/{{VERSION}}/{{executable_name}}
Docker images
Official docker images based on scratch
can be found here:
https://github.com/users/ufoscout/packages/container/package/docker-compose-wait
Using on other systems
The simplest way of getting the wait executable is to download it from
https://github.com/ufoscout/docker-compose-wait/releases/download/{{VERSION}}/wait
or to use one of the pre-built docker images.
If you need it for an architecture for which a pre-built file is not available, you should clone this repository and build it for your target.
As it has no external dependencies, an being written in the mighty rust
programming language, the build process is just a simple cargo build --release
(well... of course you need to install the rust compiler before...)
For everything involving cross-compilation, you should take a look at Cross.
For example, to build for a raspberry pi, everything you have to do is:
- Install the latest stable rust toolchain using rustup
- Correctly configure Docker on your machine
- Open a terminal and type:
cargo install cross
cross build --target=armv7-unknown-linux-musleabihf --release
Use your shiny new executable on your raspberry device!
Notes
This utility was explicitly written to be used with docker-compose; however, it can be used everywhere since it has no dependencies on docker.
Top Related Projects
Pure bash script to test and wait on the availability of a TCP host and port
./wait-for is a script to wait for another service to become available.
Utility to simplify running applications in docker containers
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot