rsync в GitLab CI: развёртывание по SSH

Коротко: покажу, как использовать rsync внутри Docker‑окружения GitLab CI для безопасного развёртывания по SSH. Вы получите готовые примеры .gitlab-ci.yml, инструкции по добавлению SSH‑ключа и known_hosts, чеклисты безопасности и готовые сниппеты для Alpine и Debian образов.
Быстрые ссылки
- Pipeline Executors
- Getting Ready
- Adding Your Pipeline File
- Installing SSH and rsync
- Managing Host Verification
- Further Improvements
- Summary
rsync — популярная утилита для синхронизации файлов, оптимизированная по трафику. Частое применение — развёртывание готовой сборки сайта на удалённый production‑сервер. В этой статье мы объединяем гибкость rsync с автоматизацией GitLab CI, чтобы безопасно и предсказуемо доставлять артефакты на удалённый хост.
Pipeline Executors
GitLab CI поддерживает несколько типов исполнителей (executors), которые определяют окружение для выполнения job’ов.
shell — выполняет задачи на хосте раннера напрямую. Достоинство: доступ ко всем установленным в системе командам, в том числе rsync, без дополнительных шагов. Недостаток: слабая изоляция и риск загрязнения хоста.
docker — создаёт новый контейнер для каждой job’ы. Плюсы: чистое окружение, предсказуемость и повторяемость. Минус: официальный образ, например
ubuntu:latestилиalpine:latest, часто не содержитrsyncиsshпо умолчанию, поэтому придётся добавить зависимости в скрипт.
Мы предполагаем, что вы используете Docker‑based GitLab Runner. Если у вас shell‑runner и rsync уже установлен на хосте, многие шаги можно упростить.
Getting Ready
Требования перед началом:
- Доступ в репозиторий проекта в GitLab.
- Docker‑раннер или shell‑раннер с правами на выполнение необходимых команд.
- SSH‑ключи: сгенерированная пара публичного/приватного ключей, публичный ключ добавлен в
~/.ssh/authorized_keysна целевом сервере.
Генерация ключей (на вашей машине):
ssh-keygen -t rsaСкопируйте публичный ключ на сервер или используйте ssh-copy-id, если он доступен:
ssh-copy-id user@example.comПриватный ключ нужно поместить как защищённую переменную в настройки GitLab CI. На локальной машине можно показать приватный ключ в буфер обмена, например (Linux с xclip):
cat ~/.ssh/id_rsa | xclip -selection cВ GitLab: Settings → CI/CD → Variables. Нажмите Add variable, введите ключ SSH_PRIVATE_KEY и вставьте значение приватного ключа целиком, включая строки -----BEGIN/-----END.

