Dockerizing PHP Application using Docker Init
Ajeet Singh Raina
Posted on December 17, 2023
Gone are the days of manually wrangling Dockerfiles and configuration files! Enter docker init
, your new sheriff in the wild west of containerization. This revolutionary command, available in Docker Desktop 4.19.0+, simplifies Docker life for developers of all skill levels.
Think of docker init
as your one-stop shop for containerizing applications. Simply point it towards your project folder, and voila! It scans your code, automagically generating the essential Dockerfiles, Compose files, and .dockerignore files needed to run your project in a container. No more tedious configurations, no more syntax headaches - just pure containerized bliss.
The benefits are manifold:
- Speedy Experimentation: New to Docker? Want to test waters without writing mountains of code?
docker init
is your perfect partner-in-crime. Try out different languages and frameworks in containers with minimal effort. - Learning Made Easy: Want to master containerization?
docker init
can be your friendly tutor. Its automatic file generation provides a concrete template, perfect for understanding how Docker pieces fit together. - Seamless Integration: Already rocking Docker for some projects?
docker init
ensures consistent practices across your entire workflow. Standardized asset creation means less troubleshooting and more coding fun.
And the party's not over yet! The current Beta supports Go, Node, and Python, with Java, Rust, and .NET coming soon. Additionally, the Docker team welcomes your feedback - if you have a language or framework you'd love to see supported, just jump through their Google form and make your voice heard.
In a nutshell, docker init
is a game-changer for developers:
- Simplifies containerization: Get your projects Dockerized in seconds, not hours.
- Lowers the learning curve: Dive into containerization with ease, even as a beginner.
- Standardizes workflow: Say goodbye to inconsistencies and embrace uniformity.
Introduced for the first time in Docker Desktop 4.18, the new docker init
CLI generates Docker assets for projects, making it easier to create Docker images and containers. When you run the docker init
command in your project directory, it will guide you through the creation of the necessary files for your project with sensible defaults. These files include:
- .dockerignore
- Dockerfile
- docker-compose.yaml
The docker init
command also allows you to choose the application platform that your project uses and the relative directory of your main package.
Benefits of using docker init
The advantages of using the docker init
command include:
- Simplified Docker asset creation: The command streamlines the creation of necessary Docker files, reducing the chances of errors and ensuring that best practices are followed.
- Saves time and effort: With the default settings and guided prompts, users can quickly create Docker assets without the need for extensive knowledge of Docker or its syntax.
- Better project organization: The generated files provide a standardized and organized structure for the project, making it easier for developers to maintain and update the project over time. Enhanced portability: By using Docker assets, projects become more portable across different environments, making it easier to move the project from development to production.
What’s New?
The docker init
supported Python, Node, Go, ASP.NET 6 and 7 in the older versions. With this new release, the support for PHP with Apache + Composer has been introduced for the first time.
The docker init
support for PHP and Composer is a welcome addition, and it makes it easier than ever to develop and deploy PHP applications in Docker containers.
Prerequisite:
- Download and install Docker Desktop 4.26.0 and above.
To demonstrate the functionality of docker init
, we will be picking up a simple application from the template using PHP.
Getting Started
Let's set up a basic Apache + PHP environment with Composer on macOS. macOS comes with Apache and PHP preinstalled, so you'll mainly need to configure Apache and install Composer.
Step 1. Enable Apache
Apache is included with macOS, but it's not enabled by default. Open a terminal and run the following commands:
sudo apachectl start
Step 2. Enable Apache on System Boot
To have Apache start automatically on system boot, you can run:
sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist
You can check if Apache is running by visiting http://localhost in your web browser. You should see the "It works!" default page.
Step 3. Enable PHP
macOS comes with PHP, but it might not be enabled in Apache by default. Edit the Apache configuration file:
sudo nano /etc/apache2/httpd.conf
Uncomment the line that includes PHP by removing the # at the beginning of the line:
LoadModule php8_module libexec/apache2/libphp8.so
Step 4. Restart Apache
Save the file and restart Apache:
sudo apachectl restart
Step 5. Create a test PHP file in your web server's document root:
echo "<?php phpinfo(); ?>" | sudo tee /Library/WebServer/Documents/phpinfo.php
Open http://localhost/phpinfo.php in your web browser to see the PHP information page.
Step 6. Install Composer
Run the following command to download and install Composer:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
Step 7. Move the Composer executable to a directory in your PATH:
sudo mv composer.phar /usr/local/bin/composer
Step 8. Verify the installation
composer --version
Step 9. Create a PHP project with Composer:
Create a new directory for your PHP project:
mkdir my-php-project
cd my-php-project
Step 10. Initialize a new Composer project:
composer init
Follow the prompts to set up your composer.json file.
Step 11. Create a simple PHP script
In the project directory, create a file named index.php with the following content:
<?php
echo "Hello, Composer!";
Step 12. Configure Apache for the project
Create a virtual host configuration for Apache. Create a file named my-php-project.conf in /etc/apache2/other/:
<VirtualHost *:80>
ServerName my-php-project.local
DocumentRoot /path/to/your/my-php-project
<Directory /path/to/your/my-php-project>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Make sure to replace /path/to/your/my-php-project with the actual path to your project directory.
Step 13. Enable the virtual host and restart Apache
sudo apachectl restart
Step 14. Access your project
Open your web browser and navigate to http://my-php-project.local. You should see the "Hello, Composer!" message.
Let’s use docker init to containerise the whole application.
docker init
Welcome to the Docker Init CLI!
This utility will walk you through creating the following files with sensible defaults for your project:
- .dockerignore
- Dockerfile
- compose.yaml
- README.Docker.md
Let's get started!
WARNING: The following Docker files already exist in this directory:
- .dockerignore
- Dockerfile
- compose.yaml
- README.Docker.md
? Do you want to overwrite them? Yes
? What application platform does your project use? [Use arrows to move, type to filter]
> PHP with Apache - (detected) suitable for a PHP web application
Go - suitable for a Go server application
Python - suitable for a Python server application
Node - suitable for a Node server application
Rust - suitable for a Rust server application
ASP.NET Core - suitable for an ASP.NET Core application
Other - general purpose starting point for containerizing your application
Don't see something you need? Let us know!
Quit
It automatically detects the application platform as PHP.
? Do you want to overwrite them? Yes
? What application platform does your project use? PHP with Apache
? What version of PHP do you want to use? 8.3.0
? What's the relative directory (with a leading .) for your app? [Use arrows to move, type to filter]
./ (current directory)
./my-php-project
./my-php-project/vendor
./vendor
./vendor/composer
other
Step 15. Choose the right project directory path and preferred port
? What's the relative directory (with a leading .) for your app? ./my-php-project
? What local port do you want to use to access your server? 9000
CREATED: .dockerignore
CREATED: Dockerfile
CREATED: compose.yaml
CREATED: README.Docker.md
✔ Your Docker files are ready!
Take a moment to review them and tailor them to your application.
If your application requires specific PHP extensions, you can follow the instructions in the Dockerfile to add them.
When you're ready, start your application by running: docker compose up --build
Your application will be available at http://localhost:9000
Consult README.Docker.md for more information about using the generated files.
Content of Dockerfile:
# syntax=docker/dockerfile:1
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Dockerfile reference guide at
# https://docs.docker.com/go/dockerfile-reference/
################################################################################
# Create a stage for installing app dependencies defined in Composer.
FROM composer:lts as deps
WORKDIR /app
# If your composer.json file defines scripts that run during dependency installation and
# reference your application source files, uncomment the line below to copy all the files
# into this layer.
# COPY . .
# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a bind mounts to composer.json and composer.lock to avoid having to copy them
# into this layer.
# Leverage a cache mount to /tmp/cache so that subsequent builds don't have to re-download packages.
RUN --mount=type=bind,source=composer.json,target=composer.json \
--mount=type=bind,source=composer.lock,target=composer.lock \
--mount=type=cache,target=/tmp/cache \
composer install --no-dev --no-interaction
################################################################################
# Create a new stage for running the application that contains the minimal
# runtime dependencies for the application. This often uses a different base
# image from the install or build stage where the necessary files are copied
# from the install stage.
#
# The example below uses the PHP Apache image as the foundation for running the app.
# By specifying the "8.3.0-apache" tag, it will also use whatever happens to be the
# most recent version of that tag when you build your Dockerfile.
# If reproducability is important, consider using a specific digest SHA, like
# php@sha256:99cede493dfd88720b610eb8077c8688d3cca50003d76d1d539b0efc8cca72b4.
FROM php:8.3.0-apache as final
# Your PHP application may require additional PHP extensions to be installed
# manually. For detailed instructions for installing extensions can be found, see
# https://github.com/docker-library/docs/tree/master/php#how-to-install-more-php-extensions
# The following code blocks provide examples that you can edit and use.
#
# Add core PHP extensions, see
# https://github.com/docker-library/docs/tree/master/php#php-core-extensions
# This example adds the apt packages for the 'gd' extension's dependencies and then
# installs the 'gd' extension. For additional tips on running apt-get, see
# https://docs.docker.com/go/dockerfile-aptget-best-practices/
# RUN apt-get update && apt-get install -y \
# libfreetype-dev \
# libjpeg62-turbo-dev \
# libpng-dev \
# && rm -rf /var/lib/apt/lists/* \
# && docker-php-ext-configure gd --with-freetype --with-jpeg \
# && docker-php-ext-install -j$(nproc) gd
#
# Add PECL extensions, see
# https://github.com/docker-library/docs/tree/master/php#pecl-extensions
# This example adds the 'redis' and 'xdebug' extensions.
# RUN pecl install redis-5.3.7 \
# && pecl install xdebug-3.2.1 \
# && docker-php-ext-enable redis xdebug
# Use the default production configuration for PHP runtime arguments, see
# https://github.com/docker-library/docs/tree/master/php#configuration
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Copy the app dependencies from the previous install stage.
COPY --from=deps app/vendor/ /var/www/html/vendor
# Copy the app files from the app directory.
COPY ./my-php-project /var/www/html
# Switch to a non-privileged user (defined in the base image) that the app will run under.
# See https://docs.docker.com/go/dockerfile-user-best-practices/
USER www-data
Output of Docker Compose File
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
ports:
- 9000:80
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker-compose up`.
# depends_on:
# db:
# condition: service_healthy
# db:
# image: postgres
# restart: always
# user: postgres
# secrets:
# - db-password
# volumes:
# - db-data:/var/lib/postgresql/data
# environment:
# - POSTGRES_DB=example
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
# expose:
# - 5432
# healthcheck:
# test: [ "CMD", "pg_isready" ]
# interval: 10s
# timeout: 5s
# retries: 5
# volumes:
# db-data:
# secrets:
# db-password:
# file: db/password.txt
Step 16. Building and Running the Container
docker compose up --build
Results:
docker compose up --build
[+] Building 5.7s (18/18) FINISHED docker:desktop-linux
=> [server internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 3.74kB 0.0s
=> [server internal] load .dockerignore 0.0s
=> => transferring context: 725B 0.0s
=> [server] resolve image config for docker.io/docker/dockerfile:1 2.6s
=> [server auth] docker/dockerfile:pull token for registry-1.docker.io 0.0s
=> CACHED [server] docker-image://docker.io/docker/dockerfile:1@sha256:ac85f380a63b13dfcefa89046420e1781752bab2021 0.0s
=> [server internal] load metadata for docker.io/library/composer:lts 2.9s
=> [server internal] load metadata for docker.io/library/php:8.3.0-apache 2.9s
=> [server auth] library/php:pull token for registry-1.docker.io 0.0s
=> [server auth] library/composer:pull token for registry-1.docker.io 0.0s
=> [server deps 1/3] FROM docker.io/library/composer:lts@sha256:cd1ab955f511b42b377bf95338bcf38765bc7f80f2f3d5014a 0.0s
=> [server internal] load build context 0.0s
=> => transferring context: 453B 0.0s
=> [server final 1/4] FROM docker.io/library/php:8.3.0-apache@sha256:c55d99c94f804ee54177ba00961d2441333b277a67e6a 0.0s
=> CACHED [server final 2/4] RUN mv "/usr/local/etc/php/php.ini-production" "/usr/local/etc/php/php.ini" 0.0s
=> CACHED [server deps 2/3] WORKDIR /app 0.0s
=> CACHED [server deps 3/3] RUN --mount=type=bind,source=composer.json,target=composer.json --mount=type=bind, 0.0s
=> CACHED [server final 3/4] COPY --from=deps app/vendor/ /var/www/html/vendor 0.0s
=> CACHED [server final 4/4] COPY ./my-php-project /var/www/html 0.0s
=> [server] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:9f4b8292e9a7c461ec91a587da88c4bcde4c7d4c99a21ea8c885b2e4113e38b2 0.0s
=> => naming to docker.io/library/demo-app-server 0.0s
[+] Running 1/0
✔ Container demo-app-server-1 Created 0.0s
Attaching to server-1
server-1 | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.18.0.2. Set the 'ServerName' directive globally to suppress this message
server-1 | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.18.0.2. Set the 'ServerName' directive globally to suppress this message
server-1 | [Wed Nov 29 11:30:02.099427 2023] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.57 (Debian) PHP/8.3.0 configured -- resuming normal operations
server-1 | [Wed Nov 29 11:30:02.099452 2023] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
Step 17. Viewing the container using Docker Desktop
Step 18. Accessing the PHP application
curl http://localhost:9000
Hello, Composer!
Posted on December 17, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.