Туторіал з налаштування Rails-додатків на Amazon EC2 з Chef. Частина 3

Усім привіт! Ця стаття завершує цикл туторіалів із розгортання Rails-додатків за допомогою платформи автоматизації Chef та Amazon EC2. Скориставшись знаннями, отриманими у попередніх частинах нашого циклу, ми закінчимо писати cookbooks і захистимо наш сервер. Ми також пройдемо весь цикл розгортання нашого Spree-додатка.

Попередні випуски циклу: частина 1, частина 2.

Налаштування безпеки

Щоб захистити додаток, вам необхідно встановити й налаштувати OpenSSH на цьому етапі.

OpenSSH

Щоб увімкнути автентифікацію за допомогою SSH, встановіть OpenSSH за допомогою openssh cookbook.

Додайте необхідні залежності в Berksfile.

cookbook 'openssh', '~> 2.6.1'

Створіть cookbook.

mkdir site-cookbooks/app-openssh

Встановіть метадані для cookbook.

touch site-cookbooks/app-openssh/metadata.rb
# site-cookbooks/app-openssh/metadata.rb
name    'app-openssh'
version '0.1.0'
depends 'openssh'

Створіть атрибути за стандартним cookbook налаштуванням.

mkdir site-cookbooks/app-openssh/attributes
touch site-cookbooks/app-openssh/attributes/default.rb

Скасуйте автентифікацію за допомогою пароля через атрибут password_authentication та відключіть print_motd, який визначить, чи потрібно логувати SSH daemon, коли користувач входить до сервера у файл /etc/motd.

# site-cookbooks/app-openssh/attributes/default.rb

default['openssh']['server']['password_authentication'] = 'no'
default['openssh']['server']['print_motd'] = 'no'

Створіть recipe для cookbook за стандартним налаштуванням.

mkdir site-cookbooks/app-openssh/recipes
touch site-cookbooks/app-openssh/recipes/default.rb

Потім вам потрібно підключити зовнішній cookbook для встановлення Redis.

# site-cookbooks/app-openssh/recipes/default.rb

include_recipe 'openssh'

І нарешті, додайте всі cookbooks до security role.

touch roles/security.rb

У roles/security.rb

name 'security'
description 'Security setup'

run_list 'recipe[app-openssh]'

Також додайте security role до списку запуску YOUR_IP_ADDRESS.json node.

...
  "run_list": [
    "role[setup]",
    "role[database]",
    "role[web]",
    "role[security]"
  ],
...

Управління та моніторинг системних процесів

На цьому етапі налаштуємо процес моніторингу за станом процесів такого програмного забезпечення:
  • PostgreSQL;
  • Redis;
  • Nginx;
  • Puma.

Для моніторингу стану цих процесів будемо використовувати Monit. Щоб установити й налаштувати Monit, будемо використовувати chef-monit.

Також додайте необхідні залежності в Berksfile.

cookbook 'monit', '~> 1.0.0'

Створіть cookbook.

mkdir site-cookbooks/app-monit

Встановіть метадані для cookbook.

touch site-cookbooks/app-monit/metadata.rb
# site-cookbooks/app-monit/metadata.rb
name    'app-monit'
version '0.1.0'
depends 'app-attributes'
depends 'app-postgresql'
depends 'app-deploy'
depends 'monit'

Щоб у майбутньому було зручно підтримувати атрибути додатка, перемістіть Monit атрибути username та password до app-atributes.

# site-cookbooks/app-attributes/attributes/default.rb

# Monit -----------------------------------------------------------

override['monit']['username'] = 'USERNAME'
override['monit']['password'] = 'PASSWORD'

Замініть USERNAME і PASSWORD своїми значеннями. Далі (у частині розгортання програми) ми покажемо вам, як більш надійно зберігати таку інформацію, використовуючи encrypted_data_bags.

Тепер створіть атрибути для cookbook за стандартним налаштуванням.

mkdir site-cookbooks/app-monit/attributes
touch site-cookbooks/app-monit/attributes/default.rb

Визначте наступні атрибути:

# site-cookbooks/app-monit/attributes/default.rb

