diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2019-12-07 08:05:53 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2019-12-07 08:05:53 +0100 |
commit | dded66995529a0419cc56778f4ebb4247c2ab765 (patch) | |
tree | d355e6adda5b833c50c473062fb51f078918878c /modules/private/databases | |
parent | 9f6a78629aad1d22dc8b928860fd05eb40f07352 (diff) | |
download | Nix-dded66995529a0419cc56778f4ebb4247c2ab765.tar.gz Nix-dded66995529a0419cc56778f4ebb4247c2ab765.tar.zst Nix-dded66995529a0419cc56778f4ebb4247c2ab765.zip |
Add replication for redis
Diffstat (limited to 'modules/private/databases')
-rw-r--r-- | modules/private/databases/mariadb_replication.nix | 2 | ||||
-rw-r--r-- | modules/private/databases/postgresql_replication.nix | 2 | ||||
-rw-r--r-- | modules/private/databases/redis.nix | 84 | ||||
-rw-r--r-- | modules/private/databases/redis_replication.nix | 173 | ||||
-rw-r--r-- | modules/private/databases/utils.nix | 10 |
5 files changed, 263 insertions, 8 deletions
diff --git a/modules/private/databases/mariadb_replication.nix b/modules/private/databases/mariadb_replication.nix index 23648bb..5f97e84 100644 --- a/modules/private/databases/mariadb_replication.nix +++ b/modules/private/databases/mariadb_replication.nix | |||
@@ -136,7 +136,7 @@ in | |||
136 | --all-databases > ${backupDir}/$(${pkgs.coreutils}/bin/date -Iseconds).sql | 136 | --all-databases > ${backupDir}/$(${pkgs.coreutils}/bin/date -Iseconds).sql |
137 | ''; | 137 | ''; |
138 | u = pkgs.callPackage ./utils.nix {}; | 138 | u = pkgs.callPackage ./utils.nix {}; |
139 | cleanup_script = pkgs.writeScript "cleanup_mysql_${name}" (u.exponentialDumps backupDir); | 139 | cleanup_script = pkgs.writeScript "cleanup_mysql_${name}" (u.exponentialDumps "sql" backupDir); |
140 | in [ | 140 | in [ |
141 | "0 22,4,10,16 * * * root ${backup_script}" | 141 | "0 22,4,10,16 * * * root ${backup_script}" |
142 | "0 3 * * * root ${cleanup_script}" | 142 | "0 3 * * * root ${cleanup_script}" |
diff --git a/modules/private/databases/postgresql_replication.nix b/modules/private/databases/postgresql_replication.nix index cc32c2b..19ec168 100644 --- a/modules/private/databases/postgresql_replication.nix +++ b/modules/private/databases/postgresql_replication.nix | |||
@@ -116,7 +116,7 @@ in | |||
116 | ${hcfg.package}/bin/pg_dumpall -h ${dataDir} -f ${backupDir}/$(${pkgs.coreutils}/bin/date -Iseconds).sql | 116 | ${hcfg.package}/bin/pg_dumpall -h ${dataDir} -f ${backupDir}/$(${pkgs.coreutils}/bin/date -Iseconds).sql |
117 | ''; | 117 | ''; |
118 | u = pkgs.callPackage ./utils.nix {}; | 118 | u = pkgs.callPackage ./utils.nix {}; |
119 | cleanup_script = pkgs.writeScript "cleanup_postgresql_${name}" (u.keepLastNDumps backupDir 12); | 119 | cleanup_script = pkgs.writeScript "cleanup_postgresql_${name}" (u.keepLastNDumps "sql" backupDir 12); |
120 | in [ | 120 | in [ |
121 | "0 22,4,10,16 * * * postgres ${backup_script}" | 121 | "0 22,4,10,16 * * * postgres ${backup_script}" |
122 | "0 3 * * * postgres ${cleanup_script}" | 122 | "0 3 * * * postgres ${cleanup_script}" |
diff --git a/modules/private/databases/redis.nix b/modules/private/databases/redis.nix index c23ffec..693f402 100644 --- a/modules/private/databases/redis.nix +++ b/modules/private/databases/redis.nix | |||
@@ -1,4 +1,4 @@ | |||
1 | { lib, config, ... }: | 1 | { lib, config, pkgs, myconfig, ... }: |
2 | let | 2 | let |
3 | cfg = config.myServices.databases.redis; | 3 | cfg = config.myServices.databases.redis; |
4 | in { | 4 | in { |
@@ -52,6 +52,88 @@ in { | |||
52 | ''; | 52 | ''; |
53 | }; | 53 | }; |
54 | systemd.services.redis.serviceConfig.RuntimeDirectory = cfg.systemdRuntimeDirectory; | 54 | systemd.services.redis.serviceConfig.RuntimeDirectory = cfg.systemdRuntimeDirectory; |
55 | |||
56 | services.spiped = { | ||
57 | enable = true; | ||
58 | config.redis = { | ||
59 | decrypt = true; | ||
60 | source = "0.0.0.0:16379"; | ||
61 | target = "/run/redis/redis.sock"; | ||
62 | keyfile = "${config.secrets.location}/redis/spiped_keyfile"; | ||
63 | }; | ||
64 | }; | ||
65 | systemd.services.spiped_redis = { | ||
66 | description = "Secure pipe 'redis'"; | ||
67 | after = [ "network.target" ]; | ||
68 | wantedBy = [ "multi-user.target" ]; | ||
69 | |||
70 | serviceConfig = { | ||
71 | Restart = "always"; | ||
72 | User = "spiped"; | ||
73 | PermissionsStartOnly = true; | ||
74 | SupplementaryGroups = "keys"; | ||
75 | }; | ||
76 | |||
77 | script = "exec ${pkgs.spiped}/bin/spiped -F `cat /etc/spiped/redis.spec`"; | ||
78 | }; | ||
79 | |||
80 | services.filesWatcher.predixy = { | ||
81 | restart = true; | ||
82 | paths = [ "${config.secrets.location}/redis/predixy.conf" ]; | ||
83 | }; | ||
84 | |||
85 | networking.firewall.allowedTCPPorts = [ 7617 16379 ]; | ||
86 | secrets.keys = [ | ||
87 | { | ||
88 | dest = "redis/predixy.conf"; | ||
89 | user = "redis"; | ||
90 | group = "redis"; | ||
91 | permissions = "0400"; | ||
92 | text = '' | ||
93 | Name Predixy | ||
94 | Bind 127.0.0.1:7617 | ||
95 | ClientTimeout 300 | ||
96 | WorkerThreads 1 | ||
97 | |||
98 | Authority { | ||
99 | Auth "${myconfig.env.databases.redis.predixy.read}" { | ||
100 | Mode read | ||
101 | } | ||
102 | } | ||
103 | |||
104 | StandaloneServerPool { | ||
105 | Databases 16 | ||
106 | RefreshMethod fixed | ||
107 | Group shard001 { | ||
108 | + ${myconfig.env.databases.redis.socket} | ||
109 | } | ||
110 | } | ||
111 | ''; | ||
112 | } | ||
113 | { | ||
114 | dest = "redis/spiped_keyfile"; | ||
115 | user = "spiped"; | ||
116 | group = "spiped"; | ||
117 | permissions = "0400"; | ||
118 | text = myconfig.env.databases.redis.spiped_key; | ||
119 | } | ||
120 | ]; | ||
121 | |||
122 | systemd.services.predixy = { | ||
123 | description = "Redis proxy"; | ||
124 | wantedBy = [ "multi-user.target" ]; | ||
125 | after = [ "redis.service" ]; | ||
126 | |||
127 | serviceConfig = { | ||
128 | User = "redis"; | ||
129 | Group = "redis"; | ||
130 | SupplementaryGroups = "keys"; | ||
131 | Type = "simple"; | ||
132 | |||
133 | ExecStart = "${pkgs.predixy}/bin/predixy ${config.secrets.location}/redis/predixy.conf"; | ||
134 | }; | ||
135 | |||
136 | }; | ||
55 | }; | 137 | }; |
56 | } | 138 | } |
57 | 139 | ||
diff --git a/modules/private/databases/redis_replication.nix b/modules/private/databases/redis_replication.nix new file mode 100644 index 0000000..cc626f5 --- /dev/null +++ b/modules/private/databases/redis_replication.nix | |||
@@ -0,0 +1,173 @@ | |||
1 | { pkgs, config, myconfig, lib, ... }: | ||
2 | let | ||
3 | cfg = config.myServices.databasesReplication.redis; | ||
4 | in | ||
5 | { | ||
6 | options.myServices.databasesReplication.redis = { | ||
7 | enable = lib.mkEnableOption "Enable redis replication"; | ||
8 | base = lib.mkOption { | ||
9 | type = lib.types.path; | ||
10 | description = '' | ||
11 | Base path to put the replications | ||
12 | ''; | ||
13 | }; | ||
14 | hosts = lib.mkOption { | ||
15 | default = {}; | ||
16 | description = '' | ||
17 | Hosts to backup | ||
18 | ''; | ||
19 | type = lib.types.attrsOf (lib.types.submodule { | ||
20 | options = { | ||
21 | package = lib.mkOption { | ||
22 | type = lib.types.package; | ||
23 | default = pkgs.redis; | ||
24 | description = '' | ||
25 | Redis package for this host | ||
26 | ''; | ||
27 | }; | ||
28 | host = lib.mkOption { | ||
29 | type = lib.types.str; | ||
30 | description = '' | ||
31 | Host to connect to | ||
32 | ''; | ||
33 | }; | ||
34 | port = lib.mkOption { | ||
35 | type = lib.types.str; | ||
36 | description = '' | ||
37 | Port to connect to | ||
38 | ''; | ||
39 | }; | ||
40 | password = lib.mkOption { | ||
41 | type = lib.types.nullOr lib.types.str; | ||
42 | default = null; | ||
43 | description = '' | ||
44 | Password to use | ||
45 | ''; | ||
46 | }; | ||
47 | }; | ||
48 | }); | ||
49 | }; | ||
50 | }; | ||
51 | |||
52 | config = lib.mkIf cfg.enable { | ||
53 | users.users.redis = { | ||
54 | description = "Redis database user"; | ||
55 | group = "redis"; | ||
56 | uid = config.ids.uids.redis; | ||
57 | extraGroups = [ "keys" ]; | ||
58 | }; | ||
59 | users.groups.redis.gid = config.ids.gids.redis; | ||
60 | |||
61 | services.spiped = { # sync from eldiron | ||
62 | enable = true; | ||
63 | config.redis = { | ||
64 | encrypt = true; | ||
65 | source = "127.0.0.1:16379"; | ||
66 | target = "${myconfig.env.servers.eldiron.ips.main.ip4}:16379"; | ||
67 | keyfile = "${config.secrets.location}/redis/spiped_eldiron_keyfile"; | ||
68 | }; | ||
69 | }; | ||
70 | |||
71 | secrets.keys = lib.flatten (lib.mapAttrsToList (name: hcfg: [ | ||
72 | { | ||
73 | dest = "redis_replication/${name}/config"; | ||
74 | user = "redis"; | ||
75 | group = "redis"; | ||
76 | permissions = "0400"; | ||
77 | text = '' | ||
78 | pidfile ${cfg.base}/${name}/redis/redis.pid | ||
79 | port 0 | ||
80 | unixsocket /run/redis_${name}/redis.sock | ||
81 | loglevel notice | ||
82 | logfile /dev/null | ||
83 | syslog-enabled yes | ||
84 | databases 16 | ||
85 | save 900 1 | ||
86 | save 300 10 | ||
87 | save 60 10000 | ||
88 | dbfilename dump.rdb | ||
89 | dir ${cfg.base}/${name}/redis/ | ||
90 | slaveof ${hcfg.host} ${hcfg.port} | ||
91 | ${if hcfg.password != null then "masterauth ${hcfg.password}" else ""} | ||
92 | appendOnly no | ||
93 | appendfsync everysec | ||
94 | slowlog-log-slower-than 10000 | ||
95 | slowlog-max-len 128 | ||
96 | unixsocketperm 777 | ||
97 | maxclients 1024 | ||
98 | ''; | ||
99 | } | ||
100 | ]) cfg.hosts) ++ [ | ||
101 | { # For eldiron only | ||
102 | dest = "redis/spiped_eldiron_keyfile"; | ||
103 | user = "spiped"; | ||
104 | group = "spiped"; | ||
105 | permissions = "0400"; | ||
106 | text = myconfig.env.databases.redis.spiped_key; | ||
107 | } | ||
108 | ]; | ||
109 | |||
110 | services.cron = { | ||
111 | enable = true; | ||
112 | systemCronJobs = lib.flatten (lib.mapAttrsToList (name: hcfg: | ||
113 | let | ||
114 | dataDir = "${cfg.base}/${name}/redis"; | ||
115 | backupDir = "${cfg.base}/${name}/redis_backup"; | ||
116 | backup_script = pkgs.writeScript "backup_redis_${name}" '' | ||
117 | #!${pkgs.stdenv.shell} | ||
118 | |||
119 | ${pkgs.coreutils}/bin/cp ${cfg.base}/${name}/redis/dump.rdb \ | ||
120 | ${backupDir}/$(${pkgs.coreutils}/bin/date -Iseconds).rdb | ||
121 | ''; | ||
122 | u = pkgs.callPackage ./utils.nix {}; | ||
123 | cleanup_script = pkgs.writeScript "cleanup_redis_${name}" (u.exponentialDumps "rdb" backupDir); | ||
124 | in [ | ||
125 | "0 22,4,10,16 * * * root ${backup_script}" | ||
126 | "0 3 * * * root ${cleanup_script}" | ||
127 | ]) cfg.hosts); | ||
128 | }; | ||
129 | |||
130 | system.activationScripts = lib.attrsets.mapAttrs' (name: hcfg: | ||
131 | lib.attrsets.nameValuePair "redis_replication_${name}" { | ||
132 | deps = [ "users" "groups" ]; | ||
133 | text = '' | ||
134 | install -m 0700 -o redis -g redis -d ${cfg.base}/${name}/redis | ||
135 | install -m 0700 -o redis -g redis -d ${cfg.base}/${name}/redis_backup | ||
136 | ''; | ||
137 | }) cfg.hosts; | ||
138 | |||
139 | systemd.services = { | ||
140 | spiped_redis = { # For eldiron | ||
141 | description = "Secure pipe 'redis'"; | ||
142 | after = [ "network.target" ]; | ||
143 | wantedBy = [ "multi-user.target" ]; | ||
144 | |||
145 | serviceConfig = { | ||
146 | Restart = "always"; | ||
147 | User = "spiped"; | ||
148 | PermissionsStartOnly = true; | ||
149 | SupplementaryGroups = "keys"; | ||
150 | }; | ||
151 | |||
152 | script = "exec ${pkgs.spiped}/bin/spiped -F `cat /etc/spiped/redis.spec`"; | ||
153 | }; | ||
154 | } // lib.attrsets.mapAttrs' (name: hcfg: | ||
155 | let | ||
156 | dataDir = "${cfg.base}/${name}/redis"; | ||
157 | in | ||
158 | lib.attrsets.nameValuePair "redis_backup_${name}" { | ||
159 | description = "Redis replication for ${name}"; | ||
160 | wantedBy = [ "multi-user.target" ]; | ||
161 | after = [ "network.target" ]; | ||
162 | unitConfig.RequiresMountsFor = dataDir; | ||
163 | |||
164 | serviceConfig = { | ||
165 | ExecStart = "${hcfg.package}/bin/redis-server ${config.secrets.location}/redis_replication/${name}/config"; | ||
166 | User = "redis"; | ||
167 | RuntimeDirectory = "redis_${name}"; | ||
168 | }; | ||
169 | }) cfg.hosts; | ||
170 | }; | ||
171 | } | ||
172 | |||
173 | |||
diff --git a/modules/private/databases/utils.nix b/modules/private/databases/utils.nix index c296f49..06ce2cc 100644 --- a/modules/private/databases/utils.nix +++ b/modules/private/databases/utils.nix | |||
@@ -1,15 +1,15 @@ | |||
1 | { pkgs }: | 1 | { pkgs }: |
2 | { | 2 | { |
3 | keepLastNDumps = backupDir: n: '' | 3 | keepLastNDumps = ext: backupDir: n: '' |
4 | #!${pkgs.stdenv.shell} | 4 | #!${pkgs.stdenv.shell} |
5 | 5 | ||
6 | cd ${backupDir} | 6 | cd ${backupDir} |
7 | ${pkgs.coreutils}/bin/rm -f \ | 7 | ${pkgs.coreutils}/bin/rm -f \ |
8 | $(${pkgs.coreutils}/bin/ls -1 *.sql \ | 8 | $(${pkgs.coreutils}/bin/ls -1 *.${ext} \ |
9 | | ${pkgs.coreutils}/bin/sort -r \ | 9 | | ${pkgs.coreutils}/bin/sort -r \ |
10 | | ${pkgs.gnused}/bin/sed -e '1,${builtins.toString n}d') | 10 | | ${pkgs.gnused}/bin/sed -e '1,${builtins.toString n}d') |
11 | ''; | 11 | ''; |
12 | exponentialDumps = backupDir: let | 12 | exponentialDumps = ext: backupDir: let |
13 | log2rotateSrc = builtins.fetchGit { | 13 | log2rotateSrc = builtins.fetchGit { |
14 | url = "https://github.com/avian2/pylog2rotate"; | 14 | url = "https://github.com/avian2/pylog2rotate"; |
15 | ref = "master"; | 15 | ref = "master"; |
@@ -24,7 +24,7 @@ | |||
24 | #!${pkgs.stdenv.shell} | 24 | #!${pkgs.stdenv.shell} |
25 | 25 | ||
26 | cd ${backupDir} | 26 | cd ${backupDir} |
27 | ${pkgs.coreutils}/bin/rm -f $(ls -1 *.sql | grep -v 'T22:' | sort -r | sed -e '1,12d') | 27 | ${pkgs.coreutils}/bin/rm -f $(ls -1 *.${ext} | grep -v 'T22:' | sort -r | sed -e '1,12d') |
28 | ${pkgs.coreutils}/bin/rm -f $(ls -1 *T22*.sql | ${log2rotate} --skip 7 --fuzz 7 --delete --format='%Y-%m-%dT%H:%M:%S+00:00.sql') | 28 | ${pkgs.coreutils}/bin/rm -f $(ls -1 *T22*.${ext} | ${log2rotate} --skip 7 --fuzz 7 --delete --format='%Y-%m-%dT%H:%M:%S+00:00.${ext}') |
29 | ''; | 29 | ''; |
30 | } | 30 | } |