Local environments can be tough. I want anyone on my team to be able to pull down a project repository and get started without worrying about environmental differences. Like many, I resisted Docker due to the frustration of always "having to learn one more &$#*ing thing?!". I started diving into Docker a year ago and haven't looked back. There is a learning curve, it's different, and you will find yourself wondering "how do I do this with Docker?!" (a lot). But the more I have learned, the more I am certain it is worth the hype. Containers give us the promise of a better and more controlled infrastructure. One that is more isolated, portable, and disposable. Let’s dive in and take a look at how we have bootstrapped our local development with Docker at Flipbox Digital.
When you install Docker for Mac or Windows (via Docker Desktop), Docker is installed with other tools like Docker Compose. Docker Compose makes it easy to build your stack. Take a look at the following docker-compose.yml file:
version: '3' services: web: image: 'flipbox/php:72-apache' ports: - '80:80' - '443:443' volumes: - '.:/var/www/html/' environment: ENVIRONMENT: dev DB_SERVER: db DB_USER: craft DB_PASSWORD: craft DB_DATABASE: craft XDEBUG_ON: "yes" XDEBUG_HOST: "host.docker.internal" XDEBUG_IDEKEY: "PHPSTORM" APACHE_DOCUMENT_ROOT: "/var/www/html/web" db: image: 'mysql:5.7' restart: always ports: - '3306:3306' environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: craft MYSQL_USER: craft MYSQL_PASSWORD: craft
We place this file within the root of our Craft CMS project repository. Let's break down this configuration.
Above we have a 'web' and 'db' service. This is our stack so when we start the containers, we can reference them by those names, 'web' and 'db'. Docker creates a network and assigns the service names as hostnames. This is handy when we are pointing Craft CMS (the "web" container) to MySQL or Postgres (the "db" container). We use 'db' as the server hostname instead something like localhost.
We define our image here which points to a remote repository. Our PHP image extends the latest PHP 7.2 Apache image from the official PHP Docker Hub. Our code for building the image is open source and on our GitHub.
Docker has a ton of support. Almost any image you can think of is available: Redis, Memcached, Postgres, DynamoDB, and many more. Images can have some really cool features baked in as well. A good tip is to look at their environmental variables to see what you can use to easily customize the running container.
We have control over exposing ports and mapping them to our host (which with local development, is our localhost). I want to be able to connect to the MySQL database using Sequel Pro, so we expose port '3306' and map it to '3306', our localhost. Since we are mapping ports like 3306 and 80 to localhost, this can present a port conflict if something else is running on one of those ports. Make sure to shutdown any other projects running containers or local servers using those ports.
Examining the configuration for volumes is straight forward. Volumes are configured by setting the source path on your host (your computer) to the destination path on the container. We use volumes heavily in local development so we can share our code with the container while developing it. If you have a large codebase, you may see issues with performance on MacOS and presumably Windows as well. On Mac and Windows, Docker runs a virtual machine to run the containers in Linux and sharing those files can be expensive. This is just something to be aware of. It's not the end of the world. There are complicated solutions so go crazy if you feel it's worth the effort.
#Check on your mac sudo lsof -i tcp:3306 #Check if docker containers are using the port docker ps
To reiterate, we place this file within our project repo and run
docker-compose up. The "up" command pulls the images from the docker repository and starts the services. Since a container is only responsible for one process, you will see any logging the process returns. In this case you'll see MySQL and Apache logging.
#Starting for the first time or updating any image or configuration changes docker-compose up #OR docker-compose up -d #daemon mode #You can run `start` thereafter docker-compose start
The stack is now running! To check your web server go to http://localhost and to connect to the database through your preferred client, point to localhost and port 3306 (when using the configuration above). If you ran
docker-compose up and are done with the stack, Ctrl+C to kill the running containers. To verify the services aren't still running, run
docker-compose ps and viewing the "State" column, which will look for the docker-compose.yml configuration within your current directory. Furthermore, running containers can be checked globally by executing a
docker ps. If you have a stubborn container that is running when it shouldn't or you are too lazy to change directories and stop containers gracefully, grab the container id with
docker ps and run
docker kill <container id>.
#vim /etc/hosts 127.0.0.1 local.best-client-ever.com
Check out our Docker image and Dockerfile within our Github repository. Engage with us on social media at @flipboxdigital and @dsmrt. Let us know how you are working with Docker and what else you'd like us to discuss.