Docker at SmartWeb: How we ended up using Docker containers
By Daniel Fly, DevOps created on during Continuous Delivery, Development process

Disclaimer: This is my first blog post – bear with me. I promise to improve 😊
SmartWeb is growing and so is the system, number of employees and customers. The demand to move faster and be scalable is increasing. We are approx. 20 employees with 8 developers and 1600+ customers and counting. When growing you need to have more focus on not becoming a big, slow whale because you run the risk that the smaller fish might overtake you. To achieve this goal, development speed is the key component to staying ahead of these small fish. In this post, we will look at our local development environment and how it evolved.
I will approach this blog post from a DevOps perspective and look at what improvements were made on our journey towards faster development.
In the beginning – coding directly on the development webserver
Back in the day, there was no local development environment. The code was developed directly on the development server with SFTP and a Text editor (back then, we used NuSphere PhpED). This process forced us to: change a file, sync the file to the server, test it and then repeat the process over for all other files. Imagine the amount of coordination needed between two developers to be able to develop in this manner. Each developer had to know which files the other was working with to prevent introducing bugs into the system.
Here is an example of a conversation between 2 developers:
Developer 1 : “I’m editing important.php now…”
Developer 2 : “Okay, say when you are done. I need to add some to code to the same file…”
With only two developers working on the same files, this setup breaks down pretty fast. To make this process easier a versioning (SVN) service like GIT was added. One big downside to adding an SVN was the increased time for feedback when developing.
The previous process was:
Change a file, sync that file via SFTP (<1 sec), test it and repeat.
The process with SVN:
Change a file, commit this file to the versioning service (2-3 sec), test it and repeat.
Because the team was preventing one another from working efficiently, this caused some team-scaling problems. For example, If 2 developers had to develop new features in the same part of the system, one of these developers would have to postpone their feature development. This postponement was necessary because it was not possible for both of them to change the same sets of files at the same time.
Moving from coding directly on the development webserver to a local development environment
Our development process did not scale very well with the increasing amount of development tasks and developers in the SmartWeb system. This was the primary reason why we started the local development environment project.
This step required SmartWeb to run on local computers. Vagrant + Ansible were chosen for this task. Not long into the development process it became clear that our system was not designed to be hosted on a single VM (Virtual Machine). So, a lot of code changes were made to make it work locally – it turned out later that these code changes were a very important step because it made it a hell of a lot easier to move to containers.
The vagrant box was a significant improvement to our development speed. More people could work in the same areas of the system at the same time, we made less errors and the developing time was faster. As time progressed, it became clear that this was not the best approach for us:
- Virtual Box had poor performance when mounting file systems on Windows. This meant that Windows users were forced to use SFTP to sync their code changes to Virtual Box – this was better than before but the feedback was still too slow.
- A lot of things could go wrong when running the ansible setup script – this script was only used when new employee’s setup the environment for the first time or when an existing box needed reinstalling.
- It was unstable - sometimes it did not startup or some services did not start automatically. Sometimes the box even required re-installing.
- It was hard to add new services – this took too much time. In general it was not as flexible as we wanted it to be.
This created a lot of internal support issues and meant less time for development of new features.
The Vagrant project took 3 months with two developers working almost full time. Was it worth it – YES, because it prepared our application to be more portable and it was a lot easier to containerize . At the same time, we made significant improvements to our development environment.
Moving from Vagrant to Docker (containers) in 14 days
We needed a simpler, lightweight setup that was more stable. So, we started looking at Docker (containers). We found that containers give us the portability and encapsulation of services that we needed. Once we decided that Docker was the right setup for us, we started converting our local environment to containers. Converting to containers was made easier because all of the important steps had already been taken when we moved to Vagrant.
We ended up creating / using the following images.
smartweb/smartweb-apache-php extends smartweb/php:5.6-apache
This runs the apache-php service and contains apache configurations and entry scripts for some pre-initialization when starting up.
smartweb/php:5.6-apache extends php:5.6-apache
This runs an apache-php service and contains all our php module dependencies.
mysql/mysql-server:5.6
Raw image from https://hub.docker.com/r/mysql/mysql-server/ and the proper environment variables have been added to the config.
memcached:1.4
Raw image from https://hub.docker.com/_/memcached/
jwilder/nginx-proxy:alpine
Raw image from https://hub.docker.com/r/jwilder/nginx-proxy/
The above image ended up running our whole application. Using docker-compose for orchestration we could easily spin up and tear down the application locally. Just a simple docker-compose up and the whole of SmartWeb is running.
Later on we added nginx, php-fpm, phpmyadmin, tideways(profiling), memcached-dashboard and rabbitmq images.
smartweb/php:php-fpm extends php:5.6-fpm
This contains all of our php module dependences.
nginx:alpine
Raw image from https://hub.docker.com/_/nginx/
phpmyadmin/phpmyadmin
Raw image from https://hub.docker.com/r/phpmyadmin/phpmyadmin/
sazo/xhgui
Raw image from https://hub.docker.com/r/sazo/xhgui/
smartweb/phpmemcacheadmin
Raw image from https://hub.docker.com/r/smartweb/phpmemcacheadmin/
rabbitmq:3.6-management-alpine
Raw image from https://hub.docker.com/_/rabbitmq/
Architecture diagram for a request on our local environment
The advantages of containers
One of the best advantages of moving to containers was portability . Our goal is to be able to take any host provider, public cloud, private cloud or any place with computers and deploy our application in minutes. We hope that this portability will help us with our increasing number of customers outside of Denmark and the growing demands of our customers who want to be able to sell their products all around the world.
Docker containers seem to be a very good solution to help us meet our demands, they also give us the possibility to add multiple hosting locations in the future.
The red line - moving faster and keeping developers happy
Each step we take gets us one step closer to our goal of moving faster and delivering more value to the customer with as little friction as possible. The local development environment is important, you need a quick feedback loop and stability. It’s the same as when you build a house – if you don’t have the proper tooling and your drill needs recharging every 5 minutes – you lose the motivation and excitement to keep working.
Teaser for next blog post
In the next blog post, I will look at our deployment process and how we push our code to production. We went from manually looking at PR diffs and uploads via SFTP to a simple GIT pull and sync.
Links
Docker Hub: https://hub.docker.com/r/smartweb
GitHub: https://github.com/SmartWebDK
Bitbucket: https://bitbucket.org/smartwebdk/
Response