[Из песочницы] Laravel+Docker+Gitlab. С чего начать

?v=1

Я обычно всегда обходился без докера и думал, что докер нужен только для больших проектов в больших компаниях. Но однажды я увидел как работает докер в паре с гитлабом у моего товарища и понял, что мне все таки стоит его изучить. Однако, как обычно это бывает, одной подходящей статьи я не нашел — они были либо слишком сложные, либо не полные, либо подразумевали, что вы все знаете само собой. Мне пришлось долго искать различные источники, соединять все это вместе и в итоге у меня получилось сделать простенький проект и CI/CD для него.

Всю работу можно разделить на три части: на локальной машине, на гитлабе и на сервере.

Итак, для реализации проекта нам понадобится аккаунт gitlab и удаленный сервер с виртуализацией KVM или XEN.

Часть 1. Локальная машина


На локальной машине необходимо установить docker.

Замечание

Тут небольшое отступление. Docker можно поставить как на Linux системах (как Ubuntu, например), так и на Windows и MacOS. По поводу macos я ничего сказать не могу, а вот установка под Windows не самая хорошая идея для начинающего. Как минимум из-за того, что все мануалы и документации написаны для linux систем. Так и из-за того, что можно нажить проблем с доступом к различным папкам и файлам. Также докер конфликтует с виртуальной машиной VirtualBox. Поэтому проще и быстрее будет сделать виртуальную машину с Ubuntu и работать под ней


Для установки на Linux среде необходимо выполнить следующие команды.

Удалить старые контейнеры:

sudo apt-get remove docker docker-engine docker.io containerd runc


Обновить apt:

sudo apt-get update


Установить следующие пакеты, чтобы можно было скачать docker из репозитория по https:

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common


Добавить официальный GPG ключ докера:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -


Убедится в верности отпечатка:

sudo apt-key fingerprint 0EBFCD88


Ответ:

pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) 
sub   rsa4096 2017-02-22 [S]


Скачать стабильную версию:

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"


Еще раз обновить apt:

sudo apt-get update


Установить последнюю версию движка докера:

sudo apt-get install docker-ce docker-ce-cli containerd.io


Проверить работу докера:

sudo docker run hello-world


Если все верно — начнется скачивание образа Hello World.

Полная инструкция в официальной документации докер.

Также нам необходимо установить docker-compose. Официальная инструкция находится здесь.

Для его установки выполняем команды в терминале.

Скачивание из репозитория:

sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose


Добавление права исполнения:

sudo chmod +x /usr/local/bin/docker-compose


Проверка версии:

sudo docker-compose --version


Докер мы установили, теперь необходимо собрать образ. Для этого я воспользовался статьей с сайта digitalocean: www.digitalocean.com/community/tutorials/how-to-set-up-laravel-nginx-and-mysql-with-docker-compose-ru. Здесь будет перепечатка этой статьи.

Загрузка Laravel и установка зависимостей

На первом шаге мы загрузим последнюю версию Laravel и установим зависимости проекта, включая Composer, диспетчер пакетов PHP на уровне приложения. Мы установим эти зависимости с помощью Docker, чтобы не выполнять глобальную установку Composer.

Перейдите в домашний каталог и клонируйте последнюю версию Laravel в каталог с именем laravel-app:

cd ~
git clone https://github.com/laravel/laravel.git laravel-app


Перейдите в каталог laravel-app:

cd ~/laravel-app


Затем смонтируйте образ composer из Docker в каталоги, которые нужны для вашего проекта Laravel, чтобы избежать издержек глобальной установки Composer:

docker run --rm -v $(pwd):/app composer install


Флаги -v и --rm команды docker run создают виртуальный контейнер, который привязывается к текущему каталогу вплоть до его удаления. Содержимое вашего каталога ~/laravel-app будет скопировано в контейнер, а содержимое создаваемой Composer внутри контейнера папки vendor будет скопировано в текущий каталог.

В заключение установите в каталоге проекта такой уровень разрешений, чтобы ее владельцем был пользователь без привилегий root:

sudo chown -R $USER:$USER ~/laravel-app


Это будет важно, когда вы будете записывать Dockerfile для образа вашего приложения, поскольку позволит работать с кодом приложения и запускать процессы в контейнере, не имея привилегий root.

Теперь вы разместили код приложения и можете переходить к определению служб с помощью Docker Compose.

