A quick guide on how to set up a website in Docker

Hello everyone! I will try to describe, without going into complicated terms, how to quickly and easily raise a site in Docker using docker-compose.

First step


First, we need the site itself. Let's assume that we already have some index.php that sends "Hello world" to the browser. Let's also assume that you already have Docker installed.

Step two: create docker-compose.yml


Docker containers are not virtual machines, they are just some allocated space. We need to decide which ones we need.
To begin with, three should be enough for us: the first is a regular mysql. The second is phpmyadmin. The third is our application.
First, create a db folder next to the app folder, and then create a docker-compose.yml file in the root.
In the db folder, mysql will make its own database files so that they are not lost if you suddenly rebuild containers. Base folder, yes.
The structure looks like this:

Well, the docker-compose.yml itself has the following content:

version: '3'
services:
  db: #add a container named db here
    image: 'mysql:latest' #take the last image
    environment:
      MYSQL_ROOT_PASSWORD: 12345 #here you must set a password for root
    command: mysqld --default-authentication-plugin=mysql_native_password
    ports:
      - '3306:3306' #port for mysql
    volumes:
      - './db:/var/lib/mysql' #we say that the db folder is forwarded inside the container and will be used instead of /var/lib/mysql
    networks:
      - default #we tell the container to use the default network
  phpmyadmin: #container with phpmyadmin
    image: phpmyadmin/phpmyadmin
    links:
      - 'db:db' #make a link
    ports:
      - '8000:80' #we put the 80th port FROM the container on the 8000th port in our system
    environment:
      PMA_HOST: db #default host for db
      PMA_PORT: 3306 #default port for db
  app: #our main container with the site
    build: .
    ports:
      - '80:80' #we plant the 80 port from the container on the 80 port of our computer. Those. it turns out that we can get where we need from the browser at the link http://localhost
    volumes:
      - './app:/var/www/html/' #we say that the app folder will be used instead of /var/www/html
    restart: always #always restart if container crashed or exited
    links:
      - db
    networks:
      - default
volumes:
  persistent: null

Third step: creating the Dockerfile


Now we need to determine what kind of container we will have and what will be in it. To do this, we also create a Dockerfile at the root and fill it with commands to install nginx and php.
Dockerfile:
FROM ubuntu:20.04 as intermediate

# Set the default Moscow time inside the container
RUN ln -snf /usr/share/zoneinfo/"Europe/Moscow" /etc/localtime && echo "Europe/Moscow" > /etc/timezone

# Install php and nginx packages via apt (this is the default for ubuntu)
RUN apt-get update \
        && apt-get install -y nginx php7.4 php7.4-cli php7.4-common php7.4-curl php7.4-dev php7.4-mysql php7.4-fpm

# We take from our conf folder (we will create a little later) the config, which we put inside and put it along the path / etc / nginx / sites-available / default
COPY conf/nginx.conf /etc/nginx/sites-available/default

# We need an entrypoint.sh script that will run indefinitely and prevent the container from stalling
COPY conf/entrypoint.sh /entrypoint.sh
# We also give him a little bit of rights
RUN chmod a+x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

Fourth step: nginx.conf and entrypoint.sh


Before creating these files, we need the conf folder. The structure ultimately comes out like this:

In the file entrypoint.sh we hang the launch of php-fpm, nginx and reading the log.

#!/bin/bash

echo "Running nginx & php-fpm"
nginx && php-fpm7.4

# Here we hang up an endless view of the nginx log that will show errors while the container is running
tail -f /var/log/nginx/error.log

Well, we fill the nginx.conf file with almost the stock configuration for such files.

server {
    listen 80;
    listen [::]:80;
    server_name  localhost;

    root /var/www/html/;
    
    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
       fastcgi_split_path_info  ^(.+\.php)(/.+)$;
       fastcgi_index            index.php;
       fastcgi_pass             unix:/var/run/php/php7.4-fpm.sock;
       include                  fastcgi_params;
       fastcgi_param   PATH_INFO       $fastcgi_path_info;
       fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
       internal;
    }

    location ~ \.php$ {
        return 404;
    }

    error_log /var/log/nginx/project_error.log;
    access_log /var/log/nginx/project_access.log;

}

First launch


Run $ docker-compose up in the console and wait for everything to compose. :)

Upon completion, you can also open a browser and make sure that our Hello world got to the right place.

Database connection


To test the database connection, let's try modifying our index.php file to look like this:
<?php
$host = 'db';
$user = 'root';
$password = '12345';
$database = 'mysql';

// we connect to the db container, if we don't connect, exit will work and we won't see the words "fire"
$link = mysqli_connect($host, $user, $password, $database)
or exit("Error " . mysqli_error($link));


echo "Fire, connection to database is successful";

// close the connection
mysqli_close($link);

We check: