Некоторое время назад развертывание Elixir-приложений было сложным, но сейчас у нас есть столько инструментов, облегчающих нашу работу, что создать производственную среду бесплатно очень просто.
Render — это платформа как услуга, которая предлагает хост для нашего сервера, защиту от DDoS, авторазвертывание на git и многие другие функции, которые мы можем использовать, не прикладывая кредитной карты! Они также поддерживают Docker, поэтому мы будем использовать его.
Цель состоит в том, чтобы создать простое приложение LiveView, изменить его и развернуть на Render с помощью образа Docker.
Итак, давайте начнем!
Создание приложения и локальный запуск на docker
Наше приложение будет называться Render Deploy, у него нет никакой функциональности, оно просто демонстрирует развертывание.
Чтобы создать приложение LiveView, выполните команду ниже:
mix phx.new render_deploy --live --no-ecto
- — live: Это признак того, что новый проект является приложением LiveView.
- — no-ecto: Указывает, что нам не нужен ecto, поэтому у него не будет Repo.
Теперь в config/dev.exs, строка 12 измените 127, 0, 0, 1
на 0, 0, 0, 0, 0
, чтобы разрешить доступ из docker.
Мы должны создать ./Dockerfile
в корне каталога для локального запуска:
FROM hexpm/elixir:1.13.0-erlang-23.3.4.10-alpine-3.14.3 AS base
WORKDIR /render_deploy
RUN mix do local.hex --force, local.rebar --force
RUN apk add npm inotify-tools
- Это многоэтапная сборка docker, она сохраняет файл более читаемым и создает меньший образ, подробнее можно прочитать здесь.
Мы могли бы запустить docker build и docker run, но я предпочитаю использовать docker-compose для управления контейнерами, поэтому давайте создадим новый ./docker-compose.yml
в корне каталога.
version: "3.8"
services:
app:
build:
context: .
target: base
container_name: render_deploy_web
command: mix phx.server
restart: unless-stopped
ports:
- 4000:4000
volumes:
- .:/render_deploy
- При многоэтапной сборке мы можем задать определенную цель при создании контейнера, в данном случае это
target: base
.
После создания файлов мы можем выполнить эти команды для установки зависимостей, создания контейнера и локального запуска сервера.
docker-compose run --rm app mix deps.get
docker-compose up
Если мы можем получить доступ к localhost:4000, мы увидим эту страницу:
Давайте изменим ее, чтобы сделать уникальной.
lib/render_deploy_web/templates/page/index.html.heex
строка 2 изменить
<h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
to
<h1><%= gettext "Welcome to %{name}!", name: "Render deploy" %></h1>
Корректировка кода перед развертыванием
Мы собираемся использовать mix releases, который является способом упаковать наше приложение в исполняемый двоичный файл и использовать его для развертывания приложения.
Для этого мы должны добавить следующий код в конец файла ./Dockerfile
:
# -----------------
# BUILD
# -----------------
FROM base AS build
RUN apk add curl bash git
ARG MIX_ENV=prod
ENV MIX_ENV=$MIX_ENV
COPY . ./
# install application
RUN mix do deps.get, compile
# -----------------
# RELEASE
# -----------------
FROM build AS release
# digests and compresses static files
RUN mix assets.deploy
# generate release executable
RUN mix release
# -----------------
# PRODUCTION
# -----------------
FROM alpine:3.14.3
WORKDIR /render_deploy
ARG MIX_ENV=prod
# install dependencies
RUN apk add ncurses-libs curl
COPY --from=release /render_deploy/_build/$MIX_ENV/rel/render_deploy ./
# start application
CMD ["bin/render_deploy", "start"]
- Важные моменты в коде:
Теперь, перед развертыванием, мы должны настроить наш config/runtime.exs
так, чтобы Render поместил производственный URL:
import Config
if System.get_env("PHX_SERVER") && System.get_env("RELEASE_NAME") do
config :render_deploy, RenderDeployWeb.Endpoint, server: true
end
if config_env() == :prod do
secret_key_base =
System.get_env("SECRET_KEY_BASE") ||
raise """
environment variable SECRET_KEY_BASE is missing.
You can generate one by calling: mix phx.gen.secret
"""
port = String.to_integer(System.get_env("PORT") || "4000")
config :render_deploy, RenderDeployWeb.Endpoint,
url: [host: System.get_env("RENDER_EXTERNAL_HOSTNAME") || "localhost", port: 80],
http: [
ip: {0, 0, 0, 0, 0, 0, 0, 0},
port: port
],
secret_key_base: secret_key_base
config :render_deploy, RenderDeployWeb.Endpoint, server: true
end
Подготовка к развертыванию
Итак, мы закончили разработку с помощью docker и готовы к развертыванию в production с помощью render.com.
Прежде всего, нам нужно создать репозиторий с кодом на Github.
Теперь давайте зайдем на render.com и создадим проект, если у вас нет учетной записи, создайте ее, затем нажмите на New, Web Service.
Выберите ваш репозиторий:
Выберите имя, выберите Docker в качестве среды выполнения и бесплатный план.
Теперь мы должны установить секретный ключ, для этого выполните следующую команду для генерации секрета:
docker-compose run --rm app mix phx.gen.secret
После этого прокрутите страницу вниз и нажмите на «Advanced», затем поставьте SECRET_KEY_BASE с секретом, сгенерированным ранее.
Теперь мы просто нажимаем на «Create Web Service» и ждем, пока Render развернет наше приложение на производство.
Когда развертывание будет завершено, вы увидите надпись «Live», теперь просто нажмите на URL и проверьте наше новое приложение LiveView, работающее в облаке 🎉.
Render имеет некоторые ограничения на бесплатном плане, приложения автоматически отключаются после 15 минут бездействия, а новый запрос после этого времени может занять 30 секунд, чтобы снова запуститься, также бесплатный план позволяет 750 часов времени работы в месяц для всех бесплатных веб-сервисов в вашем аккаунте, вы можете увидеть все ограничения здесь.
Даже с этими ограничениями, это хорошая платформа для размещения наших сервисов и практики развертывания на производстве.
Вы можете посмотреть исходный код здесь: https://github.com/Lgdev07/render_deploy и приложение, которое мы только что создали здесь: https://render-example-71rp.onrender.com/.
Я благодарен всем, кто дочитал до конца, если у вас есть что добавить, пожалуйста, оставьте комментарий.