Reputation: 630
I have following task in my playbook:
- name: install pg_stat_statements extension in the postgres container
shell: docker exec octopus_postgres_{{ group_id }} /bin/bash -c 'psql -h localhost -U postgres -p 5433 -c "CREATE EXTENSION pg_stat_statements;"' # && service postgres restart')"
async: 10
poll: 0
Once I run the playbook this task seems to successfully finished, but if I check the postgres database - there are no changes to it. The task didn't actually worked.
If I run the above mentioned command manually on the host via bash, everything works fine and the databased gets updated, like this:
docker exec octopus_postgres_iaa /bin/bash -c 'psql -h localhost -U postgres -p 5433 -c "CREATE EXTENSION pg_stat_statements;"'
While trying to check what is wrong with the task, I tried the following:
- name: install pg_stat_statements extension in the postgres container
shell: docker exec octopus_postgres_{{ group_id }} /bin/bash -c 'touch /1 && psql -h localhost -U postgres -p 5433 -c "CREATE EXTENSION pg_stat_statements;" && touch /2' # && service postgres restart')"
async: 10
poll: 0
I've noticed that file /1
indeed has been created inside of the container, but the file /2
hasn't...
What is wrong with the command?
Upvotes: 1
Views: 427
Reputation: 159382
Using docker exec
at all isn't right here. In general you want to avoid it for tasks like this: if the container gets deleted and recreated, any local setup you've done with docker exec
will be lost. When you're trying to make a change to some sort of server using its API, you usually just call its API, instead of getting a root shell on the server host and then doing things, but this latter step is what docker exec
does.
The standard postgres
image supports putting SQL fragments in a container-side /docker-entrypoint-initdb.d
directory, which will get processed the very first time the container is started (only). A very typical use is to mount a host-system directory with initialization scripts on to that directory. In Ansible this might look like:
- name: create pg_stat_statements extension file
copy:
dest: /docker/postgres/initdb/create-stat-statements.sql
content: |-
CREATE EXTENSION pg_stat_statements;
- name: start postgres container
docker_container:
image: 'postgres:11'
name: octopus_postgres_{{ group_id }}
published_ports: ['5433:5432']
volumes:
- '/docker/postgres/initdb:/docker-entrypoint-initdb.d'
- '/docker/postgres/data:/var/lib/postgresql/data'
Alternatively, you can manage the database like any other PostgreSQL database (local, cloud-hosted, remote, ...) using Ansible's built-in tools; in this case, the postgresql_ext
module for creating extensions.
- name: enable pg_stat_statements PostgreSQL extension
postgresql_ext:
name: pg_stat_statements
port: 5433
In terms of your original statement, there are probably two things going on. First of all, if you do use the docker exec
path to interact with a container, you always need to use the port the server thinks it's running on and not any remapped ports from the docker run -p
option or equivalents: in your statement you need to use the default port 5432 and not 5433. Secondly, since you run the task with async: 10, poll: 0
, Ansible launches the task and immediately moves on to the next one, without ever checking to see whether it succeeds (see Asynchronous Actions and Polling), so you don't actually know whether or not the docker exec
task succeeded. My guess is that nothing is happening because it's failing to connect to the database, but you never see this error.
Upvotes: 3