Symfony + Docker: My Journey So Far

Please note: This is a copy of my weekly email message. Please feel free to join the mailing list (the form is on the sidebar <<<) if you like this kind of thing. No pressure, it’s cool 🙂

I want to start by saying a huge thank you to everyone who replied to last week’s email. I was very grateful of each and every one of your replies, and want to reassure everyone: the Symfony tutorials will continue 😀

Over the next few weeks I will touch on this feedback a little more, as it has led to some interesting changes in the way I am thinking about the site.

Again, thank you, I really do appreciate and value your feedback.

I did something I was reluctant to do this week: I started playing with Docker.

This isn’t the first time I’ve had a bash with it. I tried it in late 2014 when I first became aware of it. This was around version 1.3, as best I recall. The reliance on the CLI – many of the commands being long and unwieldy – completely put me off.

I put it down almost as quickly as I’d picked it up. New and shiny, maybe, but confusing as heck.

Fast forward a year and I was on site with a FTSE 250 company who were spinning up a big docker swarm. Based on my in-depth research (read: 2 hours cursing followed by giving up) only a year earlier, I thought they must be mad. But hey, if big businesses were giving this a shot, then maybe there must be something too it, right?

So I picked it back up, and had another go. Everything was roughly as I remembered it. I still didn’t gel with the CLI.

However, there was now a new way of working with Docker: docker-compose.

The benefit of docker-compose being that you can have a single config file which manages the creation of many docker containers. Awesome! Given that I had no understanding of building one container, being able to spin up many containers couldn’t possibly go wrong.

Anyway, I persisted somewhat but I kept hitting on hurdles. Figuring out how to get Symfony’s cache and log permissions to work was frustrating me. There weren’t that many blog posts or tutorials to be found, and given that Ansible was working just fine for me, I once again consigned docker to the “not ready for me yet” pile.

If docker had gone away at this point, I can’t say I would have missed it. I really didn’t get the hype.

Now, whilst all this was happening, GitLab released version 8.0.

