Запуск проекта на Laravel с использованием docker-compose

https://github.com/maxyc/laravel-tickets/blob/master/docker-compose.yml

Данная конфигурация кочует со мной из проекта в проект

Первым делом давайте разберемся: какие сервисы нам потреубуются?

  • php-fpm 7.4+ with xdebug
  • mysql | postgresql | sqlite
  • nginx | apache
  • redis | … etc…

Давайте попробуем на примере php-fpm 7.4 + mysql + nginx

Создадим папку нашего проекта /var/www/example.loc/ и создадим в ней файл docker-compose.yml, также нам понадобится папка ./docker где будем хранить конфигурации наших сервисов.

Внутренняя сеть

В нашей сборке ничего, кроме nginx не будет смотреть наружу. Ни какие порты, кроме 80. Нам не требуется извне иметь доступ к 9000 порту php или 3306 бд. Все контейнеры будут залинкованы между собой внутренней сетью, которую можно описать следующим образом:

networks:
  internal:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 192.168.220.0/28

База данных

db:
    image: mysql
    restart: always
    command: --default-authentication-plugin=mysql_native_password
    networks:
      - internal
    environment:
      - MYSQL_DATABASE=${DB_DATABASE}
      - MYSQL_USER=${DB_USERNAME}
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
    volumes:
      - ./docker/mysql/datadir:/var/lib/mysql

Нам необходимо в корне папки создать файл .env, в котором будут наши настройки БД

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=db
DB_USERNAME=user
DB_PASSWORD=123456

Эти данные в дальнейшем будут в .env файле нашего проекта на Laravel.

Стоит обратить внимание на DB_HOST=db. Здесь нельзя указывать localhost или еще какой ip. За счет удобной внутренней сети докера мы можем использовать имя сервиса в качестве пути к серверу базы данных. в нашем случае это db

Т.к. после перезапуска контейнера все данные удаляются, то нам необходимо вынести файлы таблиц базы данных. Поэтому помещаем их в папку docker/mysql

volumes:
- ./docker/mysql/datadir:/var/lib/mysql

Если вдруг вам потребуется mariadb, то вместо image: mysql, впишите image: mariadb. Конфигурация остается та же.

А что, если мы захотим использовать postgresql? Все так же просто:

db:
  image: postgres
  restart: always
  networks:
    - internal
  environment:
    - POSTGRES_DB=${DB_DATABASE}
    - POSTGRES_USER=${DB_USERNAME}
    - POSTGRES_PASSWORD=${DB_PASSWORD}
  volumes:
    - ./docker/postgres/datadir:/var/lib/postgresql/data

С базами данных закончили.

php-fpm

Будем использовать кастомную сборку php-fpm, т.к. нам необходимо добавить поддержку работы с базой данных, поддержку xdebug и пр.

Для начала опишем сервис. Условимся, что наш docker-compose.yml и папка docker будет лежать в корне laravel проекта на одном уровне с папкой app

php-fpm:
    build:
      context: docker/php-fpm
    volumes:
      - ./:/var/www
    environment:
      XDEBUG_CONFIG: "remote_host=192.168.220.1 remote_enable=1"
      PHP_IDE_CONFIG: "serverName=Docker"
    depends_on:
      - db
    networks:
      - internal

Т.к. наша сборка кастомная, то вместо image секции, нам необходимо указать путь к настройкам:

build:
context: docker/php-fpm

Создаем папку ./docker/php-fpm и в ней два файла php.ini и Dockerfile, в котором далее будем описывать процесс сборки php-fpm

В php.ini мы можем указать желаемые нами параметры, например:

max_execution_time = 1000
max_input_time = 1000

error_reporting=E_ALL
display_errors=on

short_open_tags=off

Перейдем к Dockerfile. В этом файле (с большой буквы) хранятся построчно все инструкции по установке php внутри контейнера.

FROM php:7.4-fpm

RUN apt-get update \
    && apt-get install -y wget git unzip libpq-dev libicu-dev libpng-dev libzip-dev libjpeg-dev libfreetype6-dev\
    && pecl install xdebug-2.9.1 \
    && docker-php-ext-enable xdebug \
    && docker-php-ext-install pdo_pgsql \
    && docker-php-ext-install pgsql \
    && docker-php-ext-install zip \
    && docker-php-ext-install gd \
    && docker-php-ext-enable pgsql

