Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PR] Adding configuration to deploy to fly.io and upgrading to Phoenix 1.7 #111

Merged
merged 14 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -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
5 changes: 3 additions & 2 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[
import_deps: [:ecto, :phoenix],
inputs: ["*.{ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{ex,exs}"],
subdirectories: ["priv/*/migrations"]
subdirectories: ["priv/*/migrations"],
plugins: [Phoenix.LiveView.HTMLFormatter],
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
]
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: '1.14.2' # Define the elixir version [required]
otp-version: '24.3.4' # Define the OTP version [required]
elixir-version: '1.14.3' # Define the elixir version [required]
otp-version: '25.1.2' # Define the OTP version [required]
- name: Restore dependencies cache
uses: actions/cache@v2
with:
Expand Down
95 changes: 95 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# 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-20220801-slim - for the release image
# - https://pkgs.org/ - resource for finding needed packages
# - Ex: hexpm/elixir:1.14.1-erlang-25.1.1-debian-bullseye-20220801-slim
#
ARG ELIXIR_VERSION=1.14.1
ARG OTP_VERSION=25.1.1
ARG DEBIAN_VERSION=bullseye-20220801-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/${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/liveview_chat ./

USER nobody

CMD ["/app/bin/server"]

# Appended by flyctl
ENV ECTO_IPV6 true
ENV ERL_AFLAGS "-proto_dist inet6_tcp"
1 change: 0 additions & 1 deletion Procfile

This file was deleted.

10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
[![codecov test coverage](https://img.shields.io/codecov/c/github/dwyl/phoenix-liveview-chat-example/main.svg?style=flat-square)](https://codecov.io/github/dwyl/phoenix-liveview-chat-example?branch=main)
[![HitCount](https://hits.dwyl.com/dwyl/phoenix-liveview-chat-example.svg?style=flat-square&show=unique)](https://hits.dwyl.com/dwyl/phoenix-liveview-chat-example)

**Try it**: [**liveview-chat-example.herokuapp**](https://liveview-chat-example.herokuapp.com)

![liveview-chat-with-tailwind-css](https://user-images.githubusercontent.com/194400/174119023-bb83f5f4-867c-4bfa-a005-26b39c700137.gif)

</div>
Expand Down Expand Up @@ -932,7 +930,7 @@ and then pre-fill the `name` in the message form.
As per the
[instructions](https://github.com/dwyl/auth_plug#2-get-your-auth_api_key-)
first create a new **API Key** at
https://dwylauth.herokuapp.com
https://authdemo.fly.dev/
e.g:

![image](https://user-images.githubusercontent.com/194400/174044750-73dcb29a-b236-40d4-9a91-27144b675320.png)
Expand All @@ -941,7 +939,7 @@ Then create an `.env` file
and add your new created api key:

```.env
export AUTH_API_KEY=88SwQGzaZoJYXs6ihvwMy2dRVtm6KVeg4tSCjRKtwDvMUYUbi/88SwQDatWtSTMd2rKPnaZsAWFNpbf4vv2ZK7JW2nwuSypMeg/dwylauth.herokuapp.com
export AUTH_API_KEY=88SwQGzaZoJYXs6ihvwMy2dRVtm6KVeg4tSCjRKtwDvMUYUbi/88SwQDatWtSTMd2rKPnaZsAWFNpbf4vv2ZK7JW2nwuSypMeg/authdemo.fly.dev
```

> **Note**: for security reasons, this is not a valid API key.
Expand Down Expand Up @@ -1504,6 +1502,4 @@ Here are a few other repositories you might want to read:
Any questions or suggestions? Do not hesitate to
[open new issues](https://github.com/dwyl/phoenix-liveview-chat-example/issues)!

Thank you!

![wake-sleeping-heroku-app](https://liveview-chat-example.herokuapp.com/ping)
Thank you!
5 changes: 1 addition & 4 deletions config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import Config
# manifest is generated by the `mix phx.digest` task,
# which you should run after static files are built and
# before starting your production server.
config :liveview_chat, LiveviewChatWeb.Endpoint,
url: [scheme: "https", host: "liveview-chat-example.herokuapp.com", port: 443],
force_ssl: [rewrite_on: [:x_forwarded_proto]],
cache_static_manifest: "priv/static/cache_manifest.json"
config :liveview_chat, LiveviewChatWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"

# Do not print debug messages in production
config :logger, level: :info
Expand Down
14 changes: 12 additions & 2 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import Config
# and secrets from environment variables or elsewhere. Do not define
# any compile-time configuration in here, as it won't be applied.
# The block below contains prod specific runtime configuration.
if System.get_env("PHX_SERVER") do
config :liveview_chat, LiveviewChatWeb.Endpoint, server: true
end

if config_env() == :prod do
database_url =
System.get_env("DATABASE_URL") ||
Expand All @@ -14,11 +18,14 @@ if config_env() == :prod do
For example: ecto://USER:PASS@HOST/DATABASE
"""

maybe_ipv6 = if System.get_env("ECTO_IPV6"), do: [:inet6], else: []

config :liveview_chat, LiveviewChat.Repo,
ssl: true,
# ssl: true,
# socket_options: [:inet6],
url: database_url,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
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
Expand All @@ -32,7 +39,10 @@ if config_env() == :prod do
You can generate one by calling: mix phx.gen.secret
"""

host = System.get_env("PHX_HOST") || "example.com"

config :liveview_chat, LiveviewChatWeb.Endpoint,
url: [host: host, port: 443, scheme: "https"],
http: [
# Enable IPv6 and bind on all interfaces.
# Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access.
Expand Down
3 changes: 2 additions & 1 deletion coveralls.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"lib/liveview_chat/application.ex",
"lib/liveview_chat_web/views/error_helpers.ex",
"lib/liveview_chat_web/telemetry.ex",
"lib/liveview_chat_web/channels/user_socket.ex"
"lib/liveview_chat_web/channels/user_socket.ex",
"lib/liveview_chat/release.ex"
]
}
10 changes: 0 additions & 10 deletions elixir_buildpack.config

This file was deleted.

43 changes: 43 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# fly.toml file generated for liveview-chat-example on 2023-03-15T11:43:34Z

app = "liveview-chat-example"
kill_signal = "SIGTERM"
kill_timeout = 5
primary_region = "lhr"
processes = []

[deploy]
release_command = "/app/bin/migrate"

[env]
PHX_HOST = "liveview-chat-example.fly.dev"
PORT = "8080"

[experimental]
auto_rollback = true

[[services]]
http_checks = []
internal_port = 8080
processes = ["app"]
protocol = "tcp"
script_checks = []
[services.concurrency]
hard_limit = 1000
soft_limit = 1000
type = "connections"

[[services.ports]]
force_https = true
handlers = ["http"]
port = 80

[[services.ports]]
handlers = ["tls", "http"]
port = 443

[[services.tcp_checks]]
grace_period = "1s"
interval = "15s"
restart_limit = 0
timeout = "2s"
28 changes: 28 additions & 0 deletions lib/liveview_chat/release.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule LiveviewChat.Release do
@moduledoc """
Used for executing DB release tasks when run in production without Mix
installed.
"""
@app :liveview_chat

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
7 changes: 0 additions & 7 deletions lib/liveview_chat_web/controllers/ping_controller.ex

This file was deleted.

3 changes: 1 addition & 2 deletions lib/liveview_chat_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule LiveviewChatWeb.Router do
plug :protect_from_forgery
plug :put_secure_browser_headers
end

pipeline :authOptional, do: plug(AuthPlugOptional)

scope "/", LiveviewChatWeb do
Expand All @@ -18,6 +18,5 @@ defmodule LiveviewChatWeb.Router do
live "/", MessageLive
get "/login", AuthController, :login
get "/logout", AuthController, :logout
get "/ping", PingController, :ping
end
end
4 changes: 3 additions & 1 deletion lib/liveview_chat_web/templates/layout/root.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="csrf-token" content={csrf_token_value()}>
<%= live_title_tag assigns[:page_title] || "LiveviewChat", suffix: " · Phoenix Framework" %>
<.live_title suffix=" · Phoenix Framework">
<%= assigns[:page_title] || "LiveviewChat" %>
</.live_title>
<script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
<script src="https://cdn.tailwindcss.com"></script>
</head>
Expand Down
Loading