mirror of
https://github.com/KevinMidboe/playbooks-retailor.git
synced 2026-09-07 13:32:06 +00:00
play & role for mysql server
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
---
|
||||
# ---------------------------------------------------------------------------
|
||||
mysql_root_password: "{{ lookup('env', 'MYSQL_ROOT_PASSWORD') | default('', true) }}"
|
||||
mysql_replication_user: "repl"
|
||||
mysql_replication_password: "{{ lookup('env', 'MYSQL_REPL_PASSWORD') | default('', true) }}"
|
||||
mysql_app_user: "{{ lookup('env', 'MYSQL_APP_USER') | default('appuser', true) }}"
|
||||
mysql_app_password: "{{ lookup('env', 'MYSQL_APP_PASSWORD') | default('', true) }}"
|
||||
mysql_app_database: "{{ lookup('env', 'MYSQL_APP_DATABASE') | default('appdb', true) }}"
|
||||
|
||||
mysql_version: "{{ lookup('env', 'MYSQL_VERSION') | default('8.0', true) }}"
|
||||
mysql_server_id: "{{ lookup('env', 'HOSTNAME') | default('mysql', true) }}"
|
||||
|
||||
# --- Sizing ------------------------------------------------------------
|
||||
# Set per-environment (override in host_vars if primary/replicas differ in size).
|
||||
# Rule of thumb: innodb_buffer_pool_size ~= 70-75% of RAM on a dedicated DB host.
|
||||
mysql_total_ram_mb: "{{ lookup('env', 'MYSQL_TOTAL_RAM_MB') | default(8192, true) | int }}"
|
||||
mysql_innodb_buffer_pool_size: "{{ (mysql_total_ram_mb | int * 0.70) | round | int }}M"
|
||||
|
||||
mysql_max_connections: 200
|
||||
|
||||
# --- Networking / security ----------------------------------------------
|
||||
mysql_bind_address: "0.0.0.0" # bound to all interfaces; ufw restricts who can reach it
|
||||
mysql_port: 3306
|
||||
mysql_allowed_cidrs: # who is allowed to hit port 3306 via firewall
|
||||
- "{{ lookup('env', 'MYSQL_ALLOWED_CIDR') | default('10.0.1.0/24', true) }}"
|
||||
|
||||
# --- Replication ----------------------------------------------------------
|
||||
mysql_gtid_mode: "ON"
|
||||
mysql_binlog_format: "ROW"
|
||||
mysql_binlog_expire_logs_seconds: 604800 # 7 days
|
||||
|
||||
# --- Backups ---------------------------------------------------------------
|
||||
mysql_backup_enabled: "{{ lookup('env', 'MYSQL_BACKUP_ENABLED') | default('true', true) | bool }}"
|
||||
mysql_backup_dir: /var/backups/mysql
|
||||
mysql_backup_retention_days: 7
|
||||
mysql_backup_hour: 2 # 2am local, staggered per-host below if needed
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
- name: restart mysql
|
||||
systemd:
|
||||
name: mysql
|
||||
state: restarted
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
---
|
||||
- name: Install prerequisite packages
|
||||
apt:
|
||||
name:
|
||||
- gnupg2
|
||||
- lsb-release
|
||||
- python3-pymysql # required by Ansible's community.mysql modules
|
||||
- ufw
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Install MySQL server
|
||||
apt:
|
||||
name:
|
||||
- mysql-server-8.0
|
||||
- mysql-client-8.0
|
||||
state: present
|
||||
notify: restart mysql
|
||||
|
||||
- name: Ensure MySQL data/log directories exist with correct ownership
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: mysql
|
||||
group: mysql
|
||||
mode: '0750'
|
||||
loop:
|
||||
- /var/log/mysql
|
||||
- "{{ mysql_backup_dir }}"
|
||||
|
||||
- name: Deploy tuned my.cnf
|
||||
template:
|
||||
src: my.cnf.j2
|
||||
dest: /etc/mysql/mysql.conf.d/99-production.cnf
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
# validate: 'mysqld --defaults-file=%s --validate-config'
|
||||
notify: restart mysql
|
||||
|
||||
- name: Start and enable MySQL
|
||||
systemd:
|
||||
name: mysql
|
||||
state: started
|
||||
enabled: true
|
||||
|
||||
- name: Set MySQL root password (idempotent — only runs if not already set)
|
||||
community.mysql.mysql_user:
|
||||
name: root
|
||||
password: "{{ mysql_root_password }}"
|
||||
host: localhost
|
||||
login_unix_socket: /var/run/mysqld/mysqld.sock
|
||||
state: present
|
||||
no_log: true
|
||||
|
||||
- name: Create .my.cnf for root so future plays authenticate automatically
|
||||
template:
|
||||
src: root_my_cnf.j2
|
||||
dest: /root/.my.cnf
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0600'
|
||||
no_log: true
|
||||
|
||||
# --- mysql_secure_installation equivalent, done idempotently ---------------
|
||||
- name: Remove anonymous MySQL users
|
||||
community.mysql.mysql_user:
|
||||
name: ''
|
||||
host_all: true
|
||||
state: absent
|
||||
login_unix_socket: /var/run/mysqld/mysqld.sock
|
||||
|
||||
- name: Remove test database
|
||||
community.mysql.mysql_db:
|
||||
name: test
|
||||
state: absent
|
||||
login_unix_socket: /var/run/mysqld/mysqld.sock
|
||||
|
||||
- name: Disallow remote root login
|
||||
community.mysql.mysql_user:
|
||||
name: root
|
||||
host: "{{ item }}"
|
||||
state: absent
|
||||
login_unix_socket: /var/run/mysqld/mysqld.sock
|
||||
loop:
|
||||
- "{{ ansible_hostname }}"
|
||||
- "%"
|
||||
ignore_errors: true # fine if they don't exist
|
||||
|
||||
# --- Firewall: only allow MySQL port from known CIDRs ----------------------
|
||||
- name: Allow MySQL port from trusted CIDRs only
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: "{{ mysql_port | string }}"
|
||||
proto: tcp
|
||||
from_ip: "{{ item }}"
|
||||
loop: "{{ mysql_allowed_cidrs }}"
|
||||
|
||||
- name: Reload ufw
|
||||
community.general.ufw:
|
||||
state: enabled
|
||||
|
||||
# --- Application DB + user --------------------------------------------------
|
||||
- name: Create retailor database
|
||||
community.mysql.mysql_db:
|
||||
name: "{{ mysql_app_database }}"
|
||||
state: present
|
||||
login_unix_socket: /var/run/mysqld/mysqld.sock
|
||||
|
||||
- name: Create forge user
|
||||
community.mysql.mysql_user:
|
||||
name: "{{ mysql_app_user }}"
|
||||
password: "{{ mysql_app_password }}"
|
||||
priv: "{{ mysql_app_database }}.*:ALL"
|
||||
host: '%'
|
||||
state: present
|
||||
login_unix_socket: /var/run/mysqld/mysqld.sock
|
||||
no_log: true
|
||||
|
||||
- name: Create replication user
|
||||
community.mysql.mysql_user:
|
||||
name: "{{ mysql_replication_user }}"
|
||||
password: "{{ mysql_replication_password }}"
|
||||
priv: "*.*:REPLICATION SLAVE"
|
||||
host: '%'
|
||||
state: present
|
||||
login_unix_socket: /var/run/mysqld/mysqld.sock
|
||||
no_log: true
|
||||
|
||||
- name: Deploy logrotate config
|
||||
template:
|
||||
src: logrotate_mysql.j2
|
||||
dest: /etc/logrotate.d/mysql-server
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Deploy backup script
|
||||
template:
|
||||
src: mysql_backup.sh.j2
|
||||
dest: /usr/local/bin/mysql_backup.sh
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0750'
|
||||
when: mysql_backup_enabled
|
||||
|
||||
- name: Schedule nightly backup cron
|
||||
cron:
|
||||
name: "mysql nightly backup"
|
||||
hour: "{{ mysql_backup_hour }}"
|
||||
minute: "0"
|
||||
job: "/usr/local/bin/mysql_backup.sh >> /var/log/mysql/backup.log 2>&1"
|
||||
user: root
|
||||
when: mysql_backup_enabled
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/var/log/mysql/*.log {
|
||||
daily
|
||||
rotate 14
|
||||
missingok
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 640 mysql adm
|
||||
sharedscripts
|
||||
postrotate
|
||||
/usr/bin/mysqladmin flush-logs
|
||||
endscript
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Production MySQL config — generated by Ansible for retailor.io. Edit by hand might cause drift!
|
||||
|
||||
[mysqld]
|
||||
bind-address = {{ mysql_bind_address }}
|
||||
port = {{ mysql_port }}
|
||||
max_connections = {{ mysql_max_connections }}
|
||||
server_id = {{ mysql_server_id }}
|
||||
|
||||
# --- InnoDB ------------------------------------------------------------
|
||||
innodb_buffer_pool_size = {{ mysql_innodb_buffer_pool_size }}
|
||||
innodb_log_file_size = 512M
|
||||
innodb_flush_log_at_trx_commit = 1 # full ACID durability; set to 2 only if you accept losing ~1s of txns on crash
|
||||
innodb_flush_method = O_DIRECT
|
||||
innodb_file_per_table = 1
|
||||
|
||||
# --- Replication (GTID-based) -------------------------------------------
|
||||
gtid_mode = {{ mysql_gtid_mode }}
|
||||
enforce_gtid_consistency = ON
|
||||
log_bin = /var/log/mysql/mysql-bin.log
|
||||
binlog_format = {{ mysql_binlog_format }}
|
||||
binlog_expire_logs_seconds = {{ mysql_binlog_expire_logs_seconds }}
|
||||
sync_binlog = 1
|
||||
read_only = {{ 'ON' if 'mysql_replica' in group_names else 'OFF' }}
|
||||
relay_log = /var/log/mysql/mysql-relay-bin
|
||||
|
||||
# --- Logging -------------------------------------------------------------
|
||||
slow_query_log = 1
|
||||
slow_query_log_file = /var/log/mysql/mysql-slow.log
|
||||
long_query_time = 2
|
||||
log_error = /var/log/mysql/error.log
|
||||
|
||||
# --- Security --------------------------------------------------------------
|
||||
local_infile = 0
|
||||
skip_name_resolve = 1
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[client]
|
||||
user = root
|
||||
password = "{{ mysql_root_password }}"
|
||||
|
||||
Reference in New Issue
Block a user