Hugo CMS. CI/CD нищеброда. Автоматизация деплоя на хостинге за 79 рублей в месяц
Почему именно hugo
У меня возникла идея опять снова сделать свой сайт. Но не хотелось в полной
начать снова играть в администратора - заниматься настройкой СУБД, тюнингом PHP
скриптов(Drupal, Wordpress, etc.).
Выбор пал на генераторы статических сайтов. Из нескольких вариантов был выбран hugo - за отсутсвие тотальных зависимостей от npm, nodejs, webpack и прочих вещей.
Плюс правка страниц в виде .md файлов c возможностью хранить в git - очень
пришлись по душе. При необходимости можно быстро навалять скрипт, который
перетащит контент в любую из современных CMS.

Бонусом стало то, что итоговый сайт, который вы перед собой видите – размещен на дешевом хостинге за 79 рублей в месяц.
Проблема
Размер исходного кода уже составляет порядка 20 мегабайт в сжатом виде, размер сайта в сгенерированном несжатом виде - 50 мегабайт.
На хостинге для загрузки есть FTP.
Рекомендованный способ выгрузки по документации hugo – взять утилиту rclone(корявая имитация утилиты rsync) – и производить синхронизацию файлов с ее помощью.
Но данный процесс был слишком медленный, работает с ftp rclone медленно и коряво + некорректно отрабатывает некоторые вещи с временем изменения файла.
При этом было замечено, что если запулить на хостинг архив мегабайт на 20 - это проходит довольно быстро.
Итого: нужно придумать способ быстро и надежно выгружать сайт.
Особенности хостинга
- работает и довольно свежий PHP
- можно класть статические бинарники на ftp и работает exec() в PHP
- при этом варианты использовать гит или все что работает с сетью отпадают – хостер заблокировал сеть для приложений кроме PHP
- есть какието рабочие вещи в ОС – работает sh/bash, работает tar.
- www доступен на запись
Решение
Посколько я сам себе автор, мне не надо заботиться о проблемах, что кто-то кроме меня тоже запустит деплой, это меня освобождает от общего случая решения проблемы - заботиться о блокировках множественного запуска скриптов мне не нужно.
Поэтому было принято решение:
- положить на сервере статически собранный бинарник hugo, исполняемость была проверена
- Сделать скрипт на клиентской стороне, упаковывающий исходный код сайта в архив, отправляющий его на хостинг, и вызывающий на хостинге принимающий скрипт - см п.3
- сделать PHP скрипт на сервере, который распаковывает файл, и запускает генератор hugo, пересобирая контент.
Скрипт на клиенте.
Листинг ./deploy.sh
#!/bin/sh
# грузим переменные окружения с паролями и прочим
. .deploy_cred
# архивируем сайт
tar --exclude-vcs -c -z -f ./build/azarov-pro.tgz config.toml archetypes content layouts static themes
# удаляем возможно загруженный ранее файл
curl -X DELETE "ftp://$ftp_user:$ftp_pass@$ftp_host/$ftp_upload_path/azarov-pro.tgz"
# загружаем файл
curl -T ./build/azarov-pro.tgz "ftp://$ftp_user:$ftp_pass@$ftp_host/$ftp_upload_path/"
# вызываем ответную часть на сервере
curl "http://azarov-pro.ru/deploy.php?token=$deploy_token"
# удаляем локальную сборку
rm ./build/azarov-pro.tgz
Данный файл требует своего конфига .deploy_cred
ftp_user=yourftp
ftp_pass=такяисказалвампароль
ftp_host=megaduperhost.ru
ftp_upload_path=www/azarov-pro.ru-hugo-source
deploy_token=щаз
Скрипт на сервере
Данный скрипт так же надо будет положить в папку static сайта, либо размещать так, чтобы генерация сайта его не аффектила
<?php
header('Content-type: text/plain; charset: utf-8');
error_reporting(E_ALL);
set_time_limit(0);
require_once('deploy_config.php');
$c = get_deploy_config();
if (strcmp($_GET['token'], $c['token']) !== 0) die('fuck off looser');
if (!chdir($c['source_dir']) ) die('Cannot chdir to source dir');
echo "Unpacking archive\n";
$out = [];
$result = exec('tar xvf azarov-pro.tgz', $out);
if ($result === false) {
die("Cannot unpack archive");
}
echo implode("\n", $out);
if (!chdir($c['site_dir']) ) die('Cannot chdir to site directory');
echo "\nBuilding site on production\n";
chdir($c['source_dir']);
$out = [];
$result = exec('HUGO_ENV=production ' . $c['hugo_path'] . ' --gc --source ' . $c['source_dir'] . ' -d ' . $c['site_dir'] . ' --minify 2>&1 ', $out);
if (false === $result) die('error running hugo');
echo implode("\n", $out);
echo "\ncleanup dir\n";
exec('rm -rf ' . $c['source_dir'] . '/*');
Даннный скрипт требует свой конфигурационный файл.
<?php
function get_deploy_config() {
return [
'site_dir' => '/var/www/data/www/azarov-pro.ru',
'hugo_path' => '/var/www/data/www/bin/hugo',
'source_dir' => '/var/www/data/www/azarov-pro.ru-hugo-source',
'token' => 'щаз'
];
}
Заключение
Схема дешевая и сердитая. Да, местами конфиги с открытыми паролями :-)
Но, если вы хотите как сейчас модно у хипстеров и нежных бородачей - можно поднять CI/CD, пару инстансов с раннерами, запилить триггеры на гит и деплоить по коммиту. И пароли в Vault, ага. И даже весь сайт собирать большой статический бинарник, чтобы гонять в отдельных инстансах в kubernetes
Мне на данный момент времени такая пустая переплата за воздух кажется нецелесообразной.