Синхронизируем среду разработки с production

Во время разработки зачастую нужно синхронизировать локальную базу и файлы с production.

Для этого отлично годится Capistrano.

Синхронизация базы #

Чтобы задать переменную из файла на сервере используем capture:

capture("cat #{current_path}/config/database.yml")

Чтобы спрятать пароль из логов, во время сброса дампа выводим пустышку "pg_dump":

# Surpress debug log output to hide the password
current_logger_level = self.logger.level
if current_logger_level >= Capistrano::Logger::DEBUG
  logger.debug %(executing "pg_dump")
  self.logger.level = Capistrano::Logger::INFO
end


run "PGPASSWORD='#{production_db['password']}' && export PGPASSWORD &&
     pg_dump -Fc --compress=9
             --username=#{production_db['username']}
             --host localhost
             --file=#{current_path}/tmp/#{dump}
             #{production_db['database']} ;
     unset PGPASSWORD"

# Restore logger level
self.logger.level = current_logger_level

Сам дамп создаётся с максимальным сжатием (чтобы не использовать gzip) и помещается в папку #{current_path}/tmp/#{dump}.

Загружаем дамп на локальную машину и удаляем его на сервере:

# Download
get "#{current_path}/tmp/#{dump}", "tmp/", :via => :scp

# Clean production
run "rm -f #{current_path}/tmp/#{dump}"

Осталось только загрузить дамп в локальную базу и удалить сразу после этого:

# Import
development_db = YAML::load_file('config/database.yml')['development']

run_locally "pg_restore -Fc \
                        --clean \
                        --host localhost \
                        --dbname=#{development_db['database']} \
                        tmp/#{dump} ; \
             rm -f tmp/#{dump}"

Операция будет производиться от текущего пользователя, поэтому не забудьте сделаеть его администратором pg:

createuser --superuser --username postgres --interactive

А так выглядит таск полностью, его можно добавить в конец файла config/deploy.rb:

task :import_production_db do
  require 'yaml'

  # Export
  production_db  = YAML::load(capture "cat #{current_path}/config/database.yml")['production']

  dump = "#{production_db['database']}.sql"


  # Surpress debug log output to hide the password
  current_logger_level = self.logger.level
  if current_logger_level >= Capistrano::Logger::DEBUG
    logger.debug %(executing "pg_dump")
    self.logger.level = Capistrano::Logger::INFO
  end

  run "PGPASSWORD='#{production_db['password']}' && export PGPASSWORD &&
       pg_dump -Fc --compress=9
               --username=#{production_db['username']}
               --host localhost
               --file=#{current_path}/tmp/#{dump}
               #{production_db['database']} ;
       unset PGPASSWORD"

  # Restore logger level
  self.logger.level = current_logger_level

  # Download
  get "#{current_path}/tmp/#{dump}", "tmp/", :via => :scp

  # Clean production
  run "rm -f #{current_path}/tmp/#{dump}"


  # Import
  development_db = YAML::load_file('config/database.yml')['development']

  run_locally "pg_restore -Fc \
                          --clean \
                          --host localhost \
                          --dbname=#{development_db['database']} \
                          tmp/#{dump} ; \
               rm -f tmp/#{dump}"

end

Синхронизация файлов #

Всё гораздо проще:

task :import_production_files do
  get "#{current_path}/public/uploads", "public", :via => :scp, :recursive => true
end

Ограничения #

Захват базы production и передача её в первозданном виде на локальную машину не самая лучшая идея. Гораздо более правильным вариантом будет предварительная обработка базы с удалением всех секретных данных (паролей/токенов).

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

Комментарии

aderyabin

Неплохая задача "для себя".

Если говорить про промышленное использование, то посмотри в сторону гема replicate. Он на 20 млн пользователях очень помогал.

Ну и если делаешь бекапы - то проще вытаскивать их. Например, EY так и предлагает делать

Добавить комментарий