Skip to content
Snippets Groups Projects
Commit d3734fbd authored by Jacob Vosmaer's avatar Jacob Vosmaer
Browse files

Use tar for intermediate backup storage

During the backup we create an intermediate copy of two directories:
builds and uploads. Instead of creating many small files with 'cp
-r', we now use tar (and fast gzip) to create single intermediate
files. This saves on disk IO and disk space while creating a backup.
parent a2af080a
No related branches found
No related tags found
1 merge request!1520Reduce disk IO and space usage during backups
Pipeline #
module Backup module Backup
class Builds class Builds < Files
attr_reader :app_builds_dir, :backup_builds_dir, :backup_dir
def initialize def initialize
@app_builds_dir = Settings.gitlab_ci.builds_path super(Settings.gitlab_ci.builds_path)
@backup_dir = Gitlab.config.backup.path
@backup_builds_dir = File.join(Gitlab.config.backup.path, 'builds')
end
# Copy builds from builds directory to backup/builds
def dump
FileUtils.rm_rf(backup_builds_dir)
# Ensure the parent dir of backup_builds_dir exists
FileUtils.mkdir_p(Gitlab.config.backup.path)
# Fail if somebody raced to create backup_builds_dir before us
FileUtils.mkdir(backup_builds_dir, mode: 0700)
FileUtils.cp_r(app_builds_dir, backup_dir)
end
def restore
backup_existing_builds_dir
FileUtils.cp_r(backup_builds_dir, app_builds_dir)
end
def backup_existing_builds_dir
timestamped_builds_path = File.join(app_builds_dir, '..', "builds.#{Time.now.to_i}")
if File.exists?(app_builds_dir)
FileUtils.mv(app_builds_dir, File.expand_path(timestamped_builds_path))
end
end end
end end
end end
require 'open3'
module Backup
class Files
attr_reader :name, :app_files_dir, :backup_tarball, :backup_dir, :files_parent_dir
def initialize(app_files_dir)
@app_files_dir = File.realpath(app_files_dir)
@name = File.basename(app_files_dir)
@files_parent_dir = File.realpath(File.join(@app_files_dir, '..'))
@backup_dir = Gitlab.config.backup.path
@backup_tarball = File.join(@backup_dir, name + '.tar.gz')
end
# Copy files from public/files to backup/files
def dump
FileUtils.mkdir_p(Gitlab.config.backup.path)
run_pipeline!([%W(tar -C #{files_parent_dir} -cf - #{name}), %W(gzip -c -1)], out: [backup_tarball, 'w', 0600])
end
def restore
backup_existing_files_dir
run_pipeline!([%W(gzip -cd), %W(tar -C #{files_parent_dir} -xf -)], in: backup_tarball)
end
def backup_existing_files_dir
timestamped_files_path = File.join(files_parent_dir, "#{name}.#{Time.now.to_i}")
if File.exists?(app_files_dir)
FileUtils.mv(app_files_dir, File.expand_path(timestamped_files_path))
end
end
def run_pipeline!(cmd_list, options={})
status_list = Open3.pipeline(*cmd_list, options)
abort 'Backup failed' unless status_list.compact.all?(&:success?)
end
end
end
Loading
@@ -150,11 +150,11 @@ module Backup
Loading
@@ -150,11 +150,11 @@ module Backup
private private
   
def backup_contents def backup_contents
folders_to_backup + ["backup_information.yml"] folders_to_backup + ["uploads.tar.gz", "builds.tar.gz", "backup_information.yml"]
end end
   
def folders_to_backup def folders_to_backup
folders = %w{repositories db uploads builds} folders = %w{repositories db}
   
if ENV["SKIP"] if ENV["SKIP"]
return folders.reject{ |folder| ENV["SKIP"].include?(folder) } return folders.reject{ |folder| ENV["SKIP"].include?(folder) }
Loading
Loading
module Backup module Backup
class Uploads class Uploads < Files
attr_reader :app_uploads_dir, :backup_uploads_dir, :backup_dir
   
def initialize def initialize
@app_uploads_dir = File.realpath(Rails.root.join('public', 'uploads')) super(Rails.root.join('public/uploads'))
@backup_dir = Gitlab.config.backup.path
@backup_uploads_dir = File.join(Gitlab.config.backup.path, 'uploads')
end
# Copy uploads from public/uploads to backup/uploads
def dump
FileUtils.rm_rf(backup_uploads_dir)
# Ensure the parent dir of backup_uploads_dir exists
FileUtils.mkdir_p(Gitlab.config.backup.path)
# Fail if somebody raced to create backup_uploads_dir before us
FileUtils.mkdir(backup_uploads_dir, mode: 0700)
FileUtils.cp_r(app_uploads_dir, backup_dir)
end
def restore
backup_existing_uploads_dir
FileUtils.cp_r(backup_uploads_dir, app_uploads_dir)
end
def backup_existing_uploads_dir
timestamped_uploads_path = File.join(app_uploads_dir, '..', "uploads.#{Time.now.to_i}")
if File.exists?(app_uploads_dir)
FileUtils.mv(app_uploads_dir, File.expand_path(timestamped_uploads_path))
end
end end
end end
end end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment