Today, we'll dive into the process of creating custom Docker images, publishing them to Docker Hub, and using them in your projects and CI/CD pipelines.
📋 Table of Contents
- Why Create Custom Docker Images?
- Planning Your Custom PHP Image
- Building Your Custom PHP Image
- Publishing to Docker Hub
- Automating Builds with GitHub Actions
- Conclusion
Why Create Custom Docker Images?
Creating custom Docker images offers several significant advantages:
- Standardization: Ensure all developers and environments use identical PHP configurations.
- Efficiency: Reduce build times by pre-installing common dependencies.
- Compliance: Enforce security and compliance requirements across all environments.
- Specialization: Tailor images to your specific application needs.
- Control: Manage PHP versions and extensions independently of application code.
- Scalability: Simplify scaling by standardizing your deployment units.
In our previous articles, we've been using a custom PHP image (dommin/php-8.4-fpm
) that comes pre-configured with PHP 8.4, common extensions, and tools like Node.js and Composer. Let's explore how this image was created and how you can build your own.
Planning Your Custom PHP Image
Before building a custom image, define your requirements:
Key Considerations:
- Base Image: Choose right image Debian-based (
php:8.4-fpm
). - PHP Extensions: List the PHP extensions your applications commonly need.
- System Packages: Identify system dependencies for your PHP extensions and tools.
- Additional Tools: Decide if you need tools like Composer, Node.js, or Git.
- User Permissions: Consider how to handle file permissions between host and container.
- Size vs. Functionality: Balance image size against needed functionality.
Requirements Example:
For a Laravel application, you might need:
- PHP 8.4 with FPM
- Extensions: PDO, MySQL, PostgreSQL, GD, Zip, BCMath, Redis, etc.
- Composer
- Node.js and NPM
- Git for Composer dependencies
Building Your Custom PHP Image
Let's analyze and improve the Dockerfile used to build our custom PHP 8.4 image:
FROM php:8.4-fpm
ARG USER_ID=1000
ARG GROUP_ID=1000
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl unzip zip \
libpng-dev libjpeg-dev libwebp-dev libfreetype6-dev \
libonig-dev libxml2-dev libzip-dev \
imagemagick libmagick++-dev \
libpq-dev \
autoconf g++ make \
supervisor \
rsync \
wget gnupg2 \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g npm@latest \
&& pecl install redis imagick xdebug \
&& docker-php-ext-enable redis imagick xdebug \
&& docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql pdo_pgsql mysqli \
zip bcmath pcntl intl \
gd opcache \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
&& apt-get update \
&& apt-get install -y google-chrome-stable \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN groupmod -g ${GROUP_ID} www-data \
&& usermod -u ${USER_ID} -g www-data www-data \
&& mkdir -p /var/www /var/log/supervisor /var/run/supervisor \
&& chown -R www-data:www-data /var/www /var/log/supervisor /var/run/supervisor
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www
EXPOSE 9000
CMD ["php-fpm"]
Key Components Explained:
- Base Image: Uses the official PHP 8.4 FPM image.
- User Customization: Allows customizing user/group IDs to match host permissions.
- System Dependencies: Installs libraries required for PHP extensions.
- Node.js: Installs Node.js 22.x and npm for frontend asset building.
- PHP Extensions: Installs and enables common PHP extensions for Laravel.
- Composer: Copies Composer from the official Composer image.
- Permissions: Adjusts user permissions and sets the working directory.
- Port Exposure: Exposes port 9000 for PHP-FPM.
Publishing to Docker Hub
Docker Hub is the largest repository of container images. Publishing your image there makes it available to your team, CI/CD pipelines, and potentially the broader community.
1. Create a Docker Hub Account
If you haven't already, sign up for a Docker Hub account.
2. Create a Repository
- Click "Create Repository" on your Docker Hub dashboard
- Name it appropriately (e.g.,
username/php
) - Add a description and set visibility (public or private)
- Click "Create"
3. Log in to Docker Hub from CLI
docker login
Enter your Docker Hub username and password when prompted.
4. Build Your Image
docker build -t username/php:8.4-fpm -f ./Dockerfile .
5. Push Your Image to Docker Hub
docker push username/php:8.4-fpm
6. Verify Your Upload
Visit your repository on Docker Hub to ensure your image was uploaded successfully.
Automating Builds with GitHub Actions
Manually building and pushing images can be tedious. Let's automate this with GitHub Actions.
Here's the workflow file you're using (make sure your secrets are set up correctly):
name: Build images
on:
push:
branches:
- main
env:
PHP_IMAGE: dommin/php-8.4-fpm:latest
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build images
run: docker build -t $PHP_IMAGE -f ./8.4-fpm/Dockerfile .
- name: Push images
run: docker push $PHP_IMAGE
Conclusion
Building custom Docker images for your PHP applications offers significant advantages in terms of standardization, efficiency, and control. By automating the build and publication process with GitHub Actions, you can ensure your images are always up-to-date and readily available for your projects and CI/CD pipelines.
Custom images are a powerful tool in your DevOps arsenal, enabling you to standardize your PHP environment across development, testing, and production while maintaining the flexibility to adapt to your specific application requirements.
Source Code
Follow me on LinkedIn for more DevOps and Laravel tips!
Would you like to learn more about Docker, PHP, or CI/CD? Let me know in the comments below!