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

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

У цій частині ми покажемо, як написати власні cookbooks. Крім того, ми пояснимо поняття wrapper-cookbook з використанням скриптів для встановлення й налаштування бази даних PostgreSQL та іншого програмного забезпечення, необхідного для правильної роботи сервера й додатка на ньому. Отже, почнімо.

Базова установка

Для початку розглянемо основні компоненти:

  • ім’я хоста (Hostname);
  • атрибути проекту (Project attributes);
  • групи користувачів;
  • Sudo privilege.

Ім’я хоста

На сторінці cookbook буде вказано ім’я хоста для вашого сервера. Для цього використовуйте готовий cookbook chef_hostname. Потім напишіть wrapper cookbook для цієї задачі.

Wrapper-cookbook

Wrapper-cookbook — це найпростіший тип cookbook. Він включає в себе recipes з інших cookbooks та визначає атрибути за замовчуванням.

Wrapper-cookbook складається з таких елементів:

├─ site-cookbooks
|   └─ cookbook-wrapper
│       ├─ attributes
|       │  └─ default.rb
│       ├─ recipes
|       │  └─ default.rb
│       └─ metadata.rb

Визначимо залежність від chef_hostname cookbook у Berksfile:

# Berksfile

cookbook 'chef_hostname', '~> 0.6.1'

Далі створіть каталог з cookbook:

mkdir site-cookbooks/app-hostname
touch site-cookbooks/app-hostname/metadata.rb

Опишіть додаткову інформацію про cookbook в metadata.rb. Тут ви повинні визначити назву, версію та залежності cookbook в інших cookbooks. Ви також можете додати інформацію про автора тощо. Додаткову інформацію про метадані ви можете знайти в документації Chef.

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

name    'app-hostname'
version '0.1.0'

depends 'chef_hostname'

Тепер створіть стандартний recipe для cookbook:

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

Цей recipe встановлює ім’я хоста нашого сервера на ім’я node:

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

hostname node.name

Атрибути проекту

Нам потрібно створити cookbook, який міститиме специфічні атрибути для поточного проекту. Ці атрибути часто використовуються під час написання інших cookbooks: назва проекту, репозиторій, де знаходиться проект та ін.

Давайте створимо стандартні атрибути для cookbook:

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

Тепер визначимо атрибути, в яких буде збережено ім’я проекту та посилання на репозиторій GitHub:

# Project -------------------------------------------------------

override['project']['name'] = 'spree-app'
override['project']['repository'] = '[email protected]:user/project.git'

У цьому туторіалі ми будемо використовувати готовий додаток Spree:

override['project']['repository'] = '[email protected]:bezrukavyi/spree-demo.git'

Ці атрибути будуть доступні через об’єкт node, наприклад node [’project’] [’name’].

Користувачі та групи

Потрібно створити користувачів та групи, такі як deployer. Для цього ми застосуємо cookbook користувачів. Додайте залежності для cookbook користувачів в Berksfile:

cookbook 'users', '~> 5.3.1'

Потім створіть каталог для сookbook:

mkdir site-cookbooks/app-users
touch site-cookbooks/app-users/metadata.rb

і встановіть такі метадані:

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

name    'app-users'
version '0.1.0'

depends 'users'
depends 'app-attributes'

Потім створіть каталог із системними атрибутами для сookbook:

mkdir site-cookbooks/app-users/attributes
touch site-cookbooks/app-users/attributes/system.rb

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

# site-cookbooks/app-users/attributes/system.rb

default['users']['system']['application']['name'] = node['project']['name']
default['users']['system']['application']['group'] = 'www-data'
default['users']['system']['application']['home'] = true

Тепер створіть recipe:

mkdir touch site-cookbooks/app-users/recipes
touch site-cookbooks/app-users/recipes/system.rb

Опишіть встановлення системних груп і користувачів у цьому recipe:

users_attributes = [
  node['users']['system']['application']
]

users_attributes.each do |attributes|
  # Create the system group with the name attributes ['group']
  group attributes['group'] do
    append true
    system true
    action :create
  end

  # Create the system user with the name attributes ['name']
  user attributes['name'] do
    system true
    shell '/bin/false' # disallow user to interact with shell
    group attributes['group']
    manage_home attributes['home']
    action :create
  end
end

Після цього опишіть поведінку для створення груп і користувачів із data bags:

# site-cookbooks/app-users/recipes/regular.rb

# Creates the sysadmin group and users defined in the users databag.
users_manage 'sysadmin' do
  group_id 2300
  action :create
end

Нарешті об’єднайте всі описані recipes в один, який автоматично буде запускатись для цієї сookbook:

touch site-cookbooks/app-users/recipes/default.rb
# site-cookbooks/app-users/recipes/regular.rb

include_recipe '::system'
include_recipe '::regular'

Sudo privilege

Тепер ми встановимо sudo на нашу програму. Для цього використовуйте sudo сookbook.

Додайте таку залежність до Berksfile:

cookbook 'sudo', '~> 4.0.0'

Створіть сookbook і встановіть для неї метадані:

mkdir site-cookbooks/app-sudo
touch site-cookbooks/app-sudo/metadata.rb
# site-cookbooks/app-sudo/metadata.rb

name    'app-sudo'
version '0.1.0'

depends 'sudo'

Ми хочемо, щоб усі користувачі, чиї групи містять значення sudo, а також групи, що містять wheel та sysadmin у своїй group box, мали право на sudo privileges.

Давайте створимо стандартний recipe для cookbook.

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

Потім вкажіть таке:

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

users = search(:users, 'groups:sudo').map(&:id)
node.override['authorization']['sudo']['passwordless'] = true
node.override['authorization']['sudo']['groups'] = %w(wheel sysadmin).concat(users)
node.override['authorization']['sudo']['users'] = users

include_recipe 'sudo'

Після того, як ми описали основні cookbooks, ми створимо role. Вона називається setup і об’єднує ці cookbooks:

touch roles/setup.rb

У цій role вкажіть основну інформацію, таку як назва й опис. Потім встановіть cookbooks з поточної role встановлення в переліку запусків:

# roles/setup.rb

name 'setup'
description 'Basic setup'

# Run default recipes of these cookbooks one-by-one
run_list 'recipe[app-hostname]',
         'recipe[app-users]',
         'recipe[app-sudo]'

Далі вкажіть цю роль у node вашого сервера YOUR_IP_ADDRESS.json server:

// nodes/YOUR_IP_ADDRESS.json

...
     "run_list": [
       "role[setup]"
     ],
...

Налаштування бази даних

На цьому етапі ми опишемо конфігурації для встановлення й налаштування бази даних та її компонентів на сервері. Ми рекомендуємо використовувати PostgreSQL як основну базу даних.

PostgreSQL database

Для встановлення та налаштування PostgreSQL на сервері використовуйте postgresql_lwrp. Також використовуйте locale cookbook, щоб визначити мову системи за замовчуванням.

Ось поетапна інструкція:

  1. Ініціалізуйте основний кластер баз даних для PostgreSQL версії 9.6.
  2. Створіть PostgreSQL superuser (deployer) і користувача PostgreSQL для вашого проекту.
  3. Створіть базу даних PostgreSQL для проекту.

Тепер давайте додамо необхідні залежності в Berksfile:

cookbook 'postgresql_lwrp', '~> 1.2.1'
cookbook 'locale', '~> 2.0.1'

Нарешті створюємо cookbook:

mkdir site-cookbooks/app-postgresql

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

  1. Locales за замовчуванням.
  2. Версія PostgreSQL.
  3. Користувачі PostgreSQL.
  4. Бази даних PostgreSQL.
# app-attributes/attributes/default.rb add

# Locale ---------------------------------------------------------

override['locale']['lang'] = 'en_US.UTF-8'
override['locale']['lc_all'] = node['locale']['lang']

# Postgresql -----------------------------------------------------

override['postgresql']['version'] = '9.6'
override['postgresql']['users'] = [{
  'name' => 'deployer',
  'encrypted_password' => 'PASSWORD',
  'superuser' => true
}, {
  'name' => node['project']['name'],
  'encrypted_password' => 'PASSWORD',
  'superuser' => false # the user of the project's database must have access only to the project database
}]

override['postgresql']['databases'] = [{
  'name' => "#{node['project']['name']}_#{node['environment']}",
  'owner' => node['project']['name']
}]

Функція PostgreSQL hash має формат підпису $password$username. Наприклад, якщо ім’я користувача було deployer, а пароль — spree-app, то команда для створення пароля виглядатиме так:

На Linux:

echo md5$(echo -n 'spree-appdeployer' | md5sum)

На macOS:

echo md5$(echo -n 'spree-appdeployer' | md5)

