{"id":23637043,"url":"https://github.com/ansibleguy/infra_mariadb","last_synced_at":"2025-03-21T07:26:54.076Z","repository":{"id":53920673,"uuid":"422924788","full_name":"ansibleguy/infra_mariadb","owner":"ansibleguy","description":"Ansible Role to provision MariaDB instances","archived":false,"fork":false,"pushed_at":"2024-07-21T05:15:44.000Z","size":166,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"latest","last_synced_at":"2024-07-21T18:05:42.528Z","etag":null,"topics":["ansible","ansible-role","automation","database-management","iac","infrastructure-as-code","mariadb","mysql"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ansibleguy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"ko_fi":"ansible0guy","github":"ansibleguy"}},"created_at":"2021-10-30T15:53:15.000Z","updated_at":"2024-07-21T05:15:47.000Z","dependencies_parsed_at":"2023-02-15T17:16:08.580Z","dependency_job_id":"9946bcf9-f8ec-4713-a54e-eab9c513989f","html_url":"https://github.com/ansibleguy/infra_mariadb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansibleguy%2Finfra_mariadb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansibleguy%2Finfra_mariadb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansibleguy%2Finfra_mariadb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansibleguy%2Finfra_mariadb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ansibleguy","download_url":"https://codeload.github.com/ansibleguy/infra_mariadb/tar.gz/refs/heads/latest","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244754973,"owners_count":20504815,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-role","automation","database-management","iac","infrastructure-as-code","mariadb","mysql"],"created_at":"2024-12-28T06:17:29.949Z","updated_at":"2025-03-21T07:26:54.069Z","avatar_url":"https://github.com/ansibleguy.png","language":"Shell","funding_links":["https://ko-fi.com/ansible0guy","https://github.com/sponsors/ansibleguy"],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"https://mariadb.com/wp-content/uploads/2019/11/mariadb-logo-vertical_blue.svg\" alt=\"MariaDB Logo\" width=\"300\"/\u003e\n\n# Ansible Role - MariaDB Database - Multi-Instance\nAnsible Role to deploy one or multiple MariaDB instances on a linux server.\n\n[![Lint](https://github.com/ansibleguy/infra_mariadb/actions/workflows/lint.yml/badge.svg)](https://github.com/ansibleguy/infra_mariadb/actions/workflows/lint.yml)\n[![Ansible Galaxy](https://badges.ansibleguy.net/galaxy.badge.svg)](https://galaxy.ansible.com/ui/standalone/roles/ansibleguy/infra_mariadb)\n\n**Molecule Integration-Tests**:\n\n* Status: [![Molecule Test Status](https://badges.ansibleguy.net/infra_mariadb.molecule.svg)](https://github.com/ansibleguy/_meta_cicd/blob/latest/templates/usr/local/bin/cicd/molecule.sh.j2) |\n[![Functional-Tests](https://github.com/ansibleguy/infra_mariadb/actions/workflows/integration_test_result.yml/badge.svg)](https://github.com/ansibleguy/infra_mariadb/actions/workflows/integration_test_result.yml)\n* Logs: [API](https://ci.ansibleguy.net/api/job/ansible-test-molecule-infra_mariadb/logs?token=2b7bba30-9a37-4b57-be8a-99e23016ce70\u0026lines=1000) | [Short](https://badges.ansibleguy.net/log/molecule_infra_mariadb_test_short.log) | [Full](https://badges.ansibleguy.net/log/molecule_infra_mariadb_test.log)\n\nInternal CI: [Tester Role](https://github.com/ansibleguy/_meta_cicd) | [Jobs API](https://github.com/O-X-L/github-self-hosted-jobs-systemd)\n\n**Tested:**\n* Debian 11\n* Debian 12\n\n----\n\n## Install\n\n```bash\n# latest\nansible-galaxy role install git+https://github.com/ansibleguy/infra_mariadb\n\n# from galaxy\nansible-galaxy install ansibleguy.infra_mariadb\n\n# or to custom role-path\nansible-galaxy install ansibleguy.infra_mariadb --roles-path ./roles\n\n# install dependencies\nansible-galaxy install -r requirements.yml\n```\n\n----\n\n## Advertisement\n\n* Need **professional support** using Ansible or MariaDB? Contact us:\n\n  E-Mail: [contact@oxl.at](mailto:contact@oxl.at)\n\n  Tel: [+43 3115 40 900 0](tel:+433115409000)\n\n  Web: [EN](https://www.o-x-l.com) | [DE](https://www.oxl.at)\n\n  Language: German or English\n\n* You want a simple **Ansible GUI**?\n\n  Check-out this [Ansible WebUI](https://github.com/ansibleguy/webui)\n\n----\n\n## Usage\n\n### Config\n\nYou need to define your instances by configuring the 'mariadb' dictionary!\n\n```yaml\nmariadb:\n  service:\n    SyslogIdentifier: 'mariadb_ag_%I'  # %I = Instance-Key\n    \n  instances:\n    api:\n      root_pwd: !vault |\n        $ANSIBLE_VAULT;1.1;AES256\n        64373031333937633163366236663237623464336461613334343739323763373330393930666331\n        3333663262346337636536383539303834373733326631310a393865653831663238383937626238\n        35396531316338373030353530663465343838373635363633613035356338353366373231343264\n        3437356663383466630a666161363163346533333139656566386466383733646134616166376638\n        35313765356134396130333439663461353336313230366338646165376666313232\n\n      dbs:\n        api:\n          encoding: 'utf8mb4'\n\n        templates:\n        deprecated:\n          state: 'absent'\n      \n      users:\n        app:\n          priv: 'api.*:ALL'\n          pwd: !vault ...\n        guy:\n          priv: 'api.*:SELECT,SHOW VIEW'\n          state: 'absent'\n          pwd: !vault ...\n\n      settings:\n        # port: 3306\n        innodb_log_file_size: 5G\n        max_connections: 2000\n\n      backup:\n        enabled: true\n        dbs: ['api']\n        time: '*-*-* 01:00'\n        # for date-time format see:\n        #   https://wiki.archlinux.org/title/Systemd/Timers\n        #   https://silentlad.com/systemd-timers-oncalendar-(cron)-format-explained\n        creds:\n          create: true\n\n    test:\n      ansible_user: 'not_root'\n      ansible_pwd: !vault ...\n      dbs:\n        test:\n          \n      users:\n        dummy:\n          priv: 'test.*:ALL'\n          pwd: !vault ...\n          update_pwd: 'always'  # else it will only be set on creation; changing the password always might bring problems with active-active replications\n\n      settings:\n        port: 3307\n        log_warnings: 4\n        long_query_time: 2\n        max_allowed_packet: 2G\n\n    old_instance:\n      state: 'absent'\n\n```\n\nYou might want to use 'ansible-vault' to encrypt your passwords:\n```bash\nansible-vault encrypt_string\n```\n\n### Execution\n\nRun the playbook:\n```bash\nansible-playbook -K -D -i inventory/hosts.yml playbook.yml --ask-vault-pass\n```\n\nThere are also some useful **tags** available:\n* base =\u003e only configure basics; instances will not be touched\n* instances\n* config =\u003e configuration (base and instances)\n* dbs\n* backup =\u003e instance backup-jobs\n* users\n\nTo debug errors - you can set the 'debug' variable at runtime:\n```bash\nansible-playbook -K -D -i inventory/hosts.yml playbook.yml -e debug=yes\n```\n\n----\n\n## Functionality\n\n* Package installation\n  * Ansible dependencies (_minimal_)\n  * MariaDB\n\n* Configuration\n  * Multiple MariaDB Instances\n  * Database and User creation/deletion\n  * Startup-Check-Script that supports multiple instances\n\n  * Default opt-in:\n    * Running secure-installation tasks\n    * Swappiness lowered\n    * Open file limit increased (_sysctl, service, db_)\n\n  * Default opt-outs:\n    * DB Backup Job\n\n  * Default config:\n    * Instance datadir: \"/var/lib/mysql/instance_${KEY}/\"\n    * Instance config: \"/etc/mysql/instance.conf.d/server_${KEY}.cnf\"\n    * Service restart on failure\n    * Logging to syslog\n    * Bind only to localhost\n    * SSL OFF\n    * Slow-Query logs\n    * InnoDB file per table\n    * DB DNS-lookups disabled\n    * _for more info check out the example below_\n\n## Info\n\n* **WARNING:** This role expects that the **default mariadb/mysql instance** (_mysql.service/mariadb.service_) on the target system is not and will not be used!\u003cbr\u003e\nIt's **socket and port is changed** by running this role!\n\n\n* **WARNING:** If you are running your db servers in an active-active configuration you should **NEVER** run the role on both nodes at the same time!\u003cbr\u003e\nElse the user-/db-creation tasks might break your sync!\n\n\n* **Note:** this role currently only supports debian-based systems\n\n\n* **Note:** Most of the role's functionality can be opted in or out.\n\n  For all available options - see the default-config located in [the main defaults-file](https://github.com/ansibleguy/infra_mariadb/blob/latest/defaults/main/1_main.yml)!\n\n\n* **Note:** We use the official community modules for [database](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_db_module.html) and [user](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_user_module.html#ansible-collections-community-mysql-mysql-user-module) configuration. [Replication support](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_replication_module.html#ansible-collections-community-mysql-mysql-replication-module) might get added later on.\n\n\n* **Note:** Certificate management might be added later on to this role.\u003cbr\u003e\nFor now, you need to provide the certificates manually (_placed in /etc/mysql/ssl/{INSTANCE_KEY}/[ca|cert|key].pem_)\n\n\n* **Note:** You need to provide the [mysql-user](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_user_module.html#ansible-collections-community-mysql-mysql-user-module) privileges EXACTLY as returned by a SHOW GRANT statement!\n\n\n* **Tip:** If you are mounting the datadir explicitly - you should set some mount options to optimize performance:\n  * noatime,nodiratime\n\n\n* **Warning:** Connections via TCP/IP to localhost/127.0.0.1 will not work by default when 'skip-name-resolve' is enabled!\n\n  It will throw this error: ```Host '127.0.0.1' is not allowed to connect to this MariaDB server```\n\n----\n\n### Example\n\n\n**Config**\n```yaml\nmariadb:\n  instances:\n    guydb:\n      root_pwd: !vault ...\n\n      dbs:\n        nice:\n        memes:\n\n      users:\n        django:\n          priv: 'backup.creds.defaults_file is not nonmemes.*:ALL'\n          pwd: !vault ...\n        backup:\n          priv: '*.*:SELECT,RELOAD,PROCESS,LOCK TABLES,BINLOG MONITOR,SHOW VIEW,EVENT,TRIGGER'\n          pwd: !vault ...\n\n```\n\n**Result:**\n```bash\n# config directories\nguy@ansible:~# tree /etc/mysql\n\u003e /etc/mysql/\n\u003e ├── conf.d\n\u003e │   ├── mysql.cnf\n\u003e │   └── mysqldump.cnf\n\u003e ├── debian.cnf\n\u003e ├── debian-start  # default instance start-script\n\u003e ├── debian-start-instance.sh  # multi-instance start-script\n\u003e ├── instance.conf.d  # instance configurations\n\u003e │   ├── client_guydb_startup-checks.cnf  # login data for startup-check service-user\n\u003e │   └── server_guydb.cnf  # instance server config\n\u003e ├── mariadb.cnf  # default instance config\n\u003e ├── mariadb.conf.d\n\u003e ├── my.cnf -\u003e /etc/alternatives/my.cnf\n\u003e └── my.cnf.fallback\n\n# data directories\nguy@ansible:~# tree /var/lib/mysql\n\u003e /var/lib/mysql/\n\u003e ├── default\n\u003e │  └── ...  # mysql default instance\n\u003e │\n\u003e ├── instance_guydb\n\u003e │  └── ...  # configured instance\n\u003e │\n\u003e └── ...  # default files =\u003e not automatically cleaned\n\n# instance config-file\nguy@ansible:~# cat /etc/mysql/instance.conf.d/server_guydb.cnf \n\u003e # Ansible managed\n\u003e [mysqld]\n\u003e datadir = /var/lib/mysql/instance_guydb\n\u003e basedir = /usr\n\u003e pid-file = /run/mysqld/mysqld_guydb.pid\n\u003e socket = /run/mysqld/mysqld_guydb.sock\n\u003e lc_messages_dir = /usr/share/mysql\n\u003e \n\u003e # settings\n\u003e user = mysql\n\u003e group = mysql\n\u003e bind_address = 127.0.0.1\n\u003e port = 3306\n\u003e log_warnings = 2\n\u003e character-set-server = utf8mb4\n\u003e collation-server = utf8mb4_general_ci\n\u003e innodb_file_per_table = 1\n\u003e innodb_buffer_pool_size = 512M\n\u003e innodb_log_file_size = 1GB\n\u003e max_allowed_packet = 512M\n\u003e max_connections = 500\n\u003e query_cache_size = 64M\n\u003e tmp_table_size = 64M\n\u003e max_heap_table_size = 64M\n\u003e slow-query-log = 1\n\u003e slow-query-log-file = slow-queries.log\n\u003e long_query_time = 1\n\u003e wait_timeout = 60\n\u003e symbolic-links = 0\n\u003e local-infile = 0\n\u003e open_files_limit = 1048576\n\n# service config\nguy@ansible:~# cat /etc/systemd/system/mariadb@.service.d/override.conf \n\u003e # Ansible managed\n\u003e \n\u003e [Unit]\n\u003e ConditionPathExists=/etc/mysql/instance.conf.d/server_%I.cnf\n\u003e ConditionPathExists=/etc/mysql/debian-start-instance.sh\n\u003e ConditionPathExists=/etc/mysql/instance.conf.d/client_%I_startup-checks.cnf\n\u003e Documentation=https://github.com/ansibleguy/infra_mariadb\n\u003e \n\u003e [Service]\n\u003e Environment='MYSQLD_MULTI_INSTANCE=--defaults-file=/etc/mysql/instance.conf.d/server_%I.cnf --defaults-group-suffix=.%I'\n\u003e ExecStartPost=\n\u003e ExecStartPost=/etc/mysql/debian-start-instance.sh %I\n\u003e \n\u003e LimitNOFILE=1048576\n\u003e StandardOutput=journal\n\u003e StandardError=journal\n\u003e SyslogIdentifier=mariadb_%I\n\u003e TimeoutStartSec=900\n\u003e TimeoutStopSec=900\n\u003e Restart=on-abort\n\u003e RestartSec=5s\n\u003e OOMScoreAdjust=-600\n\u003e BlockIOWeight=1000\n\n# service status\nguy@ansible:~# systemctl status mariadb@guydb.service \n\u003e ● mariadb@guydb.service - MariaDB 10.5.12 database server (multi-instance guydb)\n\u003e      Loaded: loaded (/lib/systemd/system/mariadb@.service; enabled; vendor preset: enabled)\n\u003e     Drop-In: /etc/systemd/system/mariadb@.service.d\n\u003e              └─override.conf\n\u003e      Active: active (running)\n\u003e        Docs: man:mariadbd(8)\n\u003e              https://mariadb.com/kb/en/library/systemd/\n\u003e              https://github.com/ansibleguy/infra_mariadb\n\u003e     Process: 134872 ExecStartPre=/usr/bin/mysql_install_db $MYSQLD_MULTI_INSTANCE (code=exited, status=0/SUCCESS)\n\u003e     Process: 134910 ExecStartPost=/etc/mysql/debian-start-instance.sh guydb (code=exited, status=0/SUCCESS)\n\u003e      Status: \"Taking your SQL requests now...\"\n\u003e      CGroup: /system.slice/system-mariadb.slice/mariadb@guydb.service\n\u003e              └─134898 /usr/sbin/mariadbd --defaults-file=/etc/mysql/instance.conf.d/server_guydb.cnf --defaults-group-suffix=.guydb\n\n# databases\nguy@ansible:~# mysql --socket=/run/mysql/mysqld_guydb.sock -p -e \"show databases;\"\n\u003e +--------------------+\n\u003e | Database           |\n\u003e +--------------------+\n\u003e | nice               |\n\u003e | memes              |\n\u003e | information_schema |\n\u003e | mysql              |\n\u003e | performance_schema |\n\u003e +--------------------+\n\n# mysql users\nguy@ansible:~# mysql --socket=/run/mysql/mysqld_guydb.sock -p -e \"select user, host from mysql.user;\"\n\u003e +------------------------+-----------+\n\u003e | User                   | Host      |\n\u003e +------------------------+-----------+\n\u003e | backup                 | localhost |\n\u003e | django                 | localhost |\n\u003e | mariadb.sys            | localhost |\n\u003e | mariadb_startup_checks | localhost |  # needed service-user for startup-script (upgrade tasks and so on)\n\u003e | mysql                  | localhost |\n\u003e | root                   | localhost |\n\u003e +------------------------+-----------+\n\n# mysql privileges\nguy@ansible:~# mysql --socket=/run/mysql/mysqld_guydb.sock -p -e \"show grants for django@localhost;\"\n\u003e +---------------------------------------------------------------------------+\n\u003e | Grants for django@localhost                                               |\n\u003e +---------------------------------------------------------------------------+\n\u003e | GRANT USAGE ON *.* TO `django`@`localhost` IDENTIFIED BY PASSWORD 'XXXX'  |\n\u003e | GRANT ALL PRIVILEGES ON `memes`.* TO `django`@`localhost`                 |\n\u003e +---------------------------------------------------------------------------+\n\nguy@ansible:~# mysql --socket=/run/mysql/mysqld_guydb.sock -p -e \"show grants for backup@localhost;\"\n\u003e +------------------------------------------------------------------------------------------------+\n\u003e | Grants for backup@localhost                                                                    |\n\u003e +------------------------------------------------------------------------------------------------+\n\u003e | GRANT SELECT, RELOAD, PROCESS, LOCK TABLES, BINLOG MONITOR, SHOW VIEW, EVENT, TRIGGER ON *.*   |\n\u003e | TO `backup`@`localhost` IDENTIFIED BY PASSWORD 'XXXX'                                          |\n\u003e +------------------------------------------------------------------------------------------------+\n\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fansibleguy%2Finfra_mariadb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fansibleguy%2Finfra_mariadb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fansibleguy%2Finfra_mariadb/lists"}