This playbook deploys PostgreSQL in a Docker container using Ansible to manage the entire lifecycle including Docker installation, volume setup, and container orchestration.
---
- name: Deploy PostgreSQL with Docker
hosts: postgres_docker
become: true
vars:
# PostgreSQL version
postgres_version: "18"
# Directory structure
postgres_base_dir: /opt/postgres
postgres_data_dir: "{{ postgres_base_dir }}/data"
postgres_config_dir: "{{ postgres_base_dir }}/config"
# Container settings
postgres_container_name: postgres-db
# Network settings
postgres_host_port: 5432
postgres_container_port: 5432
postgres_bind_address: "127.0.0.1"
# Database credentials (use Ansible Vault in production)
postgres_db: appdb
postgres_user: appuser
postgres_password: "{{ vault_postgres_password | default('change_me') }}"
# PostgreSQL configuration
postgres_max_connections: 100
postgres_shared_buffers: "256MB"
postgres_effective_cache_size: "1GB"
postgres_work_mem: "4MB"
postgres_maintenance_work_mem: "64MB"
tasks:
- name: Create base directory
file:
path: "{{ postgres_base_dir }}"
state: directory
mode: '0755'
- name: Create data directory
file:
path: "{{ postgres_data_dir }}"
state: directory
mode: '0755'
- name: Create config directory
file:
path: "{{ postgres_config_dir }}"
state: directory
mode: '0755'
- name: Install Docker prerequisites
package:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- lsb-release
state: present
when: ansible_os_family == "Debian"
- name: Add Docker GPG key (Debian/Ubuntu)
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
when: ansible_os_family == "Debian"
- name: Add Docker repository (Debian/Ubuntu)
apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
state: present
filename: docker
when: ansible_os_family == "Debian"
- name: Install Docker packages
package:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-compose-plugin
state: present
notify: restart docker
- name: Enable and start Docker service
systemd:
name: docker
state: started
enabled: true
daemon_reload: true
- name: Ensure current user is in docker group
user:
name: "{{ ansible_user }}"
groups: docker
append: true
when: ansible_user is defined
- name: Create PostgreSQL custom configuration
copy:
dest: "{{ postgres_config_dir }}/custom.conf"
content: |
# Connection settings
listen_addresses = '*'
max_connections = {{ postgres_max_connections }}
# Memory settings
shared_buffers = {{ postgres_shared_buffers }}
effective_cache_size = {{ postgres_effective_cache_size }}
work_mem = {{ postgres_work_mem }}
maintenance_work_mem = {{ postgres_maintenance_work_mem }}
# Logging
logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_min_duration_statement = 1000
# Checkpoints
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
mode: '0644'
notify: restart postgres container
- name: Create environment file
copy:
dest: "{{ postgres_base_dir }}/.env"
content: |
POSTGRES_DB={{ postgres_db }}
POSTGRES_USER={{ postgres_user }}
POSTGRES_PASSWORD={{ postgres_password }}
PGDATA=/var/lib/postgresql/data/pgdata
mode: '0600'
no_log: true
- name: Create Docker Compose file
copy:
dest: "{{ postgres_base_dir }}/compose.yaml"
content: |
services:
postgres:
image: postgres:{{ postgres_version }}
restart: unless-stopped
container_name: {{ postgres_container_name }}
ports:
- "{{ postgres_bind_address }}:{{ postgres_host_port }}:{{ postgres_container_port }}"
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- ./data:/var/lib/postgresql/data
- ./config/custom.conf:/etc/postgresql/postgresql.conf
command: postgres -c config_file=/etc/postgresql/postgresql.conf
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- postgres-network
networks:
postgres-network:
driver: bridge
mode: '0644'
notify: restart postgres container
- name: Start PostgreSQL container
community.docker.docker_compose_v2:
project_src: "{{ postgres_base_dir }}"
state: present
build: never
register: compose_result
- name: Wait for PostgreSQL to be ready
wait_for:
host: "{{ postgres_bind_address }}"
port: "{{ postgres_host_port }}"
delay: 5
timeout: 60
delegate_to: localhost
- name: Validate PostgreSQL connection
command: >
docker exec {{ postgres_container_name }}
pg_isready -U {{ postgres_user }} -d {{ postgres_db }}
register: pg_ready
changed_when: false
failed_when: pg_ready.rc != 0
- name: Display PostgreSQL status
debug:
msg: "PostgreSQL container is running and accepting connections"
handlers:
- name: restart docker
systemd:
name: docker
state: restarted
- name: restart postgres container
community.docker.docker_compose_v2:
project_src: "{{ postgres_base_dir }}"
state: present
build: never
listen: restart postgres container
post_tasks:
- name: Show container status
command: docker ps --filter name={{ postgres_container_name }}
register: container_status
changed_when: false
- name: Display container information
debug:
var: container_status.stdout_lines
Create an encrypted vault file for sensitive credentials:
# Create vault file
ansible-vault create group_vars/postgres_docker/vault.yml
# Add credentials
# vault_postgres_password: "your_secure_password_here"
# Run playbook with vault
ansible-playbook -i inventory postgres-docker.yml --ask-vault-pass
# inventory.yml
all:
children:
postgres_docker:
hosts:
db-primary:
ansible_host: 192.168.1.10
postgres_version: "18"
postgres_max_connections: 200
db-secondary:
ansible_host: 192.168.1.11
postgres_version: "18"
postgres_max_connections: 150
# Basic deployment
ansible-playbook -i inventory.yml postgres-docker.yml
# With vault password
ansible-playbook -i inventory.yml postgres-docker.yml --ask-vault-pass
# Limit to specific host
ansible-playbook -i inventory.yml postgres-docker.yml --limit db-primary
# Check mode (dry run)
ansible-playbook -i inventory.yml postgres-docker.yml --check
# Verbose output
ansible-playbook -i inventory.yml postgres-docker.yml -vv