Создание файла Docker Compose

Построение приложений с помощью Docker Compose упрощает процесс настройки и контроля версий в вашей инфраструктуре. Чтобы настроить наше приложение Laravel, мы создадим файл docker-compose с определением служб веб-сервера, базы данных и приложения.

Откройте файл:

nano ~/laravel-app/docker-compose.yml


В файле docker-compose определяются три службы: app, webserver и db. Добавьте в файл следующий код, при этом замените пароль root для MYSQL_ROOT_PASSWORD, определяемый как переменная среды службы db, надежный паролем по своему выбору:

~/laravel-app/docker-compose.yml

version: '3'
services:

  #PHP Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: app
      SERVICE_TAGS: dev
    working_dir: /var/www
    networks:
      - app-network

  #Nginx Service
  webserver:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped
    tty: true
    ports:
      - "80:80"
      - "443:443"
    networks:
      - app-network

  #MySQL Service
  db:
    image: mysql:5.7.22
    container_name: db
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: your_mysql_root_password
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    networks:
      - app-network

#Docker Networks
networks:
  app-network:
    driver: bridge


Сюда включены следующие службы:

  • app: это определение службы содержит приложение Laravel и запускает персонализированный образ Docker, digitalocean.com/php. Также оно устанавливает для параметра working_dir в контейнере значение /var/www.
  • webserver: это определение службы берет образ nginx: alpine из Docker и открывает порты 80 и 443.
  • db: это определение службы извлекает образ mysql:5.7.22 из Docker и определяет новые переменные среды, в том числе базу данных laravel для вашего приложения и пароль пользователя root для базы данных. Вы можете использовать любое имя базы данных, которое захотите, также вам следует заменить your_mysql_root_password собственным надежным паролем. Это определение службы также сопоставляет порт хоста 3306 и порт контейнера 3306.


Каждое свойство container_name определяет имя контейнера, соответствующее имени службы. Если вы не определите это свойство, Docker будет присваивать каждому контейнеру имена, состоящие из имени исторической личности и случайного слова, разделенных символом подчеркивания.

Для упрощения взаимодействия между контейнерами, службы подключаются к соединительной сети с именем app-network. Соединительная сеть использует программный мост, позволяющий подключенным к этой сети контейнерам взаимодействовать друг с другом. Драйвер моста автоматически устанавливает правила хоста, чтобы контейнеры в разных соединительных сетях не могли напрямую взаимодействовать друг с другом. Это повышает уровень безопасности приложений, поскольку друг с другом могут взаимодействовать только связанные службы. Также это означает, что вы сможете задавать разные сети и службы, подключающиеся к связанным функциям: например, клиентские службы приложения могут использовать сеть frontend, а серверные — сеть backend.

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

Постоянное сохранение данных

В Docker имеются мощные и удобные средства для постоянного сохранения данных. В нашем приложении мы будем использовать тома и монтируемые образы для постоянного сохранения файлов базы данных, приложения и конфигурации. Тома обеспечивают гибкость резервного копирования и сохранение по прекращении жизненного цикла контейнера, а привязываемые монтируемые образы упрощают изменение кода во время разработки с немедленным отражением изменений файлов или каталогов хоста в контейнерах. Мы используем оба варианта.

Предупреждение!

Использование привязываемых монтируемых образов позволяет изменять файловую систему хоста через работающие в контейнеры процессы, что включает создание, изменение или удаление важных системных файлов или каталогов. Это мощная возможность с функциями безопасности, которая может повлиять на процессы без Docker в системе хоста. Привязывемые монтируемые образы следует использовать с осторожностью.


Определите в файле docker-compose том с именем dbdata в определении службы db для постоянного сохранения базы данных MySQL:

~/laravel-app/docker-compose.yml

...
#MySQL Service
db:
  ...
    volumes:
      - dbdata:/var/lib/mysql
    networks:
      - app-network
  ...


Том с именем dbdata используется для постоянного сохранения содержимого папки /var/lib/mysql внутри контейнера. Это позволяет останавливать и перезапускать службу db без потери данных.
Добавьте в конце файла определение тома dbdata:

~/laravel-app/docker-compose.yml

...
#Volumes
volumes:
  dbdata:
    driver: local


С этим определением вы сможете использовать этот том для разных служб.

