From WAMP to Docker, simply

2021-04-14 | 799 words

Motivation

Whenever we onboard a new developer to ExitShop, the biggest challenge is setting up the system locally, typically on some WAMP (Xampp, Neard…). Usually, it involves three steps:

  1. Clone the repository
  2. Upload unversioned files (configs and some default user data - images, etc.)
  3. Import databases

In the meantime, about a hundred things can go wrong:

  1. The developer won’t have the required PHP extension.
  2. They will have a different PHP version than on production.
  3. They will have PHP misconfigured.
  4. (Points 1-3 apply separately to each component of your stack.)
  5. They won’t know (or be willing) to set up virtual hosts.
  6. They won’t know (or be willing) to set up a local SSL certificate.
  7. They won’t know (or be willing) to install additional services like Redis, memcached, fake SMTP server, …

Solution - unifying the development environment

Regarding the operating system and services, that is. Of course, you can continue developing in your favorite programs. Docker has been running smoothly under Windows for some time now, so there won’t be any problem in your OS either.

Practical example - converting a PHP and MySQL application from WAMP to Docker

Imagine you have an application running on a specific PHP version, for example, 8. You will want Apache and MariaDB, and the whole thing will run on Debian.

First, install Docker Desktop.

Take the sources from WAMP and copy them somewhere else, for example, to C:\Docker\myapp.

You can turn off WAMP, but keep it in the system. You don’t have to Dockerize every application right away, and these two systems can coexist peacefully.

Dockerfile

This is the main file, put it in the root of the application, version it, but don’t upload it to production :)

Here’s an example right away. On the first line, we define which image we want to use. I chose this one, which combines Debian Buster, Apache, and PHP version 8.0.3.

FROM php:8.0.3-apache-buster

copy apache vhosts

COPY docker-config/000-default.conf /etc/apache2/sites-available/000-default.conf

copy our changes to php.ini

COPY docker-config/my-php.ini /usr/local/etc/php/conf.d/my-php.ini

update

RUN apt-get update

install PHP extension

RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli

example of installing a program from a deb package

RUN apt-get install -y wget RUN wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_amd64.deb RUN apt install -y ./wkhtmltox_0.12.6-1.buster_amd64.deb

enable apache modules

RUN a2enmod rewrite

Next is copying virtual hosts. An example of such a file is below. Note that path. Even though we’re on Windows, we define paths on the chosen OS (Debian).

<VirtualHost *:80> DocumentRoot “/var/www/html” ServerName myapp.test ServerAlias www.myapp.test

<Directory "/var/www/html">
    Options Indexes FollowSymLinks MultiViews
    AllowOverride all
</Directory>

Next is copying changes compared to the default php.ini file. It could be a higher memory limit, for example.

Then we run an update to have new versions when installing packages. We can install packages as we’re used to on Linux - from repositories or .deb packages. We can cleverly install PHP extensions via docker-php-ext-install XX.

That should be our Dockerfile, defining our container.

docker-compose.yml

This file allows us to combine multiple services into one unit. Put it in the root of the application, version it, but don’t upload it to production :)

version: ‘3.8’

services: web: image: php:8.0.3-apache-buster ports: - ‘80:80’ volumes: - .:/var/www/html/ build: . links: - db extra_hosts: - “myapp.test:127.0.0.1” hostname: myapp.test

db: image: mariadb:10.3.23 restart: ‘always’ ports: - “3306:3306” volumes: - ./docker-config/databases:/docker-entrypoint-initdb.d environment: MYSQL_ROOT_PASSWORD: password

adminer: image: adminer restart: always ports: - 8080:8080

In the example, we see three services. The first is a web server, which we practically configured above. We set the ports it should run on, the hostname, and a volume - where our project should connect in that Debian.

The next service is the database - we choose an image, set the ports, in the volumes section, we can specify the path to the directory (docker-config/databases) where we have the DB structure in SQL files - this will load the DB when we first build the container. And also the root password for the DB.

Note the next service - Adminer. It will run on port 8080, so localhost:8080. Adding more services is that simple.

Let’s do it

We have it prepared. We run this command. The images will be downloaded, their installation will be performed, and the commands in our Dockerfile will be executed - installing packages, etc.

docker-compose build

And now we run it all:

docker-compose up

And it should work :)

You can also start containers from the Docker Desktop GUI:

Is it worth it?

Yes, for larger applications you work on daily, in a team, or that have more specific configuration or service requirements, it is definitely worth it.

But you don’t have to Dockerize everything