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 SubscribeLook back at the Symfony Deployment article: we now have a parameters file! Woo! Next, we need to run composer install
- which was the original reason the site didn't work - and then warm up the Symfony cache. We're really close to a functional site. We won't need to dump the Assetic assets - we're not using Assetic. But we will need to do some asset processing later.
Let's add a new task to run composer
install. In the hook file, add "Install Composer deps". Use the composer
module and tell it to run the install
command. We also need to set the working_dir
: use {{ ansistrano_release_path.stdout }}
:
- name: Set up infrastructure-related parameters | |
... lines 3 - 6 | |
- name: Install Composer dependencies | |
composer: | |
command: install | |
working_dir: '{{ ansistrano_release_path.stdout }}' |
Perfect! One gotcha with the composer
module is that, by default, it runs composer install --no-dev
. That means that your require-dev
dependencies in composer.json
will not be downloaded:
{ | |
... lines 2 - 30 | |
"require-dev": { | |
"sensio/generator-bundle": "^3.0", | |
"symfony/phpunit-bridge": "^3.0", | |
"doctrine/data-fixtures": "^1.1", | |
"hautelook/alice-bundle": "^1.3" | |
}, | |
... lines 38 - 69 | |
} |
For production, that's a good thing: it will give you a small performance boost. Just make sure that you're not relying on anything in those packages!
Also, in Symfony 3, if you use --no-dev
, then some of the post-install
Composer tasks will fail, because they need those dependencies. To fix that, we need to set an environment variable: SYMFONY_ENV=prod
.
No problem! In deploy.yml
, add a new key called environment
. And below, SYMFONY_ENV
set to prod
:
- hosts: aws | |
... lines 3 - 27 | |
environment: | |
SYMFONY_ENV: prod | |
... lines 30 - 33 |
Thanks to this, the Composer post-install tasks will not explode. And that's good... it's not great when your deployment explodes.
Oh, and important note: for this all to work, Composer must be already installed on your server. We did that in our provision playbook.
Before we try this, let's tackle one last thing: clearing the Symfony cache... which basically means running two console commands.
To make this easier, in deploy.yml
, add a new variable: release_console_path
. Copy the ansistrano_release_path.stdout
variable and paste it: {{ ansistrano_release_path.stdout }}/bin/console
:
- hosts: aws | |
... lines 3 - 14 | |
vars: | |
release_console_path: "{{ ansistrano_release_path.stdout }}/bin/console" | |
# Ansistrano vars | |
... lines 19 - 35 |
Cool! Back in the hook file, add a new task to clear the cache. Use the command
module to simply say {{ release_console_path }} cache:clear --no-warmup --env=prod
:
... lines 1 - 6 | |
- name: Install Composer dependencies | |
... lines 8 - 11 | |
- name: Clear the cache | |
command: '{{ release_console_path }} cache:clear --no-warmup --env=prod' | |
... lines 14 - 17 |
That's basically the command that you see in the docs.
If you're not familiar with the --no-warmup
flag, it's important. In Symfony 4, instead of running cache:clear
and expecting it to clear your cache and warm up your cache, cache:clear
will only clear your cache. Then, you should use cache:warmup
separately to warm it up. By passing --no-warmup
, we're imitating the Symfony 4 behavior so that we're ready.
Add the second task: "Warm up the Cache". Copy the command, but change it to just cache:warmup --env=prod
:
... lines 1 - 11 | |
- name: Clear the cache | |
command: '{{ release_console_path }} cache:clear --no-warmup --env=prod' | |
- name: Warm up the cache | |
command: '{{ release_console_path }} cache:warmup --env=prod' |
Now, technically, since the cache/
directory is not shared between deploys, we don't really need to run cache:clear
: it will always be empty at this point! But, I'll keep it.
Ok! Phew! I think we've done everything. Let's deploy! Find your local terminal and run the playbook:
ansible-playbook -i ansible/hosts.ini ansible/deploy.yml --ask-vault-pass
Use beefpass
as the vault password and deploy to master
. Then... wait impatiently! Someone fast forward, please!
Yes! No errors! On the server, move out of current/
and then back in. Check it out! Our vendor/
directory is filled with goodies!
Moment of truth: try the site again: mootube.example.com. Bah! It still doesn't work. Let's find out why. On the server, tail the log file:
sudo tail /var/log/nginx/mootube.example.com_error.log
Ooooh:
PHP Fatal error: The stream or file "var/logs/prod.log" could not be opened
Of course! We have permissions problems on the var/
directory! Fixing this is actually a very interesting topic. There is an easy way to fix this... and a more complex, but more secure way.
For now, let's use the simple way: I really want our app to work! Add a new task: "Setup directory permissions for var". Use the file
module. But, quickly, go back to deploy.yml
and make another variable: release_var_path
set to the same path {{ ansistrano_release_path.stdout }}/var
:
- hosts: aws | |
... lines 3 - 14 | |
vars: | |
release_console_path: "{{ ansistrano_release_path.stdout }}/bin/console" | |
release_var_path: "{{ ansistrano_release_path.stdout }}/var" | |
... lines 18 - 36 |
Now, back in after-symlink-shared.yml
, set the path to {{ release_var_path }}
, state
to directory
, mode
to 0777
and recurse: true
:
... lines 1 - 17 | |
- name: Setup directory permissions for var/ | |
file: | |
path: "{{ release_var_path }}" | |
state: directory | |
mode: 0777 | |
recurse: true |
On deploy, this will make sure that the directory exists and is set to 777. That's not the best option for security... but it should get things working!
Deploy one more time:
ansible-playbook -i ansible/hosts.ini ansible/deploy.yml --ask-vault-pass
Type beefpass
, deploy to master
... and watch the magic. I can see the new directory permissions task... and it finishes.
Refresh the site! Eureka! Yea, it's still a 500 error, but this comes from Symfony! Symfony is running! Change the URL to http://mootube.example.com/about
. It works! Yea, it's super ugly - we need to do some work with our assets - but it does work. The homepage is broken because our database isn't setup. But this static page proves our deploy is functional! Victory!
Now, let's smooth out the missing details... like the insecure permissions, the database and our assets... because this site is horrible to look at!
Hey Cesar
Have you tried to put that env var on .env
with a dummy value and then override it on .env.local
file?
Cheers!
In another project I currently use the ansistrano workflow (and I have tested this additionally with your finished downloaded version).
When I start to deploy I get this message:
An error occurred when executing the \"'cache:clear --no-warmup'\" command: \n PHP Fatal error: Uncaught Error: Class 'Liip\ImagineBundle\LiipImagineBundle' not found in /var/www/project/releases/20180123144814Z/app/AppKernel.php:23 Stack trace: #0 /var/www/project/releases/20180123144814Z/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(448): AppKernel->registerBundles()
In deploy.yml I set
environment:
SYMFONY_ENV: prod
In after-symlink-shared.yml:
- name: Clear the cache
command: "{{ release_console_path }} cache:clear --no-warmup --env=prod"
- name: Warm up the cache
command: "{{ release_console_path }} cache:warmup --env=prod"
In composer.json I add:
"require": {
"liip/imagine-bundle": "^1.9"
}
Can you please help me to get my deployment going? At this point after researching for hours I'm clueless what to do next.
Thank you very much :)
I manged it to install liip/imagine-bundle onto my ec2 server,
Installing jms/serializer-bundle (2.3.1): Loading from cache - Installing imagine/imagine (v0.7.1): Loading from cache - Installing liip/imagine-bundle (1.9.1): Loading from cache -
but now I get
[Symfony\\Component\\Config\\Exception\\FileLoaderLoadException] \n Class Doctrine\\Bundle\\FixturesBundle\\Fixture not found in /var/www/project/ \n releases/20180124103155Z/app/config/services.yml (which is being imported f \n rom \"/var/www/project/releases/20180124103155Z/app/config/config.yml\").
After digging into it, I used this approach: https://github.com/doctrine/DoctrineFixturesBundle/issues/225#issuecomment-352538507
If there is a better solution, please let me know.
Have a nice day,
Chris
Hey Chris!
I'm glad you figured out the first issue :). What was the fix? Your original code looked good to me, so I was also surprised that the bundle wasn't originally being installed on your server.
About your second issue, this is fascinating! I'm afraid that I caused this bug with the new DoctrineFixturesBundle system :). I've already added a comment on the issue you linked and created an issue on Symfony's main repository. Basically, I think we have a "bug", or a situation we hadn't thought of. But the solution is 100% fine. In fact, it's basically what the "fix" would do internally - so there's no downside to that fix, other than it's annoying that you need to write all that code :).
Cheers!
It's weird and to be honest I actually don't know what the problem was. It's pretty inconclusive for me how this problem could happen to me.
For the second problem it's nice to see that you are fixing this issue. Thanks for the fast reply. With it it's assured that this approach is valid and the error is not caused through a mistake of my own.
Many greetings and keep up the good work!
Chris
// 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
Hello guys:
I just upgrade my Symfony app to 4.3 version from 3.4. Everything is working in local but I have problems deploying by Ansistrano.
The task Install Composer dependencies is exploting and appears the message "Executing script cache:clear [KO]", Environment variable not found: \"DATABASE_URL\". But, I put that variable in a file .env.prod.local that I put in the ansistrano_release_path.stdout using the synchronize module of Ansible. Please, can you tell me any suggestion about how to fix this?
Thanks.
Cesar