ADD ./php.ini /usr/local/etc/php/php.ini

RUN wget https://getcomposer.org/installer -O - -q \
    | php -- --install-dir=/bin --filename=composer --quiet

USER 1000

WORKDIR /var/www

В первой строке (команда FROM) мы указали какую версию image файла нам использовать. В данном случае php:7.4-fpm

Следующая команда RUN устанавливает требуемые зависимости

Далее, мы указываем контейнеру, что php.ini необходимо брать из нашей текущей папки.
Далее, Устанавливаем composer. Он нужен нам только на уровне php-fpm контейнера.

Ну и наконец указываем контейнеру, где лежат все наши файлы со стороны контейнера. В нашем случае, мы указали, что корень нашего сервера это /var/www

Вы можете с легкостью указать любую другую версию php, например php:7.3-fpm, но учтите, для этой версии может потребуется xdebug более низкой версии, например 2.7.1

Nginx

nginx:
    build:
      context: docker/nginx
    volumes:
      - ./:/var/www/
      - ./storage/app/public/:/var/www/public/storage/
    ports:
      - 80:80
    depends_on:
      - php-fpm
    networks:
      - internal

Обратите внимание, что папку storage мы пробрасываем на уровне конфигурации. Симлинки не работают между контейнерами. В нашем случае nginx и php-fpm

Nginx у нас так же имеет кастомную сборку, потому указываем путь к файлу Dockerfile как в прошлом примере.

Создаем папку ./docker/nginx и там файл Dockerfile и папку conf.d
В conf.d у нас будут храниться виртуальные хосты, обычно 1-2 достаточно. Обрабатываются только файлы с расширением .conf. Например, default.conf:

server {
    charset utf-8;
    client_max_body_size 128M;

    listen 80; ## listen for ipv4

    server_name example.loc localhost;
    root /var/www/public;
    index       index.php;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        fastcgi_read_timeout 1000;
        #fastcgi_pass unix:/var/run/php5-fpm.sock;
        try_files $uri =404;
        #fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~* /\. {
        deny all;
    }
}

Настроим Dockerfile следующим образом:

FROM nginx

ADD ./conf.d /etc/nginx/conf.d/

WORKDIR /var/www

На этом настройка окружения для нашего проекта закончена. Нам остается только запустить контейнеры командой

docker-compose up -d --build

Если все ок, то наше приложение теперь доступно по адресу http://localhost

Одна из возможных причин, почему не запустилось, может крыться в том, что 80 порт может быть уже занят. В любом случае, понять причину ошибки можно запустив команду docker-compose logs и проанализировав ее.

Установка Laravel

Предположим, что мы разворачиваем фреймфорк впервые на машине, где не установлен php. Для того, чтобы установить фреймворк, нам необходимо скачать его командой

git clone https://github.com/laravel/laravel.git laravelapp

И скопировать все файлы в папке laravelapp в корень нашего сервера.

Для того, чтобы можно было использовать artisan, нам необходимо обращаться к нему внутри контейнера, а именно docker-compose exec php-fpm php artisan make:controller, либо запускать команды внутри контейнера запустив команду docker-compose exec php-fpm bash, а затем уже использовать php artisan make:controller

Часто у новичков и не только, у кого локально установлен php? возникает ошибка подключения к базе данных, при использовании команд artisan. Для решения которой, как бы не было это глупо и банально, предлагаю проверить как вы запускаете команду. Возможно вы запускаете ее локально, а не в контейнере. =)

