diff --git a/README.md b/README.md index fe10c1a9a1a5a4e8f22f8e1d5c505cb89f576199..cd93efdbdfaf134335863d8a89adb296d53bc920 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,46 @@ An Ansible role to install and configure [Valkey](https://valkey.io/) on Debian and Ubuntu. +## Multiple Valkey instances + +The advice is to have [one instance per application](https://redis.io/blog/benchmark-shared-vs-dedicated-redis-instances/) rather than having one instance and adding seperate users and databases to it. + +If UNIX sockets are used, rather than TCP/IP ports, then socket groups can be used for access control. + +The Debian advice for multiple instances in `/usr/lib/systemd/system/valkey-server@.service` is: + +``` +# Templated service file for valkey-server(1) +# +# Each instance of valkey-server requires its own configuration file: +# +# $ cp /etc/valkey/valkey.conf /etc/valkey/valkey-myname.conf +# $ chown valkey:valkey /etc/valkey/valkey-myname.conf +# +# Ensure each instance is using their own database: +# +# $ sed -i -e 's@^dbfilename .*@dbfilename dump-myname.rdb@' /etc/valkey/valkey-myname.conf +# +# We then listen exlusively on UNIX sockets to avoid TCP port collisions: +# +# $ sed -i -e 's@^port .*@port 0@' /etc/valkey/valkey-myname.conf +# $ sed -i -e 's@^\(# \)\{0,1\}unixsocket .*@unixsocket /run/valkey-myname/valkey-server.sock@' /etc/valkey/valkey-myname.conf +# +# ... and ensure we are logging, etc. in a unique location: +# +# $ sed -i -e 's@^logfile .*@logfile /var/log/valkey/valkey-server-myname.log@' /etc/valkey/valkey-myname.conf +# $ sed -i -e 's@^pidfile .*@pidfile /run/valkey-myname/valkey-server.pid@' /etc/valkey/valkey-myname.conf +# +# We can then start the service as follows, validating we are using our own +# configuration: +# +# $ systemctl start valkey-server@myname.service +# $ valkey-cli -s /run/valkey-myname/valkey-server.sock info | grep config_file +# +# -- Lucas Kanashiro <kanashiro@debian.org> Wed, 26 Jun 2024 18:17:24 -0300 + +``` + ## Copyright Copyright 2025 Chris Croome, <[chris@webarchitects.co.uk](mailto:chris@webarchitects.co.uk)>. diff --git a/defaults/main.yml b/defaults/main.yml index 92723cb361d7943c9a03ea8c0c1d7748a070701e..b1411da1bfc1a750ed8ba909b446d8cf75f73aaf 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -9,6 +9,33 @@ # You should have received a copy of the GNU General Public License along with the Webarchitects Valkey Ansible role. If not, see <https://www.gnu.org/licenses/>. --- valkey: false +valkey_instances: + - name: server + state: enabled + config: + - name: unixsocket + value: /run/valkey/valkey-server.sock + - name: unixsocketperm + value: "770" + config_file: /etc/valkey/valkey.conf + # - name: nextcloud + # state: enabled + # config: + # - name: dbfilename + # value: dump-nextcloud.rdb + # - name: logfile + # value: /var/log/valkey/valkey-netxcloud.log + # - name: pidfile + # value: /run/valkey/valkey-nextcloud.pid + # - name: port + # value: 0 + # - name: unixsocket + # value: /run/valkey/valkey-nextcloud.sock + # - name: unixsocketgroup + # value: nextcloud + # - name: unixsocketperm + # value: "770" + # config_file: /etc/valkey/valkey-nextcloud.conf valkey_enabled: true valkey_pkgs: - name: bookworm diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..f7e92d5c7ed2058077a8099b05abb391e5973a33 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,37 @@ +# This file is part of the Webarchitects Valkey Ansible role. +# +# The Webarchitects Valkey Ansible role is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# +# The Webarchitects Valkey Ansible role is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with the Webarchitects Valkey Ansible role. If not, see <https://www.gnu.org/licenses/>. +--- +- name: Valkey handlers + block: + + - name: Reload systemd + ansible.builtin.systemd: + daemon_reload: true + listen: Reload systemd + + - name: Valkey restarted + ansible.builtin.systemd: + name: valkey-server + state: restarted + listen: Restart valkey + + - name: Ensure Valkey is running + ansible.builtin.service_facts: + register: valkey_service_facts + until: (valkey_service_facts | community.general.json_query(valkey_jpq.service)).state == "running" + retries: 10 + delay: 2 + listen: Restart valkey + + tags: + - valkey + - valkey_conf + - valkey_config + - valkey_install + - valkey_pkg +... diff --git a/meta/argument_specs.yml b/meta/argument_specs.yml index bb2eda5b76cba24f0e4d737832c3ee4cb09c85e5..7e263afbc03f56b4722682a40bda643f81192d93 100644 --- a/meta/argument_specs.yml +++ b/meta/argument_specs.yml @@ -22,10 +22,48 @@ argument_specs: type: str required: true description: String that will be present in the apt cache policy when backports are enabled. + valkey_config: + type: list + required: false + description: A list of Valkey config names and values. + options: + name: + type: str + required: true + description: A Valkey config variable name. + value: + type: str + required: true + description: A Valkey config variable value. + valkey_config_backup: + type: str + required: true + description: Path for the Valkey config backup. valkey_enabled: type: bool required: true description: Enable and start Valkey. + valkey_jpq: + type: dict + required: true + description: A dictionary of JMESPath query strings. + options: + pkgs_absent: + type: str + required: true + description: JMESPath query string for the packages absent. + pkgs_present: + type: str + required: true + description: JMESPath query string for the packages present. + pkgs_present_backports: + type: str + required: true + description: JMESPath query string for the backports packages present. + service: + type: str + required: true + description: JMESPath query string for the Valkey service. valkey_pkgs: type: list elements: dict @@ -52,6 +90,10 @@ argument_specs: type: list required: true description: A list of deb packages that should be present from backports. + valkey_protected_configs: + type: list + required: false + description: A list of Valkey config to be editing using lineinfile. valkey_verify: type: bool required: true diff --git a/tasks/check.yml b/tasks/check.yml new file mode 100644 index 0000000000000000000000000000000000000000..ced7ce718a7709cddb129b1d3db830e00b0ab274 --- /dev/null +++ b/tasks/check.yml @@ -0,0 +1,30 @@ +# Copyright 2025 Chris Croome +# +# This file is part of the Webarchitects Valkey Ansible role. +# +# The Webarchitects Valkey Ansible role is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# +# The Webarchitects Valkey Ansible role is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with the Webarchitects Valkey Ansible role. If not, see <https://www.gnu.org/licenses/>. +--- +- name: Valkey Checks + block: + + - name: Get server information + community.general.redis_info: + register: valkey_info + + - name: Debug valkey_info + ansible.builtin.debug: + var: valkey_info + verbosity: "{% if ansible_check_mode | bool or ansible_diff_mode | bool %}0{% else %}1{% endif %}" + + - name: Debug valkey_info.info.valkey_version + ansible.builtin.debug: + var: valkey_info.info.valkey_version + + tags: + - valkey + - valkey_check +... diff --git a/tasks/conf.yml b/tasks/conf.yml new file mode 100644 index 0000000000000000000000000000000000000000..09818036cd4a0f877b542574759cf9fcf8f21ee0 --- /dev/null +++ b/tasks/conf.yml @@ -0,0 +1,40 @@ +# The Webarchitects Valkey Ansible role is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# +# The Webarchitects Valkey Ansible role is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with the Webarchitects Valkey Ansible role. If not, see <https://www.gnu.org/licenses/>. +--- +- name: Valkey Conf + block: + + - name: Configure Valkey protected config + ansible.builtin.lineinfile: + path: /etc/valkey/valkey.conf + line: "{{ valkey_cfg.name }} {{ valkey_cfg.value }}" + regex: "{{ valkey_cfg_name_regex }}" + mode: "0640" + owner: valkey + group: valkey + vars: + valkey_cfg_name_regex: "^[#]?[ ]?{{ valkey_cfg.name | ansible.builtin.regex_escape }}[ ]" + when: valkey_cfg.name in valkey_protected_configs + register: valkey_protected_cfg + notify: Restart valkey + + - name: Flush handlers for Valkey protected config change + ansible.builtin.meta: flush_handlers + when: valkey_protected_cfg.changed | bool + + - name: Configure Valkey non-protected config + community.general.redis: + command: config + name: "{{ valkey_cfg.name }}" + value: "{{ valkey_cfg.value }}" + when: valkey_cfg.name not in valkey_protected_configs + register: valkey_non_protected_config + notify: Restart valkey + + tags: + - valkey + - valkey_config +... diff --git a/tasks/config.yml b/tasks/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..2f08431ac6c0def1934167495bea71cbc5bbb83b --- /dev/null +++ b/tasks/config.yml @@ -0,0 +1,68 @@ +# Copyright 2025 Chris Croome +# +# This file is part of the Webarchitects Valkey Ansible role. +# +# The Webarchitects Valkey Ansible role is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +# +# The Webarchitects Valkey Ansible role is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with the Webarchitects Valkey Ansible role. If not, see <https://www.gnu.org/licenses/>. +--- +- name: Valkey Config + block: + + - name: Set a fact for the Valkey config backup path + ansible.builtin.set_fact: + valkey_config_backup: "/etc/valkey/.valkey.conf.{{ ansible_facts.date_time.iso8601_basic_short }}.bak" + + - name: Backup Valkey config + ansible.builtin.copy: + src: /etc/valkey/valkey.conf + dest: "{{ valkey_config_backup }}" + remote_src: true + mode: "0400" + owner: valkey + group: valkey + changed_when: false + + - name: Configure Valkey + ansible.builtin.include_tasks: conf.yml + loop: "{{ valkey_config }}" + loop_control: + loop_var: valkey_cfg + label: "{{ valkey_cfg.name }}" + tags: + - valkey_conf + - valkey_config + + - name: Stat Valkey config + ansible.builtin.stat: + path: /etc/valkey/valkey.conf + checksum_algorithm: sha256 + get_attributes: false + get_checksum: true + get_mime: false + register: valkey_cgf_path + + - name: Stat Valkey config backup + ansible.builtin.stat: + path: "{{ valkey_config_backup }}" + checksum_algorithm: sha256 + get_attributes: false + get_checksum: true + get_mime: false + register: valkey_cgf_bak_path + + - name: Unchanged Valkey config backup absent + ansible.builtin.file: + path: "{{ valkey_config_backup }}" + state: absent + changed_when: false + when: + - valkey_cgf_bak_path.stat.exists | bool + - valkey_cgf_path.stat.checksum == valkey_cgf_bak_path.stat.checksum + + tags: + - valkey + - valkey_config +... diff --git a/tasks/main.yml b/tasks/main.yml index ad548cf419f52752485b0a2f36ffdc03e9d069ee..f0bc8933134fcf8967cd411d30349c5698cf0670 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -32,6 +32,17 @@ - valkey_install - valkey_pkg + - name: Include Valkey checks + ansible.builtin.include_tasks: check.yml + tags: + - valkey_check + + - name: Include Valkey config + ansible.builtin.include_tasks: config.yml + tags: + - valkey_conf + - valkey_config + when: valkey | bool tags: - valkey diff --git a/tasks/pkg.yml b/tasks/pkg.yml index a4603cc904570c5cf30a3c3e5c328275a482d022..791919a6fa1be0dcf4f3c946fd5bf5428dc946a9 100644 --- a/tasks/pkg.yml +++ b/tasks/pkg.yml @@ -11,6 +11,16 @@ - name: Valkey packages present and absent block: + - name: Set vm.overcommit_memory to 1 in /etc/sysctl.conf + ansible.posix.sysctl: + name: vm.overcommit_memory + value: '1' + state: present + sysctl_file: /etc/sysctl.conf + sysctl_set: true + reload: true + notify: Restart valkey + - name: Update apt cache ansible.builtin.apt: update_cache: true @@ -21,7 +31,9 @@ ansible.builtin.apt: pkg: - gnupg + - procps - python3-debian + - python3-redis state: present - name: Update package facts @@ -148,6 +160,7 @@ ( ( valkey_apt_installed is defined ) and ( valkey_apt_installed.changed | bool ) ) or ( ( valkey_apt_removed is defined ) and ( valkey_apt_removed.changed | bool ) ) + # TODO move to handlers - name: Valkey service enabled and started block: @@ -166,6 +179,7 @@ - ( "valkey-server" in valkey_pkgs_installed ) - valkey_enabled | bool + # TODO move to handlers - name: Valkey service disabled and stopped block: @@ -186,5 +200,6 @@ tags: - valkey + - valkey_install - valkey_pkg ... diff --git a/vars/main.yml b/vars/main.yml index 16a99d8320bd4416d6cbc90241beed7e7d5a21fe..fb2e1f1f2e991891ded3cbba1b7393c77027c782 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -12,15 +12,28 @@ valkeyvarnames: "{{ q('varnames', '^valkey_') | sort }}" valkeyhostvars: "{{ dict(valkeyvarnames | list | zip(q('vars', *valkeyvarnames))) }}" -# backports string +# Distro backports string valkey_apt_backports: "{{ ansible_facts.distribution_release }}-backports" +# Valkey config backup path +valkey_config_backup: "/etc/valkey/.valkey.conf.{{ ansible_facts.date_time.iso8601_basic_short }}.bak" + # JMESPath queries valkey_jpq: pkgs_absent: "[?name=='{{ ansible_facts.distribution_release }}'].pkgs_absent|[0]" pkgs_present: "[?name=='{{ ansible_facts.distribution_release }}'].pkgs_present|[0]" pkgs_present_backports: "[?name=='{{ ansible_facts.distribution_release }}'].pkgs_present_backports|[0]" + service: 'ansible_facts.services.["valkey-server.service"]|[0]' -# Check veriables using the arg spec +# Check variables using the arg spec valkey_verify: true + +# Valkey config that can't be changed using community.general.redis +valkey_protected_configs: + - enable-debug-command + - enable-module-command + - enable-protected-configs + - unixsocket + - unixsocketperm +... ...