default['monit']['poll_period'] = 5 # Interval in seconds to check all Monit services at
default['monit']['port'] = 2812 # Port to listen on for Monit's HTTPD interface
default['monit']['address'] = '0.0.0.0' # Local address to bind to for Monit's HTTPD interface
default['monit']['logfile'] = '/var/log/monit.log' # Path to log messages to

Тепер ви можете написати recipes і шаблони конфігурації Monit для зазначеного вище програмного забезпечення.

mkdir -p site-cookbooks/app-monit/{recipes,templates}

PostgreSQL

Створіть recipe для підключення Monit до PostgreSQL.
touch site-cookbooks/app-monit/recipes/postgresql.rb

З’єднайте зовнішній cookbook і шаблон PostgreSQL з конфігураціями.

include_recipe 'monit'

monit_config 'postgresql' do
  source 'postgresql.conf.erb'
  variables(
    version: node['postgresql']['defaults']['server']['version']
  )
end

Потім створіть сам шаблон.

touch site-cookbooks/app-monit/templates/postgresql.conf.erb

Напишіть конфигурацію для відстежування PostgreSQL-процесу:

# site-cookbooks/app-monit/templates/postgresql.conf.erb

check process postgresql with pidfile /var/run/postgresql/<%= @version %>-main.pid
  group database
  start program = "/etc/init.d/postgresql start"
  stop program  = "/etc/init.d/postgresql stop"

  if failed unixsocket /var/run/postgresql/.s.PGSQL.5432 protocol pgsql then restart
  if failed host 127.0.0.1 port 5432 protocol pgsql then restart

Потім оновіть перелік запусків для database role .

# roles/database.rb

run_list 'recipe[app-postgresql]',
         'recipe[app-monit::postgresql]'

Redis

Створіть recipe для підключення Monit до Redis.
touch site-cookbooks/app-monit/recipes/redis.rb

Вам потрібно підключити зовнішній cookbook і шаблон Redis до ваших конфігурацій.

# site-cookbooks/app-monit/recipes/redis.rb

include_recipe 'monit'

monit_config 'redis' do
  source 'redis.conf.erb'
end

Створіть шаблон.

touch site-cookbooks/app-monit/templates/redis.conf.erb

Напишіть конфігурацію для відстежування Redis-процесу:

# site-cookbooks/app-monit/templates/redis.conf.erb

check process redis with pidfile /var/run/redis/redis-server.pid
  start program = "/etc/init.d/redis-server start"
  stop program  = "/etc/init.d/redis-server stop"

Тепер додайте цей recipe до web role.

# roles/web.rb

run_list 'recipe[app-redis]',
         'recipe[app-ruby]',
         'recipe[app-nodejs]',
         'recipe[app-imagemagick]',
         'recipe[app-nginx]',
         'recipe[app-monit::redis]'

Nginx

Створіть recipe для інтеграції Monit з Nginx.

touch site-cookbooks/app-monit/recipes/nginx.rb

З’єднайте зовнішній cookbook та інтегруйте шаблон Nginx з конфігураціями.

# site-cookbooks/app-monit/recipes/nginx.rb

include_recipe 'monit'

monit_config 'nginx' do
  source 'nginx.conf.erb'
end

Тепер створіть шаблон.

touch site-cookbooks/app-monit/templates/nginx.conf.erb

Напишіть конфігурацію для відстежування Nginx-процесу:

# site-cookbooks/app-monit/templates/nginx.conf.erb

check process nginx with pidfile /var/run/nginx.pid
  start program = "/etc/init.d/nginx start"
  stop program  = "/etc/init.d/nginx stop"

Вам також потрібно додати recipe, який уже був доданий у web role.

# roles/web.rb

run_list 'recipe[app-redis]',
         'recipe[app-ruby]',
         'recipe[app-nodejs]',
         'recipe[app-imagemagick]',
         'recipe[app-nginx]',
         'recipe[app-monit::redis]',
         'recipe[app-monit::nginx]'

Puma

Створіть recipe для інтеграції Monit з Puma.
touch site-cookbooks/app-monit/recipes/puma.rb

Далі вам необхідно підключити зовнішній cookbook та інтегрувати шаблон Puma з конфігураціями.

# site-cookbooks/app-monit/recipes/puma.rb

include_recipe 'monit'

