Резервное копирование GitLab с помощью rsync



На днях я задался целью, полностью автоматизировать процесс резервного копирования GitLab. Для решения этой задачи я решил использовать rsync. На другой машине запустил rsync-сервер. Осталось дело за малым, написать shell-скрипт и добавить его в cron, но я решил пойти немного другим путем…

Задачи:

  • Настроить резервное копирование GitLab с помощью rsync;
  • Запускать задачу резервного копирования по cron, раз в сутки;
  • Отправлять уведомления через HipChat.

Версия ПО:

  • Ubuntu Server 15.04;
  • GitLab 7.10.4;
  • ZSH 5.0.7.

Первым делом, создаем необходимую структуру для нашего мини-проекта:

$ mkdir ~/gitlab_backup && cd ~/gitlab_backup
$ for dir (bin config lib models); do mkdir $dir; done
$ touch Gemfile

Добавляем в Gemfile необходимые библиотеки:

source 'https://rubygems.org'

# Easy full stack backup operations on UNIX-like systems
# https://github.com/backup/backup
gem 'backup'

# Cron jobs in Ruby
# https://github.com/javan/whenever
gem 'whenever', require: false

# Loads environment variables from `.env`
# https://github.com/bkeepers/dotenv
gem 'dotenv'

И устанавливаем их:

$ bundle install

Основные настройки нашего мини-проекта буду храниться в файле .env:

ROOT_PATH="$HOME/gitlab_backup"

HIPCHAT_TOKEN=test_token
HIPCHAT_ROOMS=Backup

RSYNC_HOST=example.com
RSYNC_SSH_USER=user
RSYNC_PATH=/home/user/backup

А тепень подробнее о каждом из них:

  • ROOT_PATH - местоположение проекта;
  • HIPCHAT_TOKEN - ключ, необходимый для работы с HipChat;
  • HIPCHAT_ROOMS - список комнат, куда будут отправляться уведомления;
  • RSYNC_HOST - адрес rsync-сервера;
  • RSYNC_SSH_USER - имя пользователя, для доступа по ssh;
  • RSYNC_PATH - путь, куда будет выполняться резервное копирование на rsync-сервере.

Чтобы иметь возможность, выполнять резервное копирование системных файлов, необходимо запускать rsync через sudo. Для этого, потребуется немного доработать библиотеку backup. Создаем файл lib/rsync.rb:

# encoding: utf-8

require 'backup'

module Backup
  module Syncer
    module RSync
      class Push
        attr_accessor :use_sudo

        private

        def rsync_command
          command = (super << compress_option << password_option << transport_options)
          command = "#{utility(:sudo)} #{command}" if use_sudo
          command
        end
      end
    end
  end
end

Теперь нужно подключить наш небольшой патч к библиотеке backup. Для этого создаем файл bin/backup:

#!/usr/bin/env ruby

require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
  Pathname.new(__FILE__).realpath)

require 'rubygems'
require 'bundler/setup'

require File.expand_path('../lib/rsync', __dir__)

load Gem.bin_path('backup', 'backup')

Следующим шагом будет создание файла config.rb, в котором будут храниться настройки библиотеки backup:

# encoding: utf-8
# Backup v4.x Configuration
require 'dotenv'
Dotenv.load

root_path ENV['ROOT_PATH']
tmp_path  'tmp'
data_path 'data'

Syncer::RSync::Push.defaults do |rsync|
  rsync.use_sudo = true
  rsync.mode = :ssh
  rsync.host = ENV['RSYNC_HOST']
  rsync.port = 22
  rsync.ssh_user = ENV['RSYNC_SSH_USER']
  rsync.additional_ssh_options = "-i '#{ENV['HOME']}/.ssh/id_rsa'"
  rsync.mirror   = true
  rsync.compress = true
  rsync.path = ENV['RSYNC_PATH']
end

Compressor::Gzip.defaults do |compression|
  compression.level = 6
  compression.rsyncable = true
end

