Update the shared storage design document
[ganeti-local] / doc / design-shared-storage.rst
1 ======================================
2 Ganeti shared storage support for 2.3+
3 ======================================
4
5 This document describes the changes in Ganeti 2.3+ compared to Ganeti
6 2.3 storage model.
7
8 .. contents:: :depth: 4
9
10 Objective
11 =========
12
13 The aim is to introduce support for externally mirrored, shared storage.
14 This includes two distinct disk templates:
15
16 - A shared filesystem containing instance disks as regular files
17   typically residing on a networked or cluster filesystem (e.g. NFS,
18   AFS, Ceph, OCFS2, etc.).
19 - Instance images being shared block devices, typically LUNs residing on
20   a SAN appliance.
21
22 Background
23 ==========
24 DRBD is currently the only shared storage backend supported by Ganeti.
25 DRBD offers the advantages of high availability while running on
26 commodity hardware at the cost of high network I/O for block-level
27 synchronization between hosts. DRBD's master-slave model has greatly
28 influenced Ganeti's design, primarily by introducing the concept of
29 primary and secondary nodes and thus defining an instance's “mobility
30 domain”.
31
32 Although DRBD has many advantages, many sites choose to use networked
33 storage appliances for Virtual Machine hosting, such as SAN and/or NAS,
34 which provide shared storage without the administrative overhead of DRBD
35 nor the limitation of a 1:1 master-slave setup. Furthermore, new
36 distributed filesystems such as Ceph are becoming viable alternatives to
37 expensive storage appliances. Support for both modes of operation, i.e.
38 shared block storage and shared file storage backend would make Ganeti a
39 robust choice for high-availability virtualization clusters.
40
41 Throughout this document, the term “externally mirrored storage” will
42 refer to both modes of shared storage, suggesting that Ganeti does not
43 need to take care about the mirroring process from one host to another.
44
45 Use cases
46 =========
47 We consider the following use cases:
48
49 - A virtualization cluster with FibreChannel shared storage, mapping at
50   least one LUN per instance, accessible by the whole cluster.
51 - A virtualization cluster with instance images stored as files on an
52   NFS server.
53 - A virtualization cluster storing instance images on a Ceph volume.
54
55 Design Overview
56 ===============
57
58 The design addresses the following procedures:
59
60 - Refactoring of all code referring to constants.DTS_NET_MIRROR.
61 - Obsolescence of the primary-secondary concept for externally mirrored
62   storage.
63 - Introduction of a shared file storage disk template for use with networked
64   filesystems.
65 - Introduction of shared block device disk template with device
66   adoption.
67 - Introduction of an External Storage Interface.
68
69 Additionally, mid- to long-term goals include:
70
71 - Support for external “storage pools”.
72
73 Refactoring of all code referring to constants.DTS_NET_MIRROR
74 =============================================================
75
76 Currently, all storage-related decision-making depends on a number of
77 frozensets in lib/constants.py, typically constants.DTS_NET_MIRROR.
78 However, constants.DTS_NET_MIRROR is used to signify two different
79 attributes:
80
81 - A storage device that is shared
82 - A storage device whose mirroring is supervised by Ganeti
83
84 We propose the introduction of two new frozensets to ease
85 decision-making:
86
87 - constants.DTS_EXT_MIRROR, holding externally mirrored disk templates
88 - constants.DTS_MIRRORED, being a union of constants.DTS_EXT_MIRROR and
89   DTS_NET_MIRROR.
90
91 Additionally, DTS_NET_MIRROR will be renamed to DTS_INT_MIRROR to reflect
92 the status of the storage as internally mirrored by Ganeti.
93
94 Thus, checks could be grouped into the following categories:
95
96 - Mobility checks, like whether an instance failover or migration is
97   possible should check against constants.DTS_MIRRORED
98 - Syncing actions should be performed only for templates in
99   constants.DTS_NET_MIRROR
100
101 Obsolescence of the primary-secondary node model
102 ================================================
103
104 The primary-secondary node concept has primarily evolved through the use
105 of DRBD. In a globally shared storage framework without need for
106 external sync (e.g. SAN, NAS, etc.), such a notion does not apply for the
107 following reasons:
108
109 1. Access to the storage does not necessarily imply different roles for
110    the nodes (e.g. primary vs secondary).
111 2. The same storage is available to potentially more than 2 nodes. Thus,
112    an instance backed by a SAN LUN for example may actually migrate to
113    any of the other nodes and not just a pre-designated failover node.
114
115 The proposed solution is using the iallocator framework for run-time
116 decision making during migration and failover, for nodes with disk
117 templates in constants.DTS_EXT_MIRROR. Modifications to gnt-instance and
118 gnt-node will be required to accept target node and/or iallocator
119 specification for these operations. Modifications of the iallocator
120 protocol will be required to address at least the following needs:
121
122 - Allocation tools must be able to distinguish between internal and
123   external storage
124 - Migration/failover decisions must take into account shared storage
125   availability
126
127 Introduction of a shared file disk template
128 ===========================================
129
130 Basic shared file storage support can be implemented by creating a new
131 disk template based on the existing FileStorage class, with only minor
132 modifications in lib/bdev.py. The shared file disk template relies on a
133 shared filesystem (e.g. NFS, AFS, Ceph, OCFS2 over SAN or DRBD) being
134 mounted on all nodes under the same path, where instance images will be
135 saved.
136
137 A new cluster initialization option is added to specify the mountpoint
138 of the shared filesystem.
139
140 The remainder of this document deals with shared block storage.
141
142 Introduction of a shared block device template
143 ==============================================
144
145 Basic shared block device support will be implemented with an additional
146 disk template. This disk template will not feature any kind of storage
147 control (provisioning, removal, resizing, etc.), but will instead rely
148 on the adoption of already-existing block devices (e.g. SAN LUNs, NBD
149 devices, remote iSCSI targets, etc.).
150
151 The shared block device template will make the following assumptions:
152
153 - The adopted block device has a consistent name across all nodes,
154   enforced e.g. via udev rules.
155 - The device will be available with the same path under all nodes in the
156   node group.
157
158 Introduction of an External Storage Interface
159 ==============================================
160 Overview
161 --------
162
163 To extend the shared block storage template and give Ganeti the ability
164 to control and manipulate external storage (provisioning, removal,
165 growing, etc.) we need a more generic approach. The generic method for
166 supporting external shared storage in Ganeti will be to have an
167 ExtStorage provider for each external shared storage hardware type. The
168 ExtStorage provider will be a set of files (executable scripts and text
169 files), contained inside a directory which will be named after the
170 provider. This directory must be present across all nodes of a nodegroup
171 (Ganeti doesn't replicate it), in order for the provider to be usable by
172 Ganeti for this nodegroup (valid). The external shared storage hardware
173 should also be accessible by all nodes of this nodegroup too.
174
175 An “ExtStorage provider” will have to provide the following methods:
176
177 - Create a disk
178 - Remove a disk
179 - Grow a disk
180 - Attach a disk to a given node
181 - Detach a disk from a given node
182 - Verify its supported parameters
183
184 The proposed ExtStorage interface borrows heavily from the OS
185 interface and follows a one-script-per-function approach. An ExtStorage
186 provider is expected to provide the following scripts:
187
188 - `create`
189 - `remove`
190 - `grow`
191 - `attach`
192 - `detach`
193 - `verify`
194
195 All scripts will be called with no arguments and get their input via
196 environment variables. A common set of variables will be exported for
197 all commands, and some of them might have extra ones.
198
199 - `VOL_NAME`: The name of the volume. This is unique for Ganeti and it
200   uses it to refer to a specific volume inside the external storage.
201 - `VOL_SIZE`: The volume's size in mebibytes.
202 - `VOL_NEW_SIZE`: Available only to the `grow` script. It declares the
203   new size of the volume after grow (in mebibytes).
204 - `EXTP_name`: ExtStorage parameter, where `name` is the parameter in
205   upper-case (same as OS interface's `OSP_*` parameters).
206
207 All scripts except `attach` should return 0 on success and non-zero on
208 error, accompanied by an appropriate error message on stderr. The
209 `attach` script should return a string on stdout on success, which is
210 the block device's full path, after it has been successfully attached to
211 the host node. On error it should return non-zero.
212
213 Implementation
214 --------------
215
216 To support the ExtStorage interface, we will introduce a new disk
217 template called `ext`. This template will implement the existing Ganeti
218 disk interface in `lib/bdev.py` (create, remove, attach, assemble,
219 shutdown, grow), and will simultaneously pass control to the external
220 scripts to actually handle the above actions. The `ext` disk template
221 will act as a translation layer between the current Ganeti disk
222 interface and the ExtStorage providers.
223
224 We will also introduce a new IDISK_PARAM called `IDISK_PROVIDER =
225 provider`, which will be used at the command line to select the desired
226 ExtStorage provider. This parameter will be valid only for template
227 `ext` e.g.::
228
229  gnt-instance add -t ext --disk=0:size=2G,provider=sample_provider1
230
231 The Extstorage interface will support different disks to be created by
232 different providers. e.g.::
233
234  gnt-instance add -t ext --disk=0:size=2G,provider=sample_provider1
235                          --disk=1:size=1G,provider=sample_provider2
236                          --disk=2:size=3G,provider=sample_provider1
237
238 Finally, the ExtStorage interface will support passing of parameters to
239 the ExtStorage provider. This will also be done per disk, from the
240 command line::
241
242  gnt-instance add -t ext --disk=0:size=1G,provider=sample_provider1,
243                                   param1=value1,param2=value2
244
245 The above parameters will be exported to the ExtStorage provider's
246 scripts as the enviromental variables:
247
248 - `EXTP_PARAM1 = str(value1)`
249 - `EXTP_PARAM2 = str(value2)`
250
251 We will also introduce a new Ganeti client called `gnt-storage` which
252 will be used to diagnose ExtStorage providers and show information about
253 them, similarly to the way  `gnt-os diagose` and `gnt-os info` handle OS
254 definitions.
255
256 Long-term shared storage goals
257 ==============================
258 Storage pool handling
259 ---------------------
260
261 A new cluster configuration attribute will be introduced, named
262 “storage_pools”, modeled as a dictionary mapping storage pools to
263 external storage providers (see below), e.g.::
264
265  {
266   "nas1": "foostore",
267   "nas2": "foostore",
268   "cloud1": "barcloud",
269  }
270
271 Ganeti will not interpret the contents of this dictionary, although it
272 will provide methods for manipulating them under some basic constraints
273 (pool identifier uniqueness, driver existence). The manipulation of
274 storage pools will be performed by implementing new options to the
275 `gnt-cluster` command::
276
277  gnt-cluster modify --add-pool nas1 foostore
278  gnt-cluster modify --remove-pool nas1 # There may be no instances using
279                                        # the pool to remove it
280
281 Furthermore, the storage pools will be used to indicate the availability
282 of storage pools to different node groups, thus specifying the
283 instances' “mobility domain”.
284
285 The pool, in which to put the new instance's disk, will be defined at
286 the command line during `instance add`. This will become possible by
287 replacing the IDISK_PROVIDER parameter with a new one, called `IDISK_POOL
288 = pool`. The cmdlib logic will then look at the cluster-level mapping
289 dictionary to determine the ExtStorage provider for the given pool.
290
291 gnt-storage
292 -----------
293
294 The `gnt-storage` client can be extended to support pool management
295 (creation/modification/deletion of pools, connection/disconnection of
296 pools to nodegroups, etc.). It can also be extended to diagnose and
297 provide information for internal disk templates too, such as lvm and
298 drbd.
299
300 .. vim: set textwidth=72 :