diff --git a/mysql/README.md b/mysql/README.md new file mode 100644 index 00000000..9e641ec2 --- /dev/null +++ b/mysql/README.md @@ -0,0 +1,29 @@ +# mysql + +Installation de MySQL, une configuration type Evolix et quelques outils. + +## Taches + +Les taches sont éclatées dans différents fichiers, inclus dans `tasks/main.yml` : + +* `packages.yml` : installation des paquets +* `users.yml` : remplacement de l'utilisateur `root` par `mysqladmin` +* `config.yml` : copie des configurations +* `datadir.yml` : configuration du dossier de travail +* `tmpdir.yml` : configuration du dossier temporaire +* `nrpe.yml` : utilisateur `nrpe` pour checks Nagios +* `munin.yml` : activation des plugins Munin +* `log2mail.yml` : recettes log2mail +* `utils.yml` : installation d'outils utiles + +## Variables possibles + +Les seules variables sont liées au hostname (court et complet) qui sont simplement déduites des facts. + +* `mysql_replace_root_with_mysqladmin`: remplacement de `root` par `mysqladmin` – `true` par défaut +* `mysql_thread_cache_size`: nombre de threads pour le cache – nombre de vCPU par défaut +* `mysql_innodb_buffer_pool_size`: taille du buffer InnoDB – 30% de la RAM installée par défaut +* `mysql_custom_datadir`: le dossier de travail personnalisé +* `mysql_custom_tmpdir`: le dossier temporaire personnalisé + +NB : le changement de _datadir_ peut se faire plusieurs fois, tant qu'on ne revient pas vers la valeur par défaut (car une fois déplacé un lien symbolique est créé au point de départ). diff --git a/mysql/defaults/main.yml b/mysql/defaults/main.yml new file mode 100644 index 00000000..7c66116d --- /dev/null +++ b/mysql/defaults/main.yml @@ -0,0 +1,7 @@ +mysql_replace_root_with_mysqladmin: true + +mysql_custom_datadir: '' +mysql_custom_tmpdir: '' + +mysql_thread_cache_size: '{{ ansible_processor_cores }}' +mysql_innodb_buffer_pool_size: '{{ (ansible_memtotal_mb * 0.3) | int }}M' diff --git a/mysql/files/evolinux-defaults.cnf b/mysql/files/evolinux-defaults.cnf new file mode 100644 index 00000000..96095a58 --- /dev/null +++ b/mysql/files/evolinux-defaults.cnf @@ -0,0 +1,61 @@ +[mysqld] + +###### Connexions +# Maximum de connexions concurrentes (defaut = 100)... provoque un +# "Too many connections" +max_connections = 250 +# Maximum de connexions en attente en cas de max_connections atteint +# (defaut = 50) +back_log = 100 +# Maximum d'erreurs avant de blacklister un hote +max_connect_errors = 10 + +###### Tailles +# Taille reservee au buffer des index MyIsam +# A ajuster selon les resultats +key_buffer_size = 512M +# Taille max des paquets envoyés/reçus ... provoque un "Packet too large" +max_allowed_packet = 64M +# Taille de la memoire reserve pour un thread +thread_stack = 192K +# A mettre le nombre de CPU x2 +thread_cache_size = 2 + +###### Cache +# max_connections x nbre max de tables dans une jointure (defaut = 64) +table_cache = 4096 +table_open_cache = 4096 +table_definition_cache = 4096 +# Taille max des requetes cachees (defaut = 1M) +query_cache_limit = 8M +# Taille reservee pour le cache (defaut = 0) +query_cache_size = 256M +# Type de requetes a cacher (defaut = 1 : tout peut etre cache) +query_cache_type = 1 +# Cache tables +max_heap_table_size = 128M +tmp_table_size = 128M + +###### InnoDB +# Si InnoDB n'est pas utilise... le desactiver +#skip-innodb +# En general, il est plus optimum d'avoir un fichier par table +innodb_file_per_table +# Taille memoire allouee pour le cache des datas et index +# A ajuster en fonction de sa RAM (si serveur dedie a MySQL, on peut aller +# jusqu'a 80%) +innodb_buffer_pool_size = 2G +# Taille buffer memoire pour structures internes InnoDB +innodb_additional_mem_pool_size = 16M +# Nombre maximum de threads systeme concurents +innodb_thread_concurrency = 16 +# Ajuste la valeur des logs InnoDB +# (attention, il faut ensuite stopper MySQL et effacer les fichiers +# ib_logfile*) +#innodb_log_file_size = 128M +#innodb_log_files_in_group = 2 + +###### Misc +# charset utf8 par defaut +character-set-server = utf8 +collation-server = utf8_unicode_ci diff --git a/mysql/files/log2mail.conf b/mysql/files/log2mail.conf new file mode 100644 index 00000000..e030d0f3 --- /dev/null +++ b/mysql/files/log2mail.conf @@ -0,0 +1,24 @@ +file = /var/log/syslog +pattern = "is marked as crashed and should be repaired" +mailto = alert3@evolix.fr +template = /etc/log2mail/mail + +file = /var/log/syslog +pattern = "init function returned error" +mailto = alert3@evolix.fr +template = /etc/log2mail/mail + +file = /var/log/syslog +pattern = "try to repair it" +mailto = alert3@evolix.fr +template = /etc/log2mail/mail + +file = /var/log/syslog +pattern = "InnoDB: Fatal error" +mailto = alert3@evolix.fr +template = /etc/log2mail/mail + +file = /var/log/syslog +pattern = "as a STORAGE ENGINE failed" +mailto = alert3@evolix.fr +template = /etc/log2mail/mail diff --git a/mysql/files/my-add.sh b/mysql/files/my-add.sh new file mode 100644 index 00000000..4e8c2e9c --- /dev/null +++ b/mysql/files/my-add.sh @@ -0,0 +1,43 @@ +!/bin/sh + +echo "Ajout d'un compte/base MySQL" +echo "Entrez le nom de la nouvelle base MySQL" +read base + +echo "Entrez le login qui aura tous les droits sur cette base" +echo "(Vous pouvez entrer un login existant)" +read login + +echo -n "Cet utilisateur est-il deja existant ? [y|N] " +read confirm + +if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then +echo "Attention, si l'utilisateur etait existant, il sera ecrase !" +echo -n "Entrez le mot de passe MySQL (ou vide pour aleatoire) :" +read -s passe2 +echo "" + +length=${#passe2} + +if [ -n $passe ]; then + passe2=$(apg -n1 -E FollyonWek7) + echo "Mot de passe genere : $passe2" +fi + +mysql << END_SCRIPT + CREATE DATABASE \`$base\`; + GRANT ALL PRIVILEGES ON \`$base\`.* TO \`$login\`@localhost IDENTIFIED BY "$passe2"; + FLUSH PRIVILEGES; +END_SCRIPT + +else + +mysql << END_SCRIPT + CREATE DATABASE \`$base\`; + GRANT ALL PRIVILEGES ON \`$base\`.* TO \`$login\`@localhost; + FLUSH PRIVILEGES; +END_SCRIPT + +fi + +echo "Si aucune erreur, creation de la base MySQL $base OK" diff --git a/mysql/files/mysql-optimize b/mysql/files/mysql-optimize new file mode 100644 index 00000000..0c89d74e --- /dev/null +++ b/mysql/files/mysql-optimize @@ -0,0 +1,5 @@ +#!/bin/sh + +# Do some weekly optimizations. +# Reset the cache to avoid fragmentation. +mysql --defaults-extra-file=/etc/mysql/debian.cnf -e "RESET QUERY CACHE;" diff --git a/mysql/handlers/main.yml b/mysql/handlers/main.yml new file mode 100644 index 00000000..35d5b5bf --- /dev/null +++ b/mysql/handlers/main.yml @@ -0,0 +1,15 @@ +--- +- name: restart munin-node + service: + name: munin-node + state: restarted + +- name: restart nagios-nrpe-server + service: + name: nagios-nrpe-server + state: restarted + +- name: restart mysql + service: + name: mysql + state: restarted diff --git a/mysql/tasks/config.yml b/mysql/tasks/config.yml new file mode 100644 index 00000000..1b061b7e --- /dev/null +++ b/mysql/tasks/config.yml @@ -0,0 +1,21 @@ +--- + +- name: Copy Evolinux defaults + copy: + src: evolinux-defaults.cnf + dest: /etc/mysql/conf.d/000-evolinux-defaults.cnf + mode: 0640 + tags: + - mysql + +- name: Custom mysqld config values + ini_file: + dest: /etc/mysql/conf.d/100-evolinux-custom.cnf + section: mysqld + option: '{{ item.option }}' + value: '{{ item.value }}' + with_items: + - { option: thread_cache_size, value: '{{ mysql_thread_cache_size }}' } + - { option: innodb_buffer_pool_size, value: '{{ mysql_innodb_buffer_pool_size }}' } + tags: + - mysql diff --git a/mysql/tasks/datadir.yml b/mysql/tasks/datadir.yml new file mode 100644 index 00000000..d6b30d2f --- /dev/null +++ b/mysql/tasks/datadir.yml @@ -0,0 +1,40 @@ +--- + +- block: + - name: "Is {{ mysql_custom_datadir }} present ?" + stat: + path: "{{ mysql_custom_datadir }}" + register: mysql_custom_datadir_test + + - name: "read the real datadir" + command: readlink -f /var/lib/mysql + changed_when: false + register: mysql_current_real_datadir_test + tags: + - mysql + when: mysql_custom_datadir != '' + +- block: + - name: MySQL is stopped + service: + name: mysql + state: stopped + + - name: Move MySQL datadir to {{ mysql_custom_datadir }} + command: mv {{ mysql_current_real_datadir_test.stdout }} {{ mysql_custom_datadir }} + args: + creates: "{{ mysql_custom_datadir }}" + + - name: Symlink {{ mysql_custom_datadir }} to /var/lib/mysql + file: + src: "{{ mysql_custom_datadir }}" + dest: '/var/lib/mysql' + state: link + + - name: MySQL is started + service: + name: mysql + state: started + tags: + - mysql + when: mysql_custom_datadir != '' and mysql_custom_datadir != mysql_current_real_datadir_test.stdout and not mysql_custom_datadir_test.stat.exists diff --git a/mysql/tasks/log2mail.yml b/mysql/tasks/log2mail.yml new file mode 100644 index 00000000..b0fbd547 --- /dev/null +++ b/mysql/tasks/log2mail.yml @@ -0,0 +1,19 @@ +--- + +- name: Is log2mail present ? + stat: + path: /etc/log2mail/config + register: log2mail_config_dir + tags: + - mysql + - log2mail + +- name: Copy log2mail config + copy: + src: log2mail.conf + dest: /etc/log2mail/config/mysql.conf + mode: 0640 + when: log2mail_config_dir.stat.exists + tags: + - mysql + - log2mail diff --git a/mysql/tasks/main.yml b/mysql/tasks/main.yml new file mode 100644 index 00000000..273960a9 --- /dev/null +++ b/mysql/tasks/main.yml @@ -0,0 +1,19 @@ +--- + +- include: packages.yml + +- include: users.yml + +- include: config.yml + +- include: datadir.yml + +- include: tmpdir.yml + +- include: nrpe.yml + +- include: munin.yml + +- include: log2mail.yml + +- include: utils.yml diff --git a/mysql/tasks/munin.yml b/mysql/tasks/munin.yml new file mode 100644 index 00000000..e9ea5d63 --- /dev/null +++ b/mysql/tasks/munin.yml @@ -0,0 +1,53 @@ +--- + +- name: is Munin present ? + stat: + path: /etc/munin/plugin-conf.d/munin-node + register: munin_node_plugins_config + tags: + - mysql + - munin + +- block: + - name: Install libcache-cache-perl for Munin + apt: + name: libcache-cache-perl + state: present + + - name: Enable core Munin plugins + file: + src: '/usr/share/munin/plugins/{{ item }}' + dest: /etc/munin/plugins/{{ item }} + state: link + with_items: + - mysql_bytes + - mysql_queries + - mysql_slowqueries + - mysql_threads + notify: restart munin-node + + - name: Enable contributed Munin plugins + file: + src: /usr/share/munin/plugins/mysql_ + dest: '/etc/munin/plugins/mysql_{{ item }}' + state: link + with_items: + - connections + - files_tables + - innodb_bpool + - innodb_bpool_act + - innodb_io + - innodb_log + - innodb_rows + - innodb_semaphores + - myisam_indexes + - qcache + - qcache_mem + - sorts + - tmp_tables + notify: restart munin-node + + when: munin_node_plugins_config.stat.exists == true + tags: + - mysql + - munin diff --git a/mysql/tasks/nrpe.yml b/mysql/tasks/nrpe.yml new file mode 100644 index 00000000..c185c00e --- /dev/null +++ b/mysql/tasks/nrpe.yml @@ -0,0 +1,40 @@ +--- + +- name: is NRPE present ? + stat: + path: /etc/nagios/nrpe.d/evolix.cfg + register: nrpe_evolix_config + tags: + - mysql + - nrpe + +- block: + - name: Create a password for NRPE + shell: perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..16)' + register: mysql_nrpe_password + changed_when: false + + - debug: + msg: "repl password: {{ mysql_nrpe_password.stdout }}" + + - name: Create nrpe user + mysql_user: + name: nrpe + password: '{{ mysql_nrpe_password.stdout }}' + config_file: /root/.my.cnf + update_password: on_create + state: present + register: create_nrpe_user + + - name: config check_mysql to use the new password + replace: + dest: /etc/nagios/nrpe.d/evolix.cfg + regexp: '\bMYSQL_PASSWD\b' + replace: '{{ mysql_nrpe_password.stdout }}' + notify: restart nagios-nrpe-server + when: create_nrpe_user.changed + + when: nrpe_evolix_config.stat.exists + tags: + - mysql + - nrpe diff --git a/mysql/tasks/packages.yml b/mysql/tasks/packages.yml new file mode 100644 index 00000000..0ef7cbc1 --- /dev/null +++ b/mysql/tasks/packages.yml @@ -0,0 +1,16 @@ +--- + +- name: Ensure MySQL packages are installed + apt: + name: mysql-server + state: installed + with_items: + - mysql-server + tags: + - mysql + - packages + +- name: MySQL is started + service: + name: mysql + state: started diff --git a/mysql/tasks/tmpdir.yml b/mysql/tasks/tmpdir.yml new file mode 100644 index 00000000..4916d182 --- /dev/null +++ b/mysql/tasks/tmpdir.yml @@ -0,0 +1,23 @@ +--- + +- block: + - name: "Create {{ mysql_custom_tmpdir }}" + file: + path: "{{ mysql_custom_tmpdir }}" + owner: mysql + group: mysql + mode: 0700 + state: directory + tags: + - mysql + + - name: Configure tmpdir + ini_file: + dest: /etc/mysql/conf.d/100-evolinux-custom.cnf + section: mysqld + option: tmpdir + value: "{{ mysql_custom_tmpdir }}" + notify: restart mysql + tags: + - mysql + when: mysql_custom_tmpdir != '' diff --git a/mysql/tasks/users.yml b/mysql/tasks/users.yml new file mode 100644 index 00000000..366c9510 --- /dev/null +++ b/mysql/tasks/users.yml @@ -0,0 +1,50 @@ +--- + +# dependency for mysql_user and mysql_db + +- name: python-mysqldb is installed + apt: + name: python-mysqldb + state: installed + tags: + - mysql + +- name: create a password for mysqladmin + shell: perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..16)' + register: mysql_admin_password + changed_when: false + tags: + - mysql + +- name: there is a mysqladmin user + mysql_user: + name: mysqladmin + password: '{{ mysql_admin_password.stdout }}' + priv: "*.*:ALL,GRANT" + update_password: on_create + state: present + register: create_mysqladmin_user + tags: + - mysql + +- name: mysqladmin is the default user + ini_file: + dest: /root/.my.cnf + mode: 0600 + section: client + option: '{{ item.option }}' + value: '{{ item.value }}' + with_items: + - { option: 'user', value: 'mysqladmin' } + - { option: password, value: '{{ mysql_admin_password.stdout }}' } + when: create_mysqladmin_user.changed + tags: + - mysql + +- name: remove root user + mysql_user: + name: root + config_file: /root/.my.cnf + state: absent + tags: + - mysql diff --git a/mysql/tasks/utils.yml b/mysql/tasks/utils.yml new file mode 100644 index 00000000..a831f71e --- /dev/null +++ b/mysql/tasks/utils.yml @@ -0,0 +1,79 @@ +--- + +# mytop + +- name: Install mytop + apt: + name: mytop + state: installed + tags: + - packages + - mytop + - mysql + +- name: Read debian-sys-maint password + shell: cat /etc/mysql/debian.cnf | grep -m1 "password = .*" | cut -d" " -f3 + register: mysql_debian_password + changed_when: False + +- name: Configure mytop + template: + src: mytop.j2 + dest: /root/.mytop + mode: 0600 + force: yes + tags: + - mytop + - mysql + +# mysqltuner + +- name: Install mysqltuner + copy: + src: mysqltuner.pl + dest: /usr/local/bin/mysqltuner.pl + mode: 700 + tags: + - mysql + - mysqltuner + +- name: Install aha + apt: + name: aha + tags: + - mysql + - mysqltuner + +# automatic optimizations + +- name: Weekly cron to optimize MySQL + copy: + src: mysql-optimize + dest: /etc/cron.monthly/mysql-optimize + mode: 0755 + tags: + - mysql + +# my-add.sh + +- name: Install apg + apt: + name: apg + tags: + - mysql + +- name: Ensure /usr/share/scripts exists + file: + dest: /usr/share/scripts + mode: 0700 + state: directory + tags: + - mysql + +- name: Install my-add.sh + copy: + src: my-add.sh + dest: /usr/local/bin/my-add.sh + mode: 0700 + tags: + - mysql diff --git a/mysql/templates/mytop.j2 b/mysql/templates/mytop.j2 new file mode 100644 index 00000000..507ab99d --- /dev/null +++ b/mysql/templates/mytop.j2 @@ -0,0 +1,3 @@ +user = debian-sys-maint +pass = {{ mysql_debian_password.stdout }} +db = mysql