user = node['project']['user']
project_root = node['project']['root']
rvm = File.join('/', 'home', user, '.rvm', 'scripts', 'rvm')

monit_config 'puma' do
  source 'puma.conf.erb'
  variables(
    user: user,
    project_root: project_root,
    rvm: rvm
  )
end

Створіть шаблон.

touch site-cookbooks/app-monit/templates/puma.conf.erb

Напишіть конфігурацію для відстежування Puma-процесу:

# site-cookbooks/app-monit/templates/puma.conf.erb

check process puma with pidfile <%= @project_root %>/shared/tmp/pids/puma.pid
  start program = "/bin/su - <%= @user %> -s /bin/bash -c 'source <%= @rvm %> && cd <%= @project_root %>/current && bundle exec puma -C <%= @project_root %>/shared/puma.rb -e <%= node.environment %> --daemon'"
    with timeout 30 seconds
  stop program  = "/bin/su - <%= @user %> -s /bin/bash -c 'source <%= @rvm %> && cd <%= @project_root %>/current && bundle exec pumactl -P <%= @project_root %>/shared/tmp/pids/puma.pid stop'"
    with timeout 30 seconds

Нарешті, додайте цей recipe до web role.

# roles/web.rb

run_list 'recipe[app-redis]',
         'recipe[app-ruby]',
         'recipe[app-nodejs]',
         'recipe[app-imagemagick]',
         'recipe[app-nginx]',
         'recipe[app-monit::redis]',
         'recipe[app-monit::nginx]',
         'recipe[app-monit::puma]'

Розгортання додатка

Setup

У цьому розділі нашого туторіалу ми розглянемо, як можна розгорнути додаток, використовуючи Chef.

Основи

Почнемо зі створення app-deploy cookbook, де буде описаний recipe розгортання додатків.

Спочатку додайте залежності до метаданих.

# site-cookbooks/app-deploy/metadata.rb

name    'app-deploy'
version '0.1.0'

depends 'app-attributes'
depends 'app-users'

Використовуйте encrypted_data_bags для збереження конфіденційної інформації про проект: пароль бази даних або ключі від зовнішніх служб (AWS та ін.).

Чому ми використовуємо encrypted_data_bags

Головна причина — безпека. За допомогою encrypted_data_bags усі дані зберігаються у зашифрованому вигляді. Таким чином, навіть якщо зловмисник отримає доступ до сховища зі скриптами, він не зможе використати конфіденційну інформацію.

Щоб мати змогу використовувати зашифровані data bags, потрібно створити файл, у якому зберігатимуться ключі шифрування й дешифрування. Використовуйте OpenSSL для створення приватного ключа й помістіть його у файл encrypted_data_bag_secret.

Зауважте! Якщо ви перезапишете існуючий файл encrypted_data_bag_secret або видалите його, ви не зможете розшифрувати дані, зашифровані раніше.

Щоб створити ключ, запустіть у терміналі цю команду:

openssl rand -base64 512 | tr -d '\\r\\n' > encrypted_data_bag_secret

Зауважте! Варто не зберігати у репозиторії створений файл, а поділитися ним з членами вашої команди. Для цього потрібно додати його до .gitignore.

# .gitignore

encrypted_data_bag_secret

Далі вкажіть додатковий елемент encrypted_data_bag_secret для knife solo.

# .chef/knife.rb

...
encrypted_data_bag_secret 'encrypted_data_bag_secret'

Використовуючи knife solo, створіть файл конфігурації для середовища Dev за допомогою приватного ключа.

knife solo data bag create configs dev --secret-file encrypted_data_bag_secret

У текстовий редактор, відкритий у терміналі, введіть database credentials, секретні ключі додатка та Monit credentials.

# data_bags/configs/dev.json

{
  "id": "dev",
  "database": {
    "name": "NAME",
    "user": "USER",
    "password": "PASSWORD"
  },
  "application": {
    "AWS_ACCESS_KEY_ID": "AWS_ACCESS_KEY_ID",
    "AWS_SECRET_ACCESS_KEY": "AWS_SECRET_ACCESS_KEY",
    "S3_BUCKET_NAME": "S3_BUCKET_NAME",
    "S3_REGION": "S3_REGION",
    "S3_HOST_NAME": "S3_HOST_NAME",
    "DEVISE_SECRET_KEY": "DEVISE_SECRET_KEY",
    "SECRET_KEY_BASE": "SECRET_KEY_BASE"
  },
  "monit": {
    "username": "USER_NAME",
    "password": "PASSWORD"
  }
}

