Рубрики
Uncategorized

Работа с Capistrano: задачи, роли и переменные

Капистрано. Tagged с DevOps, Ruby, Capistrano, Rails.

Капистрано является отличным инструментом для автоматизации развертывания и обслуживания веб -приложений. Я использую его для развертывания Ruby на Rails и других приложениях на основе стоек. Он заботится обо всех утомительных битах, таких как установка зависимостей, компиляция активов или мигрирующие схемы базы данных. Альтернативой будет вручную войти в сервер через SSH и запустить все необходимые команды сами. Это открыло бы путь к ужасным грехам и потребляет много времени и терпения. К счастью, нам не нужно.

Модульная конструкция Capistrano означает, что есть множество плагинов и сценариев. Они сделают возможным даже самые колючие потребности в развертывании. Даже если вы не найдете то, что хотите от полки, гибкая природа Capistrano поможет вам легко написать ваши собственные задачи. Вы сможете рассказать Capistrano, как именно вы хотите, чтобы ваше развертывание выглядело. Затем он подготовит сервер и продолжит помочь вам поддерживать обновления вашего приложения.

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

Все образцы кода в этой статье предполагают Capistrano 3. На момент написания этой статьи это означает установку Capistrano 3.11.2. Пожалуйста, прочитайте Официальные гиды о том, как настроить Capistrano в вашем проекте.

С учетом сказанного, давайте начнем!

Капистрано задачи

По своей сути, Capistrano использует задачи, предоставленные Рейбл Постройте инструмент для описания различных действий, которые будут обновлять и развернуть ваше приложение. Затем он перегружает эти задачи своим собственным интуитивно понятным DSL, который помогает выполнять команды в оболочке Unix на локальной машине или удаленном сервере.

В течение долгого времени я использовал вручную входить в разные серверы над SSH-соединением, чтобы выполнить одноразовые обновления. Это, в свою очередь, означало, что мне нужно было знать и ввести в оболочку использование пользователя и имени сервера развертывания каждый раз, когда я хотел, например, получить доступ к проставочному серверу. Это утомительно и склонно к ошибкам!

Конечно, есть лучший способ?

В идеале я хотел бы иметь постоянный способ входа на любой сервер на основе среды развертывания без необходимости знать детали. Эквивалент сказать: «Я хочу войти в промежуточный сервер». В Capistrano это приведет к выполнению следующей команды:

$ cap staging login

Давайте посмотрим, как мы могли бы реализовать эту команду как задачу.

По умолчанию Capistrano автоматически загружает файлы из lib/capistrano/tasks каталог. Мы пойдем дальше и создаем Login.rake Файл внутри этого каталога. Обратите внимание на *.rake Расширение, которое обычно используется для названия рубиновых файлов, которые содержат грабли. Рейбл предоставляет метод под названием desc Это можно использовать для добавления описания задачи. Описание будет отображаться, когда пользователь работает Cap — -Tasks Чтобы увидеть все доступные задачи. Рейбл также раскрывает метод под названием Задача Это может быть использовано для выражения поведения задачи. Сразу после описания мы используем Задача Блок, чтобы зарегистрировать новый, хотя и пустой на данный момент, : Вход задача:

# lib/capistrano/tasks/login.rake

desc "Login into a server based on the deployment stage"
task :login do
  ...
end

До сих пор задача входа ничего не сделает. Чтобы иметь возможность войти в систему, нам нужно собрать информацию о нашем сервере приложений. Это требует, чтобы мы говорили о концепции ролей.

Капистрано роли

Чтобы дать нам мелкозернистый контроль над тем, как выполняются задачи на каких серверах, Capistrano использует концепцию роли. Например, вы можете применить задачу только на сервер базы данных и пропустить ее при развертывании на веб -сервер. Роль действует как фильтр, который говорит Capistrano для групповых задач с той же ролью вместе, прежде чем выполнять их на сервере, соответствующем конкретной роли.

В задачах Capistrano используются три общие роли:

  • приложение Роль используется любой задачей, которая работает на сервере приложений, сервере, который генерирует динамический контент. В рельсах это Puma сервер Встроенные задачи Капистрано Развертывание: Проверка , Развертывание: публикация или Развертывание: закончено все работают в этой роли.
  • DB Роль используется задачами, которые выполняются против сервера базы данных. Например, Капистрано-Рейли плагин предоставляет Развертывание: мигрировать Задача для миграции схемы базы данных Rails.
  • Интернет Роль используется задачами, которые занимаются веб -серверами, которые обслуживают статический контент, думайте Nginx здесь. Созданное сообщество capistrano3-nginx Плагин использует эту роль во всех своих задачах, таких как nginx: start , nginx: reload или nginx: сайт: отключить Анкет