Убедитесь, что флажок «Protect variable»/«Masked» выставлен в соответствии с вашей политикой безопасности.
Adding Your Pipeline File
GitLab CI использует файл .gitlab-ci.yml в корне репозитория. Простейший пример job’ы, который попытается выполнить rsync, но упадёт на чистом Alpine образе, выглядит так:
deploy:
stage: deploy
image: alpine:latest
script:
- rsync -atv --delete --progress ./ user@example.com:/var/www/htmlЭта конфигурация синхронизирует рабочую директорию репозитория в /var/www/html на сервере example.com под пользователем user. На деле rsync отсутствует в базовом Alpine, поэтому pipeline завершится с ошибкой.
Installing SSH and rsync
Лучше добавить OpenSSH и rsync в контейнер. Alpine подойдёт, потому что он лёгкий, а установка занимает мало места и времени. Пример расширенной секции before_script:
deploy:
stage: deploy
image: alpine:latest
before_script:
- apk update && apk add --no-cache openssh-client rsync
- mkdir -p ~/.ssh
- eval "$(ssh-agent -s)"
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
script:
- rsync -atv --delete --progress ./ user@example.com:/var/www/htmlПояснения:
apk add --no-cache openssh-client rsync— устанавливает необходимые пакеты в контейнере.mkdir -p ~/.ssh— создаёт директорию для ключей и known_hosts.ssh-agentиssh-add— добавляют приватный ключ в агент для аутентификации.tr -d '\r'— удаляет возможные символы CRLF, которые могут сломать формат ключа при копировании из Windows.
Альтернативный образ: Debian/Ubuntu
Если вы предпочитаете Debian/Ubuntu как базу, используйте официальный образ и установите пакеты через apt:
deploy-debian:
stage: deploy
image: debian:stable-slim
before_script:
- apt-get update && apt-get install -y openssh-client rsync ca-certificates
- mkdir -p ~/.ssh
- eval "$(ssh-agent -s)"
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
script:
- rsync -az --delete ./ user@example.com:/var/www/htmlИспользуйте -a/-z флаги rsync в зависимости от требований: -a (архивный режим) сохраняет права и симлинки, -z включает сжатие при пересылке.
Managing Host Verification
SSH по умолчанию запрашивает подтверждение ключа сервера при первом подключении — в CI это невозможно ответить интерактивно. Есть два подхода:
- Отключить строгую проверку хоста (несмотря на риск).
- Добавить known_hosts заранее как защищённую переменную — предпочтительный безопасный вариант.
Пример (небезопасный) — отключение проверки хоста:
- echo "Host *\n StrictHostKeyChecking no\n UserKnownHostsFile=/dev/null" >> ~/.ssh/configЭтот метод упрощает подключение, но делает вас уязвимыми к MITM‑атакам — не рекомендуем для production.
Безопасный вариант — добавить строку из вашего ~/.ssh/known_hosts в переменные GitLab как SSH_HOST_KEY, затем в pipeline:
before_script:
- mkdir -p ~/.ssh
- echo "$SSH_HOST_KEY" > ~/.ssh/known_hostsЧтобы получить строку known_hosts локально, выполните на своей машине:
ssh-keyscan -t rsa example.comили подключитесь к серверу один раз и скопируйте соответствующую строку из ~/.ssh/known_hosts.

