Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Ansible project-deploy

"A re-usable Ansible role to deploy projects".

When deploying software to production, it pays to have an automated process in place. This presentation describes a workflow to deploy your project (those familiar with Capistrano wil recognize this method), and then takes you step by step through an Ansible role that you can simply implement in your own ansible scripts.

  • Login to see the comments

Ansible project-deploy

  1. 1. ANSIBLE-PROJECT-DEPLOY a re-usable Ansible role to deploy projects
  2. 2. ABOUT US 2 Ramon de la Fuente @f_u_e_n_t_e Jasper N. Brouwer @jaspernbrouwer
  3. 3. ABOUT US 3 Ramon de la Fuente @f_u_e_n_t_e Jasper N. Brouwer @jaspernbrouwer Future500 B.V.
  4. 4. WHY ANSIBLE? • Easy. Period. 4 “I wrote Ansible because none of the existing tools fit my brain.” ! - Michael de Haan
  5. 5. WHY ANSIBLE? • Easy. Period. • No unnecessary complexity → No agent! 5
  6. 6. WHY ANSIBLE? • Easy. Period. • No unnecessary complexity → No agent! • Built for re-use and sharing. 6
  7. 7. WHY ANSIBLE? • Easy. Period. • No unnecessary complexity → No agent! • Built for re-use and sharing. • Extendable in your own language. 7
  8. 8. THE PROBLEM • Continuous deployment 8
  9. 9. THE PROBLEM • Continuous deployment • Easy maintenance of the deploy procedure. 9
  10. 10. THE PROBLEM • Continuous deployment • Easy maintenance of the deploy procedure. • Small learning curve. 10
  11. 11. THE PROBLEM • Continuous deployment • Easy maintenance of the deploy procedure. • Small learning curve. • Reuse between projects with little effort. 11
  12. 12. WHAT IS A DEPLOY? Directory structure: . !"" releases | !"" 20140415234508 | #"" 20140415235146 !"" shared | !"" sessions | !"" source | #"" uploads #"" current -> releases/20140415235146 12
  13. 13. WHAT IS A DEPLOY? Directory structure: . !"" releases | !"" 20140415234508 | #"" 20140415235146 !"" shared | !"" sessions | !"" source | #"" uploads #"" current -> releases/20140415235146 13
  14. 14. WHAT IS A DEPLOY? 1. Update the codebase + configuration 14
  15. 15. WHAT IS A DEPLOY? 1. Update the codebase + configuration 2. Install dependencies 15
  16. 16. WHAT IS A DEPLOY? 1. Update the codebase + configuration 2. Install dependencies 3. Preserve shared resources 16
  17. 17. WHAT IS A DEPLOY? 1. Update the codebase + configuration 2. Install dependencies 3. Preserve shared resources 4. Build tasks 17
  18. 18. WHAT IS A DEPLOY? 1. Update the codebase + configuration 2. Install dependencies 3. Preserve shared resources 4. Build tasks 5. Finalize 18
  19. 19. THE ROLE 19 https://galaxy.ansible.com/list#/roles/732 project_deploy
  20. 20. GETTINGTHE ROLE Installation with ansible-galaxy command: ! $ ansible-galaxy install f500.project_deploy,v1.0.0 Optional: create a galaxy file for all roles: ! f500.nginx f500.mariadb55 f500.php f500.project_deploy,v1.0.0 ! $ ansible-galaxy install -r ansible/galaxy.txt 20
  21. 21. ROLE WALKTHROUGH ! --- ! - name: Initialize deploy: "path={{ project_root }} state=present" 21
  22. 22. ROLE WALKTHROUGH ! Deploy module variables: ! deploy: project_path current_path releases_path shared_path last_release last_release_path new_release new_release_path unfinished_filename ! ! 22
  23. 23. ROLE WALKTHROUGH ! Deploy module variables: ! deploy: project_path: /path/to/project/ current_path: /path/to/project/current releases_path: /path/to/project/releases shared_path: /path/to/project/shared last_release: 20140415234508 last_release_path: /path/to/project/releases/20140415234508 new_release: 20140415235146 new_release_path: /path/to/project/releases/20140415235146 unfinished_filename: DEPLOY_UNFINISHED Used as: {{ deploy.new_release }} 23
  24. 24. 1. UPDATETHE CODEBASE ! - name: Clone project files git: repo={{ project_git_repo }} dest={{ project_source_path }} version={{ project_version }} when: project_deploy_strategy == 'git' ! - name: Rsync project files synchronize: src={{ project_local_path }} dest={{ project_source_path }} rsync_timeout={{ project_deploy_synchronize_timeout }} recursive=yes when: project_deploy_strategy == 'synchronize' ! 24
  25. 25. 1. UPDATETHE CODEBASE ! - name: Clone project files git: repo={{ project_git_repo }} dest={{ project_source_path }} version={{ project_version }} when: project_deploy_strategy == 'git' ! - name: Rsync project files synchronize: src={{ project_local_path }} dest={{ project_source_path }} rsync_timeout={{ project_deploy_synchronize_timeout }} recursive=yes when: project_deploy_strategy == 'synchronize' ! 25
  26. 26. 1. UPDATETHE CODEBASE ! - name: Clone project files git: repo={{ project_git_repo }} dest={{ project_source_path }} version={{ project_version }} when: project_deploy_strategy == 'git' ! - name: Rsync project files synchronize: src={{ project_local_path }} dest={{ project_source_path }} rsync_timeout={{ project_deploy_synchronize_timeout }} recursive=yes when: project_deploy_strategy == 'synchronize' ! 26
  27. 27. 1. UPDATETHE CODEBASE ! - name: Write unfinished file file: path={{ project_source_path }}/{{ deploy.unfinished_filename }} state=touch ! - name: Copy files to new build dir command: "cp -pr {{ project_source_path }} {{ deploy.new_release_path }}" ! - name: Remove unwanted files/folders from new release file: path={{ deploy.new_release_path }}/{{ item }} state=absent with_items: project_unwanted_items 27
  28. 28. 1. UPDATETHE CONFIG FILES ! - name: Copy project files copy: src={{ item.src }} dest={{ deploy.new_release_path }}/{{ item.dest }} mode={{ item.mode|default('0644') }} with_items: project_files ! - name: Copy project templates template: src={{ item.src }} dest={{ deploy.new_release_path }}/{{ item.dest }} mode={{ item.mode|default('0644') }} with_items: project_templates 28
  29. 29. 2. INSTALL DEPENDENCIES ! - name: Do composer install command: "{{ project_command_for_composer_install }} chdir=…" environment: project_environment when: project_has_composer ! - name: Do npm install command: "{{ project_command_for_npm_install }} chdir=…" environment: project_environment when: project_has_npm ! - name: Do bower install command: "{{ project_command_for_bower_install }} chdir=…" environment: project_environment when: project_has_bower 29
  30. 30. 2. INSTALL DEPENDENCIES ! - name: Do composer install command: "{{ project_command_for_composer_install }} chdir=…" environment: project_environment when: project_has_composer ! - name: Do npm install command: "{{ project_command_for_npm_install }} chdir=…" environment: project_environment when: project_has_npm ! - name: Do bower install command: "{{ project_command_for_bower_install }} chdir=…" environment: project_environment when: project_has_bower 30
  31. 31. 3. SHARED RESOURCES ! - name: Ensure shared sources are present file: "path='{{ deploy.shared_path }}/{{ item.src }}' state={{ item.type }}“ with_items: project_shared_children ! - name: Ensure shared paths are absent file: "path='{{ deploy.new_release_path }}/{{ item.path }}' state=absent" with_items: project_shared_children ! - name: Create shared symlinks file: path='{{ deploy.new_release_path }}/{{ item.path }}' src='{{ deploy.shared_path }}/{{ item.src }}' state=link" with_items: project_shared_children 31
  32. 32. 4. BUILD STEPS ! - name: Run post_build_commands in the new_release_path command: "{{ item }} chdir={{ deploy.new_release_path }}" with_items: project_post_build_commands environment: project_environment 32 ! project_post_build_commands: - "app/console cache:clear" - "app/console assets:install" - "app/console assetic:dump"
  33. 33. 5. FINALIZE ! - name: Remove unfinished file file: path={{ deploy.new_release_path }}/{{ deploy.unfinished_filename }} state=absent when: project_finalize ! - name: Finalize the deploy file: src={{ deploy.new_release_path }} dest={{ deploy.current_path }} state=link when: project_finalize 33
  34. 34. 34
  35. 35. IT’S NOT COMPLICATED! • Only 75 lines • Number of tasks: 18 • Variables to configure: 24 35
  36. 36. EXAMPLE PLAYBOOK 1. Set minimum variables 2. Add the role to “roles” section 36
  37. 37. MINIMAL PLAYBOOK ! - name: Deploy the application hosts: production remote_user: deploy sudo: no ! vars: project_root: /var/www/my_project project_git_repo: git@github.com:me/my_project.git project_deploy_strategy: git ! roles: - f500.project_deploy 37
  38. 38. EXAMPLE PLAYBOOK ! - name: Deploy the application hosts: production remote_user: "{{ production_deploy_user }}" sudo: no ! vars: project_root: "{{ sweetlakephp_root }}" project_git_repo: "{{ sweetlakephp_github_repo }}" project_deploy_strategy: git 38
  39. 39. EXAMPLE PLAYBOOK ! - name: Deploy the application hosts: production remote_user: "{{ production_deploy_user }}" sudo: no ! vars: project_root: "{{ sweetlakephp_root }}" project_git_repo: "{{ sweetlakephp_github_repo }}" project_deploy_strategy: git ! project_environment: SYMFONY_ENV: "prod" 39
  40. 40. EXAMPLE PLAYBOOK ! project_environment: SYMFONY_ENV: "prod" ! project_shared_children: - path: "/app/sessions" src: "sessions" - path: "/web/uploads" src: "uploads" ! project_templates: - name: parameters.yml src: "templates/parameters_prod.yml.j2" dest: "/app/config/parameters_prod.yml" ! 40
  41. 41. EXAMPLE PLAYBOOK ! project_environment: SYMFONY_ENV: "prod" ! project_shared_children: - path: "/app/sessions" src: "sessions" - path: "/web/uploads" src: "uploads" ! project_templates: - name: parameters.yml src: "templates/parameters_prod.yml.j2" dest: "/app/config/parameters_prod.yml" ! 41
  42. 42. EXAMPLE PLAYBOOK ! project_has_composer: yes ! project_post_build_commands: - "php vendor/sensio/…/DistributionBundle/…/bin/build_bootstrap.php” - "app/console cache:clear" - "app/console doctrine:migrations:migrate --no-interaction" - "app/console assets:install" - "app/console assetic:dump" ! roles: - f500.project_deploy ! post_tasks: - name: Remove old releases deploy: "path={{ project_root }} state=clean" 42
  43. 43. EXAMPLE PLAYBOOK ! project_has_composer: yes ! project_post_build_commands: - "php vendor/sensio/…/DistributionBundle/…/bin/build_bootstrap.php” - "app/console cache:clear" - "app/console doctrine:migrations:migrate --no-interaction" - "app/console assets:install" - "app/console assetic:dump" ! roles: - f500.project_deploy ! post_tasks: - name: Remove old releases deploy: "path={{ project_root }} state=clean" 43
  44. 44. EXAMPLE PLAYBOOK 44 ! project_has_composer: yes ! project_post_build_commands: - "php vendor/sensio/…/DistributionBundle/…/bin/build_bootstrap.php” - "app/console cache:clear" - "app/console doctrine:migrations:migrate --no-interaction" - "app/console assets:install" - "app/console assetic:dump" ! roles: - f500.project_deploy ! post_tasks: - name: Remove old releases deploy: "path={{ project_root }} state=clean"
  45. 45. WHAT DOESN’T IT DO? 45 • Rollbacks (the cake rollback is a lie)
  46. 46. WHAT DOESN’T IT DO? 46 • Rollbacks • Set maintenance mode (the cake rollback is a lie)
  47. 47. WHAT DOESN’T IT DO? 47 • Rollbacks • Set maintenance mode • DB migrations (the cake rollback is a lie)
  48. 48. WHAT’S NEXT? 48 • Full-blown Actions in addition to commands
  49. 49. WHAT’S NEXT? 49 • Full-blown Actions in addition to commands • Setfacl support
  50. 50. WHAT’S NEXT? 50 • Full-blown Actions in addition to commands • Setfacl support • Your ideas?
  51. 51. THANKYOU! 51 Feedback: joind.in? https://github.com/f500/ansible-project_deploy (But we’re also people. You could just talk to us and tell us what you think…)

×