Create a Docker virtual machine environment with a web-server and database
A virtual developer environment is a software environment that acts as a subsitute for a physical computer system, offering the same architectures and functionality. The main purpose of virtual machines is so that we can operate multiple operating systems (like Windows and Linux) on the same piece of hardware.
Vagrant and Virtualbox
Vagrant and VirtualBox are commonly recommended virtual developer environment tools. I use Docker instead because a co-worker mentioned that with Docker, if we want to upgrade MySQL then we can just upgrade it inside the MySQL container. Whereas if we were using Vagrant, then we might run into issues with the operating system when we set up Vagrant, like "Sorry, MySQL version is not compatible with this operating system".
Vagrant
Vagrant is a tool for building and distributing development environments. Vagrant lets us create and manage complete portable development environments over the command-line, via a configuration file. These development environments can live on your computer or in the cloud, and are portable between Windows, Mac OS X, and Linux.
We can install Vagrant on mac using Homebrew with this command: brew install --cask vagrant
VirtualBox allows you to run nearly any operating system on a single machine, and to freely switch between operating system instances running simultaneously.
VirtualBox
VirtualBox is a hosted hypervisor. A hypervisor abstracts virtual developer environments and the operating systems they run on from the actual hardware. They create a layer that seperates CPU/Processors, RAM and other physical resources from the virtual machines you create. Hosted means that VirtualBox requires an existing operating system to be installed.We can install VirtualBox on mac using Homebrew with this command: brew install --cask virtualbox
Docker
Docker allows us to package an application and its dependencies in a virtual container that can run on any Linux, Windows or MacOS computer. This lets us run the application across many locations, like on-site, or in a public or private cloud environment etc.
Each container is isolated from each other. They bundle their own software, libraries and configuration files, and can communicate with each other through channels that we define.
We can run many containers at the same time from a single virtual machine. We might use one container to store our web server and one for our database etc.
Install Docker
We can install Docker on mac using Homebrew with this command: brew install --cask docker
To check it's working, run the docker --version
command to check the version we've installed. When I first did this, it didn't recognise the docker
command. Searching for "Docker" on my Mac and running it manually prompted me for permissions. Once given I could use the docker command to check the version even with Docker turned off.
Start Docker
To start Docker, search for the Docker app on your computer and run it. You'll be prompted to enter your password. Once you entered it, Docker will start running, and you'll see a cute little whale icon carrying boxes in your toolbar.
Create a Docker Compose file with a web-server and database
A Docker compose file is a place to configure all of our application's services (containers), like a web server, a database and any other kind of application or service. Then we can create and start all of those services with a single command: docker-compose up
To create a Docker compose file, create a file with the name "docker-compose.yml" at the root of your project's directory.
Inside that file, add the following:
version: "3.8"
services:
nginx:
image: trafex/alpine-nginx-php7
ports:
- "8080:8080"
volumes:
- "./:/var/www/html"
networks:
- backend
mariadb:
image: mariadb:10.5
networks:
- backend
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=pwd
- MYSQL_USER=pwd
- MYSQL_PASSWORD=pwd
networks:
backend:
A line by line breakdown:
version: "3.8"
is the latest version of docker composeservices:
are the things we want to containerize, like our web-server, database, or a different application etc. Each service that we specify runs in it's own container.nginx
is the web-server we are going for, which is an alternative to Apache (part of the LAMP web stack).image: trafex/alpine-nginx-php
A Docker image is a read-only template that contains a set of instructions for creating a container. In this case, we are using an image from this Github repository which describes how to create our NGINX web server. A suggested going for an "alpine" NGINX image because of the smaller file size. We searched for "nginx alpine php", clicked on the repo that came up, checked the filesize of the image (38mb) and entered the repo name for the image.ports: "8080:8080"
The port before the colon is the port our computer listens on, whilst the port after the colon is the one the Virtual Machine listens on. The documentation for the trafex nginx repo said it should be "8080:80", but it didn't work. They're documentation hadn't been updated to explain that they'd changed the listening port to 8080 as well.volumes: "./:/var/www/html"
Volumes are directories or files that exist on the host filesystem, not the Docker image filesystem. The address we have specified says: Current directory (.), the split between the local directory and the directory on the image (:), the directory on the image (/var/www/html).networks:
A network is a communication channel. We can create a network that lets different containers communication with each other. In this case, we have created a network (communication channel) called "backend" - the name we give it doesn't matter. We also gave our database container the same network, which means they can communicate with each other. We declare the names of our networks at the end of the file too.mariadb:
Is the database service I decided to go with. Mariadb is the same as MySQL, but not owned by Oracle. People literally forked MySQL and renamed it MariaDB.- Image, networks, ports are the same thing explained above. We specified a different port for MariaDB to operate on to prevent a clash between it and our web server (NGINX).
environment:
Includes the environment variables for our database configuration, including our root password, database name, user name and password. We can choose what we want for each of these.