У меня есть следующая задача в моей пьесе:
- 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
Как только я запускаю playbook, эта задача кажется успешно завершенной, но если я проверю базу данных postgres, в ней нет никаких изменений. Задача фактически не удалась.
Если я запускаю вышеупомянутую команду вручную на хосте через bash, все работает нормально, и база данных обновляется, например:
docker exec octopus_postgres_iaa /bin/bash -c 'psql -h localhost -U postgres -p 5433 -c "CREATE EXTENSION pg_stat_statements;"'
Пытаясь проверить, что не так с задачей, я попробовал следующее:
- 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
Я заметил, что файл /1
действительно был создан внутри контейнера, но файл /2
не...
Что не так с командой?
Использование docker exec
здесь неуместно. В общем, вы хотите избежать этого для таких задач: если контейнер будет удален и воссоздан, любая локальная настройка, которую вы сделали с помощью docker exec
, будет потеряна. Когда вы пытаетесь внести изменения в какой-то сервер, используя его API, вы обычно просто вызываете его API, вместо того, чтобы получить корневую оболочку на хосте сервера и затем что-то делать, но этот последний шаг — это то, что делает docker exec
.
стандартное postgres
изображение поддерживает размещение фрагментов SQL в каталоге на стороне контейнера /docker-entrypoint-initdb.d
, который будет обрабатываться при первом запуске контейнера (только). Очень типичным использованием является монтирование каталога хост-системы со сценариями инициализации в этот каталог. В Ansible это может выглядеть так:
- 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'
В качестве альтернативы вы можете управлять базой данных, как и любой другой базой данных PostgreSQL (локальной, облачной, удаленной и т. д.), используя встроенные инструменты Ansible; в данном случае модуль postgresql_ext
для создания расширений.
- name: enable pg_stat_statements PostgreSQL extension
postgresql_ext:
name: pg_stat_statements
port: 5433
С точки зрения вашего первоначального утверждения, вероятно, происходят две вещи. Прежде всего, если вы используете путь docker exec
для взаимодействия с контейнером, вам всегда нужно использовать порт, на котором, по мнению сервера, он работает, а не какие-либо переназначенные порты из опции docker run -p
или эквивалентов: в вашем заявлении вам нужно использовать порт по умолчанию 5432, а не 5433. Во-вторых, поскольку вы запускаете задачу с помощью async: 10, poll: 0
, Ansible запускает задачу и сразу переходит к следующей, даже не проверяя, успешно ли она выполнена (см. Асинхронные действия и опрос), поэтому вы на самом деле не знаете успешно ли выполнена задача docker exec
. Я предполагаю, что ничего не происходит, потому что не удается подключиться к базе данных, но вы никогда не видите эту ошибку.