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 (phpbenelux 2015)

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

Ansible is a provisioning tool rapidly growing in popularity, mainly due to it’s simplicity. But it’s capable of more than just provisioning! In this talk, I’ll walk you through an Ansible role that can be used to deploy your projects. Those familiar with Capistrano wil recognize the method, but I’ll explain it step by step and in the end I’ll show a real-world example from a Symfony2 project: the SweetlakePHP website. (this talk assumes some knowledge of how Ansible works)

  • Login to see the comments

Ansible Project Deploy (phpbenelux 2015)

  1. 1. ANSIBLE-PROJECT-DEPLOY a re-usable Ansible role to deploy projects
  2. 2. ABOUT ME 2 Ramon de la Fuente Future500 B.V. @f_u_e_n_t_e SweetlakePHP
  3. 3. WHY ANSIBLE? • Easy. Period. 3 “I wrote Ansible because none of the existing tools fit my brain.” - Michael de Haan
  4. 4. WHY ANSIBLE? • Easy. Period. • No unnecessary complexity → No agent! 4
  5. 5. WHY ANSIBLE? • Easy. Period. • No unnecessary complexity → No agent! • Built for re-use and sharing. 5
  6. 6. WHY ANSIBLE? • Easy. Period. • No unnecessary complexity → No agent! • Built for re-use and sharing. • Extendable in your own language. 6
  7. 7. THE PROBLEM • Continuous deployment 7
  8. 8. THE PROBLEM • Continuous deployment • Easy maintenance of the deploy procedure. 8
  9. 9. THE PROBLEM • Continuous deployment • Easy maintenance of the deploy procedure. • Small learning curve. 9
  10. 10. THE PROBLEM • Continuous deployment • Easy maintenance of the deploy procedure. • Small learning curve. • Reuse between projects with little effort. 10
  11. 11. WHAT IS A DEPLOY? Directory structure: . !"" releases | !"" 20140415234508 | #"" 20140415235146 !"" shared | !"" sessions | !"" source | #"" uploads #"" current -> releases/20140415235146 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? 1. Update the codebase + configuration 13
  14. 14. WHAT IS A DEPLOY? 1. Update the codebase + configuration 2. Install dependencies 14
  15. 15. WHAT IS A DEPLOY? 1. Update the codebase + configuration 2. Install dependencies 3. Preserve shared resources 15
  16. 16. WHAT IS A DEPLOY? 1. Update the codebase + configuration 2. Install dependencies 3. Preserve shared resources 4. Build tasks 16
  17. 17. WHAT IS A DEPLOY? 1. Update the codebase + configuration 2. Install dependencies 3. Preserve shared resources 4. Build tasks 5. Finalize 17
  18. 18. THE ROLE 18 https://galaxy.ansible.com/list#/roles/732 project_deploy
  19. 19. GETTINGTHE ROLE Installation with ansible-galaxy command: $ ansible-galaxy install f500.project_deploy,v2.1.0 Optional: create a galaxy file for all roles: f500.nginx f500.mariadb55 f500.php f500.project_deploy,v2.1.0 $ ansible-galaxy install -r ansible/galaxy.txt 19
  20. 20. ROLE WALKTHROUGH --- - name: Initialize deploy_helper: "path={{ project_root }} state=present" 20
  21. 21. ROLE WALKTHROUGH Deploy module variables: deploy_helper: project_path current_path releases_path shared_path previous_release previous_release_path new_release new_release_path unfinished_filename 21
  22. 22. ROLE WALKTHROUGH Deploy module variables: deploy_helper: project_path: /path/to/project/ current_path: /path/to/project/current releases_path: /path/to/project/releases shared_path: /path/to/project/shared previous_release: 20140415234508 previous_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_helper.new_release }} 22
  23. 23. 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' 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: Write unfinished file file: path={{ project_source_path }}/{{ deploy_helper.unfinished_filename }} state=touch - name: Copy files to new build dir command: "cp -pr {{project_source_path}} {{deploy_helper.new_release_path}}" - name: Remove unwanted files/folders from new release file: path={{ deploy_helper.new_release_path }}/{{ item }} state=absent with_items: project_unwanted_items 26
  27. 27. 1. UPDATETHE CONFIG FILES - name: Copy project files copy: src={{ item.src }} dest={{ deploy_helper.new_release_path }}/{{ item.dest }} mode={{ item.mode|default('0644') }} with_items: project_files - name: Copy project templates template: src={{ item.src }} dest={{ deploy_helper.new_release_path }}/{{ item.dest }} mode={{ item.mode|default('0644') }} with_items: project_templates 27
  28. 28. 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 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. 3. SHARED RESOURCES - name: Ensure shared sources are present file: path='{{ deploy_helper.shared_path }}/{{ item.src }}' state={{ item.type }} with_items: project_shared_children - name: Ensure shared paths are absent file: path='{{ deploy_helper.new_release_path }}/{{ item.path }}' state=absent with_items: project_shared_children - name: Create shared symlinks file: path='{{ deploy_helper.new_release_path }}/{{ item.path }}' src='{{ deploy_helper.shared_path }}/{{ item.src }}' state=link" with_items: project_shared_children 30
  31. 31. 4. BUILD STEPS - name: Run post_build_commands in the new_release_path command: "{{ item }} chdir={{ deploy_helper.new_release_path }}" with_items: project_post_build_commands environment: project_environment 31 project_post_build_commands: - "app/console cache:clear" - "app/console assets:install" - "app/console assetic:dump"
  32. 32. 5. FINALIZE - name: Finalize the deploy
 deploy_helper: path={{ project_root }} release={{ deploy_helper.new_release }} state=finalize
 when: project_finalize
 32
  33. 33. 33
  34. 34. IT’S NOT COMPLICATED! • Only 98 lines • Number of tasks: 22 • Variables to configure: 28 34
  35. 35. MINIMAL PLAYBOOK 1. Set minimum variables 2. Add the role to “roles” section 35
  36. 36. 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 36
  37. 37. 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 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 project_environment: SYMFONY_ENV: "prod" 38
  39. 39. 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" 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.yml" 40
  41. 41. 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 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 42
  43. 43. EXAMPLE PLAYBOOK 43 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
  44. 44. WHAT DOESN’T IT DO? 44 • Rollbacks (the cake rollback is a lie)
  45. 45. WHAT DOESN’T IT DO? 45 • Rollbacks • Set maintenance mode (the cake rollback is a lie)
  46. 46. WHAT DOESN’T IT DO? 46 • Rollbacks • Set maintenance mode • DB migrations (the cake rollback is a lie)
  47. 47. WHAT’S NEXT? 47 • Injecting your own tasks in addition to commands
  48. 48. WHAT’S NEXT? 48 • Injecting your own tasks in addition to commands • Copy vendor folders from previous release ✓
  49. 49. WHAT’S NEXT? 49 • Injecting your own tasks in addition to commands • Copy vendor folders from previous release • Setfacl support ✓
  50. 50. WHAT’S NEXT? 50 • Injecting your own tasks in addition to commands • Copy vendor folders from previous release • Setfacl support • Your ideas? ✓
  51. 51. THANKYOU! 51 Feedback: joind.in 13405 f500/ansible-project_deploy (But I’m also just a human. You could talk to me and tell me what you think…) https://github.com/

×