Created
November 8, 2022 14:52
-
-
Save mikehostetler/87fabdce8d72543a32b295e180eada0f to your computer and use it in GitHub Desktop.
Elixir + Rust + ESBuild + SASS + Tailwind deploy setup to Fly.io
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: "Deploy Server Prod" | |
on: | |
workflow_dispatch: | |
env: | |
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} | |
jobs: | |
deploy: | |
name: Deploy Server to Production | |
runs-on: ubuntu-18.04 | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v2 | |
- name: Setup Docker layer caching | |
uses: satackey/[email protected] | |
continue-on-error: true | |
- name: Build app Docker image | |
run: docker build ./fitclub_server -t fitclub | |
- uses: superfly/[email protected] | |
env: | |
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} | |
FLY_PROJECT_PATH: "./fitclub_server" | |
with: | |
args: "deploy -a hrmfitclub-prod --config ./fly.toml" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app = "hrmfitclub-prod" | |
kill_signal = "SIGTERM" | |
kill_timeout = 5 | |
[env] | |
[deploy] | |
release_command = "/app/bin/fitclub eval Fitclub.Release.migrate" | |
[[services]] | |
internal_port = 4000 | |
protocol = "tcp" | |
[services.concurrency] | |
hard_limit = 25 | |
soft_limit = 20 | |
[[services.ports]] | |
handlers = ["http"] | |
port = 80 | |
[[services.ports]] | |
handlers = ["tls", "http"] | |
port = 443 | |
[[services.tcp_checks]] | |
grace_period = "30s" # allow some time for startup | |
interval = "15s" | |
restart_limit = 6 | |
timeout = "2s" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Using the Hex.pm docker images. You have much better version control for | |
# Elixir, Erlang and Alpine. | |
# | |
# - https://hub.docker.com/r/hexpm/elixir/tags | |
# - Ex: hexpm/elixir:1.11.2-erlang-23.3.2-alpine-3.13.3 | |
# | |
# Debugging Notes: | |
# | |
# docker build -it --rm hello_elixir /bin/ash | |
# docker run -it --rm hello_elixir /bin/ash | |
### | |
### Fist Stage - Building the Release | |
### | |
FROM hexpm/elixir:1.13.3-erlang-24.2.1-alpine-3.15.0 AS build | |
# install build dependencies | |
RUN apk add --no-cache build-base npm yarn git ca-certificates gcc | |
# Add glibc for dart_sass - https://github.com/CargoSense/dart_sass#faq | |
RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub | |
RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.34-r0/glibc-2.34-r0.apk | |
RUN apk add glibc-2.34-r0.apk | |
# Install Rust for MJML | |
ENV RUSTUP_HOME=/usr/local/rustup \ | |
CARGO_HOME=/usr/local/cargo \ | |
PATH=/usr/local/cargo/bin:$PATH \ | |
RUST_VERSION=1.56.0 | |
RUN set -eux; \ | |
apkArch="$(apk --print-arch)"; \ | |
case "$apkArch" in \ | |
x86_64) rustArch='x86_64-unknown-linux-musl'; rustupSha256='bdf022eb7cba403d0285bb62cbc47211f610caec24589a72af70e1e900663be9' ;; \ | |
aarch64) rustArch='aarch64-unknown-linux-musl'; rustupSha256='89ce657fe41e83186f5a6cdca4e0fd40edab4fd41b0f9161ac6241d49fbdbbbe' ;; \ | |
*) echo >&2 "unsupported architecture: $apkArch"; exit 1 ;; \ | |
esac; \ | |
url="https://static.rust-lang.org/rustup/archive/1.24.3/${rustArch}/rustup-init"; \ | |
wget "$url"; \ | |
echo "${rustupSha256} *rustup-init" | sha256sum -c -; \ | |
chmod +x rustup-init; \ | |
./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch}; \ | |
rm rustup-init; \ | |
chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \ | |
rustup --version; \ | |
cargo --version; \ | |
rustc --version; | |
# prepare build dir | |
WORKDIR /app | |
# extend hex timeout | |
ENV HEX_HTTP_TIMEOUT=20 | |
# install hex + rebar | |
RUN mix local.hex --force && \ | |
mix local.rebar --force | |
# set build ENV as prod | |
ENV MIX_ENV=prod \ | |
SECRET_KEY_BASE=nokey \ | |
RUSTFLAGS='--codegen target-feature=-crt-static' | |
# Copy over the mix.exs and mix.lock files to load the dependencies. If those | |
# files don't change, then we don't keep re-fetching and rebuilding the deps. | |
COPY mix.exs mix.lock ./ | |
COPY config config | |
RUN mix deps.get --only prod && \ | |
mix deps.compile | |
# install npm dependencies | |
COPY assets/package.json assets/yarn.lock ./assets/ | |
# RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error | |
RUN yarn --cwd ./assets --no-progress --non-interactive | |
COPY priv priv | |
COPY assets assets | |
# NOTE: If using TailwindCSS, it uses a special "purge" step and that requires | |
# the code in `lib` to see what is being used. Uncomment that here before | |
# running the npm deploy script if that's the case. | |
COPY lib lib | |
# build assets | |
# RUN npm run --prefix ./assets deploy | |
RUN mix assets.deploy | |
# copy source here if not using TailwindCSS | |
# COPY lib lib | |
# compile and build release | |
COPY rel rel | |
RUN mix do compile, release | |
### | |
### Second Stage - Setup the Runtime Environment | |
### | |
# prepare release docker image | |
FROM alpine:3.15.0 AS app | |
RUN apk add --no-cache libstdc++ openssl ncurses-libs imagemagick file | |
WORKDIR /app | |
RUN chown nobody:nobody /app | |
USER nobody:nobody | |
COPY --from=build --chown=nobody:nobody /app/_build/prod/rel/fitclub ./ | |
ENV HOME=/app | |
ENV MIX_ENV=prod | |
ENV SECRET_KEY_BASE=nokey | |
ENV PORT=4000 | |
CMD ["bin/fitclub", "start"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Fitclub.MixProject do | |
use Mix.Project | |
@version "0.12.8" | |
def project do | |
[ | |
app: :fitclub, | |
version: @version, | |
elixir: "~> 1.13", | |
elixirc_paths: elixirc_paths(Mix.env()), | |
elixirc_options: [ | |
# warnings_as_errors: true, | |
debug_info: Mix.env() == :dev | |
], | |
compilers: [:phoenix, :gettext] ++ Mix.compilers(), | |
# dialyzer: [plt_add_apps: [:ex_unit, :mix], ignore_warnings: "config/dialyzer.ignore"], | |
start_permanent: Mix.env() == :prod, | |
aliases: aliases(), | |
deps: deps() | |
] | |
end | |
# Configuration for the OTP application. | |
# | |
# Type `mix help compile.app` for more information. | |
def application do | |
[ | |
mod: {Fitclub.Application, []}, | |
extra_applications: [:ex_machina, :logger, :runtime_tools] | |
] | |
end | |
# Specifies which paths to compile per environment. | |
defp elixirc_paths(:test), do: ["lib", "test/support"] | |
defp elixirc_paths(_), do: ["lib"] | |
# Specifies your project dependencies. | |
# | |
# Type `mix help deps` for examples and options. | |
defp deps do | |
[ | |
# Configuration Management - Upstream confix has issue with Mix Releases | |
{:confix, git: "https://github.com/mikehostetler/confix.git"}, | |
# Monitoring | |
{:appsignal, "~> 2.0"}, | |
{:appsignal_phoenix, "~> 2.0.0"}, | |
{:sentry, "~> 8.0"}, | |
{:prom_ex, "~> 1.6.0"}, | |
# Absinthe for GraphQL | |
{:absinthe, "~> 1.7.0", override: true}, | |
{:absinthe_plug, "~> 1.5.5"}, | |
{:absinthe_relay, "~> 1.5.0"}, | |
{:absinthe_error_payload, "~> 1.0"}, | |
{:dataloader, "~> 1.0.0"}, | |
# Background Jobs | |
{:oban, "~> 2.9"}, | |
# Kaffy administration | |
{:kaffy, "~> 0.9.0"}, | |
{:guardian, "~> 2.0"}, | |
{:phoenix, "~> 1.6.0", override: true}, | |
{:phoenix_ecto, "~> 4.1"}, | |
{:ecto_sql, "~> 3.4"}, | |
{:postgrex, ">= 0.0.0"}, | |
{:phoenix_live_view, "~> 0.17.0", override: true}, | |
{:phoenix_html, "~> 3.0", override: true}, | |
{:phoenix_live_reload, "~> 1.2", only: :dev}, | |
{:phoenix_live_dashboard, "~> 0.5"}, | |
{:brady, "~> 0.0.10"}, | |
{:heroicons_liveview, "~> 0.5.0"}, | |
# Asset pipeline | |
{:esbuild, "~> 0.2", runtime: Mix.env() == :dev}, | |
{:tailwind, "~> 0.1", runtime: Mix.env() == :dev}, | |
{:dart_sass, "~> 0.4", runtime: Mix.env() == :dev}, | |
# Monitoring | |
{:telemetry, "~> 1.0", override: true}, | |
{:telemetry_metrics, "~> 0.6"}, | |
{:telemetry_poller, "~> 1.0", override: true}, | |
{:gettext, "~> 0.11"}, | |
{:jason, "~> 1.0"}, | |
{:plug_cowboy, "~> 2.0"}, | |
{:plug_canonical_host, "~> 2.0"}, | |
# Pagination & Filtering | |
{:scrivener_ecto, "~> 2.7"}, | |
{:filtrex, "~> 0.4.3"}, | |
# Policies | |
{:bodyguard, "~> 2.4"}, | |
# Caching | |
{:cachex, "~> 3.4"}, | |
# Date Time management | |
{:castore, "~> 0.1.10"}, | |
{:mint, "~> 1.3"}, | |
{:tz, "~> 0.20.1"}, | |
{:tz_extra, "~> 0.20.1"}, | |
{:timex, "~> 3.0"}, | |
# SVG Charting | |
{:contex, "~> 0.4.0"}, | |
# Data Mocking | |
{:ex_machina, "~> 2.7.0"}, | |
{:faker, "~> 0.17.0"}, | |
# Stripe for Payments | |
{:stripity_stripe, "~> 2.0"}, | |
# Bamboo for Emailing | |
{:bamboo, "~> 2.0"}, | |
{:bamboo_phoenix, "~> 1.0"}, | |
{:premailex, "~> 0.3.0"}, | |
{:floki, ">= 0.0.0"}, | |
{:mjml, "~> 1.2.0"}, | |
# Waffle for file upload | |
{:waffle, "~> 1.1.1"}, | |
{:waffle_ecto, "~> 0.0.9"}, | |
# If using Waffle with S3: | |
{:ex_aws, "~> 2.2.3"}, | |
{:ex_aws_s3, "~> 2.0"}, | |
{:hackney, "~> 1.9"}, | |
{:sweet_xml, "~> 0.6"}, | |
{:phx_gen_auth, "~> 0.6", only: [:dev], runtime: false}, | |
{:bcrypt_elixir, "~> 3.0"}, | |
{:ecto_psql_extras, "~> 0.2"}, | |
{:hashids, "~> 2.0"}, | |
# Intercom | |
{:intercom, "~> 2.0", hex: :intercom_elixir}, | |
# CSV parsing | |
{:csv, "~> 2.4"}, | |
# Testing | |
{:assertions, "~> 0.19.0", only: [:test]}, | |
{:ex_check, "~> 0.14.0", only: [:dev, :test], runtime: false}, | |
{:credo, ">= 0.0.0", only: [:dev, :test], runtime: false}, | |
{:dialyxir, ">= 0.0.0", only: [:dev, :test], runtime: false}, | |
{:doctor, ">= 0.0.0", only: [:dev, :test], runtime: false}, | |
{:ex_doc, ">= 0.0.0", only: [:dev, :test], runtime: false}, | |
{:sobelow, ">= 0.0.0", only: [:dev, :test], runtime: false} | |
] | |
end | |
# Aliases are shortcuts or tasks specific to the current project. | |
# For example, to install project dependencies and perform other setup tasks, run: | |
# | |
# $ mix setup | |
# | |
# See the documentation for `Mix` for more info on aliases. | |
defp aliases do | |
[ | |
setup: ["setup.deps", "ecto.setup"], | |
"setup.deps": ["deps.get", "cmd yarn --prefix assets", "assets.deploy"], | |
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], | |
"ecto.reset": ["ecto.drop", "ecto.setup"], | |
test: ["ecto.drop --quiet", "ecto.create --quiet", "ecto.migrate --quiet", "test"], | |
sentry_recompile: ["compile", "deps.compile sentry --force"], | |
"assets.deploy": [ | |
"esbuild default --minify", | |
"sass default --no-source-map --style=compressed", | |
"tailwind default --minify", | |
"phx.digest" | |
] | |
] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment