Как стать автором
Обновить

Как быстро сделать flatfile-сайт с CI/CD и бэкапами

Уровень сложностиСредний

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

Что требовалось:

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

  2. шустрая и плоская (flat-file) CMS, потому что для такой задачи БД не нужна

  3. чтобы была админка для добавления контента

  4. настроить бэкапы

  5. чтобы все было безопасно

  6. чтобы можно было дописывать всякий функционал если надо

Выбирал между:

  • Lektor CMS (python + jinja2)

  • Automad (PHP+ AML)

  • GravCMS (PHP+ twig)

Сначала тестил Lektor, т.к. python это мой основной язык и с jinja2 я отлично знаком. Но не понравилась убогая админка и мутноватая документация. Бывает так, что читаешь документацию и все понятно, а тут нужно прям рисерч делать, а на это времени нет (см. пункт 1 требований). Приятно, что можно хостить бесплатно на Github, но если так сделать, то серверные скрипты потребовали бы передеплоя на виртуальный хостинг или на VPS.

Вердикт: не подошло

Automad - новый интересный проект, выглядит очень нарядно и хочется его потестировать. Забраковал его, главным образом, из-за того, что поднятая в docker-е тестовая сборка заметно лагала. Возможно проблема на моей стороне, но разбираться и тестить некогда, надо дело делать а не в кроличьи норы прыгать. Плюс у них свой шаблонизатор AML (Automad Markup Language), его надо отдельно изучать, можно залипнуть надолго.

Вердикт: интересно, но нет времени разбираться

GravCMS - не новый, но проверенный проект на PHP + Twig. PHP не сильно люблю, но знаю. С twig работал еще на symfony. Очень подробная документация. Куча skeleton-проектов где можно потыкать и посмотреть как сделано. Хорошая админка.

Вердикт: подходит, берем

Рабочая среда

Разработкой занимаюсь в Linux Mint, считай та же убунта. Редактор кода VSCodium (форк MS VSCode но без телеметрии). И docker как основной инструмент изоляции среды.

В самом Grav для базового теста нет встроенного веб-сервера. Но он и не нужен, ведь можно dev-сервер на "голой" PHP запустить, выполнив из рута проекта:

php -S localhost:8000 system/router.php

Но в целом конечно надо запускать в докере, т.к. тогда никаких проблем с совместимостью не будет. Локально пишешь в докере, деплоишь в докере - красота.

Обычно для проектов на python я быстренько пишу docker-compose.yml файл с gunicorn, и все быстро запускается и работает. А вот с PHP все не так легко оказалось, там надо apache или nginx настраивать под нужный для Grav конфиг. Конфиг для nginx (мой выбор) заботливо поставляется в комплекте, но тоже своего рода запара.

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

В итоге гугления я нашел готовый docker образ от довольно толковой команды https://docs.linuxserver.io/images/docker-grav/
Я привык запускать контейнеры через docker-compose, потому что обычно в достойном деплоя в докере проекте более одного контейнера. Сборщики образа заботливо предоставили готовый docker-compose.yml:

services:
  grav:
    image: lscr.io/linuxserver/grav:latest
    container_name: grav
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
    volumes:
      - /path/to/grav/config:/config
    ports:
      - 80:80
    restart: unless-stopped

Запустил образ, залез в папку config и порадовался тому, что туда вывели все что нужно: конфиги сервера, логи и те файлы самой CMS, которые как раз нужно бэкапить:

  • user/pages - контент

  • user/themes - шаблоны

  • user/config - конфиг сайта

  • user/plugins - плагины

  • user/data - всякие нестандартные загруженные данные

В моем случае используется слегка модифицированный шаблон learn2 и стандартный набор плагинов, поэтому я в схему моего кастомного деплоя и бэкапа включил user/pages и user/themes. Все прочее в случае чего восстанавливается за 20 минут.

Деплой и бэкап

Вот тут как раз я решил сделать бескомпромиссную схему backup-first, т.к. я как любой уважающий себя разработчик рационально ленив, а значит надо делать так, чтобы все нужное делалось само. Ну или в рамках общего workflow и нельзя было срезать угол.

А еще я умею в автоматизацию с помощью github actions, что делает меня чертовски эффективным лентяем. Я реализовал такую схему:

Локально у меня Grav висит в докере, аналогично тому как он задеплоен на VPS. В нем я пишу контент и вношу правки в шаблон.

Все это конечно же пушится в github-репозиторий.

В репозитории настроена CI/CD схема деплоя на VPS, которая при пуше в main:

  • подключается к серверу по SSH

  • идет в папку с репозиторием

  • пуллит свеженькие изменения из ветки main

  • копирует изменившиеся файлы в папку проекта

Почему отдельная папка для репозитория? Когда репо был в папке проекта, что-то капитально ломалось на стороне прода, и куда проще пуллить в отдельную папку и оттуда только нужное копировать, чем искать где там проблема.

Для любопытствующих привожу конфиг для github actions:

name: CI/CD Pipeline

on:
  push:
    branches: [ main ]

jobs:
  deploy:

    runs-on: ubuntu-latest
    steps:

    - name: Checkout code
      uses: actions/checkout@v2

    - name: Exec remote cmd w. ssh key
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.SERVER_IP }}
        username: ${{ secrets.SSH_USER }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        port: ${{ secrets.SSH_PORT }}
        script: |
          cd project_git
          GIT_SSH_COMMAND="ssh -i /home/user/.ssh/github_project" git stash
          GIT_SSH_COMMAND="ssh -i /home/user/.ssh/github_project" git pull
          cp -R ./config/www/user/pages/* /home/user/project_folder/config/www/user/pages/
          cp -R ./config/www/user/themes/* /home/user/project_folder/config/www/user/themes/

Пояснительная бригада превентивно выехав поясняет, что параметр:

GIT_SSH_COMMAND="ssh -i /home/user/.ssh/github_project"

идущий перед привычным вызовом git - ни что иное, как указание какой ssh-ключ использовать для подключения к репо. Дело в том, что deploy key в разных репо не может быть один и тот же, а у меня на этом сервере несколько проектов автоматизированы аналогичным способом. Можно конечно написать в ~/.ssh/config инструкции на этот счет, но написать так в YAML-файл который управляет деплоем проще и быстрее.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.