Замініть змінене значення ‒ PASSWORD ‒ для кожного користувача з результатом цієї команди.

Далі опишіть метадані cookbooks:

touch site-cookbooks/app-postgresql/metadata.rb
# site-cookbooks/app-postgresql/metadata.rb

name    'app-postgresql'
version '0.1.0'

depends 'app-attributes'
depends 'apt'
depends 'postgresql_lwrp'
depends 'locale'

Визначте стандартні атрибути для cookbooks:

mkdir site-cookbooks/app-postgresql/attributes
touch site-cookbooks/app-postgresql/attributes/default.rb
# site-cookbooks/app-postgresql/attributes/default.rb

default['postgresql']['client']['version'] = node['postgresql']['version']
default['postgresql']['defaults']['server']['version'] = node['postgresql']['version']
override['postgresql']['defaults']['server']['hba_configuration'] = []

Перш ніж визначити поведінку для описаних вище завдань, створіть recipe за замовчуванням і підключіть залежності на початку файлу. Ви також повинні визначити стандартні змінні, з якими ви будете працювати в recipe:

mkdir site-cookbooks/app-postgresql/recipes
touch site-cookbooks/app-postgresql/recipes/default.rb
# site-cookbooks/app-postgresql/recipes/default.rb

include_recipe 'locale'
include_recipe 'postgresql_lwrp::apt_official_repository'
include_recipe 'postgresql_lwrp'

locale = node['locale']['lang']
version = node['postgresql']['defaults']['server']['version']
users = node['postgresql']['users']
databases = node['postgresql']['databases']

1. Ініціалізуйте основний кластер бази даних для PostgreSQL версії 9.6.

Визначте конфігурацію аутентифікації клієнта для основного кластера, який називається pg_hba:

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

# Basic  settings for authentication
general_hba = [
  { type: 'host', database: 'all', user: 'all', address: '::1/128', method: 'md5' },
  { type: 'host', database: 'all', user: 'all', address: '127.0.0.1/32', method: 'md5' },
  { type: 'local', database: 'all', user: 'postgres', address: '', method: 'peer' }
]

# Authentication settings for the user
users_hba = users.map do |attributes|
  {
    type: 'local',
    database: attributes['name'],
    user: attributes['name'],
    address: '',
    method: attributes['superuser'] ? 'peer' : 'md5'
  }
end

# Authentication settings for groups
databases_hba = databases.map do |attributes|
  {
    type: 'local',
    database: attributes['name'],
    user: attributes['owner'],
    address: '',
    method: 'md5'
  }
end

Тепер ініціалізуйте основний кластер:

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

postgresql 'main' do
  cluster_version(version)
  cluster_create_options(locale: locale)
  configuration(max_connections: 300)
  hba_configuration([*general_hba, *users_hba, *databases_hba])
end

2. Створіть PostgreSQL superuser з іменем deployer, а також користувача PostgreSQL для проекту.

Використаємо зазначені вище змінні, щоб створити користувача PostgreSQL та базу даних PostgreSQL з іменем користувача:

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

users.each do |attributes|
  postgresql_user attributes['name'] do
    in_cluster 'main'
    in_version version
    superuser attributes['superuser']
    encrypted_password attributes['encrypted_password']
  end

  postgresql_database attributes['name'] do
    in_cluster 'main'
    in_version version
    owner attributes['name']
  end
end

3. Створіть базу даних PostgreSQL для проекту, застосовуючи перераховані вище змінні.

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

databases.each do |attributes|
  postgresql_database attributes['name'] do
    in_cluster 'main'
    in_version version
    owner attributes['owner']
  end
end

Потім додайте cookbook, який ви створили, до database role:

touch roles/database.rb

Визначте необхідну інформацію про role in roles/database.rb:

name 'database'
description 'Database setup'

run_list 'recipe[app-postgresql]'

Нарешті додайте role to run_list до nodes/YOUR_IP_ADDRESS.json.

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

Web-налаштування

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

  • Ruby;
  • Node.js;
  • ImageMagick;
  • Redis;
  • Nginx.

Встановлення Ruby

Щоб встановити Ruby, вам потрібна chef_rvm cookbook. Додайте необхідні залежності до Berksfile:

cookbook 'chef_rvm', '~> 2.0.0'

Після цього розмістіть атрибути, такі як версії (усі версії, які вам потрібно встановити) та стандартну версію до site-cookbooks/app-attributes/attributes/default.rb:

