Fork CMS comes with a Docker PHP development environment that facilitates running your website in a containerized environment.
Included is a
docker-compose-powered stack to get your Fork CMS PHP project up and running in no time, without the hassle of installing and configuring PHP yourself locally, like in a Vagrant box or in MAMP/WAMP. By default the containerized development environment comes with: * PHP 7.1 (with extensions GD2, pdo, zip, intl, … and XDebug) * Apache * MariaDB (latest)
Features: * Easy to set and start up a project (
docker-compose up). * Easily disposable stack (
docker-compose down). * Easily switch between PHP versions: 7.1, 7.2, … by editing the Dockerfile to fit your needs. * Easy to customize, e.g. add PHP extensions, with a simple edit to the
Dockerfile. * Clean and well structured Dockerfile * Simple configuration (single .env file) * All containers extend from an official, trusted base image. * Everything is visible and editable to fit your needs of the project. * Docker runtime independent (run it on Docker for Mac, VM, AWS…) * Any team member can quickly boot up your project because the Dockerfile and docker-compose files are added to your version control. * Easily add new containers to
docker-compose.yml to fit your project needs (only a few lines to add Redis, MongoDB, RabbitMQ…)
Docker is a platform that allows us to develop, ship and run applications. With Docker, you can manage your infrastructure in the same ways you manage your application.
Docker containers wrap up a piece of software in a complete filesystem that contains everything it needs to run: code, runtime, system tools, system libraries – anything you can install on a server. This guarantees that it will always run the same, regardless of the environment it is running in.
Docker has 3 important advantages:
The most important files in our containerized environment are
docker-compose.yml. You can find both in the Fork CMS root directory.
A very basic example of a
Dockerfile, found in the root, describes that we start from a “base image” (php+apache), typically found on the Docker Store. We add our project-specific configuration to this base image: additional php extensions, custom php.ini settings, Xdebug, installation of the composer dependencies, … This Dockerfile will be used to build a Docker “image” which is used to boot up the container.
docker-compose.ymlfile, found in the root, describes how our services work together. We only have 2 services: the app and the db service. In the
docker-compose.ymlfile, we specify that the app-service is linked and can communicate with the database, which ports we expose to our host machine, which environment variables are set inside the container, and which volumes get mounted from our host computer to the container.
So why use Docker and not Vagrant? While Vagrant creates a virtual machine in minutes, Docker creates virtual “containers” in seconds. Instead of providing a full VM like Vagrant does, Docker provides you with lightweight containers that share the same kernel and allow you to safely execute independent processes. This means that Docker uses only what it needs to run your application — nothing more. In addition to speed, Docker gives you a lot of features that cannot be achieved with Vagrant. The most important fact about Docker is that it can be used for development and on production, ensuring a consistent environment everywhere that bundles with the code you write. Vagrant is designed for development only, so a production server still needs to be provisioned every time.
Take a quick look at the differences between lightweight Docker containers and virtual machines:
While you can run and develop Fork CMS websites on a local webserver (WAMP, MAMP Pro even has Fork CMS integration), these local webservers are usually good as a “one size fits all” solution. If you occasionally create a website, using shared hosting, then WAMP/MAMP probably fits your needs. Nevertheless, Docker is definitely worth looking into!
The easiest way to run Docker containers on your computer is by installing Docker for Mac. For Windows-based systems, you can download Docker for Windows. If you’re a Linux user, you’re lucky because Docker is meant to run on Linux. Find the installation for your Linux distro on docker.com. E.g. Docker for Ubuntu.
After installing, you can run Docker. Make sure to visit the preferences and assign it a decent amount of CPU’s and memory (at least a few GB"s). While Docker is running, you can use commands such as
docker-compose in the terminal.
If this is an existing project, remove your
app/config/parameters.yml. This ensures that we can install a fresh copy and it won’t try to look for an existing database. You can import a database backup later.
Let’s see how easy it is to get Fork CMS up and running on PHP7, Apache and MariaDB.
git clone email@example.com:forkcms/forkcms.git
docker-compose up -d
This command will look at the
docker-compose.yml file and spin up a container for every service we defined (app and db). Wait for the containers to boot. The first time this can be slow because it needs to build the
Dockerfile container image. Once that’s done, starting and stopping the containers will be very fast. We start the containers with the option
-d to make sure they start in “detached” mode, which basically means that they’ll run in the background and our website won’t stop running when we quit the terminal.
docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------------------- forkcms_app_1 docker-php-entrypoint apac ... Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp forkcms_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp
You should see something similar appear: two containers are up and running. One container for the webserver/php and one for the database. Port 80, 443 and 3306 are exposed to our host machine. If one of the containers is down, you can inspect the logs by running:
docker-compose logs -f -t app or
docker-compose logs -f -t db.
You can easily use different credentials by adjusting them in the
docker-compose.yml file, but these are the default.
Video - watch how to setup PHPStorm and Xdebug
It’s easy to setup PHPStorm in combination with Docker and Xdebug, one of the most popular tools to debug your PHP application. In the
var/docker folder you will find a
.env file containing some defaults for Docker.
.envfile to add or change in some information for your system and configure XDebug. By default it contains a special hostname available for Docker for Mac users, but you can change it to point to your own Docker host IP.
docker-compose down docker-compose up -d
In PHPStorm’s preferences, go to “Build, Execution, Deployment > Docker”. Make sure you create a Docker configuration that connects to the Docker daemon “Docker for mac”.
We also need to configure PHPStorm to use the PHP interpreter that resides inside the app container. To do so, go to preferences to “Languages & Frameworks > PHP”. Click the “…” icon for the PHP interpreter. Create a new interpreter and use type “Docker”. Select the Docker for mac server you created, and the Docker image name for the project you’re working on. Make sure PHPStorm detects your php version correctly (see video above). Next, configure the Docker container by clicking the “…”, and fill in the Network mode with the value you find when running
docker network ls. Next, go to Volume bindings and make sure the container path is set to
/var/www/html. This is the path where our code lives inside the container.
Let’s configure Xdebug now. In PHPStorm’s preferences, go to the PHP > Debug section. Make sure Xdebug accepts connections and listens on port 9000 (should be default configuration). Go to DBGp Proxy and enter the following settings:
Optionally: Go to Languages & Frameworks > PHP > Servers. Make sure you have a server with a name that matches your
PHP_IDE_CONFIG key in
.env and make sure to map the project root path with the server correctly. Configuring a server is an optional step as the first time you put a breakpoint, turn on XDebug and visit your website, PHPStorm will detect the incoming connection and set up the server configuration automatically (see video above).
Place a breakpoint in your code, start listening for incoming debug connections by clicking the telephone icon . Now, open your browser and visit the page you want to debug and start debugging!
Because we inject
XDEBUG_CONFIG as environment variable (see docker-compose.yml), it’s also possible to debug Symfony commands. Simply put a breakpoint in your PHP command and run the command inside Docker:
$ docker-compose ps # View which containers are running $ docker-compose exec app bash # Go inside the Docker app container root@b50c9fefe23d:/var/www/html# bin/console forkcms:cache:clear # Run your command and PHPStorm will help you debug it.
Video - watch how to setup PHPStorm with PHPUnit
A few commands that you will definitely need:
|Start docker containers with logs||
|Start docker containers (detached mode)||
|List running containers||
|Close all running containers||
|Stop a single container||
|Delete all existing containers||
|Rebuild the docker containers (after modifying Dockerfile)||
|View the Log files||
|Run bash on a service container (think of SSH’ing)||
|Pull the latest image updates||
|List all the images you have installed||
|Remove unused images from your system. Great for saving space!||
|Remove unused volumes from your system. Great for saving space!||
|Remove unused containers, images, networks and volumes.||
* You can safely delete all containers, because your local PHP files are volume-mounted into the Docker container. You won’t lose your database either, as this data is stored in your project’s
/var/docker/db/data folder and gets mounted as a volume.
docker-compose psand verify that they’re up and running.
appcontainer and run the command:
# Bash into the container (think of SSH'ing but not quite like that) $ docker-compose exec app bash root@b50c9fefe23d:/var/www/html# bin/console forkcms:cache:clear # Or run the command with a oneliner $ docker-compose exec app composer install $ docker-compose exec app bin/console forkcms:cache:clear $ docker-compose exec app bin/console doctrine:schema:update --force $ docker-compose exec app composer test
ERROR: for forkcms_app_1 Cannot start service app: driver failed programming external connectivity on endpoint forkcms_app_1 (39e623f7a1b0f8361f3d14383f7c56af173e71282fae26495340eb1cdfa94de1): Error starting userland proxy: Bind for 0.0.0.0:80: unexpected error (Failure EADDRINUSE)
The Fork CMS containers run on port 80 and 3306. Check on your host machine if you don’t have another webserver running on port 80, or MySQL running on port 3306. Shutdown those services and try bringing your containers up again. If you want to specify a different port to run the containers, modify the exposed ports in
docker-compose.yml and change anything you want. Examples:
Change MySQL database name:
environment: - MYSQL_DATABASE=myprojectdatabase
Change the default Apache port from 80 to 8080 (format for ports is host:docker).
ports: - "8080:80"
Any change you do in the
docker-compose.yml file requires a restart of the containers. You can run
docker-compose up -d again and it will restart the changed container, or just run
Imagine that your project also needs a Redis key-value store, or a MongoDB, Elasticsearch, RabbitMQ, … With Docker, you can spin up a container with that software in seconds. Example: for Redis, simply add a new Docker service to your
redis: image: redis:latest ports: - "6379:6379"
And add a link to your
app service so PHP is allowed to communicate with the Redis container:
app: depends_on: - db - redis
Learn more about the docker-compose syntax on the official Docker documentation page
Edit the php+apache
Dockerfile in the root and add the needed
RUN commands to install the PHP extensions of your choice. PHP settings can be tweaked inside
var/docker/php/php.ini. Make sure you build the
Dockerfile to ensure that it has no errors, and then start up your containers again:
$ docker-compose build $ docker-compose up -d $ docker-compose exec app php -i # Check the phpinfo configuration to see that your extensions are active.
Choose a specific PHP version from the Docker store’s PHP base container, edit the
Dockerfile and change the
FROM statement to include a specific version of PHP as base image. Make sure to build the docker containers again using
You can use a MySQL client app such as Sequel Pro on Mac, or MySQL Workbench on Windows. If you’re using Docker for Mac/Windows, simply connect to 127.0.0.1 with port 3306. Use the credentials found in
Sharing code into Docker containers with osxfs has very poor performance compared to Linux. This is especially noticeable in PHP apps as they are not compiled and just interpreted at runtime from the mounted volume. There are some workarounds to speed up things, such as using docker-sync. Fork CMS implements User-guided caching which speeds up performance by 2.7 times.
More info about the issue here and here.
Make sure to take a look at the logs, using e.g.
docker-compose -f -t logs app for the application container. It might be that you see a “address already in use” or “port is already allocated” error. In that case, make sure the ports for the services you are trying to run (80, 3306) are not being used by other programs on the host, such as the built-in apache/httpd service on mac, or maybe MAMP server is still running on port 80?
The default Fork CMS docker containers are not recommended to use in production. One would have to remove devtools (Xdebug), tweak PHP.ini settings, etc. Interested in deploying Docker containers to production? Check out Docker Swarm, Kubernetes, Dokku, or Apache Mesos.