Reputation: 2600
I'm using secrets to manage username, password, and dbname with a Docker stack using Postgres as a DB. I now want to use the healthcheck feature that Docker provides.
docker-compose.yml:
x-db-secrets: &db_secrets
- psql_user
- psql_pass
- psql_dbname
services:
db:
image: postgres:13.1
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_USER_FILE=/run/secrets/psql_user
- POSTGRES_DB_FILE=/run/secrets/psql_dbname
- POSTGRES_PASSWORD_FILE=/run/secrets/psql_pass
secrets: *db_secrets
healthcheck:
test: pg_isready -U myuser -d db_prod
interval: 10s
timeout: 3s
retries: 3
(... other services...)
volumes:
postgres_data:
static_content:
media_content:
secrets:
psql_user:
external: true
psql_pass:
external: true
psql_dbname:
external: true
As can be noted in the healthcheck:
section, I'm exposing the db username & the dbname with the healthcheck. My question (with some follow-up based on the answer):
Thoughts? Workaround?
Additional details:
Upvotes: 47
Views: 83580
Reputation: 4682
You can use pg_isready without any username/password to check if container is 'healthy'.
bbepostgres:
image: postgres:14.2
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=pangea_local_dev
- PGUSER=postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready", "-d", "db_prod"]
interval: 30s
timeout: 60s
retries: 5
start_period: 80s
This will do the same thing as you wanted.
Reference: https://github.com/peter-evans/docker-compose-healthcheck
Upvotes: 59
Reputation: 311
It seems like the usage of CMD-SHELL
gives false negatives when not in the format of:
"{CMD} || exit 1"
After some testing I found that indeed the issue was that for pg_isready
you need to set PG{KEYWORD}
environment args instead of POSTGRES_{KEYWORD}
args.
Nevertheless, I found pg_ready
to be redundant and went for the following approach:
test: ["CMD-SHELL", "psql -U ${DB_USER} -d ${DB_MAIN} -c 'SELECT 1' || exit 1"]
This approach saves you from having to set env vars twice.
You can test that it works by replacing 'SELECT 1'
with 'SELECT 1 from some_nonexistent_table'
. You will see it fails after n retries.
To check the logs for the test, use the following command: (credit)
docker inspect --format "{{json .State.Health }}" ${CONTAINER_NAME}
Edit:
I would like to add that setting pg_isready
username and database via args does not work. This means that passing values for -U
--username
and-d
--database
is useless and will be overwritten by the environment variables, regardless of having set those.
Upvotes: 7
Reputation: 35
I have set it in following way using docker secrets:
db:
container_name: db
image: postgres:16
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
POSTGRES_USER_FILE: /run/secrets/db_user
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
POSTGRES_DB_FILE: run/secrets/db_name
PGUSER_FILE: /run/secrets/db_user
secrets:
- db_name
- db_password
- db_user
healthcheck:
test: [ "CMD-SHELL", "pg_isready -d `cat $$POSTGRES_DB_FILE` -U `cat $$PGUSER_FILE`" ]
interval: 2s
timeout: 5s
retries: 10
Upvotes: 1
Reputation: 616
as mentioned above, you can use the pg_isready
I also added a 'dummy' container to wait for multiple container, for example postgres
and mysql
version: "3.2"
services:
postgres-db:
image: postgres:13
restart: always
environment:
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
networks:
- default
healthcheck:
test: pg_isready -U postgres
enter code here
mysql-db:
platform: linux/x86_64
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- "3306:3306"
healthcheck:
test: 'mysql --user=root --password=password --execute "SHOW DATABASES;"'
ready:
image: hello-world
depends_on:
postgres-db:
condition: service_completed_successfully
mysql-db:
condition: service_healthy
Upvotes: -1
Reputation: 2153
So this can be done by using a .env
file and slightly modifiying your docker-compose.yml
file.
POSTGRES_HOST=db
POSTGRES_USER=root
POSTGRES_PASSWORD=password
POSTGRES_DB=dev
services:
db:
image: postgres:13.1
volumes:
- postgres_data:/var/lib/postgresql/data/
env_file:
- .env
secrets: *db_secrets
healthcheck:
test: ["CMD-SHELL", "sh -c 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}'"]
interval: 10s
timeout: 3s
retries: 3
Upvotes: 49
Reputation: 11
Since, the docker socket is on the host, the healthcheck command is visible through docker inspect
, so it does (really) matter only if the password could be retrieved from username and/or dbname.
One could say that it always matter, but it depends on your needs.
Upvotes: 1