В 2012 году, чтобы упростить развертывание приложений, написанных на Ruby on Rails, компания Heroku сделала свой знаменитый продукт. В статье мы рассмотрим несколько вариантов для хостинга и разберем, как задеплоить Ruby on Rails на конкретном примере приложения.

Хостинг Ruby on Rails. Провайдеры

  1. Heroku - компания, которая изобрела GitOps-подход и начинала свой путь именно как хостинг для Ruby. Достаточно запушить ваше ruby-приложение в репозиторий через git push, и Heroku развернет его автоматически. Потребуется иностранная карта. Тарифы стартуют от 5-7$ в месяц. 

  1. Amvera Cloud - российский сервис. По функционалу похож на Heroku, только можно оплачивать российской картой. Поддерживает развертывание и обновление через push в привязанный Git-репозиторий либо через интерфейс, если вам не знаком Git. Есть нативная поддержка как C#, так и других окружений - достаточно в интерфейсе выбрать нужную конфигурацию. Стоимость начинается от 170 руб. в месяц, и есть стартовый баланс для бесплатного начала использования.

  2. Движки приложений от Azure, GCE, AWS. Позволяют легко развернуть ваше ruby-приложение в инфраструктуре данных облачных провайдеров.

Развернем Fullstack-приложение на Ruby c подключением к SQLite

Приведем видеопример и подробную инструкцию.

Для этого воспользуемся сервисом Amvera. Чтобы развернуть основное приложение в Amvera, нужно выполнить следующие простые шаги:

1.  Открываем страницу https://cloud.amvera.ru/projects   (необходимо предварительно зарегистрироваться в Amvera)

2.  Нажимаем кнопку “Создать” и выбираем тип сервиса “Приложение” 

3.  Выгружаем все файлы (можно через git, а можно через интерфейс). Убедитесь, что вы выгрузили все нужные файлы. Для проекта из примера ниже это:

- static/styles.css

- app.rb 

- Gemfile

- amvera.yml и/или Dockerfile

4.  После этого начнется сборка и развертывание приложения. Дождитесь появления статуса «Успешно развернуто».

Рассмотрим процесс подробнее

Давайте создадим простое веб-приложение на языке программирования Ruby, которое будет отслеживать посещения сайта. Для хранения этой информации мы будем использовать СУБД SQLite.

Директория приложения имеет следующую структуру:

└─ code/

├── static

│   └── styles.css

├── amvera.yml

├── app.rb

├── Gemfile

└── Dockerfile

Конфигурация

amvera.yml

Можно как написать yaml файл самостоятельно, так и воспользоваться нашим генератором yaml по ссылке либо в разделе «Конфигурация» личного кабинета.

Пример файла amvera.yml при использовании только amvera.yml:

meta:
  environment: ruby
  toolchain:
    name: bundle
    version: 3.0
build:
  image: ruby:3.0
run:
  image: ruby:3.0
  mainScript: app.rb
  persistenceMount: /data
  containerPort: 80

Пример файла amvera.yml при использовании вместе с Dockerfile:

meta:
  environment: docker
  toolchain:
    name: docker
    version: latest
build:
  dockerfile: Dockerfile
  skip: false
run:
  persistenceMount: /data
  containerPort: 80

Важно: сохранять изменяемые файлы (база данных и т.д.) именно в постоянное хранилище /data. Это позволит избежать их потери при пересборке. Папка Data в коде и постоянное хранилище /data - разные директории.

Рассмотрим альтернативный способ задания конфигурации - через Dockerfile.

Dockerfile

Замечание: если вы используете Dockerfile, то конфигурационный файл amvera.yml в большинстве случаев можно не добавлять.

Шаги:

1. Создаем Dockerfile в директории с проектом.

2. В Dockerfile указываем базовый образ:

FROM ruby:3.0

вместо 3.0 можете указать любую другую версию, которая вам нужна.

3. Устанавливаем рабочую директорию:

WORKDIR /app

4. Копируем файл Gemfile в текущую директорию рабочего каталога:

COPY Gemfile ./

5. Устанавливаем зависимости, указанные в Gemfile:

RUN bundle install

6. Обновляем информацию об установленных зависимостях:

RUN bundle update

7. Копируем оставшиеся файлы внутрь контейнера:

COPY . ./

8. Открываем порт 80 для внешних подключений:

EXPOSE 80

9. Добавляем команду для запуска приложения

CMD ["ruby", "app.rb"]