Затем добавьте привязку монтируемого образа к службе db для файлов конфигурации MySQL:

~/laravel-app/docker-compose.yml

...
#MySQL Service
db:
  ...
    volumes:
      - dbdata:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/my.cnf
  ...


Этот монтируемый образ привязывает файл ~/laravel-app/mysql/my.cnf к каталогу /etc/mysql/my.cnf в контейнере.

Затем добавьте монтируемые образы в службу веб-сервера. Их будет два: один для кода приложения, а другой — для определения конфигурации Nginx

~/laravel-app/docker-compose.yml

#Nginx Service
webserver:
  ...
  volumes:
      - ./:/var/www
      - ./nginx/conf.d/:/etc/nginx/conf.d/
  networks:
      - app-network


Первый монтируемый образ привязывает код приложения в каталоге ~/laravel-app к каталогу /var/www внутри контейнера. Файл конфигурации, добавляемые в ~/laravel-app/nginx/conf.d/, также монтируется в /etc/nginx/conf.d/ в контейнере, что позволяет добавлять и изменять содержимое каталога конфигурации по мере необходимости.

В заключение добавьте следующие привязки монтируемых образов в службу app для кода приложения и файлов конфигурации:

~/laravel-app/docker-compose.yml

#PHP Service
app:
  ...
  volumes:
       - ./:/var/www
       - ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
  networks:
      - app-network


Служба app привязывает монтируемый образ папки ~/laravel-app, который содержит код приложения, к папке /var/www. Это ускорит процесс разработки, поскольку любые изменения в локальном каталоге приложения будут немедленно отражаться в контейнере. Также вы привязываете файл конфигурации PHP ~/laravel-app/php/local.ini к файлу /usr/local/etc/php/conf.d/local.ini в контейнере. Позже вы создадите локальный файл конфигурации PHP.

Теперь ваш файл docker-compose будет выглядеть следующим образом:

~/laravel-app/docker-compose.yml

version: '3'
services:

  #PHP Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: app
      SERVICE_TAGS: dev
    working_dir: /var/www
    volumes:
      - ./:/var/www
      - ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
    networks:
      - app-network

  #Nginx Service
  webserver:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped
    tty: true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./:/var/www
      - ./nginx/conf.d/:/etc/nginx/conf.d/
    networks:
      - app-network

  #MySQL Service
  db:
    image: mysql:5.7.22
    container_name: db
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: your_mysql_root_password
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - dbdata:/var/lib/mysql/
      - ./mysql/my.cnf:/etc/mysql/my.cnf
    networks:
      - app-network

#Docker Networks
networks:
  app-network:
    driver: bridge
#Volumes
volumes:
  dbdata:
    driver: local


Создание файла Dockerfile

Docker позволяет задавать среду внутри отдельных контейнеров с помощью файла Dockerfile. Файл Dockerfile позволяет создавать персонализированные образы. которые можно использовать для установки требуемого программного обеспечения приложения и изменения настроек в соответствии с требованиями. Вы можете передавать созданные образы в Docker Hub или любой частный реестр.

Файл Dockerfile будет располагаться в каталоге ~/laravel-app. Создайте файл:

nano ~/laravel-app/Dockerfile


Этот файл Dockerfile будет задавать базовый образ и необходимые команды и инструкции для построения образа приложения Laravel. Добавьте в файл следующий код:

~/laravel-app/php/Dockerfile

FROM php:7.2-fpm

# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/

# Set working directory
WORKDIR /var/www

# Install dependencies
RUN apt-get update && apt-get install -y \
    build-essential \
    mysql-client \
    libpng-dev \
    libjpeg62-turbo-dev \
    libfreetype6-dev \
    locales \
    zip \
    jpegoptim optipng pngquant gifsicle \
    vim \
    unzip \
    git \
    curl

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install extensions
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/
RUN docker-php-ext-install gd

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www

# Copy existing application directory contents
COPY . /var/www

# Copy existing application directory permissions
COPY --chown=www:www . /var/www

# Change current user to www
USER www

# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]


Сначала Dockerfile создает образ поверх образа php:7.2-fpm Docker. Это образ на базе с установленным экземпляром PHP FastCGI PHP-FPM. Также этот файл устанавливает требуемые пакеты для Laravel: mcrypt, pdo_mysql, mbstring и imagick с composer.

Директива RUN задает команды для обновления, установки и настройки параметров внутри контейнера, включая выделенного пользователя и группу с именем www. Инструкция WORKDIR задает каталог /var/www как рабочий каталог приложения.

Создание отдельного пользователя и группы с ограниченными правами доступа снижает уязвимость при запуске контейнеров Docker, которые по умолчанию запускаются с привилегиями root. Вместо запуска этого контейнера с привилегиями root мы создали пользователя www с правами чтения и записи для папки /var/www с помощью команды COPY с флагом --chown для копирования разрешений папки приложения.

Команда EXPOSE открывает порт 9000 в контейнере для сервера php-fpm. CMD указывает команду, которая должна запускаться после создания контейнера. Здесь CMD указывает команду php-fpm, которая запускает сервер.

Когда закончите вносить изменения, сохраните файл и закройте редактор.

Теперь вы можете перейти к определению конфигурации PHP.

Настройка PHP

Вы определили инфраструктуру в файле docker-compose, и теперь можете настроить службу PHP для работы в качестве процессора PHP для входящих запросов Nginx.

Для настройки PHP вы создадите файл local.ini в папке php. Это файл, который вы привязали к файлу /usr/local/etc/php/conf.d/local.ini в контейнере выше. Создание этого файла позволит вам игнорировать файл по умолчанию php.ini, который PHP считывает при запуске.

Создайте каталог php:

mkdir ~/laravel-app/php


Затем откройте файл local.ini:

nano ~/laravel-app/php/local.ini


Чтобы продемонстрировать настройку PHP, мы добавим следующий код для установки ограничений размера выгруженных файлов:

~/laravel-app/php/local.ini

upload_max_filesize=40M
post_max_size=40M


Директивы upload_max_filesize и post_max_size задают максимальный разрешенный размер выгружаемых файлов и показывают, как задавать конфигурации php.ini из файла local.ini. Вы можете вставить любой параметр конфигурации PHP, который хотите игнорировать в файле local.ini.

Настройка Nginx

При настройке службы PHP вы можете изменять службу Nginx для использования PHP-FPM как сервера FastCGI для обслуживания динамического контента. Сервер FastCGI основан на двоичном протоколе для взаимодействия интерактивных программ с веб-сервером. Дополнительную информацию можно найти в статье «Понимание и реализация прокси FastCGI в Nginx».
Для настройки Nginx вы создадите файл app.conf с конфигурацией служб в папке ~/laravel-app/nginx/conf.d/.

Вначале создайте каталог nginx/conf.d/:

mkdir -p ~/laravel-app/nginx/conf.d


Затем создайте файл конфигурации app.conf:

nano ~/laravel-app/nginx/conf.d/app.conf


Добавьте в файл следующий код, чтобы задать конфигурацию Nginx:

~/laravel-app/nginx/conf.d/app.conf

server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}


Серверный блок задает конфигурацию веб-сервера Nginx с помощью следующих директив:

  • listen: эта директива определяет порт, который сервер прослушивает для получения входящих запросов.
  • error_log и access_log: эти директивы определяют файлы для записи журналов.
  • root: эта директива задает путь к корневой папке, формируя полный путь для любого запрошенного файла в локальной файловой системе.


В блоке расположения php директива fastcgi_pass указывает, что служба app прослушивает сокет TCP на порту 9000. С ней сервер PHP-FPM выполняет прослушивание через сеть, а не через сокет Unix. Хотя сокет Unix дает небольшое преимущество в скорости по сравнению с сокетом TCP, у него нет сетевого протокола и он пропускает сетевой стек. В случаях расположения хостов в одной системе использование сокета Unix может иметь смысл, но если службы работают на разных хостах, сокет TCP дает преимущество, позволяя подключаться к распределенным службам. Поскольку наши контейнеры app и webserver работают на разных хостах, в нашей конфигурации эффективнее использовать сокет TCP.

Когда закончите вносить изменения, сохраните файл и закройте редактор.

Благодаря привязке, созданной ранее, любые изменения в папке nginx/conf.d/ прямо отражаются в контейнере webserver.

Теперь посмотрим на параметры MySQL.

Настройка MySQL

После настройки PHP и Nginx вы можете активировать MySQL как базу данных для вашего приложения.

