Develop, Dockerize & Deploy Contao 4: Part 2
Learn how to start a local development container and manage your source code via GitLab.
In the last part I walked you through the steps to set up your development environment and how to build our container for the first time. This time we are setting up a container for local development purposes and see how we can utilize Git & GitLab.com to manage our source code.
A local development container
To avoid having to build our container every time we change our code, we will build a local development container to which we directly mount our source directory. Furthermore we will spin up a MariaDB-Container to serve as our MySQL server. To do all of this with one simple command, we will be using Docker Compose, a tool to create and manage a complete stack of containers including volumes and Docker networking.
Thinking back to the last article where we explored which containers and volumes we need, we can derive the components we need for local development:
- Our PHP-Container with PHP and the Caddy Webserver
- A MySQL Container
- A volume for the MySQL data
- Our code inside the PHP container
Docker compose is controlled by a YAML file which contains the information on how to start the application container and what values those need. We start by creating one called ‘docker-compose_dev.yml’ in a subfolder called ‘docker’.
We start out with the version level — it is the version of the instruction set the docker-compose command needs to support in order to work with our configuration file. The current version at the time of writing (05/2020) is
Next we define the volumes we will need: In this case only a data volume for the MariaDB/MySQL container to store its database.
After that, we can define a network for our database container. This is a good practice for security reasons it ensures only the containers added to that network can access the database.
With volume and network defined, we can add the two containers under the
services section. Starting with the MySQL container — its options were taken straight out of the README file on DockerHub, defining user, password and database as well as connecting the volume defined earlier and where to mount it. Finally the container is attached to the
db network defined in the networks section in the beginning.
Now we have all the prerequisites for defining our Contao 4 container. Note the ports definiton: The left side of the colon contains the port on our host machine and the right side the port inside the container — in our case it is the same but we still need to explicitly tell docker compose that we want this happening, otherwise it will get assigned to a random port on our host machine. In the
environment section you notice the variable
DEVMODE set to
True, this will perform a couple extra things to make our development life easier (setting up a user, aliases and running composer install in our mounted source code directory).
The most important thing though is in the
volumes section of the contao4 container: We instruct the Docker daemon to mount the complete source code directory inside the container, so that changes to the PHP code we make in our local directory are immediately available in our container. Remember that this breaks the “disposability” concept of containers so we will only use this method of mounting our source code directly during our local development to speed things up.
At this point you should be able to change into the docker directory inside our project and run
docker-compose -f docker-compose_dev.yml up -d and see docker-compose creating the network, volume and containers.
Setting up Contao
Let us now create a simple site that serves as a demonstration to deploy. Currently we have an empty Contao 4 installation with nothing but a database configured.
First we should set or disable the Contao Install password. To do that, create a file
config.yml in the folder
/config of our Contao 4 Installation and fill it with the following:
This replaces the file
/system/config/localconfig. Notice the lines beginning with
%env(. These take the values from environment variables stored in a file called
.env in the root directory of your Contao 4 installation. To override values for local development, you can create a file called
.env.local that overrides everything found in it for your local machine (for example, setting
APP_ENV=dev will enable debug mode permanently on your local machine regardless what was specified in the
Now we have two options:
- Disable the Install-Password altogether and use the command line way of executing migrations
- Set the install password in the .env file and use the install tool normally
As we are going to deploy our finished container automatically later on, we should go with option 1. To disable the Install-Tool, you can set the variable
INSTALL_PASSWORD to blank with
If you try to set the password now via the install tool, it will loop forever in the enter password screen as it can not write to neither the
config.yml nor the
.env file — thus effectively disabling the install tool.
However — we do not have an administrative user account yet. Unfortunately Contao 4 does not provide a command for creating a user account via command line, you can only change passwords of already existing users. So we are going to take option 2 for now. Go to the Bcrypt Generator site and generate a hash of a password of your choice. Copy the generated hash and put it in the
.env file like so:
INSTALL_PASSWORD='myhashstring'(remember to put it in single quotes).
The second thing you will notice is that the MySQL connection string is also combined from values set in the
.env. This means we only need to provide values in one place when we deploy our application later. We should set our database credentials like we configured them in the docker-compose file earlier:
Running the initial setup
Now that we have configured the necessary credentials we can run our initial migration to have contao setup a blank database. To do this we are going to connect to the running Contao 4 container via command line and run the contao migration command just to see how this works. We will later run this command everytime a container starts on the production server, so the database gets updated to eventual schema changes.
Connect to the container by running the
docker-compose -f docker-compose_dev.yml exec contao4 /bin/ash command inside the ‘docker’ directory. You will see a new command prompt appear. You will already be in the application directory as we set the working directory in our Dockerfile.
You can now run
vendor/bin/contao-console contao:migrate. This will show you the migrations that will be executed. Confirm them by hitting the number 0 key. Contao should now apply the initial database schema.
After this you can create the initial admin user via the install tool. After that you should be able to login into the Contao backend.
Creating a Git repository and initial commit
At this point we have a basis to develop our application, therefore it is now time to think about version control. The most common version control used today is Git. To create a git repository in our project directory, open or reuse a command prompt inside our project and simply run
git init. This will create a Git repository in the current directory.
With the local Git repository created we can add all of our files by using the command
git add .. The dot here stands for everything and the command will now add all files except those mentioned in the .gitignore file created in Part 1 to the staging queue for a new commit. If you do not know much about source control, you can think of a commit as a snapshot of the repository at a specific point in time which you can later come back to if you want (or find out between which commits a file has changed). Finish off the commit by typing
git commit -m "Initial commit" — the m-Option standing for ‘message’. This message will be saved for this specific commit and should give another developer a short overview of what you changed in this commit.
In order to enable continuous automatic building of our image and deployment we need a server or service that does this independently of our development machine. This is where GitLab comes in. Like GitHub it allows you to host your Git remote repository there but it also features a docker image registry and its own build pipeline we both can use to build and store our docker image. Plus it’s generous free plan is more than enough for most smaller projects.
Start by setting up a new account if you don’t already have one and create a new, blank repository. I chose the same name as the folder I created the Dockerfile in ‘contao-on-docker’ (You can find it here).
After you have created the new repository you can push your local repository to it by using the command
git remote add origin https://gitlab.com/<your username>/contao-on-docker.git to connect the repositories and then running
git push origin master. This will copy all your local commits on the master branch to the GitLab.com server.
Now you have your projects source code and history available anywhere!
This is it for today! Stay tuned for the next part, where we get to the most interesting bits: Using the GitLab CI pipeline to build our Docker image, storing it in the GitLab registry and then deploying it to a server! You will find a link here as soon as it is released!