Після того, як ви збережете свої дані до /data_bags/configs/dev.json, ви побачите, що вони тепер зашифровані.

Замініть значення, встановлені у пунктах 5.2 та 5.5, за допомогою тих, що були встановлені під час 5.2 Database setup та 5.5 Monit setup.

Ви можете редагувати дані із зашифрованих data bags за допомогою наступної команди:

knife solo data bag edit configs dev

Ви також можете читати ці дані за допомогою цієї команди:

knife solo data bag show configs dev

Оскільки ваші ключі та credentials тепер зберігаються в encrypted_data_bag, ви можете видалити явне визначення Monit credentials з app-attributes.

# site-cookbooks/app-attributes/attributes/default.rb

# Monit -----------------------------------------------------------

monit_configs = Chef::EncryptedDataBagItem.load('configs', node.environment)['monit']

override['monit']['username'] = monit_configs['username']
override['monit']['password'] = monit_configs['password']

Set up SSH

Додаток знаходиться у приватному репозиторії. Тому для стиснення проекту використовуйте обгортку SSH. Для цього вам потрібні ключі SSH, які ви додасте до cookbook.

Якщо у вас немає ключа SSH, ви можете створити його за допомогою наведеної нижче команди. Не потрібно встановлювати пароль private key, оскільки він блокує chef-client під час запуску сценаріїв розгортання. Вам також потрібно буде вказати свою адресу електронної пошти замість Данный адрес e-mail защищен от спам-ботов, Вам необходимо включить Javascript для его просмотра. .

ssh-keygen -t rsa -b 4096 -C "
 Данный адрес e-mail защищен от спам-ботов, Вам необходимо включить Javascript для его просмотра.
 "

Потім створіть каталог — site-cookbooks/app-deploy/files — де ви розмістите приватні та публічні ключі.

mkdir site-cookbooks/app-deploy/files
mkdir site-cookbooks/app-deploy/files/default
touch site-cookbooks/app-deploy/files/default/key
touch site-cookbooks/app-deploy/files/default/key.pub

Додайте ключі у створений файл.

cp ~/.ssh/id_rsa site-cookbooks/app-deploy/files/default/key
cp ~/.ssh/id_rsa.pub site-cookbooks/app-deploy/files/default/key.pub

Зауважте! Додайте site-cookbooks/app-deploy/files/default каталог до .gitignore, оскільки ніхто не повинен знати ваш приватний ключ.

# .gitignore

site-cookbooks/app-deploy/files/default

Далі створіть recipe за стандартним налаштуванням, де ви докладно розпишете процес розгортання.

mkdir site-cookbooks/app-deploy/recipes
touch site-cookbooks/app-deploy/recipes/default.rb

У верхній частині цього файлу визначте змінні, з якими ви будете працювати у recipe:

# site-cookbooks/app-deploy/recipes/default.rb

encrypted_data = Chef::EncryptedDataBagItem.load('configs', node.environment)

config = node['project']

deployer = config['user']
deployer_group = config['group']

root_path = config['root']
home_path = File.join('/', 'home', deployer)
shared_path = File.join(root_path, 'shared')
bundle_path = File.join(shared_path, 'vendor', 'bundle')
config_path = File.join(shared_path, 'config')
ssh_path = File.join(shared_path, '.ssh')

puma_state_file = File.join(shared_path, 'tmp', 'pids', 'puma.state')
sidekiq_state_file = File.join(shared_path, 'tmp', 'pids', 'sidekiq.pid')
maintenance_file = File.join(shared_path, 'tmp', 'maintenance')

Тепер ми можемо почати описувати recipe розгортання додатка. Recipe складається з декількох етапів:

  • Використання SSH ключів;
  • Створення спільних каталогів;
  • Створення бази даних і конфігурації Puma.

Використання SSH ключів

Перш за все, ми опишемо використання SSH ключів:
# site-cookbooks/app-deploy/recipes/default.rb