Полный пример .gitlab-ci.yml — готовый к использованию
Ниже пример CI‑конфига с переменными для удобства и безопасными шагами:
stages:
- build
- deploy
variables:
TARGET_USER: "user"
TARGET_HOST: "example.com"
TARGET_DIR: "/var/www/html"
deploy:
stage: deploy
image: alpine:latest
before_script:
- apk update && apk add --no-cache openssh-client rsync
- mkdir -p ~/.ssh
- echo "$SSH_HOST_KEY" > ~/.ssh/known_hosts
- eval "$(ssh-agent -s)"
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
script:
- rsync -az --delete --progress ./ "$TARGET_USER"@"$TARGET_HOST":"$TARGET_DIR"
only:
- mainКлючевые моменты:
- Переменные
TARGET_USER,TARGET_HOST,TARGET_DIRвыносятся в разделvariablesдля простоты изменения и безопасности. only: - mainограничивает выполнение деплоя веткой main (можно заменить на protected branches или тэги).
Further Improvements
Рекомендации для повышения надёжности и повторяемости:
- Собирайте кастомный Docker‑образ с уже установленными rsync и ssh, публикуйте его в приватном реестре. Так вы ускорите pipeline и уменьшите количество команд в
before_script. - Разделяйте стадии: сначала создавайте артефакт (build), затем в stage deploy используйте только нужные артефакты, минимизируя размер данных.
- Используйте проверки целостности: перед релизом выполняйте быструю проверку контрольных сумм (например,
sha256sum) и сохраняйте их в артефакте. - Настройте SLI/SLO для пайплайнов: время выполнения деплоя и его успешность.
- Логируйте вывод rsync в отдельный артефакт для последующего анализа (особенно при проблемах с синхронизацией).
Безопасность и лучшие практики
- Храните приватный ключ как защищённую/защищённую и защищённую переменную (protected/masked) в GitLab.
- Минимизируйте привилегии ключа: используйте отдельного пользователя на сервере с ограниченными правами; применяйте
command=иfrom=вauthorized_keys, если нужно. - Ограничьте доступ по IP, если возможно (firewall, cloud security groups).
- Используйте проверку known_hosts вместо отключения StrictHostKeyChecking.
- Рассмотрите использование более безопасного ключа (ed25519) вместо устаревшего rsa.
Troubleshooting — распространённые проблемы и их решения
- Ошибка
Permission denied (publickey): проверьте, что приватный ключ корректно добавлен в GitLab и что публичный ключ вauthorized_keysсовпадает. - Ошибка с форматом ключа: используйте
tr -d '\r'при чтении переменной, чтобы убрать CRLF. - Rsync завершает работу с ошибкой прав: проверьте права на целевой директории и пользователя, под которым выполняется rsync.
- Производительность низкая: включите
-zдля сжатия, оптимизируйте exclude (исключайте node_modules, .git и т. п.).
Playbook для безопасного деплоя (шаги)
- На локальной машине сгенерируйте ключи:
ssh-keygen -t ed25519. - Добавьте публичный ключ в
/home/deploy/.ssh/authorized_keysна целевом сервере. - В GitLab Settings → CI/CD → Variables добавьте
SSH_PRIVATE_KEY(masked, protected) иSSH_HOST_KEY(masked). - Добавьте
.gitlab-ci.ymlс приведённой выше конфигурацией и переменными. - Протестируйте деплой в staging‑ветке на отдельном сервере.
- После успешного теста включите запуск только для protected ветки main или тэгов релиза.
Критерии приёмки
- Pipeline успешно завершает job деплоя без интерактивных подсказок.
- Файлы в целевой директории совпадают с ожидаемыми (проверка checksum или директории).
- Приватный ключ хранится как защищённая переменная; known_hosts добавлен заранее.
Примеры exclude/rsync‑шаблонов
Если не нужно копировать временные или локальные каталоги, добавьте файл .rsync-filter или флаг --exclude:
rsync -az --delete --progress --exclude 'node_modules' --exclude '.git' ./ user@example.com:/var/www/htmlФайл .rsync-filter (пример):
- node_modules/
- .git/
- tmp/Snippet: создание собственного Docker образа с rsync и ssh
Dockerfile для образа, который можно использовать как image в .gitlab-ci.yml:
FROM alpine:latest
RUN apk update && apk add --no-cache openssh-client rsync ca-certificates
ENTRYPOINT ["/bin/sh", "-lc"]Соберите и загрузите образ в реестр, затем указывайте его в конфиге:
image: registry.example.com/ci-images/alpine-rsync:latestЭто ускорит время запуска job’ов и упростит содержание before_script.
Mini‑методология: как подойти к деплою через rsync
- Минимизируйте права доступа и используйте отдельного пользователя deploy.
- Храните секреты в CI переменных, не в репозитории.
- Используйте known_hosts для проверки подлинности сервера.
- Тестируйте на staging перед production.
- Логируйте и сохраняйте артефакты логов для диагностики.
Глоссарий (1‑строчные определения)
- rsync: утилита для эффективной синхронизации файлов между локальным и удалённым узлом.
- GitLab Runner: процесс, выполняющий CI job’ы для проекта.
- SSH agent: менеджер приватных ключей для аутентификации по SSH.
- known_hosts: файл, содержащий публичные ключи серверов для проверки подлинности.
Decision flow (Mermaid)
flowchart TD
A[Есть Docker Runner?] -->|Да| B[Добавить rsync и ssh в before_script]
A -->|Нет| C[Проверить, установлен ли rsync на хосте]
B --> D{Добавлен known_hosts?}
D -->|Да| E[Добавить SSH_PRIVATE_KEY как переменную]
D -->|Нет| F[Добавить SSH_HOST_KEY в GitLab Variables]
C --> G[Использовать shell runner или встроенный rsync]
E --> H[Запустить pipeline]
F --> H
G --> HSummary
Использование rsync в GitLab CI даёт быстрый и надёжный способ развёртывания файлов по SSH, но требует ручной настройки окружения в Docker‑job’ах: установки openssh-client и rsync, добавления приватного ключа в CI‑переменные и регистрации known_hosts. Оптимальный путь — выносить часто используемые зависимости в свой Docker‑образ, выносить параметры (хост, путь, пользователь) в переменные, и следовать практикам безопасности при хранении ключей.
Вам доступны варианты: быстрое, но рискованное отключение проверки хоста, либо безопасный метод с добавлением known_hosts. Для production рекомендуется второй.
Важно
- Никогда не храните приватный ключ в репозитории.
- Тестируйте деплой в staging перед production.
Дополнительные ресурсы и чеклисты размещены выше в статье.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента