This playbook deploys MySQL in a Docker container using Ansible to manage the entire lifecycle including Docker installation, volume setup, and container orchestration.
---
- name: Deploy MySQL with Docker
hosts: mysql_docker
become: true
vars:
mysql_version: "8.4"
mysql_base_dir: /opt/mysql
mysql_data_dir: "{{ mysql_base_dir }}/data"
mysql_config_dir: "{{ mysql_base_dir }}/conf"
mysql_logs_dir: "{{ mysql_base_dir }}/logs"
mysql_init_dir: "{{ mysql_base_dir }}/initdb"
mysql_container_name: mysql-primary
mysql_host_port: 3306
mysql_container_port: 3306
mysql_bind_address: "127.0.0.1"
mysql_root_password: "{{ vault_mysql_root_password | default('change_me_root') }}"
mysql_database: appdb
mysql_user: appuser
mysql_password: "{{ vault_mysql_app_password | default('change_me_app') }}"
mysql_max_connections: 200
mysql_innodb_buffer_pool_size: "512M"
mysql_innodb_log_file_size: "128M"
tasks:
- name: Create base directories
file:
path: "{{ item }}"
state: directory
mode: '0755'
loop:
- "{{ mysql_base_dir }}"
- "{{ mysql_data_dir }}"
- "{{ mysql_config_dir }}"
- "{{ mysql_logs_dir }}"
- "{{ mysql_init_dir }}"
- 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: Create MySQL custom configuration
copy:
dest: "{{ mysql_config_dir }}/custom.cnf"
content: |
[mysqld]
max_connections = {{ mysql_max_connections }}
bind_address = 0.0.0.0
character_set_server = utf8mb4
collation_server = utf8mb4_unicode_ci
innodb_buffer_pool_size = {{ mysql_innodb_buffer_pool_size }}
innodb_log_file_size = {{ mysql_innodb_log_file_size }}
innodb_flush_log_at_trx_commit = 1
skip_name_resolve = ON
slow_query_log = ON
long_query_time = 0.5
mode: '0644'
notify: restart mysql container
- name: Create environment file
copy:
dest: "{{ mysql_base_dir }}/.env"
content: |
MYSQL_ROOT_PASSWORD={{ mysql_root_password }}
MYSQL_DATABASE={{ mysql_database }}
MYSQL_USER={{ mysql_user }}
MYSQL_PASSWORD={{ mysql_password }}
mode: '0600'
no_log: true
- name: Create Docker Compose file
copy:
dest: "{{ mysql_base_dir }}/compose.yaml"
content: |
services:
mysql:
image: mysql:{{ mysql_version }}
container_name: {{ mysql_container_name }}
restart: unless-stopped
ports:
- "{{ mysql_bind_address }}:{{ mysql_host_port }}:{{ mysql_container_port }}"
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- ./data:/var/lib/mysql
- ./conf:/etc/mysql/conf.d
- ./logs:/var/log/mysql
networks:
- mysql-net
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 20s
retries: 10
start_period: 30s
interval: 10s
networks:
mysql-net:
driver: bridge
mode: '0644'
notify: restart mysql container
- name: Start MySQL container
community.docker.docker_compose_v2:
project_src: "{{ mysql_base_dir }}"
state: present
build: never
- name: Wait for MySQL to become available
wait_for:
host: "{{ mysql_bind_address }}"
port: "{{ mysql_host_port }}"
delay: 5
timeout: 60
delegate_to: localhost
- name: Validate MySQL connection
command: docker exec {{ mysql_container_name }} mysqladmin -u root -p{{ mysql_root_password }} ping
register: mysql_ready
changed_when: false
no_log: true
failed_when: mysql_ready.rc != 0
- name: Display MySQL status
debug:
msg: "MySQL container is running and accepting connections"
handlers:
- name: restart docker
systemd:
name: docker
state: restarted
- name: restart mysql container
community.docker.docker_compose_v2:
project_src: "{{ mysql_base_dir }}"
state: present
build: never
listen: restart mysql container
# Create vault file
ansible-vault create group_vars/mysql_docker/vault.yml
# Add: vault_mysql_root_password: "your_secure_password_here"
# Run: ansible-playbook -i inventory mysql-docker.yml --ask-vault-pass
all:
children:
mysql_docker:
hosts:
db-primary:
ansible_host: 192.168.1.10
mysql_version: "8.4"
# Basic deployment
ansible-playbook -i inventory.yml mysql-docker.yml
# With vault password
ansible-playbook -i inventory.yml mysql-docker.yml --ask-vault-pass
# Check mode (dry run)
ansible-playbook -i inventory.yml mysql-docker.yml --check