Notifier::Hipchat.defaults do |hipchat|
  hipchat.on_success = true
  hipchat.on_warning = true
  hipchat.on_failure = true

  hipchat.success_color = 'green'
  hipchat.warning_color = 'yellow'
  hipchat.failure_color = 'red'

  hipchat.token = ENV['HIPCHAT_TOKEN']
  hipchat.from = 'Backup'
  hipchat.rooms_notified = ENV['HIPCHAT_ROOMS'].split(',').collect(&:strip)
end

После того, как созданы все файлы с настройками, можно приступить к созданию модели для резервного копирования. Создаем файл models/rsync_backup.rb:

# encoding: utf-8

require 'dotenv'
Dotenv.load

Model.new(:rsync_backup, 'Rsync backup') do
  before do
    system('sudo gitlab-rake gitlab:backup:create')
  end

  sync_with RSync::Push do |rsync|
    rsync.directories do |directory|
      directory.add '/etc/gitlab'
      directory.add '/var/opt/gitlab/backups'
    end
  end

  compress_with Gzip

  notify_by Hipchat
end

Здесь указываем, что в самом начале должен запуститься скрипт sudo gitlab-rake gitlab:backup:create, который создаст резервную копию БД и всех проектов из GitLab в директории /var/opt/gitlab/backups. Только после этого запуститься процесс резервного копирования.

Чтобы в процессе создания резервной копии, постоянно не вводить пароль для доступа к rsync-серверу, нужно сгенерировать ssh-ключи без пароля и скопировать их на удаленный сервер:

$ ssh-keygen -t rsa
$ ssh-copy-id -i ~/.ssh/id_rsa.pub user@example.com

Необходимо так же добавить правило в /etc/sudoers, чтобы rsync не запрашивал пароль, при каждом запуске через sudo:

$ sudo -s
$ echo "user ALL= NOPASSWD: /usr/bin/rsync, /usr/bin/gitlab-rake" >> /etc/sudoers
$ exit

Важно! Замените user - на реального пользователя вашей системы, например ubuntu.

Для запуска резервного копирования можно воспользоваться следующей командой:

$ chmod +x bin/backup
$ bin/backup perform -t rsync_backup -r ~/gitlab_backup

Осталось только автоматизировать этот процесс, для этого создаем файл config/schedule.rb:

require 'dotenv'
Dotenv.load

set :job_template, "/usr/bin/zsh -l -c 'source #{ENV['HOME']}/.zshrc && :job'"
job_type :run_backup, 'cd :path && ./bin/backup perform -t :task -c :config_path'

every 1.day, at: '02:00 am' do
  run_backup 'rsync_backup', config_path: "#{ENV['ROOT_PATH']}/config.rb"
end

И добавляем задачу в cron:

$ whenever --update-crontab

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

На этом можно поставить точку, все наши GitLab-проекты теперь в полной целостности и сохранности.

Исходный код: https://github.com/mgrachev/gitlab_backup

Похожие записи

Автоматическая проверка кода на Go

Обзор инструмента для автоматической проверки кода на Go.

Docker for Mac и Kubernetes

Небольшой эксперимент с Docker for Mac и Kubernetes.

Автоматическая проверка кода с помощью Vexor

Пошаговая инструкция, что для этого нужно сделать.

Управление зависимостями через Homebrew

Управление внешними зависимостями проекта c помощью Homebrew Bundle.

Класс Set и уникальные коллекции объектов

Рассмотрим решение одной задачи с использованием класса Set и DDD.

Настройка Passenger для работы с Action Cable

Решаем проблему работы WebSocket-сервера через Phusion Passenger.

Настройка Rails-сервера на DigitalOcean

Настройка боевого Rails-сервера на DigitalOcean. Шаг за шагом.

Настройка Rails-окружения на OS X Yosemite

Полноценное рабочее окружение на OS X 10.10 Yosemite: Ruby, Homebrew, Oh My ZSH, rbenv и многое другое.