# Ruby -----------------------------------------------------------

override['ruby']['versions'] = ['2.4.2']
override['ruby']['default'] = '2.4.2'

Тепер створіть cookbook:

mkdir site-cookbooks/app-ruby

Потім встановіть метадані для cookbook:

touch site-cookbooks/app-ruby/metadata.rb
# site-cookbooks/app-ruby/metadata.rb

name    'app-ruby'
version '0.1.0'

depends 'app-attributes'
depends 'chef_rvm'

Щоб встановити RVM, вам потрібно додати gpg2 ключ. Для цього створіть recipe, який додасть gpg2 ключ до вашої програми. Більше інформації про gpg2 ключі ви можете дізнатись тут.

mkdir site-cookbooks/app-ruby/recipes
touch site-cookbooks/app-ruby/recipes/gpg2.rb
# site-cookbooks/app-ruby/recipes/gpg2.rb

user = node['project']['user']
group = node['project']['group']

package 'gnupg2' do
  action :install
end

execute 'add gpg2 key' do
  environment ({
    'HOME' => "/home/#{user}",
    'USER' => user
  })

  command 'command curl -sSL https://rvm.io/mpapis.asc | gpg2 --import -'
end

execute 'chown ~/.gnupg' do
  command "chown -R #{user}:#{group} /home/#{user}/.gnupg"
  user 'root'
end

Тепер створіть recipe для встановлення Ruby:

touch site-cookbooks/app-ruby/recipes/setup.rb

Опишіть встановлення всіх необхідних версій Ruby в цьому recipe:

# site-cookbooks/app-ruby/recipes/setup.rb

user = node['project']['user']
attributes = node['ruby']

# Install the required versions of Ruby
chef_rvm 'install rubies' do
  rubies attributes['versions']
  rvmrc(rvm_autoupdate_flag: 1)
  user user
end

# Set Ruby version by default
chef_rvm_ruby 'set default ruby version' do
  version attributes['default']
  default true
  user user
end

Потім створіть стандартний cookbook для recipe:

touch site-cookbooks/app-ruby/recipes/default.rb

У цій cookbook вам необхідно об’єднати створені recipes в потрібному порядку:

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

include_recipe '::gpg2'
include_recipe '::setup'

Встановлення Node.js

Ми будемо використовувати Node.js як середовище для часу виконання JavaScript. Node.js дозволяє використовувати CoffeeScript та конвеєр об’єктів у додатку Rails, які поєднують і мінімізують ваш JavaScript, щоб забезпечити більш швидке production середовище. Щоб встановити node з офіційних попередньо встановлених бінарних файлів, використовуйте nodejs.

Додайте залежності до Berksfile:

cookbook 'nodejs', '~> 5.0.0'

Далі додайте версію (версію Node.js) і checksum атрибути до site-cookbooks/app-attributes/attributes/default.rb:

# Node.js --------------------------------------------------------

override['nodejs']['version'] = '9.3.0'
override['nodejs']['binary']['checksum'] = 'b7338f2b1588264c9591fef08246d72ceed664eb18f2556692b4679302bbe2a5'

Тепер створіть cookbook:

mkdir site-cookbooks/app-nodejs

Потім встановіть метадані для cookbook:

touch site-cookbooks/app-nodejs/metadata.rb
# site-cookbooks/app-nodejs/metadata.rb

name    'app-nodejs'
version '0.1.0'

depends 'app-attributes'
depends 'nodejs'

Створіть стандартні атрибути для cookbook:

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

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

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

default['nodejs']['install_method'] = 'binary'

Створіть стандартний cookbook:

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

Підключіть зовнішню cookbook для встановлення Node.js:

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

include_recipe 'nodejs'

Встановлення ImageMagick

Використовуйте Carrierwave для обробки завантажених файлів і виконання операцій зображень на стороні сервера. Carrierwave залежить від mini_magick, який, у свою чергу, базується на ImageMagick. Тому вам слід встановити ImageMagick. Для цього скористайтеся imagemagick cookbook.

Додайте залежності до Berksfile:

cookbook 'imagemagick', '~> 0.2.3'

Створіть cookbook:

mkdir site-cookbooks/app-imagemagick

Потім встановіть метадані для cookbook:

touch site-cookbooks/app-imagemagick/metadata.rb
# site-cookbooks/app-imagemagick/metadata.rb

