I will show you how to build a PHP-FPM Docker Image with your projects PHP source by using Docker Compose and how to push these Container Images to a (private) Container Registry like GitLab.
In my previous blog posts we talked about how to set up a PHP and Symfony development environment with Docker Compose, how to install the latest version of Symfony with Composer in a Docker Container and how to add MongoDB with environment variables to your Docker Compose file. Your development environment is now running locally, but in the beginning I promised you to show how to use your Docker Compose Setup also for Production.
Docker Image containing your latest PHP source code
Before we can start with the production system, you have to build your Docker Container from your development environment including your custom PHP source code. Of course, we don’t want to mount the PHP source in our PHP-FPM container on a live system. We need to have a ready to go Image with our latest code.
On the internet, there are a lot of instructions on how to build Container Images for a single Dockerfile with Docker, but there is few information on how to utilize Docker Compose for building your Docker Images. But once you figured out how to do that, it is pretty easy!
Copying PHP source code into Docker Image
Let’s start by adding a live
Target to our Dockerfile.
# myapp/php-fpm/Dockerfile FROM php:8.1-fpm-alpine as base RUN apk --update \ --no-cache \ add git make g++ autoconf rabbitmq-c-dev libtool tzdata \ && pecl install mongodb \ && docker-php-ext-enable mongodb ENV TZ=Europe/Berlin RUN apk del --purge make g++ autoconf libtool \ && rm -rf /var/cache/apk/* RUN cd /usr/local/etc/php/conf.d/ && \ echo 'memory_limit = -1' >> /usr/local/etc/php/conf.d/docker-php-ram-limit.ini COPY --from=composer /usr/bin/composer /usr/bin/composer WORKDIR /var/www EXPOSE 9000 CMD composer install; php-fpm ### PROD IMAGE ### FROM base as prod WORKDIR /var/www COPY ./src . CMD composer install; php-fpm
These changes add a new build target which we will use in your build process. In our development system, we mount our PHP source code so that we can make changes without rebuilding the Image. For production we need our code unchangeable in the Image. That is exactly what line 25
in the changed Dockerfile does.
Using Build Targets with Docker Compose
In order to use our new live target, we need to adjust our docker-compose.yml
file. But since we don’t want to affect our development system, let’s add a new docker-compose.build.yml
file:
# myapp/docker-compose.build.yml version: '3.7' services: php-fpm: build: context: . dockerfile: ./php-fpm/Dockerfile target: "prod" restart: unless-stopped image: registry.gitlab.com/yourname/myapp/php-fpm:latest environment: - COMPOSER_MEMORY_LIMIT=-1
When you compare the new file with your docker-compose.dev.yml
file, you see a big difference in the build key and also added the image key. Also the docker-compose.build.yml
contains only the services, which we customized and need to build a custom image. We don’t want to do that for NGINX and MongoDB.
You have to customize line 11
. I assume that you followed the other parts of my tutorial and use a GitLab repository for your project.
You have to do the following adoptions for the image name registry.gitlab.com/yourname/myapp/php-fpm:latest
- Replace
yourname
with your GitLab username - Replace
myapp
with your projects name - If you like, you can rename the container from
php-fpm
to anything you think is better suited
So your image name in line 11
could be for example registry.gitlab.com/digitizedliving/important-product/shop-php:latest
. You just have to remember for later.
Locally building the Image
So, now we are ready to locally run the build command with Docker Compose.
Open your terminal, navigate into your project folder and execute the following commands.
cd myapp/ docker-compose -f docker-compose.build.yml build
This build process should take up to some minutes, but finally you will see the message that the image is written and named like your specified in the image key before.
Now, there is one more thing to do: we want to push our fresh build Image to our GitLab Container Registry, so that we can use the Image in a live Docker Compose File without the need for building it.
Connecting with GitLab Container Registry
To be able to push our Images to the GitLab Container Registry, we have to log in from our local machine. To do so, you have to create a Personal Access Token. We will restrict our Token to just allow access to Registry, nothing else in GitLab.
To do so, just log into GitLab and navigate to User Settings > Access Tokens
or open the following link: https://gitlab.com/-/profile/personal_access_tokens
Choose a Token name, e.g. Build Test
and select the required Scopes. In our case, I selected read_registry
and write_registry
.

Click on Create personal access token
to create the token. On the next screen you can access your token. You have to save it now, because you won’t be able to access it again. If you forgot the token, you have to delete it and create a new token. You can click on the eye button
to show the token or on the little clipboard
to copy token.

Let’s login from your local machine to the GitLab Container Registry. Open your terminal again and enter the following commands:
cd myapp/ docker login registry.gitlab.com -u <username> -p <token>
Of course, you have to replace <username> and <token> with your GitLab Username and the before created personal access token. This tutorial uses GitLab, but you can also use any other Container Host. You just need the Username and a Token or Password.
Pushing your Images to GitLab Container Registry
You are able to push your custom Docker Images to your GitLab Container Registry. Let’s try it out:
cd myapp/ docker-compose -f docker-compose.build.yml build docker-compose -f docker-compose.build.yml push
That’s it! Your Image is now saved to the Container Registry.
Summary and next steps
You are now able to build Images from your Docker Compose File, log in with a personal access token to the GitLab Container registry and push your Images to your Container Registry.
There is still a lot to do on the way to our Deployment Pipeline with GitLab, but that was a big step, e.g. tagging your Images. Next Sunday, 2nd April, in the next blog post, we will take the next step.