Note (2026): This article was written in 2015 and uses outdated versions: Ubuntu 14.04 (EOL), PHP 5.6 (EOL). The basic Docker concepts remain relevant, but for modern projects use current images, for example
ubuntu:24.04or a currentphp:*-fpmimage.
Containerization is the new virtualization
The Docker Book
What Is Docker?
Unlike classic virtualization systems, which emulate computer hardware and the operating system kernel on top of it, Docker uses virtualization at the kernel level: all processes virtualized by it share the host operating system kernel, which makes it possible to significantly reduce both the required resources and the time needed to start and maintain such systems. Ideally, each process is isolated in its own container (Linux container, LXC), which contains the set of libraries it needs, letting us forget about dependency hell and also easily move the project stack between servers. In the article below I will illustrate how Docker can be used to configure a developer environment that repeats production: let us suppose that production uses Ubuntu LTS, PHP 5.4, and Nginx.
Installing Docker
You can read about installing Docker on different operating systems on the official project site: https://docs.docker.com/installation/#installation
Configuring The Container
First of all, we must write the instructions by which Docker should form the image on the basis of which our application will run: a Dockerfile.
# src: build/backend/Dockerfile
# Use Ubuntu 14.04 LTS as the base container
FROM ubuntu:14.04
# Switch Ubuntu into noninteractive mode to avoid extra prompts
ENV DEBIAN_FRONTEND noninteractive
# Install the locale
RUN locale-gen ru_RU.UTF-8 && dpkg-reconfigure locales
# Add the necessary repositories and install packages
RUN apt-get install -y software-properties-common
RUN add-apt-repository -y ppa:ondrej/php5-5.6
RUN add-apt-repository -y ppa:nginx/stable
RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4F4EA0AAE5267A6C
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y wget curl php5-fpm php5-mysql php5-gd php5-curl php-pear php-apc php5-mcrypt php5-imagick php5-memcache supervisor nginx
# Add the virtual host description
ADD astgo.ru /etc/nginx/sites-enabled/astgo.ru
# Disable daemon mode for Nginx because we will start it ourselves
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# Disable daemon mode for php-fpm
RUN sed -i -e "s/;daemonize\s*=\s*yes/daemonize = no/g" /etc/php5/fpm/php-fpm.conf
# Add the supervisor config describing the processes we want to see running in this container
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Declare which directories we will mount
VOLUME ["/var/www"]
# Declare which port this container will expose
EXPOSE 80
# Start supervisor
CMD ["/usr/bin/supervisord"]
# src: build/backend/supervisord.conf
[supervisord]
nodaemon=true
loglevel=debug
[program:nginx]
command=/usr/sbin/nginx
autorestart=true
[program:php5-fpm]
command=/usr/sbin/php5-fpm
autorestart=true
- FROM specifies the name of the image that will be used as the base.
- ENV sets an environment variable.
- RUN runs a command in the container. All commands are executed with full rights inside the container.
- ADD adds a file to the container.
- VOLUME specifies mounted directories. They can be mounted to the host machine or to other containers.
- EXPOSE specifies exposed ports. They can be exposed to the host machine or to other containers.
- CMD starts a process. This is the process around which the container is built.
For the full list of instructions allowed in a Dockerfile, you can refer to the guide.
Building The Image
Using the instructions we have written, we need to build an image. Let us call it astgo.ru/dev.
docker build -t astgo.ru/dev ~/PATH_TO_DOCKERFILE_DIR
We have seen the step-by-step build of our image. If errors occurred during the build process, they can be fixed at this stage and then we can try to build the image again. Let us check that everything went successfully and that the image appeared in the system:
docker images | grep 'astgo.ru/dev'
astgo.ru/dev latest d2444af3ee61 3 minutes ago 387.2 MB
Running The Container
Now let us create a container by running the image. We will run the astgo.ru/dev image, bind port 80 of the host to port 80 of the container, and also bind the host’s /var/www directory to the container’s /var/www. The latter lets us keep the project code on the host machine itself, without losing it every time we recreate the container for one reason or another.
docker run -v /var/www:/var/www -p 80:80 -t astgo.ru/dev
That is it, the container is running. We can make sure that it works by looking at the list of running containers:
docker ps | grep 'astgo.ru/dev'
d8429cc192c0 astgo.ru/dev:latest "/usr/bin/supervisor 20 seconds ago
Up 19 seconds 0.0.0.0:80->80/tcp reverent_fermi
Since we did not specify a name for the new container, it received the automatically generated name reverent_fermi, by which we can now address it.
Connecting To The Running Container
Let us try to enter the container and see how it is doing. This may be needed, for example, to run some console commands in the application environment.
docker exec -i -t reverent_fermi bash
root@d8429cc192c0:/#
In the following articles I will tell how to create a container for the database, and also how the process of starting a stack of containers can be simplified.