name    'app-imagemagick'
version '0.1.0'

depends 'imagemagick'

Створіть стандартний recipe для cookbook:

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

Потім опишіть установку cookbook:

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

include_recipe 'imagemagick::devel'

directory '/etc/ImageMagick' do
  owner 'root'
  group 'root'
  mode '0755'
end

Встановлення Redis

Вам потрібно застосувати Sidekiq для фонової обробки для Ruby. Sidekiq використовує Redis як репозиторій. Щоб встановити Redis, використовуйте chef-redis cookbook.

Додайте залежності до Berksfile:

cookbook 'redis', git: 'git://github.com/phlipper/chef-redis.git'

Створіть cookbook:

mkdir site-cookbooks/app-redis

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

touch site-cookbooks/app-redis/metadata.rb
# site-cookbooks/app-redis/metadata.rb

name    'app-redis'
version '0.1.0'

depends 'redis'

Створіть стандартні атрибути для cookbook:

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

Потім встановіть maxmemory для Redis:

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

default['redis']['maxmemory'] = '256Mb'

Створіть стандартний recipe для cookbook:

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

Підключіть зовнішній cookbook для встановлення Redis:

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

include_recipe 'redis::server'

Встановлення Nginx

Ми будемо використовувати Nginx як веб-сервер для додатка. Щоб встановити Nginx, використовуйте nginx cookbook.

Спочатку додайте залежності до Berksfile:

cookbook 'nginx', '~> 7.0.2'

Перш ніж розпочати встановлення й налаштування Nginx, створіть системного користувача. Пізніше цей користувач системи буде прив’язаний до Nginx. Щоб створити користувача, додайте такий код до атрибутів користувачів системи:

# site-cookbooks/app-users/attributes/system.rb

default['users']['system']['nginx']['name'] = 'nginx'
default['users']['system']['nginx']['group'] = 'www-data'
default['users']['system']['nginx']['home'] = false

Потім включіть цього користувача у recipe для встановлення користувачів системи:

# site-cookbooks/app-users/recipes/system.rb

users_attributes = [
  node['users']['system']['nginx'],
  node['users']['system']['application']
]

Створіть cookbook:

mkdir site-cookbooks/app-nginx

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

touch site-cookbooks/app-nginx/metadata.rb
# site-cookbooks/app-nginx/metadata.rb

name    'app-nginx'
version '0.1.0'

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

Після цього встановіть версію (версію Nginx) і checksum атрибути в site-cookbooks/app-attributes/attributes/default.rb:

# Nginx -----------------------------------------------------------

override['nginx']['source']['version'] = '1.13.7'
override['nginx']['source']['checksum'] = 'beb732bc7da80948c43fd0bf94940a21a21b1c1ddfba0bd99a4b88e026220f5c'

Створіть стандартні атрибути для cookbook:

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

Встановіть атрибути для Nginx:

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

include_attribute 'nginx::source'

source = node['nginx']['source']
user = node['users']['system']['nginx']

override['nginx']['install_method'] = 'source'
override['nginx']['version'] = source['version']
override['nginx']['source']['prefix'] = "/opt/nginx-#{source['version']}"
override['nginx']['source']['sbin_path'] = "#{source['prefix']}/sbin/nginx"
override['nginx']['binary'] = source['sbin_path']
override['nginx']['init_style'] = 'systemd'
override['nginx']['user'] = user['name']
override['nginx']['group'] = user['group']
override['nginx']['source']['default_configure_flags'] = %W[
  --prefix=#{source['prefix']}
  --conf-path=#{node['nginx']['dir']}/nginx.conf
  --sbin-path=#{source['sbin_path']}
]
override['nginx']['default_site_enabled'] = false

Ми будемо буферизувати всі запити й відповіді між клієнтом і додатком Rails через Puma. Для цього встановіть path to puma.sock, який буде розташовано в каталозі проекту. Оскільки path to the project необхідний для розгортання додатку та інших компонентів, якi залежать від розгортання, ми створимо стандартні атрибути для app-deploy cookbook для подальшого використання. Пізніше ми опишемо app-deploy cookbook.

Встановіть метадані для app-deploy cookbook:

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

name    'app-deploy'
version '0.1.0'

depends 'app-attributes'

Вам також потрібно встановити стандартні атрибути:

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