Мы также можем определить собственные пользовательские роли. Например, роль под названием Redis Это будет выполнять только задачи, связанные с Redis Экземпляр базы данных:

role :redis, "redis-server"

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

В нашем случае мы будем развертываться на одной машине, которая размещает серверы приложений, веб -базы и базы данных. Чтобы применить все три роли приложение , DB и Интернет На нашем сервере мы используем определение сокращения через сервер Метод:

# config/deploy/staging.rb

server "staging-server.example.com", roles: %w[app db web], primary: true

Если вы изучите приведенное выше определение сервера, вы заметите свойство с именем первичный Анкет Это свойство позволит Капистрано узнать порядок приоритета при выполнении задач. Задачи с ролями, связанными с основным сервером, будут выполняться первыми. Это становится особенно полезным, когда ваше приложение разделено между многими хостами. Если это так, то мы могли бы расширить наше определение, чтобы сосредоточиться на ролях:

# config/deploy/staging.rb

role :app, "app-server.example.com"
role :db, "db-server.example.com", primary: true
role :web, "static-server.exmaple.com"

Продвигаясь вперед, мы посмотрим, как применить наши определенные роли в задаче.

Получение конфигурации хоста

Чтобы получить доступ к конфигурации нашего сервера, мы будем использовать Роли вспомогательный метод. Этот метод принимает одно или несколько определений ролей и возвращает список всех соответствующих экземпляров хоста. Мы указываем : app Роль, чтобы получить, в нашем случае, список только с одним экземпляром конфигурации сервера Capistrano:: configuration:: server Анкет

Среди многих инноваций Capistrano 3 представляет более модульную архитектуру. Он разгружает управление сеансом SSH на другую зависимость, рубиновый драгоценный камень под названием Sshkit Анкет Sshkit через его DSL предоставляет на Метод, который позволяет нам запускать команды, описанные в области блока на многих серверах. Как аргумент, на принимает массив объектов конфигурации хоста, а затем использует Sshkit:: координатор Для запуска команд параллельно на каждом хосте:

# lib/sshkit/dsl.rb

module SSHKit
  module DSL
    def on(hosts, options={}, &block)
      Coordinator.new(hosts).each(options, &block)
    end
  end
  ...
end

Если у вас настроен более одного хоста, вероятно, лучше инструктировать Capistrano вход на каждый сервер в последовательности:

on roles(:app), in: :sequence do |server|
  ...
end

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

# lib/capistrano/tasks/login.rake

desc "Login into a server based on the deployment stage"
task :login do
  on roles(:app) do |server|
    ...
  end
end

Капистрано переменные

К ssh В сервер, мы должны знать имя пользователя, имя сервера и путь, чтобы войти в систему пользователя. Для ваших потребностей в конфигурации Capistrano предоставляет метод под названием установить Это позволяет настроить переменную, такие как настройки по всему миру или для конкретных задач, и сделать их доступными для других частей вашего сценария. Например, мы можем установить : Пользователь и : deploy_to переменные следующим образом:

# config/deploy/staging.rb

set :user, "deploy-user"
set :deploy_to, "/path/to/deploy/directory"

Чтобы помочь нам прочитать наши переменные конфигурации, Capistrano делает доступным метод под названием принести . Например, мы можем использовать его, чтобы получить имя пользователя и путь развертывания:

# lib/capistrano/tasks/login.rake

desc "Login into a server based on the deployment stage"
task :login do
  on roles(:app) do |server|
    user = fetch(:user)
    path = fetch(:deploy_to)
    ...
  end
end

Теперь, когда мы знаем имя пользователя и путь к входу в систему, мы можем построить URI, который мы будем использовать в качестве аргумента для ssh Командная утилита. Мы строим строку URI, объединив имя пользователя, имя сервера и номер порта. Код будет обрабатывать случаи, когда отсутствуют имя пользователя или порт:

# lib/capistrano/tasks/login.rake

desc "Login into a server based on the deployment stage"
task :login do
  on roles(:app) do |server|
    user = fetch(:user)
    path = fetch(:deploy_to)

    uri = [
      user,
      user && '@',
      server.hostname,
      server.port && ":",
      server.port
    ].compact.join
  end