Рейтинг
( 5 оценок, среднее 2.4 из 5 )
Maxyc Webber/ автор статьи
Мне 35 лет. Опыт профессиональной разработки 15 лет. Занимаюсь разработкой и поддержкой корпоративных систем автоматизации бизнеса, а также высоконагруженными проектами. Мне нравится решать нестандартные проблемы бизнеса. Имею опыт формирования команд под проект, налаживания процесса разработки, коммуникации программистов и заказчиков. Есть опыт работы с зарубежными заказчиками (ОАЭ, Польша, Германия, Швейцария).
Понравилась статья? Поделиться с друзьями:
Комментарии: 4
  1. schel4ok

    Здравствуйте, что-то у меня не так
    в конце выполнения docker-compose up -d –build возникают ошибки

    Creating db … done
    Creating php-fpm … error

    ERROR: for php-fpm Cannot start service php-fpm: OCI runtime create failed: container_linux.go:345: starting container process caused “chdir to cwd (\”/var/www\”) set in config.json failed: permission denied”: unknown
    ERROR: Encountered errors while bringing up the project.

    Потом смотрю в portainer контейнер db вроде running, а php-fpm просто created и при попытке запуска выдаёт ту же ошибку OCI runtime create failed.

    В логах db
    2020-11-28 15:16:15+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.22-1debian10 started.,
    2020-11-28 15:16:16+00:00 [Note] [Entrypoint]: Switching to dedicated user ‘mysql’,
    2020-11-28 15:16:17+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.22-1debian10 started.,
    2020-11-28 15:16:17+00:00 [Note] [Entrypoint]: Initializing database files,
    mysqld: Can’t create directory ‘/var/lib/mysql/’ (OS errno 17 – File exists),
    2020-11-28T15:16:17.119612Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.22) initializing of server in progress as process 43,
    2020-11-28T15:16:17.120948Z 0 [ERROR] [MY-013236] [Server] The designated data directory /var/lib/mysql/ is unusable. You can remove all files that the server added to it.,
    2020-11-28T15:16:17.120984Z 0 [ERROR] [MY-010119] [Server] Aborting,
    2020-11-28T15:16:17.121088Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.22) MySQL Community Server – GPL.

    1. Maxyc Webber (автор)

      Привет. Сложно так будет сказать что у вас. У вас что то с правами доступа.
      https://youtu.be/9TlXDyoCK10
      Я вот попробовал впервые видео записать. Вдруг поможет вместе со мной повторять действия

  2. schel4ok

    Привет.
    Видео с ошибкой не помогло. Но хорошее – поставил доп компоненты
    Creating cache … done
    Creating db … done
    Creating node … error
    Creating backend … error

    ERROR: for backend Cannot start service backend: OCI runtime create failed: container_linux.go:345: starting container process caused “chdir to cwd (\”/var/www\”) set in config.json failed: permission denied”: unknown
    ERROR: for node Cannot start service node: OCI runtime create failed: container_linux.go:345: starting container process caused “chdir to cwd (\”/home/node/app\”) set in config.json failed: permission denied”: unknown

    Похоже действительно были проблемы с правами доступа. Папка проекта выглядела вот так в листинге
    drwx——+ 1 schel4ok users 556 Nov 29 20:34 example.loc

    Я попробовал изменил права для юзера 1000 вот так
    chown -vR 1000:1000 example.loc
    chmod 700 example.loc

    Теперь стало так.
    drwx—— 1 1000 1000 556 Nov 29 20:34 example.loc

    И после этого php стартанул. Что это за юзер 1000?
    Это типа www-data? У меня просто линукс не чистый, а сборка Synology DSM. Там много изменений.
    Например не работают команды make и нет юзера www-data нет, но есть юзер http. Может вместо 1000 использовать id юзера http?

    В логе nginx всё ОК
    /docker-entrypoint.sh: Configuration complete; ready for start up

    В логе php есть вот такие строчки, которые мне не очень ясны. Вроде работает, но первые 2 строки напрягают
    NOTICE: [pool www] ‘user’ directive is ignored when FPM is not running as root,
    NOTICE: [pool www] ‘group’ directive is ignored when FPM is not running as root
    NOTICE: fpm is running, pid 1,
    NOTICE: ready to handle connections

    В логе db всё ОК
    LOG: database system is ready to accept connections

    cache вообще никакого лога не выводит

    А node какой-то странный. Он стартует, а потом автоматически останавливается со статусом Stopped for a few seconds with exit code 1.

    1. Maxyc Webber (автор)

      да , нода не висит в качестве демона. в видео показал как им пользоваться. как обычной программой запускать

Добавить комментарий для schel4ok Отменить ответ

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.