vagrant-compose 0.2.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f830b936e191533e4b7af81b6a8a28aff5895b65
4
- data.tar.gz: 340bfc23e34b5538bf2efd653042e851594bb2f1
3
+ metadata.gz: b301a6a6168fb5d273e7cc98304c808f07609304
4
+ data.tar.gz: cf8fe8a74f47f7e7f85dbe3cfe8854545fe88ac2
5
5
  SHA512:
6
- metadata.gz: d898460561c00f26860490b0ef1f1f60bc0244cef3b049bc3faffcbc69b705d82b2a291c21c1955ace7850ca505a44e92bb5d6160490921cbc348f77d18d524d
7
- data.tar.gz: 6f28b559521b5ee1a340b2dc4e09c7d6cc03aef6c6760c0332437f437c837d700fe1400f522c3c51a444eb5e0e5eb19c7cfbcd54b80e6b197d2430499ae06eae
6
+ metadata.gz: df46b624b131f9fc8e81c217b9d894ba1b6aaf3111de9e88438c6a00d3ec698efec71cdc82fcb6c477631547001ba09c56d336444ce2b87118d2358b2c295340
7
+ data.tar.gz: 14403ed71cafd28eda089b2bfea7c918fb5c7f919aa9e6ae04ee37d5c1ab08c706edd7f2460132f35dafbe6dc1022c88f768c2a666faa8bd2956fe56be0f2250
data/.gitignore CHANGED
@@ -16,4 +16,5 @@ Gemfile.lock
16
16
  Vagrantfile
17
17
 
18
18
  # Test
19
- provisioning
19
+ provisioning
20
+ declarative.yaml
data/CHANGELOG.md CHANGED
@@ -31,3 +31,7 @@ other changes:
31
31
 
32
32
  NB. breaking change
33
33
  ansible_group_vars_path and ansible_host_vars_path are not supported anymore
34
+
35
+ # 0.7.0 (November 02, 2016)
36
+
37
+ * introduced support for declarative cluster definition
data/README.md CHANGED
@@ -1,438 +1,45 @@
1
1
  # vagrant-compose
2
2
 
3
- A Vagrant plugin that helps building complex multi-machine scenarios.
3
+ A Vagrant plugin that helps building complex scenarios with many VMs.
4
4
 
5
- Complex multi-machine scenarios includes several set of nodes, each one with different characteristic, software stacks and configuration.
5
+ Each VM is a node in the cluster.
6
+ Typically, in a cluster nodes are grouped by type, and each group of nodes has different characteristic, software stacks and configuration.
6
7
 