У стандартних cookbooks опишіть основну інформацію про розгортання проекту, включаючи ім’я користувача та групу, від імені якої ви будете розгортати додаток. Вам також потрібно описати шлях до каталогу, у якому ви розмістите додаток:

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

default['project']['user'] = default['users']['system']['application']['name']
default['project']['group'] = default['users']['system']['application']['group']
default['project']['root'] = File.join('/home', node['project']['user'], node['domain_name'])

Після цього додайте цей cookbook до залежностей:

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

depends 'app-deploy'

Тепер ви можете почати створювати стандартний recipe для cookbook:

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

Підключіть зовнішній cookbook та опишіть установку Nginx:

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

include_recipe 'nginx::source'

template "#{node['nginx']['dir']}/sites-available/#{node.domain_name}"
  source "#{node.environment}.erb"
  owner 'root'
  group 'root'
  mode '0644'
  variables(
    ip: node[:ipaddress],
   domain: node[:domain_name],
    project_dir: node['project']['root']
  )
  notifies :restart, 'service[nginx]', :delayed
end

nginx_site node.domain_name do
  enable true
end

Ми рекомендуємо встановити конфігурацію Nginx в окремий шаблон, прив’язаний до певного середовища. У нашому випадку це dev.erb.

Створіть шаблони каталогу та файл конфігурації Nginx для середовища:

mkdir site-cookbooks/app-nginx/templates
touch site-cookbooks/app-nginx/templates/dev.erb

Потім напишіть конфігурації:

# site-cookbooks/app-nginx/templates/dev.erb

upstream puma {
  server unix://<%= @project_dir %>/shared/tmp/sockets/puma.sock;
}

server {
  listen 80;
  server_name <%= @ip %> <%= @domain %> ;
  access_log /var/log/nginx.access.log;
  error_log /var/log/nginx.error.log info;
  client_max_body_size 64M;
  keepalive_timeout 10;
  root <%= @project_dir %>/current/public;
  index index.html;

  location / {
    if (-f <%= @project_dir %>/shared/tmp/maintenance) {
      return 503 "{}";
    }

    proxy_redirect off;
    proxy_set_header Client-Ip $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    gzip_static on;
    proxy_pass http://puma;
  }

  location ~* \.(?:manifest|appcache|html?|json)$ {
    expires -1;
  }

  location ~* \.(?:css|js)$ {
    try_files $uri =404;
    expires 1y;
    access_log off;
    add_header Cache-Control "public";
  }

  location ~* \.(?:jpg|jpeg|gif|png|ico|bmp|swf|txt|svg|ttf|woff)$ {
    try_files $uri =404;
    access_log off;
    expires max;
  }

  error_page 503 @maintenance;

  location @maintenance {
    rewrite ^(.*)$ /maintenance.html break;
  }
}

Ми рекомендуємо дізнатись, як налаштувати Nginx із документації.

Тепер ви можете зібрати всі ці recipes в role під назвою web для подальшого використання у node сервера:

touch roles/web.rb

Далі опишіть основну інформацію про role та список її виконання:

# roles/web.rb

name 'web'
description 'Web setup'

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

Потім додайте цю role до run_list of the nodes/YOUR_IP_ADDRESS.json node:

// nodes/YOUR_IP_ADDRESS.json

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

Висновки

Тож тепер ви знаєте, як писати власні cookbooks. У наступній частині туторіалу ми завершимо написання cookbooks із конфігураціями для безпеки сервера та моніторингу серверних процесів. Ми застосуємо всі раніше написані конфігурації для розгортання додатка на Ruby on Rails на попередньо встановлену версію EC2.


Читайте також інші частини туторіалу: частина 1, частина 3.

Все про українське ІТ в телеграмі — підписуйтеся на канал DOU

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn



9 коментарів

Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.

Спасибі за статтю, цікаво, якраз все це зараз гризу 8-)

Чесно кажучи, маючи вибір між chef, ansible, puppet, saltstack для нового проекту — chef явно не буде на першому місці.

А шановному творцеві(цям) концепту omnibus на основі тих ідей — взагалі при житті «пожизненный эцих с гвоздями» )

Да, ладно вам Chef один из лучших продуктов для DevOps-ов.