Для настройки MySQL нужно создать файл my.cnf в папке mysql. Это файл, который вы привязали к файлу /etc/mysql/my.cnf внутри контейнера на этапе конфигурирования базы данных. Привязка монтируемого образа позволяет игнорировать любые параметры my.cnf, если и когда это требуется.

Чтобы продемонстрировать, как это работает, мы добавим в файл my.cnf настройки, которые включают журнал общих запросов и задают файл журнала.

Создайте каталог mysql:

mkdir ~/laravel-app/mysql


Создайте файл my.cnf:

nano ~/laravel-app/mysql/my.cnf


Добавьте в файл следующий код, чтобы активировать журнал запросов и задать местоположение файла журнала:

~/laravel-app/mysql/my.cnf

[mysqld]
general_log = 1
general_log_file = /var/lib/mysql/general.log


Файл my.cnf поддерживает журналы, задавая для параметра general_log значение 1, разрешающее общие журналы. Параметр general_log_file указывает, где будут храниться журналы.

Запуск контейнеров и изменение параметров среды

Вы определили все службы в файле docker-compose и создали файлы конфигурации для этих служб. Теперь вы можете запускать контейнеры. В заключение мы создадим копию файла .env.example, которую Laravel включает по умолчанию, и назовем ее .env, поскольку Laravel использует такой файл для определения среды:

cp .env.example .env


После запуска контейнеров мы настроим в этом файле конкретные параметры установки.

Теперь все ваши службы определены в файле docker-compose, и вам просто нужно запустить одну команду для запуска всех контейнеров, создания томов и настройки и подключения сетей:

docker-compose up -d


При первом запуске docker-compose up будут загружены все необходимые образы Docker, что может занять некоторое время. После загрузки образов и их сохранения на локальном компьютере Compose создаст ваши контейнеры. Флаг -d преобразует процесс в демона, с которым контейнеры остаются запущенными в фоновом режиме.

После завершения процесса используйте следующую команду для вывода списка всех запущенных контейнеров:

docker ps

Вы увидите следующие результаты с данными о контейнерах app, webserver и db:

Output
CONTAINER ID        NAMES               IMAGE                             STATUS              PORTS
c31b7b3251e0        db                  mysql:5.7.22                      Up 2 seconds        0.0.0.0:3306->3306/tcp
ed5a69704580        app                 digitalocean.com/php              Up 2 seconds        9000/tcp
5ce4ee31d7c0        webserver           nginx:alpine                      Up 2 seconds        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp


В этих результатах CONTAINER ID — это уникальный идентификатор каждого контейнера, а NAMES перечисляет имена служб для каждого контейнера. Вы можете использовать для доступа к контейнерам оба эти идентификатора. IMAGE определяет имя образа каждого контейнера, а STATUS предоставляет информацию о состоянии контейнера: запущен, перезапускается или остановлен.

Теперь вы можете изменить файл .env в контейнере app, чтобы добавить определенные параметры вашей системы.

Откройте файл с помощью docker-compose exec, позволяющего запускать определенные команды в контейнерах. В этом случае вы открываете файл для редактирования:

docker-compose exec app nano .env


Найдите блок, задающий DB_CONNECTION и обновите его для отражения особенностей настройки вашей системы. Вы измените следующие поля:

  1. DB_HOST будет вашим контейнером базы данных db.
  2. DB_DATABASE будет базой данных laravel.
  3. DB_USERNAME будет именем пользователя для вашей базы данных. В этом случае мы будем использовать laraveluser.
  4. DB_PASSWORD будет защищенным паролем для этой учетной записи пользователя.


/var/www/.env

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laraveluser
DB_PASSWORD=your_laravel_db_password


Так же необходимо поправить эти же переменные в файле .env.example, так как он будет использован позже при разворачивании на сервере.

Затем настройте ключ приложения для Laravel с помощью команды php artisan key: generate. Эта команда сгенерирует ключ и скопирует его в файл .env, что обеспечит защиту сеансов пользователя и шифрованных данных:

docker-compose exec app php artisan key:generate


Теперь у вас есть все необходимые настройки среды для запуска приложения. Чтобы кэшировать эти настройки в файле, ускоряющем загрузку приложения, запустите команду:

docker-compose exec app php artisan config:cache


Настройки конфигурации будут загружены в файл /var/www/bootstrap/cache/config.php в контейнере.

В заключение откройте в браузере сайт localhost. Откроется главная страница приложения Laravel.