# SSH -------------------------------------------------------------------------------------------------

ssh_key_file = File.join(ssh_path, deployer)
ssh_wrapper_file = File.join(ssh_path, 'wrap-ssh4git.sh')

directory ssh_path do
  owner deployer
  group deployer_group
  recursive true
end

cookbook_file ssh_key_file do
  source 'key'
  owner deployer
  group deployer_group
  mode 0o600
end

file ssh_wrapper_file do
  content "#!/bin/bash\n/usr/bin/env ssh -o \"StrictHostKeyChecking=no\" -i \"#{ssh_key_file}\" $1 $2"
  owner deployer
  group deployer_group
  mode 0o755
end

Створення спільних каталогів

# site-cookbooks/app-deploy/recipes/default.rb

# DIRECTORIES ---------------------------------------------------------------------------------------------------------

%w[config log public/system public/uploads public/assets repo tmp/cache tmp/pids tmp/sockets].each do |dir|
  directory File.join(shared_path, dir) do
    owner deployer
    group deployer_group
    mode 0o755
    recursive true
  end
end

Створення бази даних і конфігурації Puma

1. Конфігурація бази даних

Опишемо використання шаблону з конфігурацією для доступу до бази даних.

# site-cookbooks/app-deploy/recipes/default.rb

template File.join(config_path, 'database.yml') do
  source File.join(node.environment, 'database.yml.erb')
  variables(
    environment: node.environment,
    database: encrypted_data['database']['name'],
    user: encrypted_data['database']['user'],
    password: encrypted_data['database']['password']
  )
  sensitive true
  owner deployer
  group deployer_group
  mode 0o644
end

Далі створимо шаблон:

# site-cookbooks/app-deploy/templates/dev/database.yml.erb

---
<%= @environment %>:
  adapter: postgresql
  encoding: unicode
  database: <%= @database %>
  user: <%= @user %>
  password: <%= @password %>
  pool: 20
mkdir site-cookbooks/app-deploy/templates
mkdir site-cookbooks/app-deploy/templates/dev
touch site-cookbooks/app-deploy/templates/dev/database.yml.erb

2. Конфігурація додатка

Тут ви маєте описати генерацію файлу application.yml, де ви будете зберігати змінні проекту.

# site-cookbooks/app-deploy/recipes/default.rb

file File.join(config_path, 'application.yml') do
  content Hash[node.environment, encrypted_data['application']].to_yaml
  sensitive true
  owner deployer
  group deployer_group
  mode 0o644
end

3. Puma

Тепер вам потрібно описати, як використовувати шаблон з конфігураціями:

# site-cookbooks/app-deploy/recipes/default.rb

template File.join(shared_path, 'puma.rb') do
  source File.join(node.environment, 'puma.rb.erb')
  variables(
    environment: node.environment,
    project_root: root_path
  )
  owner deployer
  group deployer_group
  mode 0o644
end

Вам також потрібно створити шаблон з конфігурацією:

touch site-cookbooks/app-deploy/templates/dev/puma.rb.erb
# site-cookbooks/app-deploy/templates/dev/puma.rb.erb

#!/usr/bin/env puma

directory '<%= @project_root %>/current'
rackup '<%= @project_root %>/current/config.ru'
environment '<%= @environment %>'
pidfile '<%= @project_root %>/shared/tmp/pids/puma.pid'
state_path '<%= @project_root %>/shared/tmp/pids/puma.state'
stdout_redirect '<%= @project_root %>/shared/log/puma.error.log', '<%= @project_root %>/shared/log/puma.access.log', true
threads 4, 16
bind 'unix://<%= @project_root %>/shared/tmp/sockets/puma.sock'
workers 0
preload_app!

on_restart do
  puts 'Refreshing Gemfile'
  ENV['BUNDLE_GEMFILE'] = '<%= @project_root %>/current/Gemfile'
end

on_worker_boot do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Base.establish_connection
  end
end

4. Конфігурація Sidekiq

Спочатку опишіть, як створити шаблон з конфігурацією Sidekiq:

# site-cookbooks/app-deploy/recipes/default.rb

template File.join(config_path, 'sidekiq.yml') do
  source File.join(node.environment, 'sidekiq.yml.erb')
  variables(
    environment: node.environment
  )
  sensitive true
  owner deployer
  group deployer_group
  mode 0o644