Получившийся Dockerfile:

FROM ruby:3.0
    
WORKDIR /app
    
COPY Gemfile ./
    
RUN bundle install
    
RUN bundle update
    
COPY . ./
    
EXPOSE 80
    
CMD ["ruby", "app.rb"]

Зависимости (Gemfile)

Чтобы создать Gemfile, нужно выполнить команду:

    $ bundle init

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

source 'https://rubygems.org'
gem 'sqlite3'
gem 'webrick'

Создание проекта в Amvera

Последний шаг - развернуть само приложение. В файле app.rb содержится основной код и выполняется подключение к базе данных.

Подключение к репозиторию через Git

1. Вызовем терминал в IDE, где открыто приложение, или откроем папку проекта в терминале

2. Инициализируем локальный гит репозиторий командой

git init

3. Добавим удаленный репозиторий нашего проекта (url вашего репозитория будет отличаться. Во избежание синтаксических ошибок скопируйте ссылку на втором шаге создания проекта)

git remote add amvera https://git.amvera.ru/имя_пользователя/имя_проекта

4. Добавим файлы и сделаем первый коммит

git add .
git commit -m "init"

5. Запушим наш код в репозиторий проекта

git push amvera master

После данной команды ваше приложение развернется.

Использование SQLite с Ruby приложением

Для использования SQLite в Amvera отдельное приложение/контейнер не требуется. Достаточно в коде указать путь для хранения файлов этой БД в постоянное хранилище. Подробнее можно почитать здесь.

Итог

Мы развернули Ruby on Rails на сервере Amvera и подключили базу данных SQLite. Теперь накатывать обновления можно простой командой - git push

P.S.

Код приложения из примера
require "webrick"
require "sqlite3"

DB_PATH = "../data/visits.db"

DB = SQLite3::Database.new DB_PATH
DB.execute <<-SQL
  CREATE TABLE IF NOT EXISTS visits (
    id INTEGER PRIMARY KEY,
    time_visited TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  );
SQL

class IndexHandler < WEBrick::HTTPServlet::AbstractServlet
  def do_GET(request, response)
    if request.path == "/"
      DB.execute("INSERT INTO visits DEFAULT VALUES")
    end
    
    response.status = 200
    response.content_type = "text/html"
    response.body = generate_html
  end

  private

  def generate_html
    visits = fetch_visits
    html = <<~HTML
      <!DOCTYPE html>
      <html>
      <head>
        <title>Visits</title>
        <link rel="stylesheet" type="text/css" href="/static/styles.css">
      </head>
      <body>
        <h1>Visits</h1>
        <table border="1">
          <thead>
            <tr>
              <th>Index</th>
              <th>Time of Visiting</th>
            </tr>
          </thead>
          <tbody>
    HTML
    
    visits.each do |visit|
      html += "<tr><td>#{visit[0]}</td><td>#{visit[1]}</td></tr>"
    end
    
    html += <<~HTML
          </tbody>
        </table>
      </body>
      </html>
    HTML

    html
  end

  def fetch_visits
    DB.execute("SELECT * FROM visits")
  end
end

server = WEBrick::HTTPServer.new(Port: 80)
server.mount("/static", WEBrick::HTTPServlet::FileHandler, "static")
server.mount("/", IndexHandler)
server.start
```

> Не забудьте выбрать именно тот порт, который вы указали в amvera.yml и/или Dockerfile


## Проверка работоспособности

1.  Переходим в настройки проекта и активируем доменное имя.

2.  Теперь можно перейти по нему и откроется наше приложение.

    
Если что-то не работает, рекомендуем ознакомиться с логами Сборки и Приложения.

Поздравляем, вы успешно создали свое первое приложение в Amvera!

## Код styles.css из примера:

```css
body {
    font-family: Arial, sans-serif;
}

table {
    width: 80%;
    margin: 20px auto;
    border-collapse: collapse;
}

th, td {
    padding: 10px;
    text-align: left;
}

thead {
    background-color: #f2f2f2;
}

tbody tr:nth-child(even) {
    background-color: #f9f9f9;
}

tbody tr:hover {
    background-color: #ddd;
}

Комментарии (2)


  1. kirillkosolapov
    24.04.2024 11:01

    А чем описанный выше пример деплоя отличается от деплоя Ruby на Heroku?


    1. ovchinnikovproger Автор
      24.04.2024 11:01

      Основное отличие в конфигурационном файле. Там свой формат. В остальном все практически идентично