Docker in Practice: Understanding Containers with PHP
By Felipe Carneiro • September 16, 2026
Hey everyone. So, in the last article, we talked a lot about how we could use Laradock with Laravel, and I didn't try to go as deep as possible. I just wanted to make a very simple blog for you to follow through.
But this time, we're going to be talking a little bit more in depth about Docker.
So, what Docker is, it's an open-source platform that we can use to create containers to run our code. And what does that solve?
Basically, it solves the problem where the code works on my computer, but doesn't work on someone else's because our environments are different. Maybe I have a different PHP version, different extensions, a different MySQL version, a different Nginx version, and so on. What Docker helps us with is creating a standard environment for our code. So when we create a container, we basically say, "Okay, we need X, Y, and Z for this code to work." And when someone else runs that container, Docker will reproduce that environment on their machine as closely as possible.
And what is a container? You can pretty much think of it as a recipe of ingredients. Let's say we need PHP 8.5. We can create a container with PHP 8.5 and everything else we need to run our code. What Docker is basically doing here is creating a lightweight Linux environment for us to run our code. Now, this might sound very similar to a virtual machine, but there's an important difference: A virtual machine is basically an entire computer running inside your computer. You have to give it RAM, CPU, storage, and it runs its own operating system. Docker containers are much lighter because we're not creating another full computer.
And that's one of the reasons Docker is so useful. We're not trying to create a virtual computer inside a computer. We're just creating an isolated environment with everything we need to run our code.
So how can we create this recipe of ingredients? This recipe is pretty much what a Dockerfile is. What we do is create a file with a lot of instructions that look like code. We can tell Docker to install something, configure something, or, let's say, create a Dockerfile for PHP and install the PHP version and the extensions that we need. And that can take a lot of time just creating and configuring a Dockerfile.
But thankfully, you don't always have to do everything from scratch. There are already Docker images that have been created for us, some by the community and some official ones, like the official PHP image. These images simplify our work because we don't have to create the whole recipe every time.
So, let's say we want to bake a cake. Building a Dockerfile from scratch is like making the cake ourselves, starting with all the ingredients. Using an existing image is more like buying a cake that's already been made for us. And if that image was created by someone who knows what they're doing, or it's an official image, we can take advantage of all the work that has already been done and make our lives a little bit easier.
To make sure we REALLY know how a Dockerfile works, though, we'll get our hands messy. For context, I'll have an empty folder with just the hello.php file:
<?php
echo "Hello, World!";
And our Dockerfile. I've left some comments so you'll get the gist of what we're doing:
FROM ubuntu:latest
# Install PHP
RUN apt-get update && apt-get install -y php
# Sets our working directory inside the container to /var/www/html
WORKDIR /var/www/html
# Expose port 8000 to our host machine
EXPOSE 8000
# Copy the contents of the current directory on the host machine
# to the working directory inside the container
# The left dot means the current directory on the host machine,
# and the right dot means the current working directory inside the container
COPY . .
# Start the PHP built-in server when the container starts
CMD ["php", "-S", "0.0.0.0:8000", "./hello.php"]
# Run "docker build -t helloworld ." to build the Docker image
# and tag it as "helloworld"
# Run "docker run -p 8000:8000 helloworld" to start the container
# and map port 8000 on the host machine to port 8000 inside the container
Notice that we're actually "making" a small Ubuntu environment to work with, and we're starting to run commands that we would normally use on our own PC.
This Dockerfile works, but it has a major flaw. We're installing PHP using apt-get install php, which means we're relying on whatever PHP version is available through Ubuntu's repositories. If we specifically want PHP 7.3, for example, things become much more complicated. We'd need to deal with finding the right packages, repositories, or even downloading and compiling PHP ourselves, depending on the environment.
I guess you can see by now how this can be quite troublesome to configure every time you want to start implementing Docker in your environment, but don't worry, hope is not all lost.
Remember the Docker images we talked about before? We can use the official PHP image instead of starting from Ubuntu and manually installing PHP.
And we don't even need to create a Dockerfile for this. We can use Docker Compose to tell Docker which image we want to use and how we want our container to run.
For our example, let's create a compose.yaml file:
services:
php:
image: php:8.3-cli
working_dir: /var/www/html
volumes:
- .:/var/www/html
ports:
- "8000:8000"
command: php -S 0.0.0.0:8000 ./hello.php
And that's pretty much it. We're telling Compose that we have a service called php, that we want to use the php:8.3-cli image, and that our project should be available inside the container at /var/www/html. We're also mapping port 8000 from the container to our computer and telling it which command to run when the container starts.
Now we can run:
docker compose up
Compose will download the PHP image if we don't already have it, create the container, and start it. And because we specified the command, the PHP server will automatically start with the container.
Now, if you open http://localhost:8000 in your browser, you should see our good old Hello, World!
And that's it. We just created a PHP container using an official Docker image, without having to write a Dockerfile at all.
There's a lot more that we could add here. We could talk about PHP extensions, Nginx, databases, volumes, networking, environment variables, and a lot of other things. But the goal here wasn't to build a complete production-ready PHP environment. I just wanted to show you what is actually happening when you create a Docker container and give you a basic example that you can build on top of.
And from here, once you understand these basics, tools like Laradock start making a lot more sense. Instead of feeling like you're just running a bunch of magic containers, you can start looking at what they're actually doing underneath.
See you next mission!