Создание пользователя MySQL

При установке MySQL по умолчанию создается только административная учетная запись root с неограниченными привилегиями доступа к серверу баз данных. Обычно при работе с базой данных лучше избегать использования административной учетной записи root. Вместо этого мы создадим специального пользователя базы данных для базы данных Laravel нашего приложения.
Чтобы создать нового пользователя, запустите интерактивную оболочку bash в контейнере db с помощью команды docker-compose exec:

docker-compose exec db bash


Выполните внутри контейнера вход в административную учетную запись MySQL root:

mysql -u root -p


Вам будет предложено ввести пароль, заданный для учетной записи MySQL root при установке в файл docker-compose.

Для начала проверьте наличие базы данных laravel, определенной в файле docker-compose.
Запустите команду show databases для проверки существующих баз данных:

show databases;


В результатах вы должны увидеть базу данных laravel:

Output
+--------------------+
| Database           |
+--------------------+
| information_schema |
| laravel            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)


Затем создайте учетную запись пользователя, которой будет разрешен доступ к этой базе данных.
Мы используем имя пользователя laraveluser, но вы можете заменить его любым предпочитаемым именем. Просто убедитесь, что имя пользователя и пароль соответствуют заданным в файле .env на предыдущем шаге:

GRANT ALL ON laravel.* TO 'laraveluser'@'%' IDENTIFIED BY 'your_laravel_db_password';


Обновите привилегии, чтобы уведомить сервер MySQL об изменениях:

FLUSH PRIVILEGES;


Закройте MySQL:

EXIT;


Выйдите из контейнера:

exit


Теперь можно сделать миграцию, чтобы проверить работу базы данных:

docker-compose exec app php artisan migrate


Результаты подтверждения миграции выглядят следующим образом:

Output

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table


Часть 2. Gitlab


В гитлабе необходимо создать новый проект.

Теперь нам нужно сохранить проект в репозитории гитлаба. Для этого вызываем из папки проекта на локальной машине следующие команды:

git init
git remote add origin git@gitlab.com:<аккаунт>/<проект> или 
git remote add origin https://gitlab.com/<аккаунт>/<проект> если не хочется возится с SSH
git add .
git commit -m "Initial commit"
git push -u origin master


Проект должен оказаться в Project Overview → Details
Чтобы было удобно сразу получать готовую среду мы сохраняем докер-образ среды в регистре гитлаба.

Для этого необходимо сделать:

docker login registry.gitlab.com


И закинуть образ на гитлаб:

docker build -t registry.gitlab.com/<аккаунт>/<проект> .
docker push registry.gitlab.com/<аккаунт>/<проект>


Образ будет находится в Packages→Container Registry

Чтобы закончить с гитлабом сразу получим ключ от gitlab-runner. Для этого необходимо зайти в Setting→CI/CD→Runner. Ключ находится на 3 шаге в разделе Ручная настройка (Set up a specific Runner manually).

Часть 3. Настройка на сервере


VPS сервер необходимо брать с виртуализацией типа KVM или XEN. Виртуализация типа OpenVZ делит ядро системы между всеми пользователями, поэтому у него нет возможностей изменять параметры ядра. Для теста я брал KVM сервер с предустановленным Docker. Однако докера на сервере может и не быть. В этом случае его необходимо установить вручную. Алгоритм такой же как при установке на локальной машине. Так же необходимо проверить версию php. Для Laravel нужно не менее 7.2. Так же мне пришлось отдельно установить расширение для php ext-mbstring (в моем случае для версии php 7.3):

sudo apt-get update
sudo apt-get install php7.3-mbstring


Далее нам необходимо установить gitlab-runner. Runner это сервис, который будет принимать вебхук от гитлаба при получении новой версии и разворачивать все на нашем сервере.

Для установки gitlab-runner нужно выполнить:

curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64


После скачивания задать разрешение на исполнение:

sudo chmod +x /usr/local/bin/gitlab-runner


Далее создаем пользователя gitlab-runner и запускаем сервис gitlab runner:

sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner start


Регистрируем runner. Для этого нам понадобится токен из части 2 этой статьи:

sudo gitlab-runner register


В ответ у вас спросят адрес вашего гитлаба.

Указываем gitlab.com:

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
https://gitlab.com


Далее необходимо ввести токен. Вводим токен из части 2.

