Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ansible

 Ansible

Lightning talk on Ansible, given at the Amsterdam Python meetup group on Oct 2nd, 2013

Nick Groenen

October 02, 2013
Tweet

More Decks by Nick Groenen

Other Decks in Programming

Transcript

  1. 24 years old Loves spicy food Developer @ TravelBird Python

    user since 2009 Linux user since around 2003 Big fan of Open Source Nick Groenen Twitter: @NickGroenen Web: https://zoni.nl Email: [email protected]
  2. Python WSGI app on 2 application servers (web1 & web2)

    behind 1 loadbalancer (lb1) Explore through example
  3. Vagrantfile Vagrant.configure("2") do |config| config.vm.define :lb1 do |lb1| lb1.vm.box =

    "raring-server-cloudimg-amd64-vagrant" lb1.vm.network :private_network, ip: "192.168.99.10" end config.vm.define :web1 do |web1| web1.vm.box = "raring-server-cloudimg-amd64-vagrant" web1.vm.network :private_network, ip: "192.168.99.11" end config.vm.define :web2 do |web2| web2.vm.box = "raring-server-cloudimg-amd64-vagrant" web2.vm.network :private_network, ip: "192.168.99.12" end end
  4. Vagrantfile Vagrant.configure("2") do |config| config.vm.define :lb1 do |lb1| lb1.vm.box =

    "raring-server-cloudimg-amd64-vagrant" lb1.vm.network :private_network, ip: "192.168.99.10" end config.vm.define :web1 do |web1| web1.vm.box = "raring-server-cloudimg-amd64-vagrant" web1.vm.network :private_network, ip: "192.168.99.11" end config.vm.define :web2 do |web2| web2.vm.box = "raring-server-cloudimg-amd64-vagrant" web2.vm.network :private_network, ip: "192.168.99.12" end end
  5. $ vagrant up Bringing machine 'lb1' up with 'virtualbox' provider...

    Bringing machine 'web1' up with 'virtualbox' provider… Bringing machine 'web2' up with 'virtualbox' provider...
  6. Ansible leverages SSH. No daemons to setup, no (extra) permissions

    to manage, we're ready to roll! pip install ansible or aptitude install ansible or yum install ansible or emerge ansible
  7. playbook.yml - hosts: loadbalancers user: vagrant sudo: true tasks: -

    name: Install nginx apt: name=nginx state=present - name: Install nginx config template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644
  8. playbook.yml - hosts: loadbalancers user: vagrant sudo: true tasks: -

    name: Install nginx apt: name=nginx state=present - name: Install nginx config template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644
  9. playbook.yml - hosts: loadbalancers user: vagrant sudo: true tasks: -

    name: Install nginx apt: name=nginx state=present - name: Install nginx config template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644
  10. playbook.yml - hosts: loadbalancers user: vagrant sudo: true tasks: -

    name: Install nginx apt: name=nginx state=present - name: Install nginx config template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644
  11. playbook.yml # Some stuff omitted to save space tasks: -

    name: Install nginx config template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644 notify: - restart nginx handlers: - name: restart nginx service: name=nginx state=restarted
  12. playbook.yml # Some stuff omitted to save space tasks: -

    name: Install nginx config template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644 notify: - restart nginx handlers: - name: restart nginx service: name=nginx state=restarted
  13. playbook.yml # Some stuff omitted to save space tasks: -

    name: Install nginx config template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644 validate="nginx -t -c %s" notify: - restart nginx handlers: - name: restart nginx service: name=nginx state=restarted
  14. playbook.yml # Some stuff omitted to save space tasks: -

    name: Install nginx config template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=644 validate="nginx -t -c %s" notify: - restart nginx handlers: - name: restart nginx service: name=nginx state=restarted
  15. failed: [lb1] => {"failed": true} msg: failed to validate: rc:1

    error:nginx: [emerg] directive "pid" is not terminated by ";" in /home/vagrant/. ansible/tmp/ansible-1380702362.41-73682544006063/source:5 nginx: configuration file /home/vagrant/.ansible/tmp/ansible- 1380702362.41-73682544006063/source test failed FATAL: all hosts have already failed -- aborting If you screwed up
  16. nginx.conf.j2 {{ ansible_managed }} user www-data; worker_processes {{ ansible_processor_cores }};

    pid /run/nginx.pid; events { worker_connections {{ nginx_worker_connections }}; }
  17. nginx.conf.j2 {{ ansible_managed }} user www-data; worker_processes {{ ansible_processor_cores }};

    pid /run/nginx.pid; events { worker_connections {{ nginx_worker_connections }}; }
  18. nginx.conf.j2 {{ ansible_managed }} user www-data; worker_processes {{ ansible_processor_cores }};

    pid /run/nginx.pid; events { worker_connections {{ nginx_worker_connections }}; }
  19. nginx.conf.j2 {{ ansible_managed }} user www-data; worker_processes {{ ansible_processor_cores }};

    pid /run/nginx.pid; events { worker_connections {{ nginx_worker_connections }}; }
  20. lb1 | success | rc=0 >> Linux 3.8.0-30-generic #44-Ubuntu SMP

    Thu Aug 22 20:52:24 UTC 2013 web1 | success | rc=0 >> Linux 3.8.0-30-generic #44-Ubuntu SMP Thu Aug 22 20:52:24 UTC 2013 web2 | FAILED => SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue
  21. nginx.conf.j2 (continued) upstream exampleapp { {% for host in groups['webservers']

    %} server {{ hostvars[host]['ansible_ssh_host'] }}:9001; {% endfor %} } server { listen 80; server_name example.vagrant; location / { uwsgi_pass exampleapp; } }
  22. nginx.conf.j2 (continued) upstream exampleapp { {% for host in groups['webservers']

    %} server {{ hostvars[host]['ansible_ssh_host'] }}:9001; {% endfor %} } server { listen 80; server_name example.vagrant; location / { uwsgi_pass exampleapp; } }
  23. playbook.yml - hosts: webservers user: vagrant sudo: true tasks: -

    name: Install dependencies apt: name={{ item }} state=present with_items: - python-virtualenv - python-pip - git
  24. playbook.yml - hosts: webservers user: vagrant sudo: true tasks: -

    name: Install dependencies apt: name={{ item }} state=present with_items: - python-virtualenv - python-pip - git
  25. playbook.yml - hosts: webservers user: vagrant sudo: true tasks: -

    name: Install dependencies apt: name={{ item }} state=present with_items: - python-virtualenv - python-pip - git
  26. playbook.yml - hosts: webservers user: vagrant sudo: true tasks: -

    name: Install dependencies apt: name={{ item }} state=present with_items: - python-virtualenv - python-pip - git
  27. - name: Checkout application code git: repo=https://gist.github.com/6164386.git dest=/srv/exampleapp version=HEAD update=yes

    notify: - reload uwsgi instance - name: Install requirements pip: state=present virtualenv=/srv/exampleapp requirements=/srv/exampleapp/requirements.txt playbook.yml
  28. - name: Checkout application code git: repo=https://gist.github.com/6164386.git dest=/srv/exampleapp version=HEAD update=yes

    notify: - reload uwsgi instance - name: Install requirements pip: state=present virtualenv=/srv/exampleapp requirements=/srv/exampleapp/requirements.txt playbook.yml
  29. ansible-playbook playbook.yml lb1 : ok=3 changed=0 unreachable=0 failed=0 web1 :

    ok=4 changed=3 unreachable=0 failed=0 web2 : ok=4 changed=3 unreachable=0 failed=0
  30. Python WSGI app on 2 application servers (web1 & web2)

    behind 1 loadbalancer (lb1) Deployed!
  31. Delegating actions - hosts: webservers serial: 2 tasks: - name:

    Remove from loadbalancer shell: remove_from_lb_command delegate_to: lb1 - do_stuff_here - name: Add to loadbalancer shell: add_to_lb_command delegate_to: lb1
  32. Tags tasks: - apt: name={{ item }} state=installed with_items: -

    nginx - memcached tags: - packages - template: src=templates/src.j2 dest=/etc/foo.conf tags: - configuration
  33. Tags Run with: $ ansible-playbook example.yml --tags "packages" $ ansible-playbook

    example.yml --tags "configuration" $ ansible-playbook example.yml \ --tags "configuration,packages"
  34. Prompting for input vars_prompt: - name: "some_password" prompt: "Enter password"

    private: yes - name: "release_version" prompt: "Product release version" private: no
  35. Looking up data - hosts: localhost tasks: - name: Print

    result of DNS lookup shell: echo {{ lookup('dnstxt', 'example.com') }} - name: Print file contents debug: msg="Motd content: {{ lookup('file', '/etc/motd') }}"
  36. • External inventory scripts • Python API • Custom modules

    • Custom Jinja2 filters • Moar! And more...
  37. Closing words • Ignored all best practices for demonstration (use

    roles!) • Made many assumptions http://www.ansibleworks.com/quickstart-video/ http://www.ansibleworks.com/docs