1. Ansible — полно детских болезней несовметимости версий( не знаю может сейчас уже полечили). И то что мне встречалось выглядело сильно убого.
2. Puppet — конкурет да. С ним только одна проблема, а именно они используют свой DSL, а сложные моменты решают через вставки Ruby-кода. В результате, когда ваш проект дорастет до чего-то более или менее серьезного он будет представлять из себя говно-код с кучей Ruby-вставок. Насколько я понял админам Puppet нравится именно тем, что на начальных этапах можно обойтись без программирования. Chef — сразу предлагает не трахать себе мозг, и начать учить Ruby.

Ви знаєте, я оце робив тестове завдання одне, якраз вчора, там треба було сконфігурувати пару боксів за допомогою Chef.

Я до цього ніколи не мав справи з системами провіжионінгу, Chef, Puppet, Saltstack, Ansible—всі ці речі якось пройшли повз мене. Ну, теоретично я уявляв як воно працює, але до практики руки не доходили. От тепер дойшли.

Так от я авторитетно хочу заявити, що конфігурування серваків (а тим паче аплікейшенів) за допомогою цих всіх тулзів, ручне налаштування якихось прав, писанина отих кукбуків на смішному DSL, оце все—в наш час контейнеризації всього і вся—просто якесь абсолютно безглузде та тупе марнування часу, поїдання кактусу пейот тільки з голками, опалення квартири за допомогою вогнища розведенного з паркету, їзда на трьохколісному велосипеді дружок по мосту Патона, я не знаю як це ще назвати.

Тестове завдання я виконав, і сподіваюсь що це було востаннє коли мені потрібно було мати справу з Chef.

Якщо ви новачок в RoR то не читайте цю статтю, краще git push heroku master зробіть.
Якщо ви сисадмін—ви і так все знаєте.
Якщо ви норм пацан—у вас все вже давно в контейнерах крутиться.
Якщо вам хочеться поїсти кактуса розібратися в конфігах nginx—тоді велкам.

да, на кнопочку нажать это не архитектуру серваков настраивать, так что лучше не читайте а пользуйтесь Heroku, пусть настройка серваков останется магией для программиста :)

архитектуру серваков настраивать

конфіг nginx то не архітекутра серваків.

Ви мене неправильно зрозуміли. Знати як все працює потрібно. Але ваша стаття—це набір магічних рецептів для шефа та конфігів різного софта і вона зовсім не вчить «матчасти» як ви вказали. Якби ви переробили свій приклад на використання docker-compose, наприклад, то вона була б значно кориснішою навіть якщо абстрагуватись від RoR, тому що зараз усюди контейнери.

А для новачка налаштування серверів залишиться магією що з вашими кукбуками що без них.

конфіг nginx то не архітекутра серваків.

все верно, сам конфиг nginx не есть архитектура сервера, это правда :), никто и не утверждал что это так

настройка каждого сервиса (утилиты, ПО, как будет удобнее) является одной из составляющей конфигурирования всего web сервера

тому що зараз усюди контейнери

напишем статью и про Docker, уже обработали пожелания и взяли в работу

А для новачка налаштування серверів залишиться магією що з вашими кукбуками що без них.

не соглашусь с Вами, так как задача статьи раскрыть магию, а именно, показать как сервер настраивать, какие есть конфиги у различных сервисов, какие параметры за что отвечает, а шеф и его кукбук это инструмент автоматизации работы с сервером, кукбук надо уметь создать и создать правиьно, это и показывает автор в статье, статья обучающая, через какое то время новичок начинает интересоваться, а что же в рецепте, или как собрать контейнер, вот для этого и написали статью

подход: ’вот вам кукбук или вот вам контейнер, разверни его и не парься’ - работает на приложениях где нет критичности к ’ювелирной’ оптимизации работы серверов (не на production сервере), и там где можно использовать уже кем то созданные рецепты или сборки, но все же было бы хорошо посмотреть на сам рецепт или на сборку перед тем как поднимать сервера на production

Полностью поддерживаю! Зачем разбираться со всему этими тулами если можно загнать вебсайт в докер контейнер и запустить его как AWS Elastic Beanstalk? Зачем ставить Postgres если есть Amazon Aurora? Зачем мучаться с Redis если есть Amazon ElastiCache? Для девелопера лучше потратить время на написание кода, чем на конфигурирование всего этого зоопарка.

Автору за статью спасибо — наконецто что-то техническое, но я бы советовал двигаться в сторону PaaS и перестать использовать IaaS aka EC2

та незачем учить матчасть, главное что бы это в конце не превратилось в историю: ’а я нажал на кнопочку а оно почему то не заработало’ :)

Підписатись на коментарі