• Docker: Creating And Running A Container

    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.04 or a current php:*-fpm image.

    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.