end

Команда SSH

Теперь мы готовы запустить ssh командовать с помощью URI и пути развертывания. Прежде чем мы это сделаем, здесь есть несколько интересных вещей. В частности, -t Флаг, который инструктирует ssh Утилита для запуска в режиме телетипа. Что такое режим Телетипа? По умолчанию Capistrano развертывается через SSH -соединение без прикрепления визуального терминала. Нет необходимости показывать красивые интерфейсы, так как никто ничего не может видеть. Но в нашем случае мы хотим, чтобы пользователь имел доступ ко всем возможностям оболочки.

После -t Флаг Мы указываем местоположение URI сервера. Затем в кавычки прилагают команды оболочки для запуска после вошли в систему. Мы объединяем две команды оболочки. Сначала мы перемещаемся в каталог root сайта, а затем выполняем $ Shell переменная. $ Shell является переменной среды, которая удерживает местоположение для оболочки по умолчанию, обычно Избиение . Зачем нам начинать оболочку? Без выполнения оболочки команда SSH завершила бы нас. Но мы хотим остаться войти в систему, в этом весь смысл этой задачи! В случае Bash , мы используем -l Флаг, чтобы вызвать его, как будто пользователь вошел в систему. Мы делаем это для предварительной загрузки всех конфигураций в скрытых файлах, таких как профиль Bash.

Окончательная командная строка будет выглядеть так:

"ssh -t #{uri} 'cd #{path}/current && exec $SHELL -l'"

Мы используем Ruby’s exec запустить наш ssh командование локально:

exec("ssh -t #{uri} 'cd #{path}/current && exec $SHELL -l'")

Собрать все вместе, вся задача выглядит так:

desc "Login into a server based on the deployment stage"
task :login do
  on roles(:app) do |server|
    user = fetch(:user)
    path = fetch(:deploy_to)

    uri = [
      user,
      user && '@',
      server.hostname,
      server.port && ":",
      server.port
    ].compact.join

    exec("ssh -t #{uri} 'cd #{path}/current && exec $SHELL -l'")
  end
end

Мы быстро говорили о входе на сервер с нашей машины. Но это не единственный способ улучшить наш повседневный рабочий процесс с помощью Capistrano.

Удаленные рельсовые консоли

Часто мне нужно прыгнуть прямо в консоль Rails на сервере и запустить несколько запросов против живой базы данных. Я мог бы использовать задачу входа в систему, а затем после входа в систему ввести полную команду, чтобы открыть консоль Rails. Но это будет раздражать быстро. Как насчет того, чтобы вместо этого мы сценарий Capistrano зарегистрировал нас в консоли производственных рельсов? То, как мы хотели бы сделать это, — это выполнение следующей команды:

$ cap production console

Для реализации вышеизложенного, внутри того же Login.rake Файл, мы пишем голые кости : Консоль Задача с описанием:

# lib/capistrano/tasks/login.rake

desc "Open Rails console on a server based on the deployment stage"
task :console do
    ...
end

Как и задача входа в систему, чтобы получить доступ к нашему серверу, нам нужно знать имя пользователя и путь развертывания. Кроме того, чтобы открыть консоль Rails, мы также должны знать среду, в которой работает приложение Rails. Но мы можем получить это из : rails_env переменная конфигурации, которая настроена Капистрано-Рейли драгоценный камень:

# lib/capistrano/tasks/login.rake

desc "Open Rails console on a server based on the deployment stage"
task :console do
  on roles(:app) do |server|
    env = fetch(:rails_env)
    user = fetch(:user)
    path = fetch(:deploy_to)
    ...
  end
end

Поиск исполняемых рельсов

Прежде чем мы сможем открыть консоль Rails через SSH, нам нужно решить одну дополнительную проблему. Поскольку у нас нет доступа к псевдо-концевым, ни один из файлов конфигурации профиля пользователя не будет загружен. Нам нужно как -то сказать Капистрано, где найти Rails Исполняемая и, в свою очередь, где найти установку Ruby. Для меня предпочтительным способом является использование rbenv Утилита для управления установкой Ruby и Бундлер Для установки драгоценных камней. Если вы используете другой Ruby Manager, пожалуйста, отрегулируйте свои пути соответствующим образом.