end

Потім створіть шаблон з конфігурацією:

touch site-cookbooks/app-deploy/templates/dev/sidekiq.yml.erb

---
<%= @environment %>:
  :verbose: true
  :logfile: log/sidekiq.log
  :concurrency:  1
  :strict: false
  :pidfile: tmp/pids/sidekiq.pid
  :queues:
    - [default, 1]

Розгортання

Тепер перейдемо безпосередньо до розгортання додатка. Як правило, розгортання відбувається в чотири етапи:
  1. Checkout  chef-client використовує ресурс Source Code Management (SCM) для отримання вказаної ревізії додатка й розміщення clone або checkout в субкаталозі deploy каталогу з назвою cached-copy. Потім копія додатка розміщується в цьому субкаталозі.
  2. Migrate  якщо процес міграції буде запущено, chef-client символічно пов’язує файл конфігурації бази даних з checkout (config/database.yml за замовчуванням) і запускає команду міграції. Для Ruby on Rails додатка migration_command зазвичай встановлюється в rack db: migrate.
  3. Symlink — каталог для загальних і тимчасових файлів, які видаляються з checkout (log, tmp / pids і public / system за замовчуванням). Після цього вам потрібно створити будь-які необхідні каталоги (tmp, public і config за замовчуванням), якщо їх не існує. Наприкінці цього кроку ви посилаєтеся на спільні каталоги в поточний release, public / system, tmp / pids та log каталоги, а потім — на release у current.
  4. Restart  перезапустіть додаток, використовуючи команду restart у recipe.

Ось детальна інструкція розгортання додатків:

# site-cookbooks/app-deploy/recipes/default.rb

# DEPLOYMENT ----------------------------------------------------------------------------------------------------------

timestamped_deploy node['domain'] do
  ssh_wrapper ssh_wrapper_file
  repository config['repository']
  branch config['branch']
  repository_cache 'repo'
  deploy_to config['root']
  user deployer
  group deployer_group

  # Set global environments
  environment(
    'HOME' => home_path,
    'RAILS_ENV' => node.environment
  )

  # Before you start to run the migration, create tmp and public directories.
  create_dirs_before_symlink %w[tmp public]

  # Map files in a shared directory to their paths in the current release directory.
  symlinks(
    'config/application.yml' => 'config/application.yml',
    'config/database.yml' => 'config/database.yml',
    'config/newrelic.yml' => 'config/newrelic.yml',
    'config/sidekiq.yml' => 'config/sidekiq.yml',
    'log' => 'log',
    'public/system' => 'public/system',
    'public/uploads' => 'public/uploads',
    'public/assets' => 'public/assets',
    'tmp/cache' => 'tmp/cache',
    'tmp/pids' => 'tmp/pids',
    'tmp/sockets' => 'tmp/sockets'
  )

  # Map files in a shared directory to the current release directory.
  symlink_before_migrate(
    'config/application.yml' => 'config/application.yml',
    'config/database.yml' => 'config/database.yml'
  )

  # Run this code before the migration starts
  before_migrate do
    file maintenance_file do
      owner deployer
      group deployer_group
      action :create
    end

    # Install bundler gem
    execute 'install bundler' do
      command "/bin/bash -lc 'source $HOME/.rvm/scripts/rvm && gem install bundler'"
      cwd release_path
      user deployer
      group deployer_group
      environment(
        'HOME' => home_path
      )
    end

    # Install other gems
    execute 'bundle install' do
      command "/bin/bash -lc 'source $HOME/.rvm/scripts/rvm && bundle install --without development test --deployment --path #{bundle_path}'"
      cwd release_path
      user deployer
      group deployer_group
      environment(
        'HOME' => home_path
      )
    end
  end

  migration_command "/bin/bash -lc 'source $HOME/.rvm/scripts/rvm && bundle exec rails db:migrate --trace'"
  migrate true

  restart_command do
    # If PUMA is running ‒ restart it
    if File.exist? puma_state_file
      execute 'pumactl restart' do
        command "/bin/bash -lc 'source $HOME/.rvm/scripts/rvm && bundle exec pumactl -S #{puma_state_file} restart'"
        cwd release_path
        user deployer
        group deployer_group
        environment(
          'HOME' => home_path
        )
      end
    end

    # If Sidekiq is running ‒ restart it
    if File.exist? sidekiq_state_file
      execute 'sidekiqctl stop' do
        command "/bin/bash -lc 'source $HOME/.rvm/scripts/rvm && bundle exec sidekiqctl stop #{sidekiq_state_file}'"
        cwd release_path
        user deployer
        group deployer_group
        environment(
          'HOME' => home_path
        )
      end
    end
  end

  # Run the following tasks before app restart commands
  before_restart do
    execute 'db:seed' do
      command "/bin/bash -lc 'source $HOME/.rvm/scripts/rvm && bundle exec rake db:seed'"
      cwd release_path
      user 'root'
      group 'root'
      environment(
        'HOME' => home_path,
        'RAILS_ENV' => node.environment
      )
    end

    execute 'assets:precompile' do
      command "/bin/bash -lc 'source $HOME/.rvm/scripts/rvm && bundle exec rake assets:precompile'"
      cwd release_path
      user 'root'
      group 'root'
      environment(
        'HOME' => home_path,
        'RAILS_ENV' => node.environment
      )
    end
  end

  # Once you've restarted the app, remove the maintenance file
  after_restart do
    file maintenance_file do
      action :delete
    end
  end

  action :deploy
