summaryrefslogtreecommitdiff
path: root/src/talks/tripleo-ansible.hbs
diff options
context:
space:
mode:
Diffstat (limited to 'src/talks/tripleo-ansible.hbs')
-rw-r--r--src/talks/tripleo-ansible.hbs715
1 files changed, 715 insertions, 0 deletions
diff --git a/src/talks/tripleo-ansible.hbs b/src/talks/tripleo-ansible.hbs
new file mode 100644
index 0000000..3325055
--- /dev/null
+++ b/src/talks/tripleo-ansible.hbs
@@ -0,0 +1,715 @@
1<!doctype html>
2<html lang="en">
3
4 <head>
5 <meta charset="utf-8">
6
7 <title>TripleO and Ansible</title>
8
9 </head>
10 <body>
11
12 <section id="who-am-i" class="slide level2">
13 <h1>Who am I?</h1>
14 <ul>
15 <li>Distinguished Technologist at HP</li>
16 <li>OpenStack Technical Committee</li>
17 <li>OpenStack Foundation Board of Directors</li>
18 <li>OpenStack Infra Core Team</li>
19 </ul>
20 </section>
21
22 <section id="what-are-we-going-to-talk-about" class="slide level2">
23 <h1>What are we going to talk about?</h1>
24 <ul>
25 <li>TripleO</li>
26 <li>Ironic</li>
27 <li>Ansible</li>
28 </ul>
29 </section>
30
31 <section>
32 <h1>What is TripleO?</h1>
33 <ul>
34 <li class="fragment"> an idea </li>
35 <li class="fragment"> OpenStack On OpenStack </li>
36 <li class="fragment"> use Ironic-based OpenStack to Operate Openstack </li>
37 </ul>
38 </section>
39
40
41 <section>
42 <h1>Velocity</h1>
43 <ul>
44 <li>Cloud Empowers <em>developers</em></li>
45 <li>Cloud Enables Increased Velocity</li>
46 <li>Cloud Drives Agility</li>
47 </ul>
48 </section>
49
50 <section>
51 <a href="#/2" class="image"><img src="/images/openstack-software-diagram.png" width="90%"></a>
52 <aside class="notes">
53 Perhaps you've seen this before. <br>
54 Even with addition of lots of PaaS projects, the abstraction here still holds.
55 </aside>
56 </section>
57
58 <section>
59 <h1>OpenStack is not a virtualization layer,
60 it's an abstraction layer.</h1>
61 <aside class="notes">
62 When Danny Sabah @ IBM said this, it hit home for me. I had already been working on Ironic for a year.<br>
63 KVM, NFV ... <br>
64 Virtualization is a powerful tool. Abstraction empowers people.<br>
65 OpenStack community is thriving because of the power of open abstractions layers.
66 </aside>
67 </section>
68
69 <section>
70 <section>
71 <h1>What if your <em>developers</em> aren't writing Angry Birds?</h1>
72 </section>
73
74 <section>
75 <h1>What if your <em>developers</em> aren't developers?</h1>
76 </section>
77
78 <section>
79 <h3>If infrastructure is code ...</h3>
80 <h1>What if your <em>developers</em> are <em>operators</em>?</h1>
81 </section>
82
83 <section>
84 <img src="/images/ugly-openstack.jpg" />
85 </section>
86
87 <section>
88 <h1>Why wouldn't you give your operators the same power as your
89 developers?</h1>
90 <p>Don't you like them?</p>
91 </section>
92
93 </section>
94
95 <section>
96 <h1><i>Ironic</i> is a service capable of<br>
97 managing and provisioning<br>
98 <i>physical machines</i>.</h1>
99 <aside class="notes">
100 Do one thing and do it well. Ready-state-GO!<br>
101 Vendor neutral API. Distributed control plane.<br>
102 Deploy images to reduce entropy. Servers are cattle, not pets.<br>
103 Can use stand-alone, but not simple today.
104 </aside>
105 </section>
106
107 <section>
108 <h1>Nova + Ironic</h1>
109 Same but different
110 <aside class="notes">
111 User gets same Nova API. Abstraction is maintained.<br>
112 What are the benefits using Nova? (sched, flavors, etc)<br>
113 Talk briefly about evolution from nova-baremetal.
114 </aside>
115 </section>
116
117 <section>
118 <a href="#/2" class="image"><img src="/images/ironic-nova-layer.jpg"></a>
119 <aside class="notes">
120 Talk through the slide<br>
121 Going to show some examples next
122 </aside>
123 </section>
124 <section>
125 <pre><code>
126$ ironic node-create -d pxe_ipmitool \
127 -i ipmi_username=admin -i ipmi_password=fake -i ipmi_address=10.1.2.3 \
128 -p cpus=4 -p memory_mb=8192 -p local_gb=500 \
129 -e note='spare server'
130+--------------+------------------------------------------------------------+
131| Property | Value |
132+--------------+------------------------------------------------------------+
133| chassis_uuid | None |
134| driver | pxe_ipmitool |
135| driver_info | {u'ipmi_address': u'10.1.2.3', u'ipmi_username': u'admin', |
136| | u'ipmi_password': u'fake'} |
137| extra | {u'note': u'spare server'} |
138| properties | {u'memory_mb': u'8192', u'local_gb': u'500', u'cpus': u'4'}|
139| uuid | 7a1ce8d0-9679-4d87-8f54-b11f6e8adb8f |
140+--------------+------------------------------------------------------------+
141 </code></pre>
142 </section>
143 <section>
144 <pre><code>
145$ tail -f /var/log/nova/n-cpu.log
146...
1472014-05-01 03:47:05.878 AUDIT nova.compute.resource_tracker [-]
148 Free ram (MB): 8192
1492014-05-01 03:47:05.878 AUDIT nova.compute.resource_tracker [-]
150 Free disk (GB): 500
1512014-05-01 03:47:05.878 AUDIT nova.compute.resource_tracker [-]
152 Free VCPUS: 4
153 </code></pre>
154 </section>
155
156 <section>
157 <h1>Diversity is good</h1>
158 <ul>
159 <li>Cloud providers: HP, Rackspace, Dreamhost, Cloudwatt</li>
160 <li>Deployments: Public, Managed, Private</li>
161 <li>Compute drivers: virtual, bare metal, container</li>
162 <li>Ironic drivers: pxe/impi, ilo, HP OneView</li>
163 </ul>
164 </section>
165
166 <section>
167 <h1>What can you do?</h1>
168 <h3 class="fragment">anything - it's a cloud</h3>
169 </section>
170
171 <section>
172 <h1>What the heck has the TripleO team been doing then?</h1>
173 <img src="/images/worstcat-lettuce.jpg" />
174 </section>
175
176 <section>
177 <h1>TripleO</h1>
178 <ul>
179 <li>Community developed</li>
180 <li>Opinionated</li>
181 <li>Avoid distro and config management religion</li>
182 <li>Be a usable <em>real</em> deployment we can gate on</li>
183 </ul>
184 </section>
185
186 <section>
187 <h1> Community Developed </h1>
188 <ul>
189 <li>Exist as part of the OpenStack project</li>
190 <li>Prove the story end to end</li>
191 <li>Subject to TC governance</li>
192 <li>Tighter feedback loop</li>
193 </ul>
194 </section>
195
196 <section>
197 <h1> Avoid distro and config management religion </h1>
198 <ul>
199 <li>rpm vs. deb - in the gate == rpm + deb</li>
200 <li>puppet vs. chef vs. salt vs. ansible == all of them</li>
201 <li>Choosing one excludes other folks from participating</li>
202 </ul>
203 </section>
204
205 <section>
206 <h1> Opinionated </h1>
207 <ul>
208 <li>Golden Images</li>
209 <li>Upgrade tied to HA</li>
210 <li>Target Continual Delivery</li>
211 <li>Drive fixes into OpenStack directly</li>
212 </ul>
213 </section>
214
215 <section>
216 <h1>Major Components</h1>
217 <ul>
218 <li>nova+ironic</li>
219 <li>heat</li>
220 <li>diskimage-builder</li>
221 <li>os-collect-config</li>
222 <li>os-apply-config</li>
223 <li>os-refresh-config</li>
224 </ul>
225 </section>
226
227 <section>
228 <h1>Lesson from os-*-config</h1>
229 <img class="fragment" src="/images/worstcat-dog.jpg" />
230 </section>
231
232 <section>
233 <h1>Lesson from os-*-config</h1>
234 <img class="fragment" src="/images/standards.png" />
235 </section>
236
237 <section>
238 <h1>Lesson from os-*-config</h1>
239 <p>If you ever think "oh, that's silly, it would be so much easier
240 if I just ..."<br /> it will almost never actually be easier if you
241 just ...</p>
242 </section>
243
244 <section>
245 <h1>The Deployment Story</h1>
246 <ol>
247 <li>disk-image-builder builds images and uploads to glance</li>
248 <li>Heat drives Nova/Ironic</li>
249 <li>Heat delivers metadata to os-collect-config</li>
250 <li>os-collect-config applies any in-instance changes needed</li>
251 </ol>
252 </section>
253
254 <section>
255 <h1>The Update Story</h1>
256 <p>Heat magically just updates things</li>
257 </section>
258
259 <section>
260 <h1>BUT I ALREADY USE ?????</h1>
261 <h3>(screw you guys, I'm going home)</h3>
262 </section>
263
264 <section>
265 <h1>Yeah, I do to</h1>
266 <h3>(I use puppet and ansible myself)</h3>
267 </section>
268
269 <section>
270 <h1>That's fine - use them - it's a cloud!</h1>
271 <h3 class="fragment">This is supposed to be empowering, not enforcing</h3>
272 </section>
273
274 <section>
275 <h1>Whatever you want!</h1>
276 <ul>
277 <li>Heat to deploy and update images, os-*-*config for config</li>
278 <li>Heat to deploy images, ansible to update images, puppet for config</li>
279 <li>Ansible to deploy base image + packages, salt to update packages, chef for config</li>
280 <li>juju to deploy ... nah, I'm just kidding</li>
281 </ul>
282 </section>
283
284 <section>
285 <h1>The New Update Story</h1>
286 <p>Ansible takes over for upgrades</p>
287 </section>
288
289 <section id="step-two-ansible-for-orchestration" class="titleslide slide level1">
290 <h1>Ansible for Orchestration</h1>
291 </section>
292
293 <section id="about-ansible" class="slide level2">
294 <h1>About Ansible</h1>
295 <ul>
296 <li>Open Source System Management tool</li>
297 <li>Written in Python</li>
298 <li>Sequence of steps to perform</li>
299 <li>Works over SSH</li>
300 <li>Incremental Adoption</li>
301 </ul>
302 </section>
303
304 <section>
305 <h1>ad-hoc operation</h1>
306 <pre>
307ansible '*' -m shell -p uptime
308 </pre>
309 </section>
310
311 <section id="yaml-syntax" class="slide level2">
312 <h1>YAML Syntax</h1>
313 <pre><code>
314- hosts: '*.slave.openstack.org'
315 tasks:
316 - shell: 'rm -rf ~jenkins/workspace/*{{ project }}*'
317 </code></pre>
318 <p>That's executed:</p>
319 <pre>
320ansible-playbook -f 10 /etc/ansible/clean_workspaces.yaml --extra-vars "project=$PROJECTNAME"
321 </pre>
322 </section>
323
324 <section id="ansible-organization" class="slide level2">
325 <h1>Ansible Organization</h1>
326 <ul>
327 <li>modules</li>
328 <li>plays</li>
329 <li>playbooks</li>
330 <li>roles</li>
331 </ul>
332 </section>
333
334 <section id="use-ansible-to-run-puppet" class="slide level2">
335 <h1>Use Ansible to Run Puppet!</h1>
336 </section>
337
338 <section id="puppet-module" class="slide level2">
339 <h1>puppet module</h1>
340 <pre><code>def main():
341 module = AnsibleModule(argument_spec=dict(
342 timeout=dict(default="30m"),
343 puppetmaster=dict(required=True),
344 show_diff=dict(default=False, aliases=['show-diff'], type='bool'),
345 ))
346 p = module.params
347
348 puppet_cmd = module.get_bin_path("puppet", False)
349 if not puppet_cmd:
350 module.fail_json(msg="Could not find puppet. Please ensure it is installed.")
351 </code></pre>
352 </section>
353
354 <section id="puppet-module-2" class="slide level2">
355 <h1>puppet module (cont)</h1>
356 <pre><code class="python">
357 cmd = ("timeout -s 9 %(timeout)s %(puppet_cmd)s agent --onetime"
358 " --server %(puppetmaster)s"
359 " --ignorecache --no-daemonize --no-usecacheonfailure --no-splay"
360 " --detailed-exitcodes --verbose") % dict(
361 timeout=pipes.quote(p['timeout']), puppet_cmd=PUPPET_CMD,
362 puppetmaster=pipes.quote(p['puppetmaster']))
363 if p['show_diff']:
364 cmd += " --show-diff"
365 rc, stdout, stderr = module.run_command(cmd)
366 </code></pre>
367 </section>
368
369 <section id="puppet-module-3" class="slide level2">
370 Please. Everyone. Marvel at the following logic
371 <pre><code>
372 if rc == 0: # success
373 module.exit_json(rc=rc, changed=False, stdout=stdout)
374 elif rc == 1:
375 # rc==1 could be because it's disabled OR there was a compilation failure
376 disabled = "administratively disabled" in stdout
377 if disabled:
378 msg = "puppet is disabled"
379 else:
380 msg = "puppet compilation failed"
381 module.fail_json(rc=rc, disabled=disabled, msg=msg, stdout=stdout, stderr=stderr)
382 elif rc == 2: # success with changes
383 module.exit_json(changed=True)
384 elif rc == 124: # timeout
385 module.exit_json(rc=rc, msg="%s timed out" % cmd, stdout=stdout, stderr=stderr)
386 else: # failure
387 module.fail_json(rc=rc, msg="%s failed" % (cmd), stdout=stdout, stderr=stderr)
388 </code></pre>
389 </section>
390
391 <section id="puppet-play" class="slide level2">
392 <h1>puppet play</h1>
393 <pre><code>
394- name: run puppet
395 puppet:
396 puppetmaster: "{{puppetmaster}}"
397 </code></pre>
398 </section>
399
400 <section id="puppet-role" class="slide level2">
401 <h1>puppet role</h1>
402 <p>roles/remote_puppet/tasks/main.yml</p>
403 </section>
404
405 <section id="remote-puppet-playbook" class="slide level2">
406 <h1>remote puppet playbook</h1>
407 <pre><code>
408- hosts: git0*
409 gather_facts: false
410 max_fail_percentage: 1
411 roles:
412 - { role: remote_puppet, puppetmaster: puppetmaster.openstack.org }
413- hosts: review.openstack.org
414 gather_facts: false
415 roles:
416 - { role: remote_puppet, puppetmaster: puppetmaster.openstack.org }
417- hosts: "!review.openstack.org:!git0*:!afs*"
418 gather_facts: false
419 roles:
420 - { role: remote_puppet, puppetmaster: puppetmaster.openstack.org }
421 </pre></code>
422 </section>
423
424 <section id="ansible-inventory" class="slide level2">
425 <h1>ansible inventory</h1>
426 <ul>
427 <li>List of servers to operate on</li>
428 <li>Optionally variables associated with each server</li>
429 <li>Optional groups of servers</li>
430 <li>Simple file in /etc/ansible/hosts</li>
431 <li>Dynamic executable that returns JSON</li>
432 </ul>
433 </section>
434
435 <section id="ansible-inventory-from-file" class="slide level2">
436 <h1>Simple inventory</h1>
437 <pre>
438review.openstack.org
439git01.openstack.org
440git02.openstack.org
441pypi.dfw.openstack.org
442pypi.iad.openstack.org
443
444[pypi]
445pypi.dfw.openstack.org
446pypi.iad.openstack.org
447
448[git]
449git01.openstack.org
450git02.openstack.org
451 </pre>
452 </section>
453
454 <section id="ansible-inventory-from-puppet" class="slide level2">
455 <h1>ansible inventory from puppet certs</h1>
456 <pre><code>
457import json
458import subprocess
459
460output = [
461 x.split()[1][1:-1] for x in subprocess.check_output(
462 ["puppet","cert","list","-a"]).split('\n')
463 if x.startswith('+')
464]
465
466data = {
467 '_meta': {'hostvars': dict()},
468 'ungrouped': output,
469}
470print json.dumps(data, sort_keys=True, indent=2)
471 </code></pre>
472 </section>
473
474 <section>
475 <h1>Ansible for Cloud Management</h1>
476 </section>
477
478 <section>
479 <h1>ansible and OpenStack</h1>
480 <ul>
481 <li>Ansible modules are just python</li>
482 <li>playbooks are lists of steps to take</li>
483 <li>Have plays/roles that provision servers</li>
484 <li>Infrastructure as code - for real!</li>
485 </ul>
486 </section>
487
488 <section>
489 <h1>Consider this data</h1>
490 <pre><code>
491pypi:
492 image_name: Ubuntu 12.04.4
493 flavor_ram: 2048
494 provision_group: ubuntu_hosts
495 volumes:
496 - size: 200
497 mount: /srv
498 hosts:
499 pypi.dfw:
500 region: DFW
501 pypi.iad:
502 region: IAD
503 pypi.ord:
504 region: ORD
505 pypi.region-b.geo-1:
506 cloud: hp
507 </code></pre>
508 </section>
509
510 <section>
511 <h1>Steps to launch a node</h1>
512 <ol>
513 <li>Create a compute instance</li>
514 <li>Wait for instance to exist</li>
515 <li>Create a floating IP</li>
516 <li>Attach floating IP to instance</li>
517 <li>Create one or more volumes</li>
518 <li>Attach volumes to instance</li>
519 <li>Wait for SSH to work</li>
520 <li>On host, format each volume</li>
521 <li>On host, mount each volume</li>
522 <li>On host, install config management software</li>
523 <li>On host, run config management software</li>
524 </ol>
525 </section>
526
527 <section>
528 <h1>Launch a node</h1>
529 <pre><code>
530---
531- name: Launch Node
532 os_compute:
533 cloud: "{{ cloud }}"
534 region_name: "{{ region_name }}"
535 name: "{{ name }}"
536 image_name: "{{ image_name }}"
537 flavor_ram: "{{ flavor_ram }}"
538 flavor_include: "{{ flavor_include }}"
539 meta:
540 group: "{{ group }}"
541 key_name: "{{ launch_keypair }}"
542 register: node
543- name: Create volumes
544 os_volume:
545 cloud: "{{ cloud }}"
546 size: "{{ item.size }}"
547 display_name: "{{ item.display_name }}"
548 with_items: volumes
549- name: Attach volumes
550 os_compute_volume:
551 cloud: "{{ cloud }}"
552 server_id: "{{ node.id }}"
553 volume_name: "{{ item.display_name }}"
554 with_items: volumes
555 register: attached_volumes
556- debug: var=attached_volumes
557- name: Re-request server to get up to date metadata after the volume loop
558 os_compute_facts:
559 cloud: "{{ cloud }}"
560 name: "{{ name }}"
561 when: attached_volumes.changed
562- name: Wait for SSH to work
563 wait_for: host={{ node.openstack.interface_ip }} port=22
564 when: node.changed == True
565- name: Add SSH host key to known hosts
566 shell: ssh-keyscan "{{ node.openstack.interface_ip|quote }}" &gt;&gt; ~/.ssh/known_hosts
567 when: node.changed == True
568- name: Add all instance public IPs to host group
569 add_host:
570 name: "{{ node.openstack.interface_ip }}"
571 groups: "{{ provision_group }}"
572 openstack: "{{ node.openstack }}"
573 when: attached_volumes|length == 0
574- name: Add all instance public IPs to host and volumes group
575 add_host:
576 name: "{{ node.openstack.interface_ip }}"
577 groups: "{{ provision_group }},hasvolumes"
578 openstack: "{{ node.openstack }}"
579 when: attached_volumes|length != 0
580 </code></pre>
581 </section>
582
583 <section>
584 <h1> Cloud based inventory </h1>
585 <ul>
586 <li> Just ask the cloud for the inventory </li>
587 <li> All of the meta-data the cloud knows is available </li>
588 </ul>
589 </section>
590
591 <section>
592 <pre><code>
593 "pypi.dfw.openstack.org": {
594 "ansible_ssh_host": "23.253.237.8",
595 "openstack": {
596 "HUMAN_ID": true,
597 "NAME_ATTR": "name",
598 "OS-DCF:diskConfig": "MANUAL",
599 "OS-EXT-STS:power_state": 1,
600 "OS-EXT-STS:task_state": null,
601 "OS-EXT-STS:vm_state": "active",
602 "accessIPv4": "23.253.237.8",
603 "accessIPv6": "2001:4800:7817:104:d256:7a33:5187:7e1b",
604 "addresses": {
605 "private": [
606 {
607 "addr": "10.208.195.50",
608 "version": 4
609 }
610 ],
611 "public": [
612 {
613 "addr": "23.253.237.8",
614 "version": 4
615 },
616 {
617 "addr": "2001:4800:7817:104:d256:7a33:5187:7e1b",
618 "version": 6
619 }
620 ]
621 },
622 "cloud": "rax",
623 "config_drive": "",
624 "created": "2014-09-05T15:32:14Z",
625 "flavor": {
626 "id": "performance1-4",
627 "links": [
628 {
629 "href": "https://dfw.servers.api.rackspacecloud.com/610275/flavors/performance1-4",
630 "rel": "bookmark"
631 }
632 ],
633 "name": "4 GB Performance"
634 },
635 "hostId": "adb603d4566efe0392756c76dab38ffcba22099368837c7973321e77",
636 "human_id": "pypidfwopenstackorg",
637 "id": "de672205-9245-46b6-b3df-489ccf9e0c17",
638 "image": {
639 "id": "928e709d-35f0-47eb-b296-d18e1b0a76b7",
640 "links": [
641 {
642 "href": "https://dfw.servers.api.rackspacecloud.com/610275/images/928e709d-35f0-47eb-b296-d18e1b0a76b7",
643 "rel": "bookmark"
644 }
645 ]
646 },
647 "interface_ip": "23.253.237.8",
648 "key_name": "launch-node-root",
649 "links": [
650 {
651 "href": "https://dfw.servers.api.rackspacecloud.com/v2/610275/servers/de672205-9245-46b6-b3df-489ccf9e0c17",
652 "rel": "self"
653 },
654 {
655 "href": "https://dfw.servers.api.rackspacecloud.com/610275/servers/de672205-9245-46b6-b3df-489ccf9e0c17",
656 "rel": "bookmark"
657 }
658 ],
659 "metadata": {},
660 "name": "pypi.dfw.openstack.org",
661 "networks": {
662 "private": [
663 "10.208.195.50"
664 ],
665 "public": [
666 "23.253.237.8",
667 "2001:4800:7817:104:d256:7a33:5187:7e1b"
668 ]
669 },
670 "progress": 100,
671 "region": "DFW",
672 "status": "ACTIVE",
673 "tenant_id": "610275",
674 "updated": "2014-09-05T15:32:49Z",
675 "user_id": "156284",
676 "volumes": [
677 {
678 "HUMAN_ID": false,
679 "NAME_ATTR": "name",
680 "attachments": [
681 {
682 "device": "/dev/xvdb",
683 "host_name": null,
684 "id": "c6f5229c-1cc0-47c4-aab7-60db1f6cf8e8",
685 "server_id": "de672205-9245-46b6-b3df-489ccf9e0c17",
686 "volume_id": "c6f5229c-1cc0-47c4-aab7-60db1f6cf8e8"
687 }
688 ],
689 "availability_zone": "nova",
690 "bootable": "false",
691 "created_at": "2014-09-05T14:37:42.000000",
692 "device": "/dev/xvdb",
693 "display_description": null,
694 "display_name": "pypi.dfw.openstack.org/main01",
695 "human_id": null,
696 "id": "c6f5229c-1cc0-47c4-aab7-60db1f6cf8e8",
697 "metadata": {
698 "readonly": "False",
699 "storage-node": "1845027a-5e07-47a1-9572-3eea4716f726"
700 },
701 "os-vol-tenant-attr:tenant_id": "610275",
702 "size": 200,
703 "snapshot_id": null,
704 "source_volid": null,
705 "status": "in-use",
706 "volume_type": "SATA"
707 }
708 ]
709 }
710 },
711 </code></pre>
712 </section>
713
714</body>
715</html>