Для rbenv Путь, мы используем локальную установку пользователя развертывания $ Home/.rbenv Анкет У Rbenv есть концепция прокладок, которые являются легкими исполняемыми файлами, которые отображают установленные команды Ruby, такие как жемчужина , IRB или рельс к rbenv Exec командование rbenv Exec Затем приведет определенную команду с правильным путем установки Ruby. Выполнить Rails Команда, нам нужно использовать пакет Shim, который обеспечит загрузку всех наших зависимостей. Мы можем получить доступ к пакет исполняемый файл в $ Home/.rbenv/shims каталог. Как последний шаг, мы сообщаем Rails Console Команда о среде, которую мы используем через -e флаг. Полная команда открытия консоли Rails выглядит так:

console_cmd = "$HOME/.rbenv/shims/bundle exec rails console -e #{env}"

С последним кусочком собрания головоломки мы можем ssh в текущий каталог приложений Rails и открыть консоль Rails:

"ssh -t #{uri} 'cd #{path}/current && #{console_cmd}'"

Теперь давайте связать все вместе в последнем сценарии:

desc "Open Rails console on a server based on the deployment stage"
task :console do
  on roles(:app) do |server|
    env  = fetch(:rails_env)
    user = fetch(:user)
    path = fetch(:deploy_to)

    uri = [
      user,
      user && '@',
      server.hostname,
      server.port && ":",
      server.port
    ].compact.join

    console_cmd = "$HOME/.rbenv/shims/bundle exec rails console -e #{env}"

    exec("ssh -t #{uri} 'cd #{path}/current && #{console_cmd}'")
  end
end

Удаление дублирования

Теперь все, что вы, читатели с орлиными глазами, вероятно, заметили, что у нас есть немного повторяющегося кода между задачами. Давайте справимся с этим, чтобы мы могли закончить и улучшить обслуживание. Одна вещь, которую я люблю делать, прежде чем удалить какой -либо беспорядок, — это повторить кодовый дослов, как я сделал во второй задаче. Это так, что я могу визуально выделить части, которые одинаковы. Мы видим, что, кроме переменной среды Rails и команды SSH для выполнения, задачи идентичны.

В духе удаления дублирования мы перенесем общую часть установки и запуска команды SSH в свой собственный метод, называемый run_ssh_with Анкет Метод примет в качестве аргументов конфигурация сервера и команда для запуска:

# lib/capistrano/tasks/login.rake

def run_ssh_with(server, cmd)
  user = fetch(:user)
  path = fetch(:deploy_to)

  uri = [
    user,
    user && "@",
    server.hostname,
    server.port && ":",
    server.port
  ].compact.join

  exec("ssh -t #{uri} 'cd #{path}/current && #{cmd}'")
end

Спасибо run_ssh_with , мы можем упростить обе задачи в:

# lib/capistrano/tasks/login.rake

desc "Login into a server based on the deployment stage"
task :login do
  on roles(:app) do |server|
    run_ssh_with(server, "exec $SHELL -l")
  end
end

desc "Open console on a remote server based on the deployment stage"
task :console do
  on roles(:app) do |server|
    env  = fetch(:rails_env)
    console_cmd = "$HOME/.rbenv/shims/bundle exec rails console -e #{env}"
    run_ssh_with(server, console_cmd)
  end
end

Это намного лучше! Прежде чем мы закончим, есть еще одна вещь, которую мы можем сделать, чтобы успокоить нашу природу программиста, которая жаждет оптимизации в каждом клавишном клавиатуре. Мы можем создавать псевдонимы для наших двух задач! Grable не предоставляет псевдоним как таковой, но мы можем ее подделать. Способ сделать это состоит в том, чтобы определить новую задачу, выполнение которого будет зависеть от вызова другой задачи в первую очередь. Давайте сократим обе задачи в одиночные буквы:

# lib/capistrano/tasks/login.rake

task :c => :console
task :l => :login

Резюме

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

Задачи входа и консоли обеспечивают быстрый способ автоматизации рудиментарных заданий. Одним из важных побочных эффектов задач является последовательность между проектами Rails. Вам не нужно знать, чтобы детали могли бы быстро искать файлы проекта или базу данных запросов на удаленном сервере. Эти небольшие эффективности накапливаются с течением времени и создают плавный рабочий процесс разработки. Если у вас есть похожие полезные задачи Capistrano, пожалуйста, поделитесь ими!

Эта статья была первоначально опубликована на PiotrMurach.com .

Фотография Рок -н -ролковая обезьяна на Unsplash

Оригинал: «https://dev.to/piotrmurach/working-with-capistrano-tasks-roles-and-variables-4em6»