Install MySQL and schedule backups with Ansible
ansible bash homelab mysqlIn this article, we will install and configure MySQL and schedule database backups in Ubuntu using Ansible.
Prerequisites
- Ansible
- An Ubuntu (or other Debian-based distro) host
- Package
python3-pip
installed in host
A variable mysql_password
is required in the playbook.
It is recommended to store it as a
secret.
Run the tasks as root. Either in the host definintion:
mysql ansible_user=me ansible_become=yes
or at play level:
hosts: mysql
become: yes
Installation and basic configuration
Install the required APT packages and the Python development headers and libraries (required by the MySQL collection in Ansible):
- name: install mysql
apt:
name:
- mysql-server
- default-libmysqlclient-dev
update_cache: yes
- name: enable and start mysql
service:
name: mysql
state: started
enabled: yes
- name: install mysql python library
pip:
name: mysqlclient
Credentials can be saved in $HOME/.my.cnf
, so we set the
password for the root user and save the credentials in that config file.
We set the default user password before creating the config file,
otherwise, we will have an authentication error:
- stat:
path: /root/.my.cnf
register: mycnf
- name: set default user password
mysql_user:
name: root
password: "{{ mysql_password }}"
when: "{{ not mycnf.stat.exists }}"
- name: save credentials
copy:
dest: /root/.my.cnf
content: |
[mysql]
user = root
password= {{ mysql_password }}
host = localhost
[mysqldump]
user = root
password= {{ mysql_password }} host = localhost
Allow remote access
If we want to access the MySQL server from a different host, we need to edit the MySQL settings and grant priviledges to the roor user (and allow the port used by the server).
Listen all addresses to allow remote access:
- name: allow remote access
lineinfile:
dest: /etc/mysql/mysql.conf.d/mysqld.cnf
regexp: ^(bind-address\s+=) 127.0.0.1
line: \1 0.0.0.0
backrefs: yes
state: present
notify:
- restart mysql
Allow root user to connect remotelly:
- name: allow remote access for default user
mysql_user:
name: root
host: '%'
priv: '*.*:ALL,GRANT'
password: "{{ mysql_password }}"
login_user: root
login_password: "{{ mysql_password }}"
And allow the port 3306 in the firewall:
- name: allow port 3306
ufw:
rule: allow
port: '3306'
proto: tcp
We will need to grant priviledges to other users in case we want allow them to connect remotelly.
When changing the configuration file we’ll trigger the handler
restart mysql
to restart the MySQL service:
handlers:
- name: restart mysql
service:
name: mysql
state: restarted
Schedule backups
We can create a simple script to backup all or some databases. Here’s
an example of a script to backup all the databases and upload the files
to a host named backups
:
#!/bin/bash
set -e
set -o pipefail
dir=`mktemp -d`
echo Saving tmp mysql backups to $dir...
suffix=$(date +%Y%m%d).sql
query="
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name not in ('mysql','sys','information_schema','performance_schema');
"
for db in `sudo -i mysql -e "$(echo $query)" | grep -v SCHEMA_NAME`; do
echo Saving mysql database $db...
path=$dir/$db.$suffix
sudo -i mysqldump $db > $path
done
for filename in `ls $dir`; do
echo Uploading mysql database $db...
scp $dir/$filename backups:/mysql/
done
rm -rf $dir
Note that we are running the mysql commands as user
root
.
We can then copy that script and schedule its execution, say everyday at 01:00:
- name: copy backup script
copy:
src: files/mysql/backup.sh
dest: "{{ lookup('env', 'HOME') }}/backup_mysql.sh"
owner: "{{ ansible_user }}"
- name: schedule backup
cron:
name: "backup mysql databases"
minute: "0"
hour: "1"
job: "bash {{ lookup('env', 'HOME') }}/backup_mysql.sh 2>&1 | logger -t {{ ansible_user }}-cron"
become_user: "{{ ansible_user }}"
The file and the cron job can be executed by any other sudoer, in this example, the ansible user configured in the hosts file.