PROJECT_MOVED -> https://lab.nexedi.com/nexedi/slapos
[slapos.git] / stack / resilient / README.txt
1
2 Base resilient stack
3 ====================
4
5 This stack is meant to be extended by SR profiles, or other stacks, that need to provide
6 automated backup/restore, election of backup candidates, and instance failover.
7
8 As reference implementations, both stack/lamp and stack/lapp define resilient behavior for
9 MySQL and Postgres respectively.
10
11 This involves three different software_types:
12
13  * pull-backup
14  * {mysoftware}_export
15  * {mysoftware}_import
16
17 where 'mysoftware' is the component that needs resiliency (can be postgres, mysql, erp5, and so on).
18
19
20 pull-backup
21 -----------
22
23 This software type is defined in
24
25     http://git.erp5.org/gitweb/slapos.git/blob/HEAD:/stack/resilient/instance-pull-backup.cfg.in?js=1
26
27 and there should be no reason to modify or extend it.
28
29 An instance of type 'pull-backup' will receive data from an 'export' instance and immediately populate an 'import' instance.
30 The backup data is automatically used to build an historical, incremental archive in srv/backup/pbs.
31
32
33 export
34 ------
35
36 example:
37     http://git.erp5.org/gitweb/slapos.git/blob/HEAD:/stack/lapp/postgres/instance-postgres-export.cfg.in?js=1
38
39 This is the *active* instance - the one providing live data to the application.
40
41 A backup is run via the bin/exporter script: it will
42      1) run bin/{mysoftware}-backup
43  and 2) notify the pull-backup instance that data is ready.
44
45 The pull-backup, upon receiving the notification, will make a copy of the data and transmit it to the 'import' instances.
46
47 You should provide the bin/{mysoftware}-exporter script, see for instance
48   http://git.erp5.org/gitweb/slapos.git/blob/HEAD:/slapos/recipe/postgres/__init__.py?js=1#l207
49   http://git.erp5.org/gitweb/slapos.git/blob/HEAD:/slapos/recipe/mydumper.py?js=1#l71
50
51 By default, as defined in
52   http://git.erp5.org/gitweb/slapos.git/blob/HEAD:/stack/resilient/pbsready-export.cfg.in?js=1#l27
53 the bin/exporter script is run every 60 minutes.
54
55
56
57 import
58 ------
59
60 example:
61     http://git.erp5.org/gitweb/slapos.git/blob/HEAD:/stack/lapp/postgres/instance-postgres-import.cfg.in?js=1
62
63 This is the *fallback* instance - the one that can be activated and thus become active.
64 Any number of import instances can be used. Deciding which one should take over can be done manually
65 or through a monitoring + election script.
66
67
68 You should provide the bin/{mysoftware}-importer script, see for instance
69
70   http://git.erp5.org/gitweb/slapos.git/blob/HEAD:/slapos/recipe/postgres/__init__.py?js=1#l233
71   http://git.erp5.org/gitweb/slapos.git/blob/HEAD:/slapos/recipe/mydumper.py?js=1#l71
72
73
74
75
76 In practice
77 -----------
78
79 Add resilience to your software
80
81 Let's say you already have a file instance-mysoftware.cfg.in that instantiates your
82 software. In which there is a part [mysoftware] where there is the main recipe
83 that instantiates the program.
84
85 You need to create two new files, instance-mysoftware-import.cfg.in and
86 instance-mysoftware-export.cfg.in, following this layout:
87
88
89 IMPORT:
90
91 [buildout]
92 extends = ${instance-mysoftware:output}
93           ${pbsready-import:output}
94
95 parts +=
96     mysoftware
97     import-on-notification
98
99 [importer]
100 recipe = YourImportRecipe
101 wrapper = $${rootdirectory:bin}/$${slap-parameter:namebase}-importer
102 backup-directory = $${directory:backup}
103 ...
104
105
106
107 EXPORT:
108
109 [buildout]
110 extends = ${instance-mysoftware:output}
111           ${pbsready-export:output}
112
113 parts +=
114     mysoftware
115     cron-entry-backup
116
117 [exporter]
118 recipe = YourExportRecipe
119 wrapper = $${rootdirectory:bin}/$${slap-parameter:namebase}-exporter
120 backup-directory = $${directory:backup}
121 ...
122
123
124 In the [exporter] / [importer] part, you are free to do whatever you want, but
125 you need to dump / import your data from $${directory:backup} and specify a
126 wrapper. I suggest you only add options and specify your export/import recipe.
127
128
129
130
131 Checking that it works
132 ----------------------
133
134 To check that your software instance is resilient you can proceed this way:
135 Once all instances are successfully deployed, go to your export instance, connect as the instance user and run:
136 $ ~/bin/exporter
137 It is the script responsible for triggering the resiliency stack on your instance. After doing a backup of your data, it will notify the pull-backup instances of a new backup, triggering the transfer of this data to the import instances.
138
139 Once this script is run successfully, go to your import instance, connect as its instance user and check ~/srv/backup/"your sofwtare"/, the location of the data you wanted to receive. The last part of the resiliency is up to your import script.
140
141 DEBUGGING:
142 Here is a partial list of things you can check to understand what is causing the problem:
143
144 - Check that your import script does not fail and successfully places your data in ~/srv/backup/"your software" (as the import instance user) by runnig:
145 $ ~/bin/"your software"-exporter
146 - Check the export instance script is run successfully as this instance user by running:
147 $ ~/bin/exporter
148 - Check the pull-instance system did its job by going to one of your pull-backup instance, connect as its user and check the log : ~/var/log/equeue.log
149
150
151 -----------------------------------------------------------------------------------------
152
153 Finally, instance-mysoftware-import.cfg.in and
154 instance-mysoftware-export.cfg.in need to be downloaded and accessible by
155 switch_softwaretype, and you need to extend stack/resilient/buildout.cfg and
156 stack/resilient/switchsoftware.cfg to download the whole resiliency bundle.
157
158 Here is how it's done in the mariadb case for the lamp stack:
159
160
161
162  ** buildout.cfg **
163
164 extends =
165    ../resilient/buildout.cfg
166
167 [instance-mariadb-import]
168 recipe = slapos.recipe.template
169 url = ${:_profile_base_location_}/mariadb/instance-mariadb-import.cfg.in
170 output = ${buildout:directory}/instance-mariadb-import.cfg
171 md5sum = ...
172 mode = 0644
173
174 [instance-mariadb-export]
175 recipe = slapos.recipe.template
176 url = ${:_profile_base_location_}/mariadb/instance-mariadb-export.cfg.in
177 output = ${buildout:directory}/instance-mariadb-export.cfg
178 md5sum = ...
179 mode = 0644
180
181
182
183  ** instance.cfg.in **
184
185 extends =
186   ../resilient/switchsoftware.cfg
187
188 [switch-softwaretype]
189 ...
190 mariadb = ${instance-mariadb:output}
191 mariadb-import = ${instance-mariadb-import:output}
192 mariadb-export = ${instance-mariadb-export:output}
193 ...
194
195
196
197 Then, in the .cfg file where you want to instantiate your software, you can do, instead of requesting your software
198
199  * template-resilient.cfg.in *
200
201 [buildout]
202 ...
203 parts +=
204   {{ parts.replicate("Name","3") }}
205   ...
206
207 [...]
208 ...
209 [ArgLeader]
210 ...
211
212 [ArgBackup]
213 ...
214
215 {{ replicated.replicate("Name", "3",
216                         "mysoftware-export", "mysoftware-import",
217                         "ArgLeader","ArgBackup", slapparameter_dict=slapparameter_dict) }}
218
219 and it'll expend into the sections require to request Name0, Name1 and Name2,
220 backuped and resilient. The leader will expend the section [ArgLeader], backups
221 will expend [ArgBackup]. slapparameter_dict is the dict containing the parameters given to the instance. If you don't need to specify any options, you can
222 omit the last three arguments in replicate().
223
224 Since you will compile your template with jinja2, there should be no $${},
225 because it is not yet possible to use jinja2 -> buildout template.
226
227 To compile with jinja2, see jinja2's recipe.
228
229
230 Deploying your resilient software
231 ---------------------------------
232 You can provide sla parameters to each request you make (a lot: for export, import and pbs).
233
234 example:
235 Here is a small example of parameters you can provide to control the deployment (case of a runner):
236 <?xml version='1.0' encoding='utf-8'?>
237 <instance>
238   <parameter id="-sla-1-computer_guid">COMP-GRP1</parameter>
239   <parameter id="-sla-pbs1-computer_guid">COMP-PBS1</parameter>
240   <parameter id="-sla-2-computer_guid">COMP-GROUP2</parameter>
241   <parameter id="-sla-runner2-computer_guid">COMP-RUN2</parameter>
242   <parameter id="-sla-2-network_guid">NET-2</parameter>
243   <parameter id="-sla-runner0-computer_guid">COMP-RUN0</parameter>
244 </instance>
245 Consequence on sla parameters by request:
246   * runner0: computer_guid = COMP-RUN0 (provided directly)
247   * runner1: computer_guid = COMP-GRP1 (provided by group 1)
248   * runner2: computer_guid = COMP-RUN2 (provided by group 2 but overided directly)
249              network_guid  = NET-2 (provided by group 2)
250   * PBS 1:   computer_guid = COMP-PBS1 (provided by group 1 but overided directly)
251   * PBS 2:   computer_guid = COMP-GRP2 (provided by group 2)
252              network_guid  = NET-2 (provided by group 2)
253
254
255 Parameters are analysed this way:
256  * If it starts with "-sla-" it is not transmitted to requested instance and is used to do the request as sla.
257  * -sla-foo-bar=example (foo being a magic key) will be use for each request considering "foo" as a key to use and the sla parameter is "bar". So for each group using the "foo" key, sla parameter "bar" is used with value "example"
258 About magic keys:
259 We can find 2 kinds of magic keys:
260  * id : example, in "-sla-2-foo" 2 is the magic key and the parameter will be used for each request with id 2 (in case of kvm: kvm2 and PBS 2)
261  * nameid : example, in "-sla-kvm2-foo", foo will be used for kvm2 request. Name for pbs is "pbs" -> "-sla-pbs2-foo".
262 IMPORTANT NOTE: in case the same foo parameter is asked for the group, the nameid key prevail