From 98e74dc75ce8b71d8f006a00e3cdcdcace71496e Mon Sep 17 00:00:00 2001 From: Stephen Turley Date: Sat, 16 Dec 2023 06:17:35 -0500 Subject: [PATCH] added fly.io config and removed Ecto config --- .dockerignore | 45 ++++++++++++++++ Dockerfile | 92 +++++++++++++++++++++++++++++++++ config/dev.exs | 9 ---- config/prod.exs | 6 --- config/runtime.exs | 16 ------ config/test.exs | 13 ----- elixir_buildpack.config | 2 - fly.toml | 34 ++++++++++++ lib/wordual/release.ex | 28 ++++++++++ phoenix_static_buildpack.config | 1 - rel/env.sh.eex | 8 +++ rel/overlays/bin/migrate | 3 ++ rel/overlays/bin/migrate.bat | 1 + rel/overlays/bin/server | 3 ++ rel/overlays/bin/server.bat | 2 + 15 files changed, 216 insertions(+), 47 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile delete mode 100644 elixir_buildpack.config create mode 100644 fly.toml create mode 100644 lib/wordual/release.ex delete mode 100644 phoenix_static_buildpack.config create mode 100755 rel/env.sh.eex create mode 100755 rel/overlays/bin/migrate create mode 100755 rel/overlays/bin/migrate.bat create mode 100755 rel/overlays/bin/server create mode 100755 rel/overlays/bin/server.bat diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..61a7393 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,45 @@ +# This file excludes paths from the Docker build context. +# +# By default, Docker's build context includes all files (and folders) in the +# current directory. Even if a file isn't copied into the container it is still sent to +# the Docker daemon. +# +# There are multiple reasons to exclude files from the build context: +# +# 1. Prevent nested folders from being copied into the container (ex: exclude +# /assets/node_modules when copying /assets) +# 2. Reduce the size of the build context and improve build time (ex. /build, /deps, /doc) +# 3. Avoid sending files containing sensitive information +# +# More information on using .dockerignore is available here: +# https://docs.docker.com/engine/reference/builder/#dockerignore-file + +.dockerignore + +# Ignore git, but keep git HEAD and refs to access current commit hash if needed: +# +# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat +# d0b8727759e1e0e7aa3d41707d12376e373d5ecc +.git +!.git/HEAD +!.git/refs + +# Common development/test artifacts +/cover/ +/doc/ +/test/ +/tmp/ +.elixir_ls + +# Mix artifacts +/_build/ +/deps/ +*.ez + +# Generated on crash by the VM +erl_crash.dump + +# Static artifacts - These should be fetched and built inside the Docker image +/assets/node_modules/ +/priv/static/assets/ +/priv/static/cache_manifest.json diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d08810b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,92 @@ +# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian instead of +# Alpine to avoid DNS resolution issues in production. +# +# https://hub.docker.com/r/hexpm/elixir/tags?page=1&name=ubuntu +# https://hub.docker.com/_/ubuntu?tab=tags +# +# +# This file is based on these images: +# +# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image +# - https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye-20231009-slim - for the release image +# - https://pkgs.org/ - resource for finding needed packages +# - Ex: hexpm/elixir:1.15.7-erlang-26.1.2-debian-bullseye-20231009-slim +# +ARG ELIXIR_VERSION=1.15.7 +ARG OTP_VERSION=26.1.2 +ARG DEBIAN_VERSION=bullseye-20231009-slim + +ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" +ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}" + +FROM ${BUILDER_IMAGE} as builder + +# install build dependencies +RUN apt-get update -y && apt-get install -y build-essential git \ + && apt-get clean && rm -f /var/lib/apt/lists/*_* + +# prepare build dir +WORKDIR /app + +# install hex + rebar +RUN mix local.hex --force && \ + mix local.rebar --force + +# set build ENV +ENV MIX_ENV="prod" + +# install mix dependencies +COPY mix.exs mix.lock ./ +RUN mix deps.get --only $MIX_ENV +RUN mkdir config + +# copy compile-time config files before we compile dependencies +# to ensure any relevant config change will trigger the dependencies +# to be re-compiled. +COPY config/config.exs config/words.exs config/${MIX_ENV}.exs config/ +RUN mix deps.compile + +COPY priv priv + +COPY lib lib + +COPY assets assets + +# compile assets +RUN mix assets.deploy + +# Compile the release +RUN mix compile + +# Changes to config/runtime.exs don't require recompiling the code +COPY config/runtime.exs config/ + +COPY rel rel +RUN mix release + +# start a new build stage so that the final image will only contain +# the compiled release and other runtime necessities +FROM ${RUNNER_IMAGE} + +RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales \ + && apt-get clean && rm -f /var/lib/apt/lists/*_* + +# Set the locale +RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen + +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US:en +ENV LC_ALL en_US.UTF-8 + +WORKDIR "/app" +RUN chown nobody /app + +# set runner ENV +ENV MIX_ENV="prod" + +# Only copy the final release from the build stage +COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/wordual ./ + +USER nobody + +CMD ["/app/bin/server"] diff --git a/config/dev.exs b/config/dev.exs index 54cab0f..6be9619 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -1,14 +1,5 @@ import Config -# Configure your database -config :wordual, Wordual.Repo, - username: "postgres", - password: "postgres", - hostname: "localhost", - database: "wordual_dev", - show_sensitive_data_on_connection_error: true, - pool_size: 10 - # For development, we disable any cache and enable # debugging and code reloading. # diff --git a/config/prod.exs b/config/prod.exs index 2d7a034..f035991 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -19,12 +19,6 @@ config :wordual, WordualWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json", version: Mix.Project.config()[:version] -config :wordual, Wordual.Repo, - adapter: Ecto.Adapters.Postgres, - url: "${DATABASE_URL}", - database: "", - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") - # Do not print debug messages in production config :logger, level: :info diff --git a/config/runtime.exs b/config/runtime.exs index 171be77..d612d27 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -13,22 +13,6 @@ if System.get_env("PHX_SERVER") && System.get_env("RELEASE_NAME") do end if config_env() == :prod do - database_url = - System.get_env("DATABASE_URL") || - raise """ - environment variable DATABASE_URL is missing. - For example: ecto://USER:PASS@HOST/DATABASE - """ - - maybe_ipv6 = if System.get_env("ECTO_IPV6"), do: [:inet6], else: [] - - config :wordual, Wordual.Repo, - # ssl: true, - url: database_url, - database: "wordual", - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), - socket_options: maybe_ipv6 - # The secret key base is used to sign/encrypt cookies and other secrets. # A default value is used in config/dev.exs and config/test.exs but you # want to use a different value for prod and you most likely don't want diff --git a/config/test.exs b/config/test.exs index 96b7bd0..ce7a044 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,18 +1,5 @@ import Config -# Configure your database -# -# The MIX_TEST_PARTITION environment variable can be used -# to provide built-in test partitioning in CI environment. -# Run `mix help test` for more information. -config :wordual, Wordual.Repo, - username: "postgres", - password: "postgres", - hostname: "localhost", - database: "wordual_test#{System.get_env("MIX_TEST_PARTITION")}", - pool: Ecto.Adapters.SQL.Sandbox, - pool_size: 10 - # We don't run a server during test. If one is required, # you can enable the server option below. config :wordual, WordualWeb.Endpoint, diff --git a/elixir_buildpack.config b/elixir_buildpack.config deleted file mode 100644 index 1e342d2..0000000 --- a/elixir_buildpack.config +++ /dev/null @@ -1,2 +0,0 @@ -elixir_version=1.13.2 -erlang_version=24.2 diff --git a/fly.toml b/fly.toml new file mode 100644 index 0000000..2f9429b --- /dev/null +++ b/fly.toml @@ -0,0 +1,34 @@ +# fly.toml app configuration file generated for wordual on 2023-12-16T06:04:27-05:00 +# +# See https://fly.io/docs/reference/configuration/ for information about how to use this file. +# + +app = "wordual" +primary_region = "ord" +kill_signal = "SIGTERM" + +[build] + +# [deploy] +# release_command = "/app/bin/migrate" + +[env] + PHX_HOST = "wordual.fly.dev" + PORT = "8080" + +[http_service] + internal_port = 8080 + force_https = true + auto_stop_machines = true + auto_start_machines = true + min_machines_running = 0 + processes = ["app"] + [http_service.concurrency] + type = "connections" + hard_limit = 1000 + soft_limit = 1000 + +[[vm]] + cpu_kind = "shared" + cpus = 1 + memory_mb = 1024 diff --git a/lib/wordual/release.ex b/lib/wordual/release.ex new file mode 100644 index 0000000..ee15da6 --- /dev/null +++ b/lib/wordual/release.ex @@ -0,0 +1,28 @@ +defmodule Wordual.Release do + @moduledoc """ + Used for executing DB release tasks when run in production without Mix + installed. + """ + @app :wordual + + def migrate do + load_app() + + for repo <- repos() do + {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true)) + end + end + + def rollback(repo, version) do + load_app() + {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version)) + end + + defp repos do + Application.fetch_env!(@app, :ecto_repos) + end + + defp load_app do + Application.load(@app) + end +end diff --git a/phoenix_static_buildpack.config b/phoenix_static_buildpack.config deleted file mode 100644 index 16e8c73..0000000 --- a/phoenix_static_buildpack.config +++ /dev/null @@ -1 +0,0 @@ -node_version=17.4.0 diff --git a/rel/env.sh.eex b/rel/env.sh.eex new file mode 100755 index 0000000..2bdface --- /dev/null +++ b/rel/env.sh.eex @@ -0,0 +1,8 @@ +#!/bin/sh + +# configure node for distributed erlang with IPV6 support +export ERL_AFLAGS="-proto_dist inet6_tcp" +export ECTO_IPV6="true" +export DNS_CLUSTER_QUERY="${FLY_APP_NAME}.internal" +export RELEASE_DISTRIBUTION="name" +export RELEASE_NODE="${FLY_APP_NAME}-${FLY_IMAGE_REF##*-}@${FLY_PRIVATE_IP}" diff --git a/rel/overlays/bin/migrate b/rel/overlays/bin/migrate new file mode 100755 index 0000000..02561f6 --- /dev/null +++ b/rel/overlays/bin/migrate @@ -0,0 +1,3 @@ +#!/bin/sh +cd -P -- "$(dirname -- "$0")" +exec ./wordual eval Wordual.Release.migrate diff --git a/rel/overlays/bin/migrate.bat b/rel/overlays/bin/migrate.bat new file mode 100755 index 0000000..f4691c6 --- /dev/null +++ b/rel/overlays/bin/migrate.bat @@ -0,0 +1 @@ +call "%~dp0\wordual" eval Wordual.Release.migrate diff --git a/rel/overlays/bin/server b/rel/overlays/bin/server new file mode 100755 index 0000000..70d0812 --- /dev/null +++ b/rel/overlays/bin/server @@ -0,0 +1,3 @@ +#!/bin/sh +cd -P -- "$(dirname -- "$0")" +PHX_SERVER=true exec ./wordual start diff --git a/rel/overlays/bin/server.bat b/rel/overlays/bin/server.bat new file mode 100755 index 0000000..745b6de --- /dev/null +++ b/rel/overlays/bin/server.bat @@ -0,0 +1,2 @@ +set PHX_SERVER=true +call "%~dp0\wordual" start