7
8
  For instance, if you are setting up an environment for testing [Consul](https://consul.io/), your cluster will be composed by:
8
9
 
9
10
  - consul server nodes
10
11
  - consul agent nodes
11
- - nodes simulating other datacenter
12
- - ...
13
12
 
14
- On top of that, a Consul cluster can be composed in several different ways, implementing high availability or not, merging roles/functions on the same server or keeping role/function separated etc. etc.
15
-
16
- Vagrant-compose streamline the definition of complex multi-machine scenarios, providing also support for a straight forward provisioning of nodes with Ansible.
17
-
18
- > So far, the plugin is designed for working with Ansible provisioning, but it can be easily used/extended for supporting other provisioning systems supported by Vagrant.
13
+ Vagrant-compose streamline the definition of complex multi-VMs scenarios, providing also support for a straight forward provisioning of nodes with Ansible.
19
14
 
20
15
  ## Installation
21
16
 
22
17
  Install the plugin following the typical Vagrant procedure:
23
18
 
24
- ```
25
- $ vagrant plugin install vagrant-compose
26
- ```
27
-
28
- ## Quick start
29
-
30
- Create the following `Vagrantfile` for implementing a multi-machine scenario that defines a cluster named `test` with 3 `consul-server` nodes.
31
-
32
- ``` ruby
33
- Vagrant.configure(2) do |config|
34
- #cluster definition
35
- config.cluster.compose('test') do |c|
36
- c.nodes(3, 'consul-server')
37
- end
38
-
39
- #cluster creation
40
- config.cluster.nodes.each do |node, index|
41
- config.vm.define "#{node.boxname}" do |node_vm|
42
- node_vm.vm.box = "#{node.box}"
43
- end
44
- end
45
- end
46
- ```
47
-
48
- The first part of the `Vagrantfile` contains the definition of the `test` cluster:
49
-
50
- ``` ruby
51
- config.cluster.compose('test') do |c|
52
- ...
53
- end
54
- ```
55
-
56
- Please note that the cluster definition, is followed by a block of code that allows to configure the cluster itself; in this example the configuration consists in defining a set of 3 `consul-server` nodes.
57
-
58
- ``` ruby
59
- c.nodes(3, 'consul-server')
60
- ```
61
-
62
- When the definition of the cluster is completed, behind the scene vagrant-compose take care of composing the cluster, and the resulting list of nodes will be available in the `config.cluster.nodes` variable.
63
-
64
- The second part of the `Vagrantfile` creates the cluster by defining a vm in VirtualBox for each node in the cluster:
65
-
66
- ``` ruby
67
- config.cluster.nodes.each do |node, index|
68
- config.vm.define "#{node.boxname}" do |node_vm|
69
- node_vm.vm.box = "#{node.box}"
70
- end
71
- end
72
- ```
73
-
74
- If you run `vagrant up` you will get a 3 node cluster with following machines, based on `ubuntu/trusty64` base box (default).
75
-
76
- - `test-consul-server1`
77
- - `test-consul-server2`
78
- - `test-consul-server3`
79
-
80
- Done !
81
-
82
- Of course, real-word scenarios are more complex; it is necessary to get more control in configuring the cluster topology and machine attributes, and finally you need also to implement automatic provisioning of software stack installed in the machines.
83
-
84
- See following chapters for more details.
85
-
86
- ## Configuring the cluster
87
-
88
- Each cluster can be named passing a value to `cluster.compose` method, and the default behaviour is that name of vagrant boxes and hostnames will be prefixed by such name; if cluster name will be set to nil or "", vagrant boxes and hostnames will be composed without prefix.
89
-
90
- Apart for cluster name, there are several options to customize the cluster definition.
91
-
92
- ### Defining cluster attributes
93
-
94
- Cluster attributes apply to all the node in the cluster.
95
-
96
- You can set set cluster attributes in the block of code that is passed as a second parameter to the `cluster.compose` method, as show in the following example:
97
-
98
- ``` ruby
99
- config.cluster.compose('test') do |c|
100
- c.box = "centos/7"
101
- ...
102
- end
103
- ```
104
-
105
- Following cluster attributes are available:
106
-
107
- - **box**, [String], default = 'ubuntu/trusty64'
108
-
109
- Sets the base box for nodes, a.k.a the image that will be used to spin up the machine; please note that the base box can be customized also for each set of nodes (see Defining set of nodes).
110
-
111
-
112
- - **domain**, [String], default = 'vagrant'
113
-
114
- Sets the domain used for computing the nodes in the cluster; if the `domain` value is set to `nil` or `““` (empty string), the fully qualified name and the hostname of each nodes will be the same.
115
-
116
- ### Defining set of nodes
117
-
118
- A cluster can be composed by one or more set of nodes.
119
-
120
- Each set of nodes represent a group of one or more nodes with similar characteristics. For instance, in a cluster defined for testing [Consul](https://consul.io/), you will get at least two set of nodes:
121
-
122
- - Consul server nodes
123
- - Consul agent nodes
124
-
125
- Set of nodes can be defined in the block of code that is passed as a second parameter to the `cluster.compose` method, by using the `nodes` method as show in the following example:
126
-
127
- ``` ruby
128
- config.cluster.compose('test') do |c|
129
- ...
130
- c.nodes(3, 'consul-agents')
131
- ...
132
- end
133
- ```
134
-
135
- The first parameter of the `nodes` method is the number of nodes in the set, while the second parameter is the name of the set; `nodes` accepts an optional third parameter, allowing to define a block of code where it is possible to customize several attributes of the set of nodes itself:
136
-
137
- ``` ruby
138
- config.cluster.compose('test') do |c|
139
- ...
140
- c.nodes(3, 'zookeeper') do |n|
141
- n.box = "centos/7"
142
- end
143
- ...
144
- end
145
- ```
146
-
147
- Please note that all the available attributes can be set to:
148
-
149
- - A literal value, like for instance `"centos/7". This value will be inherited - without changes - by all nodes in the set.
150
-
151
- - A block of code, afterwards value_generator, that will be executed when building the nodes in the set. When calling the block of code, three parameters will be given:
152
-
153
- - **group_index**, [integer (zero based)], uniquely assigned to each set of nodes
154
- - **group_name**, [String], with the name of the set of nodes
155
- - **node_index**, [integer (zero based)], uniquely assigned to each node in the set
156
-
157
- An example of value_generator is the following lambda expression, that computes the host-name for each node in the cluster (`test-consul-server1`, `test-consul-server2`, etc. etc.):
158
-
159
- ``` ruby
160
- lambda { |group_index, group_name, node_index|
161
- return "#{group_name}#{node_index + 1}"
162
- }
163
- ```
164
-
165
- Following set of nodes attributes are available:
166
-
167
- - **box**, [String|String_Generator], default = `cluster.box`
168
-
169
- Sets the base box used for creating nodes in this set.
170
-
171
- - **boxname**, [String|String_Generator], default = `"#{group_name}#{node_index + 1}"`
172
-
173
- Sets the box name (a.k.a. the name of the machine in VirtualBox/VMware) for each node in this set.
174
- Note: when generating nodes, if cluster name not equals to nil or empty string the resulting boxname will be automatically prefixed by `"#{cluster_name}-"` if cluster name not equals to nil or empty string.
175
-
176
- - **hostname**, [String|String_Generator], default = `"#{group_name}#{node_index + 1}"`
177
-
178
- Sets the hostname for each node in this set.
179
-
180
- Note: when generating nodes, if cluster name not equals to nil or empty string the resulting hostname will be automatically prefixed by `"#{cluster_name}-"`; additionally the **fqdn** attribute will be computed by concatenating `".#{cluster.domain}"`, if defined (if `domain` is not defined, fqdn will be the same of hostname).
181
-
182
- - **aliases**, [Array(String)|Array(String)_Generator], default = `[]`
183
-
184
- Allows to provide aliases for each node in this set.
185
-
186
- Note: when generating nodes, aliases will be automatically concatenated into a string, comma separated.
187
-
188
- - **ip**, [String|String_Generator], default = `"172.31.#{group_index}.#{100 + node_index + 1}"`
189
-
190
- Sets the ip for for each node in this set.
191
-
192
- - **cpus**, [Integer|Integer_Generator], default = `1`
193
-
194
- Sets the number of cpus for each node in this set.
195
-
196
- - **memory**, [Integer|Integer_Generator], default = `256` (MB)
197
-
198
- Sets the memory allocated for each node in this set.
199
-
200
- - **attributes**, [Hash(String, obj)|Hash(String, obj)_Generator], default = `{}`
201
-
202
- Allows to provide custom additional attributes for each node in this set.
203
-
204
- > Please note that some attribute, like boxname, hostname, ip, *must* be different for each node in the set (and in the cluster).
205
- >
206
- > Use value_generators for those attributes.
207
-
208
- ### Composing nodes
209
-
210
- By executing the code blocks provided to `cluster.compose` method, and also inner code blocks provided to `nodes` calls, the vagrant-compose plugin can compose the cluster topology, as a sum of all the nodes generated by each set.
211
-
212
- The resulting list of nodes is stored in the `config.cluster.nodes` variable; each node has following attributes assigned using value/value generators:
213
-
214
- - **box**
215
- - **boxname**
216
- - **hostname**
217
- - **fqdn**
218
- - **aliases**
219
- - **ip**
220
- - **cpus**
221
- - **memory**
222
- - **attributes**
223
-
224
- Two additional attributes will be automatically set for each node:
225
-
226
- - **index**, [integer (zero based)], uniquely assigned to each node in the cluster
227
- - **group_index**, [integer (zero based)], uniquely assigned to each node in a set of nodes
228
-
229
- ## Checking cluster configuration
230
-
231
- It is possible to check the resulting list of nodes by using the `compose.debug` command:
232
-
233
- ``` ruby
234
- Vagrant.configure(2) do |config|
235
- #cluster definition
236
- config.cluster.compose('test') do |c|
237
- ...
238
- end
239
-
240
- config.cluster.debug
241
- end
242
- ```
243
-
244
- Main information about nodes will be printed into the sequence of vagrant messages.
245
-
246
- ## Creating nodes
247
-
248
- Given the list of nodes stored in the `config.cluster.nodes` variable, it is possible to create a multi-machine environment by iterating over the list:
249
-
250
- ``` ruby
251
- config.cluster.nodes.each do |node|
252
- ...
253
- end
254
- ```
255
-
256
- Within the cycle you can instruct vagrant to create machines based on attributes of the current node; for instance, you can define a VM in VirtualBox (default Vagrant provider); the example uses the [vagrant-hostmanager](https://github.com/smdahlen/vagrant-hostmanager) plugin to set the hostname into the guest machine:
257
-
258
- ``` ruby
259
- config.cluster.nodes.each do |node|
260
- config.vm.define "#{node.boxname}" do |node_vm|
261
- node_vm.vm.box = "#{node.box}"
262
- node_vm.vm.network :private_network, ip: "#{node.ip}"
263
- node_vm.vm.hostname = "#{node.fqdn}"
264
- node_vm.hostmanager.aliases = node.aliases unless node.aliases.empty?
265
- node_vm.vm.provision :hostmanager
266
-
267
- node_vm.vm.provider "virtualbox" do |vb|
268
- vb.name = "#{node.boxname}"
269
- vb.memory = node.memory
270
- vb.cpus = node.cpus
271
- end
272
- end
273
- end
274
- ```
275
-
276
- > In order to increase performance of node creation, you can leverage on support for linked clones introduced by Vagrant 1.8.1. Add the following line to the above script:
277
- >
278
- > vb.linked_clone = true if Vagrant::VERSION =~ /^1.8/
279
-
280
- Hostmanager requires following additional settings before the `config.cluster.nodes.each` command:
281
-
282
- ``` ruby
283
- config.hostmanager.enabled = false
284
- config.hostmanager.manage_host = true
285
- config.hostmanager.include_offline = true
286
- ```
287
-
288
- ## Configuring ansible provisioning
289
-
290
- The vagrant-compose plugin provides support for a straight forward provisioning of nodes in the cluster implemented with Ansible.
291
-
292
- ### Defining ansible_groups
293
-
294
- Each set of nodes, and therefore all the nodes within the set, can be assigned to one or more ansible_groups.
295
-
296
- In the following example, `consul-agent` nodes will be part of `consul` and `docker` ansible_groups.
297
-
298
- ``` ruby
299
- c.nodes(3, 'consul-agent') do |n|
300
- ...
301
- n.ansible_groups = ['consul', 'docker']
302
- end
303
- ```
304
-
305
- This configuration is used by the `cluster.compose` method in order to define an **inventory file** where nodes (hosts in ansible "") clustered in group; the resulting list of ansible_groups, each with its own list of host is stored in the `config.cluster.ansible_groups` variable.
306
-
307
- Ansible playbook will use groups for providing different software stack to different machines.
308
-
309
- Please note that the possibility to assign a node to one or more groups introduces an high degree of flexibility; for instance, it is easy to change the topology of the cluster above for instance when it is required to implement an http load balancer based on consul service discovery:
310
-
311
- ``` ruby
312
- c.nodes(3, 'consul-agent') do |n|
313
- ...
314
- n.ansible_groups = ['consul', 'docker', 'registrator']
315
- end
316
- c.nodes(1, 'load-balancer') do |n|
317
- ...
318
- n.ansible_groups = ['consul', 'docker', 'consul-template', 'nginx']
319
- end
320
19
  ```
321
-
322
- As you can see, `consul` and `docker` ansible_groups now include both nodes from `consul-agent` and `load-balancer` node set; vice versa, other groups like `registrator`, `consul-template`, `nginx` contain node only from one of the two nodes set.
323
-
324
- Ansible playbook can leverage on groups for providing machines with the required software stacks.
325
-
326
- ### Defining group vars
327
-
328
- In Ansible, the inventory file is usually integrated with a set of variables containing settings that will influence playbooks behaviour for all the host in a group.
329
-
330
- The vagrant-compose plugin allows you to define one or more group_vars generator for each ansible_groups; group_vars generators are code block that will be instantiated during `cluster.compose` with two input parameters:
331
-
332
- - **context_vars** see below
333
- - **nodes**, list of nodes in the ansible_group
334
-
335
- Expected output type is `Hash(String, Obj)`.
336
-
337
- For instance, when building a [Consul](https://consul.io/) cluster, all the `consul-server` nodes have to be configured with the same `bootstrap_expect` parameter, that must be set to the number of `consul-server` nodes in the cluster:
338
-
339
- ``` ruby
340
- config.cluster.compose('test') do |c|
341
- ...
342
- c.ansible_group_vars['consul-server'] = lambda { |context, nodes|
343
- return { 'consul_bootstrap_expect' => nodes.length }
344
- }
345
- ...
346
- end
20
+ $ vagrant plugin install vagrant-compose
347
21
  ```
348
22
 
349
- Ansible group vars will be stored into yaml files saved into `{cluster.ansible_playbook_path}\group_vars` folder.
350
-
351
- The variable `cluster.ansible_playbook_path` defaults to the current directory (the directory of the Vagrantfile) + `/provisioning`; this value can be changed like any other cluster attributes (see Defining cluster attributes).
352
-
353
- ### Defining host vars
354
-
355
- While group vars will influence playbooks behaviour for all hosts in a group, in Ansible host vars will influence playbooks behaviour for a specific host.
23
+ The declarative approach (see below) additionally requires the vagrant-playbook python package, that can be installed with
356
24
 
357
- The vagrant-compose plugin allows to define one or more host_vars generator for each ansible_groups; host_vars generators are code block that will be instantiated during `cluster.compose` with two input parameters:
358
-
359
- - **context_vars** see below
360
- - **node**, one node in the ansible_group
361
-
362
- Expected output type is `Hash(String, Obj)`.
363
-
364
- For instance, when building a [Consul](https://consul.io/) cluster, all the `consul-server` nodes should be configured with the ip to which Consul will bind client interfaces:
365
-
366
- ``` ruby
367
- config.cluster.compose('test') do |c|
368
- ...
369
- c.ansible_host_vars['consul-server'] = lambda { |context, node|
370
- return { 'consul_client_ip' => node.ip }
371
- }
372
- ...
373
- end
374
25
  ```
375
-
376
- Ansible host vars will be stored into yaml files saved into `{cluster.ansible_playbook_path}\host_vars` folder.
377
-
378
- ### Context vars
379
-
380
- Group vars and host var generation by design can operate only with the set of information that comes with a groups of nodes or a single node.
381
-
382
- However, sometimes, it is necessary to share some information across group of nodes.
383
- This can be achieved by setting one or more context_vars generator for each ansible_groups.
384
-
385
- For instance, when building a [Consul](https://consul.io/) cluster, all the `consul-agent` nodes should be configured with the ip - the list of ip - to be used when joining the cluster; such list can be generated from the list of nodes in the `consul-server` set of nodes, and stored in a context_vars:
386
-
387
- ``` ruby
388
- config.cluster.compose('test') do |c|
389
- ...
390
- c.ansible_context_vars['consul-server'] = lambda { |context, nodes|
391
- return { 'consul-serverIPs' => nodes.map { |n| n.ip }.to_a }
392
- }
393
- ...
394
- end
26
+ $ pip install vagrant-playbook
395
27
  ```
396
28
 
397
- > Context_vars generator are always executed before group_vars and host_vars generators; the resulting context, is given in input to group_vars and host_vars generators.
29
+ # Composing a cluster
30
+ Vagrant-compose supports two appraches for definining a cluster of VMs.
398
31
 
399
- Then, you can use the above context var when generating group_vars for nodes in the `consul-agent` group.
32
+ - Programmatic Approach
400
33
 
401
- ``` ruby
402
- config.cluster.compose('test') do |c|
403
- ...
404
- c.ansible_context_vars['consul-server'] = lambda { |context, nodes|
405
- return { 'serverIPs' => nodes.map { |n| n.ip }.to_a }
406
- }
407
- c.ansible_group_vars['consul-agent'] = lambda { |context, nodes|
408
- return { 'consul_joins' => context['consul-serverIPs'] }
409
- }
410
- ...
411
- end
412
- ```
34
+ Cluster are defined by using the some ruby knowledge that is required for writing Vagrantfiles.
413
35
 
414
- ## Creating nodes (with provisioning)
36
+ see [Programmatic Approach](http://pippo) for more details.
415
37
 
416
- Given `config.cluster.ansible_groups` variable, generated group_vars and host_vars files, and of course an ansible playbook, it is possible to integrate provisioning into the node creation sequence.
38
+ - Declarative Approach
417
39
 
418
- NB. The example uses ansible parallel execution (all nodes are provisioned together in parallel after completing node creation).
40
+ By using the declarative approach also people with limited programming background can use vagrant-compose to easily define a cluster composed by many VMs; with declarative approach, the definition of the cluster is done in yaml, and the ruby programming part within the Vagrantfile is reduced to the minimum.
419
41
 
420
- ``` ruby
421
- config.cluster.nodes.each do |node|
422
- config.vm.define "#{node.boxname}" do |node_vm|
423
- ...
424
- if node.index == config.cluster.nodes.size - 1
425
- node_vm.vm.provision "ansible" do |ansible|
426
- ansible.limit = 'all' # enable parallel provisioning
427
- ansible.playbook = "provisioning/playbook.yml"
428
- ansible.groups = config.cluster.ansible_groups
429
- end
430
- end
431
- end
432
- end
433
-
434
-
435
- ```
42
+ see [Declarative Approach](http://pippo) for more details.
436
43
 
437
44
  # Additional notes
438
45
  Vagrant compose will play nicely with all vagrant commands.