ansible project-deploy
DESCRIPTION
"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.TRANSCRIPT
![Page 1: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/1.jpg)
ANSIBLE-PROJECT-DEPLOYa re-usable Ansible role to deploy projects
![Page 2: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/2.jpg)
ABOUT US
2
Ramon de la Fuente @f_u_e_n_t_e
Jasper N. Brouwer @jaspernbrouwer
![Page 3: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/3.jpg)
ABOUT US
3
Ramon de la Fuente @f_u_e_n_t_e
Jasper N. Brouwer @jaspernbrouwer
Future500 B.V.
![Page 4: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/4.jpg)
WHY ANSIBLE?• Easy. Period.
4
“I wrote Ansible because none of the existing tools fit my brain.” !
- Michael de Haan
![Page 5: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/5.jpg)
WHY ANSIBLE?• Easy. Period.
• No unnecessary complexity → No agent!
5
![Page 6: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/6.jpg)
WHY ANSIBLE?• Easy. Period.
• No unnecessary complexity → No agent!
• Built for re-use and sharing.
6
![Page 7: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/7.jpg)
WHY ANSIBLE?• Easy. Period.
• No unnecessary complexity → No agent!
• Built for re-use and sharing.
• Extendable in your own language.
7
![Page 8: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/8.jpg)
THE PROBLEM• Continuous deployment
8
![Page 9: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/9.jpg)
THE PROBLEM• Continuous deployment
• Easy maintenance of the deploy procedure.
9
![Page 10: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/10.jpg)
THE PROBLEM• Continuous deployment
• Easy maintenance of the deploy procedure.
• Small learning curve.
10
![Page 11: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/11.jpg)
THE PROBLEM• Continuous deployment
• Easy maintenance of the deploy procedure.
• Small learning curve.
• Reuse between projects with little effort.
11
![Page 12: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/12.jpg)
WHAT IS A DEPLOY?Directory structure:
.
!"" releases | !"" 20140415234508 | #"" 20140415235146 !"" shared | !"" sessions | !"" source | #"" uploads #"" current -> releases/20140415235146
12
![Page 13: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/13.jpg)
WHAT IS A DEPLOY?Directory structure:
.
!"" releases | !"" 20140415234508 | #"" 20140415235146 !"" shared | !"" sessions | !"" source | #"" uploads #"" current -> releases/20140415235146
13
![Page 14: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/14.jpg)
WHAT IS A DEPLOY?1. Update the codebase + configuration
14
![Page 15: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/15.jpg)
WHAT IS A DEPLOY?1. Update the codebase + configuration
2. Install dependencies
15
![Page 16: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/16.jpg)
WHAT IS A DEPLOY?1. Update the codebase + configuration
2. Install dependencies
3. Preserve shared resources
16
![Page 17: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/17.jpg)
WHAT IS A DEPLOY?1. Update the codebase + configuration
2. Install dependencies
3. Preserve shared resources
4. Build tasks
17
![Page 18: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/18.jpg)
WHAT IS A DEPLOY?1. Update the codebase + configuration
2. Install dependencies
3. Preserve shared resources
4. Build tasks
5. Finalize
18
![Page 19: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/19.jpg)
THE ROLE
19
https://galaxy.ansible.com/list#/roles/732project_deploy
![Page 20: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/20.jpg)
GETTING THE ROLEInstallation 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
![Page 21: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/21.jpg)
ROLE WALKTHROUGH!--- !- name: Initialize deploy: "path={{ project_root }} state=present"
21
![Page 22: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/22.jpg)
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
![Page 23: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/23.jpg)
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
![Page 24: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/24.jpg)
1. UPDATE THE 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
![Page 25: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/25.jpg)
1. UPDATE THE 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
![Page 26: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/26.jpg)
1. UPDATE THE 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
![Page 27: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/27.jpg)
1. UPDATE THE 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
![Page 28: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/28.jpg)
1. UPDATE THE 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
![Page 29: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/29.jpg)
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
![Page 30: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/30.jpg)
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
![Page 31: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/31.jpg)
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
![Page 32: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/32.jpg)
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"
![Page 33: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/33.jpg)
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
![Page 34: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/34.jpg)
34
![Page 35: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/35.jpg)
IT’S NOT COMPLICATED!• Only 75 lines
• Number of tasks: 18
• Variables to configure: 24
35
![Page 36: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/36.jpg)
EXAMPLE PLAYBOOK
1. Set minimum variables
2. Add the role to “roles” section
36
![Page 37: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/37.jpg)
MINIMAL PLAYBOOK!- name: Deploy the application hosts: production remote_user: deploy sudo: no ! vars: project_root: /var/www/my_project project_git_repo: [email protected]:me/my_project.git project_deploy_strategy: git ! roles: - f500.project_deploy
37
![Page 38: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/38.jpg)
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
![Page 39: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/39.jpg)
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
![Page 40: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/40.jpg)
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
![Page 41: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/41.jpg)
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
![Page 42: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/42.jpg)
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
![Page 43: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/43.jpg)
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
![Page 44: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/44.jpg)
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"
![Page 45: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/45.jpg)
WHAT DOESN’T IT DO?
45
• Rollbacks (the cake rollback is a lie)
![Page 46: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/46.jpg)
WHAT DOESN’T IT DO?
46
• Rollbacks
• Set maintenance mode
(the cake rollback is a lie)
![Page 47: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/47.jpg)
WHAT DOESN’T IT DO?
47
• Rollbacks
• Set maintenance mode
• DB migrations
(the cake rollback is a lie)
![Page 48: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/48.jpg)
WHAT’S NEXT?
48
• Full-blown Actions in addition to commands
![Page 49: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/49.jpg)
WHAT’S NEXT?
49
• Full-blown Actions in addition to commands
• Setfacl support
![Page 50: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/50.jpg)
WHAT’S NEXT?
50
• Full-blown Actions in addition to commands
• Setfacl support
• Your ideas?
![Page 51: Ansible project-deploy](https://reader034.vdocument.in/reader034/viewer/2022052321/53fe021a8d7f72a81c8b4c5d/html5/thumbnails/51.jpg)
THANK YOU!
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…)