Please enter the gitlab-ci token for this runner
xxx


Далее указываем описание и теги через запятую. Потом нам предлагают выбрать экзекутор. Здесь необходимо выбрать shell:


Please enter the executor:
shell


Как я понял экзекутор это среда, в которой выполняется код из файла .gitlab-ci.yml. На выбор есть bash, ssh, docker, parallels, virtualbox и kubernets. В документации рекомендуют если вы не знаете чем воспользоваться — пользоваться bash. Это универсальный вариант, который выполняется в командной строке на вашем сервере.

Потом нам необходимо добавить пользователя gitlab-runner в группу пользователей docker.

sudo usermod -aG docker gitlab-runner


Чтобы не возникало ошибок доступа, добавляем в sudoers

sudo nano /etc/sudoers


строку

gitlab-runner ALL=(ALL) NOPASSWD: ALL


Теперь мы можем создать файл .gitlab-ci.yml. Он необходим для выполнения так называемых Pipeline: последовательности команд для разворачивания проекта.

Для этого необходимо зайти в репозиторий проекта на гитлабе и нажать Создать новый файл. Гитлаб сам предложит шаблоны файлов, среди них необходимо выбрать .gitlab-ci.yml. После создания файла в гитлабе есть возможность выбрать шаблон содержимого файла. Я выбрал laravel и немного переделал под себя:


# This file is a template, and might need editing before it works on your project.
# Official framework image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/php
#Базовый образ. В нашем случае образ, который был загружен в регистр во второй части
image: registry.gitlab.com/<аккаунт>/<образ>:latest

# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
services:
  - mysql:latest
#Переменные для доступа к БД
variables:
  MYSQL_DATABASE: laravel
  MYSQL_ROOT_PASSWORD: ***********

# This folder is cached between builds
# Папки, которые будут кэшироваться при билде 
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
cache:
  paths:
    - vendor/
    - node_modules/

# This is a basic example for a gem or script which doesn't use
# services such as redis or postgres
# Здесь будут выполнены подготовительные команды
before_script:
  # Обновлены все пакеты
  - sudo apt-get update -yqq
  # Подготовлен для установки nodejs
  - sudo apt-get install gnupg -yqq
  # Обновлен Node до версии 12
  - curl -sL https://deb.nodesource.com/setup_12.x | sudo bash -
  # Установлены зависимости
  - sudo apt-get install git nodejs libcurl4-gnutls-dev libicu-dev libmcrypt-dev libvpx-dev libjpeg-dev libpng-dev libxpm-dev zlib1g-dev libfreetype6-dev libxml2-dev libexpat1-dev libbz2-dev libgmp3-dev libldap2-dev unixodbc-dev libpq-dev libsqlite3-dev libaspell-dev libsnmp-dev libpcre3-dev libtidy-dev -yqq
  # Установлен composer
  - curl -sS https://getcomposer.org/installer | php
  - php composer.phar install
  - composer install
  # Установлены зависимости Node
  - npm install
  # Copy over testing configuration.
  # Don't forget to set the database config in .env.testing correctly
  - DB_HOST=mysql
  - DB_DATABASE=laravel
  - DB_USERNAME=root
  - DB_PASSWORD=*********
  # Меняем .env.example в файл конфигурации .env
  - cp .env.example .env
  # Делаем npm build
  - npm run dev
  # Очищаем кэш и генерируем ключ для laravel
  - php artisan key:generate
  - php artisan config:cache
  - php artisan route:clear
  - php artisan config:clear
  - php artisan cache:clear
  # Делаем миграции.
  - docker-compose exec app php artisan migrate
  # Делаем сиды БД
  #- docker-compose exec app php artisan db:seed

#тестирование
test:
  script:
    # запускаем тесты
    - php vendor/bin/phpunit --coverage-text --colors=never
    # тесты npm
    - npm test

# деплой на сервере    
deploying:
  stage: deploy
  script:
    - echo "Deployed"
    - docker-compose stop
    - docker-compose up -d


После успешного выполнения пайплайна (CI/CD→Pipelines) по ip адресу вашего сервера вы должны увидеть вашу страницу laravel.

Для настройки CI/CD я использовал инструкцию от Sean Bradley:


и medium.com/@sean_bradley/auto-devops-with-gitlab-ci-and-docker-compose-f931233f080f

© Habrahabr.ru