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 SubscribeI just got great great news from our investors: the cows are practical stampeding to our site. They're watching our workout videos in herds. They're crying for mooooore!
Ahem.
But now, our site is starting to have issues! We need to go from one server to multiple. And guess what? We've already done most of the hard work to do this! Congrats!
Ready to make it happen? First, find your local terminal and use the aws.yml
playbook to create a new EC2 instance:
ansible-playbook ./ansible/aws.yml -i ./ansible/hosts.ini --ask-vault-pass
This should only take a few second while it boots the server and waits for it to become available. Perfect!
So why is it so easy to deploy to multiple servers? Because we've done everything via playbooks, and Ansible is built to work on many servers. Copy the public IP of the new server and open your ansible/hosts.ini
file. Under the aws
group, paste the new IP:
... lines 1 - 6 | |
[aws] | |
54.80.32.36 | |
54.81.150.15 | |
... lines 10 - 14 |
Now, provision both servers by using the playbook.yml
file. Add -l aws
so we only provision those hosts:
ansible-playbook ./ansible/playbook.yml -i ./ansible/hosts.ini --ask-vault-pass -l aws
This won't make many changes to our existing server, but it will do everything to the new one. Translation... this may take awhile...
Tip
To speed things up, you could use your playbook to provision a server, and then create a custom image (AMI). For new servers, you can then boot from this image, to nearly-instantly get a provisioned server.
Oh, and you may have noticed that I hardcoded the IP address in my hosts.ini
file:
... lines 1 - 6 | |
[aws] | |
54.80.32.36 | |
54.81.150.15 | |
... lines 10 - 14 |
For a truly scalable architecture, you can use Ansible's Dynamic inventory, which works extremely well with EC2. You could, for example, use it to automatically use all EC2 instances with a specific tag.
Once the provision... finally... finishes.... let's deploy! Use deploy.yml
:
ansible-playbook ./ansible/deploy.yml -i ./ansible/hosts.ini --ask-vault-pass
While that works, we need to talk about a few interesting things.
First, if you write the number pi to 2 decimal places, it spells the word pie backwards! Super interesting!
Second, Google for "Ansible serial" to find a spot on their docs called "Delegation, Rolling Updates, and Local Actions". On your playbook, Ansible allows you to set a serial
option. If you have many servers, like 100, then if serial
is set to 3, Ansible will deploy to only 3 servers at a time. The effect is a rolling deploy: your updated code reaches your 100 servers little-by-little. That's overkill for MooTube... well, at least today! But, it is a cool feature!
One possible issue with a rolling update involves the release directory name. You guys already know that each release is in a timestamped directory. In a serial deploy, that timestamp will be different on earlier servers versus later servers. For our app, that's no problem! But, if you used the directory name as part of some cache keys - like many apps do - then this would be a problem: different servers would be using different cache keys to get the same data.
In the Ansistrano docs, if you search for "serial", they mention this. By setting a variable, you can control the release directory name and make sure it's the same on all servers.
Look back at the deploy. The database migrations just ran: for the first server, it reported "OK", because there were no migrations to run. But the second server did have migrations to run.
Wait... that's kinda weird... shouldn't all servers use the same database? Yep! There are a few things you need to do in order to be ready for multiple servers. The most obvious is that all your servers need to use the same database, or database cluster. For MooTube.com, each app is using their own local database. We're not going to fix that, but you do need to fix this in real life. The other really common thing you need to change is session storage: instead of storing sessions locally, you need store them in a shared place, like the database. In fact, that's the rule: when you have multiple servers, never store anything locally, except for temporary files or cache that help your code actually function.
But wait... if all our servers shared one database... there would still be a problem! Every server would try to execute the migrations. That means that the same migration scripts would execute multiple times. Oh no!
Back in the Ansible docs, there is an option called run_once
to fix this. It's pretty simple: if this is set, the task only runs on one server.
Ok! We are now deployed to both servers. Right now, mootube.example.com
points directly to the original server. Copy the IP address to the new server. Then, open /etc/hosts
and change mootube.example.com
to point to that:
# /etc/hosts
# ...
#54.80.32.36 mootube.example.com
54.81.150.15 mootube.example.com
To test it, open a new Incognito Window to avoid caching and visit mootube.example.com
. It works! Yes! We did not load the fixtures on the new server... which means we have a convenient way to know which server is being hit.
So, if you're using a playbook for provision and deploy, using multiple servers isn't a big deal. You will need to update your code a little bit - like to share session data - but almost everything is the same.
Next, let's go a step further and add a load balancer!
Hey Omar,
We're sorry for this! I just fixed this, now the videos are playable for me. Thank you for reporting this! Please, let us know if you still can't play them.
Cheers!
Thanks!
Sure no problem, I check the videos and now i can play them 👍...
And before the fix having the option to download videos is great to sort this kind of things.
Hey Omar,
Ah, yeah, download is always a good fallback option in case of any issues to play the video on the website, good catch! :)
And thanks for confirming it works for you now!
Cheers!
Hello guys,
Is there a way to deploy a symfony app using containers? I normally deploy them using a normal EC2 server but now I have this requirement from one member of our team. I don't know much about this type of architecture but I think I would need to split my app in microservices.
I hope you can give me some tip.
Cesar
Hey Cesar!
Sorry for the slow reply! Unfortunately, I can't offer much specific guidance about Docker & containers (we use Docker a bit locally, but not on production). But I can offer you two things:
1) API Platform ships with full Docker support and they have information about deployment with Docker. I'm not saying you should use API Platform (you can, but that's not the point) - just that they have a nice guide that might be relevant to you - https://api-platform.com/do...
2) Here at SymfonyCasts, we have 3 micro-services that support our main application. We deploy all of this via SymfonyCloud, which we love. It uses containers behind the scenes, but most/all of the complexity is abstracted away from us :).
Good luck!
Yes! It's on our list, but we don't have a timeline yet (which means it's not in the top few tutorials on our list). However, I'd be happy to answer questions about it if you have them :).
Cheers!
// 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
Hi SymfonyCast Team:
Videos on chapter 20 and 21, cann't be played, HD or SD
404 Not Found
https://player.vimeo.com/ex...
https://player.vimeo.com/ex...
Regards