One of the very coolest features in GitLab 8.0 was their integration with GitLab CI (Continuous Integration). I watched the release video and I thought – oh my lord, I need me some of that! (https://about.gitlab.com/2015/09/22/gitlab-8-0-released/)

I absolutely love GitLab. It’s probably my single most used tool on any given day. The idea of being able to commit my code and have it spin up an environment that matches my dev / live setup, and then run my test suite for each commit?! What is this magic?

Alas, in reality this was not quite as easy as they made it look / sound.

A lot of this was due to the way I was working. I heavily used Ansible. And GitLab heavily expected me to be using Docker.

Undeterred, I spent night after night hacking away until I figured out how to make GitLab CI runner work with VirtualBox. Then, because this entire process was such a massive pain in the backside, I documented it all and video’d it (https://codereviewvideos.com/course/your-own-private-github/video/how-to-use-virtualbox-as-a-gitlab-ci-test-runner). I had suffered so much I hoped others would never have too.

But it griped me. This process was painful. If things changed in my environment – which they inevitably always do – I would need to build a new image, copy that over to my runner, test it all out… testing the test runners… how deep does this rabbit hole go?

What frustrated me most was that when this process works, it is incredible.

The alternative was to use Docker. In doing so, GitLab could spin up containers as needed and remove all of this pain. The caveat to this would be changing my entire development workflow. And I was so invested in Ansible this was incredibly unappealing.

Once more, I consigned docker to the “cool, but not for me just yet” pile.

Then GitLab dun’ did it again.

https://about.gitlab.com/2017/03/22/gitlab-9-0-released/

I urge you to watch the release video and not think: GIMME GIMME GIMME!

Now, I watched this video on Wednesday dinner time. Shortly thereafter I had to do a major production deploy involving Symfony, RabbitMQ, LetsEncrypt, Redis, MySQL, Node JS with PM2, a raft of cron jobs… and that’s just what I remember without looking into the Ansible configs more deeply.

The idea is simple – run a single command and let Ansible deploy all this stuff, reliably and in a managed fashion.

In (my) reality, most any new build involves some nightmare. For example, in dev you don’t need to worry about SSL. In prod, you do. This is not part of your dev Ansible scripts so manages to cause a few hours of headscratching whilst the dev / prod environments are integrated. Often this involves commenting out part of a script, running the first script, uncommenting out that part, and running another script. Reliable? Reproducible? Hmmm.

Then what about RabbitMQ in production? It needs to be protected with SSL. How does this fit into the config for LetsEncrypt… more hours lost.

And so on. I know many of these problems are specific to the way I work. But I am 100% convinced I’m not the only one who ends up in situations like this.

Anyway, I rage quit.

Deploying this stack can wait. Fortunately it’s important, but not urgent.

During all this time I couldn’t help but be seduced – once more – by the allure of docker, and GitLab’s one click easy deploys.

So this time I set myself a goal. I would take my entire Ansible orchestrated stack for this complex environment, and I would docker-ise it.

At this point I wish I could say the CLI issues had gone away. They haven’t. But this time I spent most of Thursday morning with my head in the Docker documentation. Then I started implementing a super basic config from scratch.

From there, I composed a few containers, and suddenly, it started to make sense.

I hit on a whole range of issues getting Symfony to work with Docker though. Permissions, but of course. Cache and Logs, the two Symfony stalwarts. But I’m past that now. And amazingly, it’s insanely quick. Like 1ms page renders quick.

I still have some way to go with this. And I’ve not started integrating with GitLab CI at all just yet. But there is major promise there.

Hopefully within the next week or so I will be able to share my docker scripts. There’s likely ways to improve on these yet. Still, it’s highly exciting.

With all this in mind, I would be super interested in hearing from you if you have put Docker + Symfony into production. That seems like the next major hurdle.

If you have any Docker experience – good, bad, or otherwise – please do hit reply and let me know. I’m particularly interested in those unexpected pitfalls I just know are out there, and would definitely appreciate a heads up if you are aware of any.

Video Update

This week there have been three new videos added to the site.

https://codereviewvideos.com/course/react-redux-and-redux-saga-with-symfony-3/video/change-password-part-6-avoid-blocking-and-wrap-up

Firstly we finished up the “Change Password” implementation.

On the surface, it may seem a little crazy to have 6 videos covering how to accept a user’s password change form submission. After all, this is only the front end, right? We have another two videos (https://codereviewvideos.com/course/fosuser-fosrest-lexikjwt-user-login-registration-api/video/password-management-change-password-part-1) covering how to do this on the back end!

Well, the first time you do anything like this you inevitably have to lay a whole bunch of foundations. All of these foundations make subsequent work much faster.

An example of this would be in how we can now process Symfony form errors on our front end. This will come in handy for any time we need to make a POST request – not just for changing passwords, but for registration, login, and any other Create / Update you do in your app.

Also, we extracted the repeated password fields out into their own separate component. This will allow us to re-use this component wherever we need to accept passwords – such as in the Registration screen, which is up next.

Finally, we looked at a way that Redux Saga provides for us to speed things up by allowing us to run many processes in parallel. When combined with our form error helper function, this becomes super useful should you have a form with many fields, just as one example.

https://codereviewvideos.com/course/symfony-workflow-component-tutorial/video/workflow-events-part-1

Next up we got an intro into the many events that Symfony’s Workflow Component dispatches for us during any single transition.

In case you haven’t been following along, a transition is when an object that’s flowing through our workflow goes from one place to another. These sorts of things happen all the time in our applications, even if we don’t have a formal process (or shiny Symfony component) to manage them.

In the example we have been working through, a potential customer (a prospect) can sign up with our system. When signing up, this potential customer goes through the transition of ‘sign up’. This takes them from the place of ‘prospect’ to the place of ‘free customer’.

As part of this transition, the workflow component dispatches a bunch of useful events. Each of these events can be hooked into, and if needed, some extra action can be taken. This might be as simple as logging some data out somewhere, but could be much more involved – potentially even triggering a whole different workflow.

This video is free for all, and explains when and where each of these events comes from.

https://codereviewvideos.com/course/symfony-workflow-component-tutorial/video/workflow-events-part-2-custom-audit-trail-listener

As part of the Workflow Component, a helpful utility class is included called the AuditTrailListener.

It’s got a bit of a computer science-y name, but the concept is simple enough: It listens for events, and then logs information about those events out to your Symfony log file.

In the previous video we saw just how many of these events are dispatched for every single transition.

What the provided AuditTrailListener cannot do is hook into some of the more unique events. However, we can implement our own version of this listener to capture as much information as we need. This also demonstrates exactly how you would listen to, and act upon any workflow event in your system.

How very handy! 🙂

Next week will see the final parts of the React, Redux, and Redux Saga With Symfony 3 course being uploaded. I’ve really enjoyed creating and sharing this course, and I hope you’ve found it useful too.

Until then, have a great weekend. Cross your fingers, we may even get some sunshine. Hey, that’s a big deal here in the UK 🙂

Published by

Code Review

CodeReviewVideos is a video training site helping software developers learn Symfony faster and easier.

2 thoughts on “Symfony + Docker: My Journey So Far”

  1. Well, I have tried Docker once and now I’m using Vagrant. 🙂
    It’s because I understand Vagrant approach better.
    My error with Docker was starting hard and not from a simple configuration. I tried to build a network with use of docker-compose and Consul. And I was overwhelmed in the end…

    With your video tutorial, I will give it a second chance.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.