If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeIt's time to polish our deploy. Right now, you can surf to the /app_dev.php
script on production. You can't really access it... but that file should not be deployed.
Back on the Ansistrano docs, look at the workflow diagram. So far, we've been hooking into "After Symlink Shared", because that's when the site is basically functional but not yet live. To delete app_dev.php
, let's hook into "Before Symlink". It's basically the same, but this is the last opportunity to do something right before the deploy becomes live.
Scroll down to the variables section and copy ansistrano_before_symlink_tasks_file
. In deploy.yml
, paste that and set it to a new file: before-symlink.yml
:
- hosts: aws | |
... lines 3 - 14 | |
vars: | |
... lines 16 - 48 | |
# Hooks: custom tasks if you need them | |
... line 50 | |
ansistrano_before_symlink_tasks_file: "{{ playbook_dir }}/deploy/before-symlink.yml" | |
... lines 52 - 58 |
In the deploy/
directory, create that! We only need one new task: "Remove sensitive scripts from web/ dir". Use the file
module:
- name: Remove sensitive scripts from web/ dir | |
file: | |
... lines 4 - 9 |
For path
, first go back to deploy.yml
, create a new variable release_web_path
and set it to {{ ansistrano_release_path.stdout }}/web
:
- hosts: aws | |
... lines 3 - 14 | |
vars: | |
... lines 16 - 18 | |
release_web_path: "{{ ansistrano_release_path.stdout }}/web" | |
... lines 20 - 58 |
Copy that variable and get back to work! Set path
to {{ release_web_path }}/{{ item }}
:
- name: Remove sensitive scripts from web/ dir | |
file: | |
path: '{{ release_web_path }}/{{ item }}' | |
... lines 5 - 9 |
We're also going to delete this config.php
script:
/* | |
* ************** CAUTION ************** | |
* | |
* DO NOT EDIT THIS FILE as it will be overridden by Composer as part of | |
* the installation/update process. The original file resides in the | |
* SensioDistributionBundle. | |
* | |
* ************** CAUTION ************** | |
*/ | |
... lines 12 - 423 |
Set state
to absent
and add with_items
. Delete 2: app_dev.php
and config.php
:
- name: Remove sensitive scripts from web/ dir | |
file: | |
path: '{{ release_web_path }}/{{ item }}' | |
state: absent | |
with_items: | |
- app_dev.php | |
- config.php |
Oh, and since I never deployed my services.yml
change, let's commit these changes, push, and deploy to the cloud!
ansible-playbook ansible/deploy.yml -i ansible/hosts.ini --ask-vault-pass
While we're waiting, there is one thing that could break our deploy: GitHub rate limiting. If composer install
accesses the GitHub API too often, the great and powerful GitHub monster will kill our deploy! This shouldn't happen, thanks to Composer's caching, but it is possible.
Tip
Actually, a change made to Composer in 2016 effectively fixed the rate limiting problem. But the fix (GitHub OAuth token) we will show will allow you to install dependencies from private repositories.
Google for "Composer GitHub token" to find a spot on their troubleshooting docs called API rate limit and OAuth tokens. All we need to do is create a personal access token on GitHub and then run this command on the server. This will please and pacify the GitHub monster, and the rate limiting problem will be gone.
Click the Create link and then "Generate new token". Think of a clever name and give it repo
privileges.
Perfect! We could run the composer config
command manually on the server. But instead, let's do it in our provision playbook: ansible/playbook.yml
.
This is pretty easy... except that we probably don't want to hardcode my access token. Instead, we'll use the Ansible vault: a new vault just for playbook.yml
. As soon as the deploy finishes, create it:
ansible-vault create ansible/vars/provision_vault.yml
Use the normal beefpass
as the password. And then, add just one variable: vault_github_oauth_token
set to the new access token:
# ansible/vars/provision_vault.yml
vault_github_oauth_token: 146f9e4f876164866d5afd956843d9141c4c6c47
Save and close! Whenever I have a vault, I also like to create a simple variables file. Create provision_vars.yml
. And inside, set github_oauth_token
to vault_github_oauth_token
:
github_oauth_token: "{{ vault_github_oauth_token }}" |
Finally, in playbook.yml
, let's include these! Include ./vars/provision_vault.yml
and then ./vars/provision_vars.yml
:
- hosts: webserver | |
vars_files: | |
- ./vars/provision_vault.yml | |
- ./vars/provision_vars.yml | |
- ./vars/vars.yml | |
... lines 8 - 182 |
We now have access to the github_oauth_token
variable.
We have a few tasks that install the Composer executable:
- hosts: webserver | |
... lines 3 - 35 | |
tasks: | |
... lines 37 - 100 | |
- name: Check for Composer | |
stat: | |
path: /usr/local/bin/composer | |
register: composer_stat | |
- name: Download Composer | |
script: scripts/install_composer.sh | |
when: not composer_stat.stat.exists | |
- name: Move Composer globally | |
become: true | |
command: mv composer.phar /usr/local/bin/composer | |
when: not composer_stat.stat.exists | |
- name: Set permissions on Composer | |
become: true | |
file: | |
path: /usr/local/bin/composer | |
mode: "a+x" | |
- name: Make sure Composer is at its latest version | |
composer: | |
working_dir: "/home/{{ ansible_user }}" | |
command: self-update | |
register: composer_self_update | |
changed_when: "not composer_self_update.stdout|search('You are already using composer version')" | |
... lines 127 - 182 |
After those, create a new one: "Set GitHub OAuth token for Composer". Use the composer
module and set command
to config
:
- hosts: webserver | |
... lines 3 - 35 | |
tasks: | |
... lines 37 - 100 | |
- name: Check for Composer | |
stat: | |
path: /usr/local/bin/composer | |
register: composer_stat | |
- name: Download Composer | |
script: scripts/install_composer.sh | |
when: not composer_stat.stat.exists | |
- name: Move Composer globally | |
become: true | |
command: mv composer.phar /usr/local/bin/composer | |
when: not composer_stat.stat.exists | |
- name: Set permissions on Composer | |
become: true | |
file: | |
path: /usr/local/bin/composer | |
mode: "a+x" | |
- name: Make sure Composer is at its latest version | |
composer: | |
working_dir: "/home/{{ ansible_user }}" | |
command: self-update | |
register: composer_self_update | |
changed_when: "not composer_self_update.stdout|search('You are already using composer version')" | |
- name: Set GitHub OAuth token for Composer | |
composer: | |
command: config | |
... lines 131 - 182 |
The docs show the full command we need. Copy the arguments and set arguments
to that string. Replace the <oauthtoken>
part with {{ github_oauth_token }}
:
- hosts: webserver | |
... lines 3 - 35 | |
tasks: | |
... lines 37 - 127 | |
- name: Set GitHub OAuth token for Composer | |
composer: | |
command: config | |
arguments: '-g github-oauth.github.com "{{ github_oauth_token }}"' | |
... lines 132 - 182 |
Also set working_dir
to /home/{{ ansible_user }}
... the composer
module requires this to be set. And at the end, add a tag: github_oauth
:
- hosts: webserver | |
... lines 3 - 35 | |
tasks: | |
... lines 37 - 127 | |
- name: Set GitHub OAuth token for Composer | |
composer: | |
command: config | |
arguments: '-g github-oauth.github.com "{{ github_oauth_token }}"' | |
working_dir: "/home/{{ ansible_user }}" | |
tags: | |
- github_oauth | |
... lines 135 - 182 |
Why the tag? Because I really don't want to re-run my entire provision playbook just for this task. Translation: I'm being lazy! Run the provision playbook, but with an extra -t github_oauth
, just this one time:
ansible-playbook ansible/playbook.yml -i ansible/hosts.ini --ask-vault-pass -l aws -t github_oauth
Use beefpass
! Great! So... is this working?
On GitHub, you can see that the token has never been used. When we deploy, composer install
should now use it. But first, back on the server, run composer clear-cache
:
composer clear-cache
to make sure it actually makes some API requests and doesn't just load everything from cache.
Now, deploy!
ansible-playbook ansible/deploy.yml -i ansible/hosts.ini --ask-vault-pass
As soon as this executes the "Composer install" task, our access key should be used. There it is... and yes! The key was used within the last week. Now we will never have rate limiting issues.
"Houston: no signs of life"
Start the conversation!
// composer.json
{
"require": {
"php": ">=5.5.9",
"doctrine/doctrine-bundle": "^1.6", // 1.6.8
"doctrine/orm": "^2.5", // v2.7.2
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"sensio/distribution-bundle": "^5.0.19", // v5.0.20
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.26
"symfony/monolog-bundle": "^3.1.0", // v3.1.0
"symfony/polyfill-apcu": "^1.0", // v1.4.0
"symfony/swiftmailer-bundle": "^2.3.10", // v2.6.3
"symfony/symfony": "3.3.*", // v3.3.5
"twig/twig": "^1.0||^2.0", // v1.34.4
"doctrine/doctrine-migrations-bundle": "^1.2", // v1.2.1
"predis/predis": "^1.1", // v1.1.1
"composer/package-versions-deprecated": "^1.11" // 1.11.99
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.1.6
"symfony/phpunit-bridge": "^3.0", // v3.3.5
"doctrine/data-fixtures": "^1.1", // 1.3.3
"hautelook/alice-bundle": "^1.3" // v1.4.1
}
}
# ansible/requirements.yml
-
src: DavidWittman.redis
version: 1.2.4
-
src: ansistrano.deploy
version: 2.7.0
-
src: ansistrano.rollback
version: 2.0.1