ANSIBLE-PROJECT-DEPLOYa re-usable Ansible role to deploy projects
ABOUT ME
2
Ramon de la Fuente
Future500 B.V.
@f_u_e_n_t_e
SweetlakePHP
WHY ANSIBLE?• Easy. Period.
3
“I wrote Ansible because none of the existing tools fit my brain.”
- Michael de Haan
WHY ANSIBLE?• Easy. Period.
• No unnecessary complexity → No agent!
4
WHY ANSIBLE?• Easy. Period.
• No unnecessary complexity → No agent!
• Built for re-use and sharing.
5
WHY ANSIBLE?• Easy. Period.
• No unnecessary complexity → No agent!
• Built for re-use and sharing.
• Extendable in your own language.
6
THE PROBLEM• Continuous deployment
7
THE PROBLEM• Continuous deployment
• Easy maintenance of the deploy procedure.
8
THE PROBLEM• Continuous deployment
• Easy maintenance of the deploy procedure.
• Small learning curve.
9
THE PROBLEM• Continuous deployment
• Easy maintenance of the deploy procedure.
• Small learning curve.
• Reuse between projects with little effort.
10
WHAT IS A DEPLOY?Directory structure:
.
!"" releases | !"" 20140415234508 | #"" 20140415235146 !"" shared | !"" sessions | !"" source | #"" uploads #"" current -> releases/20140415235146
11
WHAT IS A DEPLOY?Directory structure:
.
!"" releases | !"" 20140415234508 | #"" 20140415235146 !"" shared | !"" sessions | !"" source | #"" uploads #"" current -> releases/20140415235146
12
WHAT IS A DEPLOY?1. Update the codebase + configuration
13
WHAT IS A DEPLOY?1. Update the codebase + configuration
2. Install dependencies
14
WHAT IS A DEPLOY?1. Update the codebase + configuration
2. Install dependencies
3. Preserve shared resources
15
WHAT IS A DEPLOY?1. Update the codebase + configuration
2. Install dependencies
3. Preserve shared resources
4. Build tasks
16
WHAT IS A DEPLOY?1. Update the codebase + configuration
2. Install dependencies
3. Preserve shared resources
4. Build tasks
5. Finalize
17
THE ROLE
18
https://galaxy.ansible.com/list#/roles/732project_deploy
GETTING THE ROLEInstallation 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
ROLE WALKTHROUGH---
- name: Initialize
deploy_helper: "path={{ project_root }} state=present"
20
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
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
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'
23
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
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
1. UPDATE THE 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
1. UPDATE THE 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
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
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
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
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"
5. FINALIZE- name: Finalize the deploy deploy_helper: path={{ project_root }}
release={{ deploy_helper.new_release }}
state=finalize when: project_finalize
32
33
IT’S NOT COMPLICATED!• Only 98 lines
• Number of tasks: 22
• Variables to configure: 28
34
MINIMAL PLAYBOOK
1. Set minimum variables
2. Add the role to “roles” section
35
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
36
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
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
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
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
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
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
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
WHAT DOESN’T IT DO?
44
• Rollbacks (the cake rollback is a lie)
WHAT DOESN’T IT DO?
45
• Rollbacks
• Set maintenance mode
(the cake rollback is a lie)
WHAT DOESN’T IT DO?
46
• Rollbacks
• Set maintenance mode
• DB migrations
(the cake rollback is a lie)
WHAT’S NEXT?
47
• Injecting your own tasks in addition to commands
WHAT’S NEXT?
48
• Injecting your own tasks in addition to commands
• Copy vendor folders from previous release ✓
WHAT’S NEXT?
49
• Injecting your own tasks in addition to commands
• Copy vendor folders from previous release
• Setfacl support
✓
WHAT’S NEXT?
50
• Injecting your own tasks in addition to commands
• Copy vendor folders from previous release
• Setfacl support
• Your ideas?
✓
THANK YOU!
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/