end

Застосування конфігурацій

Тепер вам потрібно додати app-deploy cookbook до deploy role, щоб використовувати цей cookbook далі в node.
touch roles/deploy.rb

Опишемо базову інформацію про цю role та її run list.

# roles/deploy.rb

name 'deploy'

description 'Deployment'

run_list 'recipe[app-deploy]'

Далі додайте цю role до загального списку nodes/ YOUR_IP_ADDRESS.json node.

// nodes/YOUR_IP_ADDRESS.json

 ...
 "run_list": [
   "role[setup]",
   "role[database]",
   "role[web]",
   "role[security]",
   "role[deploy]"
 ],
...

Тепер ви можете застосувати скрипти, які ви написали, щоб запустити додаток на сервері.

Встановіть Chef і застосуйте всі конфігурації за допомогою такої команди:

knife solo bootstrap ubuntu@YOUR_IP_ADDRESS -i spree_dev.pem

Після завершення розгортання Spree-додаток буде доступний через публічний DNS. У нашому прикладі — адреса ec2-18-221-230-71.us-east-2.compute.amazonaws.com.

Тепер ви можете увійти на сервер через SSH як deployer-користувач:

ssh deployer@YOUR_IP_ADDRESS

У майбутньому ви зможете розгорнути додаток на віддаленому комп’ютері за допомогою такої команди:

knife solo cook deployer@YOUR_IP_ADDRESS -o "'recipe[app-deploy]'"

Підбиваємо підсумки

Коли я створював цей туторіал, то мав на меті показати надзвичайну гнучкість Chef та його можливості розгортання проектів будь-якої складності. Також зауважу, що туторіал буде цікавий у першу чергу для новачків, адже в ньому детально розібрані компоненти, необхідні для коректної роботи Spree-додатка та показані всі етапи розгортання додатка.

Сподіваюсь, що туторіал був для вас корисним. Запрошую вас поділитися своїм досвідом використання Chef нижче у коментарях.

Дякую команді RubyGarage за допомогу у підготовці матеріалу.

Похожие статьи:
Як і навесні, більшість ІТ-спеціалістів проти спецрежиму. Проте частка тих, хто за, трішки збільшилася — з 9% до 12%. Представляємо...
После успешного завершения курса JavaScript и AngularJS мы получали много вопросов о начале следующего курса. Поэтому с 23 ноября...
Меня зовут Влад Пронский, мне 23, и я руковожу отделом разработки в Lucky Labs. В компанию пришел в январе 2014-го. Изначально...
У випуску: як використовувати Composer ефективно, curly bracket, PHP 7.2.1, функція monotonic timer. Статті Перелік крутих, але маловідомих...
28 жовтня відбулося змагання IEEEXtreme 17.0 — це щорічний хакатон, який об’єднує команди студентів-членів IEEE зі всього...
Яндекс.Метрика