feat: execute service as distributed erlang (#96)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
To create a cluster with distributed nodes, the following changes were made: * Use [`dns_cluster`][0] to execute distributed nodes * Add _script_ to execute distributed nodes locally Also, improve local execution by: * Use [`mix release`][1] to make easier [deploy `phoenix`][2] * Use [`compose watch`][3] to synchronize code from the host with the service Some minor improvements: * Ignore files and folders in git and docker * Remove boilerplate comments [0]: https://github.com/phoenixframework/dns_cluster [1]: https://hexdocs.pm/mix/Mix.Tasks.Release.html [2]: https://hexdocs.pm/phoenix/releases.html [3]: https://docs.docker.com/compose/how-tos/file-watch/ Co-authored-by: Joao P Dubas <joao.dubas@gmail.com> Reviewed-on: #96 Co-authored-by: Joao P Dubas <joao.dubas+gitea@gmail.com> Co-committed-by: Joao P Dubas <joao.dubas+gitea@gmail.com>
This commit is contained in:
parent
0a4e262b91
commit
9be7566cbb
33
.dockerignore
Normal file
33
.dockerignore
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
.dockerignore
|
||||||
|
docker-compose.yml
|
||||||
|
docker-compose.*.yml
|
||||||
|
|
||||||
|
# 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
|
||||||
|
/.elixir-tools/
|
||||||
|
|
||||||
|
# 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/plts/
|
||||||
|
/priv/static/assets/
|
||||||
|
/priv/static/cache_manifest.json
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,4 +1,6 @@
|
|||||||
# paths
|
# paths
|
||||||
|
/.elixir_ls/
|
||||||
|
/.elixir-tools/
|
||||||
/_build/
|
/_build/
|
||||||
/cover/
|
/cover/
|
||||||
/report/
|
/report/
|
||||||
@ -13,5 +15,5 @@ erl_crash.dump
|
|||||||
*.ez
|
*.ez
|
||||||
wabanex-*.tar
|
wabanex-*.tar
|
||||||
docker-compose.*.yml
|
docker-compose.*.yml
|
||||||
priv/docker/pgcli/history
|
/priv/docker/pgcli/history
|
||||||
priv/docker/pgcli/log
|
/priv/docker/pgcli/log
|
||||||
|
72
Dockerfile
72
Dockerfile
@ -1,10 +1,70 @@
|
|||||||
FROM hexpm/elixir:1.17.2-erlang-27.0.1-debian-bookworm-20240701-slim AS builder
|
ARG ELIXIR_VERSION=1.17.3
|
||||||
|
ARG OTP_VERSION=27.1
|
||||||
|
ARG DEBIAN_VERSION=bookworm-20240904-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
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get -y install git make
|
&& apt-get -y install \
|
||||||
|
build-essential \
|
||||||
|
git \
|
||||||
|
make \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/ap/lists/*_*
|
||||||
WORKDIR /opt/app
|
WORKDIR /opt/app
|
||||||
|
# install hex + rebar
|
||||||
|
RUN mix do local.hex --force, local.rebar --force
|
||||||
|
# set build ENV
|
||||||
|
ARG BUILD_MIX_ENV=prod
|
||||||
|
ENV MIX_ENV=${BUILD_MIX_ENV}
|
||||||
|
# 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/${BUILD_MIX_ENV}.exs config/
|
||||||
|
RUN mix deps.compile
|
||||||
|
COPY priv priv
|
||||||
|
COPY lib lib
|
||||||
|
# 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
|
||||||
COPY ./mix.exs ./
|
COPY ./mix.exs ./
|
||||||
COPY ./mix.lock ./
|
EXPOSE 4000
|
||||||
RUN mix do local.hex --force, local.rebar --force \
|
ENTRYPOINT ["./priv/docker/service/docker-entrypoint.sh"]
|
||||||
&& mix do deps.get, deps.compile
|
CMD ["sample-cookie"]
|
||||||
|
|
||||||
|
# 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 \
|
||||||
|
ca-certificates \
|
||||||
|
libncurses5 \
|
||||||
|
libstdc++6 \
|
||||||
|
locales \
|
||||||
|
openssl \
|
||||||
|
tini \
|
||||||
|
&& 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 /opt/app
|
||||||
|
RUN chown nobody /opt/app
|
||||||
|
# set runner ENV
|
||||||
|
ARG BUILD_MIX_ENV=prod
|
||||||
|
ENV MIX_ENV=${BUILD_MIX_ENV}
|
||||||
|
# Only copy the final release from the build stage
|
||||||
|
COPY --from=builder --chown=nobody:root /app/_build/${BUILD_MIX_ENV}/rel/wabanex ./
|
||||||
|
USER nobody
|
||||||
|
EXPOSE 4000
|
||||||
|
ENTRYPOINT ["tini", "--"]
|
||||||
|
CMD ["/app/bin/server"]
|
||||||
|
18
Makefile
18
Makefile
@ -32,21 +32,17 @@ test: ## run tests
|
|||||||
compose_up: ## start containers for this service
|
compose_up: ## start containers for this service
|
||||||
@$(COMPOSE) up -d
|
@$(COMPOSE) up -d
|
||||||
|
|
||||||
.PHONY: compose_deps_upgrade
|
.PHONY: compose_watch
|
||||||
compose_deps_upgrade: ## install/upgrade deps
|
compose_watch: ## start containers for this service watching for updates in filesystem
|
||||||
@$(COMPOSE) run --entrypoint mix app do deps.get, deps.compile, compile
|
@$(COMPOSE) up -w
|
||||||
|
|
||||||
.PHONY: compose_test
|
|
||||||
compose_test: ## run tests in containers
|
|
||||||
@$(COMPOSE) run -e MIX_ENV=test --entrypoint make app test
|
|
||||||
|
|
||||||
.PHONY: compose_database_create
|
.PHONY: compose_database_create
|
||||||
compose_database_create:
|
compose_database_create:
|
||||||
@$(COMPOSE) --profile setup run db_setup
|
@$(COMPOSE) run --rm --entrypoint mix app ecto.create
|
||||||
|
|
||||||
.PHONY: compose_database_migrate
|
.PHONY: compose_database_migrate
|
||||||
compose_database_migrate: ## apply migrations to our database
|
compose_database_migrate: ## apply migrations to our database
|
||||||
@$(COMPOSE) --profile migrate run db_migrate
|
@$(COMPOSE) run --rm --entrypoint mix app ecto.migrate
|
||||||
|
|
||||||
.PHONY: compose_database_setup
|
.PHONY: compose_database_setup
|
||||||
compose_database_setup: compose_database_create compose_database_migrate ## create and apply migrations
|
compose_database_setup: compose_database_create compose_database_migrate ## create and apply migrations
|
||||||
@ -55,6 +51,10 @@ compose_database_setup: compose_database_create compose_database_migrate ## cre
|
|||||||
compose_ps: ## status of containers
|
compose_ps: ## status of containers
|
||||||
@$(COMPOSE) ps
|
@$(COMPOSE) ps
|
||||||
|
|
||||||
|
.PHONY: compose_remote
|
||||||
|
compose_remote: ## connect to remote node
|
||||||
|
@$(COMPOSE) exec app ./priv/docker/service/docker-remote.sh
|
||||||
|
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
help:
|
help:
|
||||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
@ -1,10 +1,3 @@
|
|||||||
# This file is responsible for configuring your application
|
|
||||||
# and its dependencies with the aid of the Mix.Config module.
|
|
||||||
#
|
|
||||||
# This configuration file is loaded before any dependency and
|
|
||||||
# is restricted to this project.
|
|
||||||
|
|
||||||
# General application configuration
|
|
||||||
import Config
|
import Config
|
||||||
|
|
||||||
config :wabanex,
|
config :wabanex,
|
||||||
@ -21,7 +14,6 @@ config :wabanex, Wabanex.PromEx,
|
|||||||
grafana: :disabled,
|
grafana: :disabled,
|
||||||
metrics_server: :disabled
|
metrics_server: :disabled
|
||||||
|
|
||||||
# Configures the endpoint
|
|
||||||
config :wabanex, WabanexWeb.Endpoint,
|
config :wabanex, WabanexWeb.Endpoint,
|
||||||
url: [host: "localhost"],
|
url: [host: "localhost"],
|
||||||
secret_key_base: "wkyuhU+mCGwXUSBYVKZSRGoFmDYCbOFzdokbVmBBI9JgCWOqGPfuA/3JI5/b4Wdl",
|
secret_key_base: "wkyuhU+mCGwXUSBYVKZSRGoFmDYCbOFzdokbVmBBI9JgCWOqGPfuA/3JI5/b4Wdl",
|
||||||
@ -29,14 +21,10 @@ config :wabanex, WabanexWeb.Endpoint,
|
|||||||
pubsub_server: Wabanex.PubSub,
|
pubsub_server: Wabanex.PubSub,
|
||||||
live_view: [signing_salt: "SXtw7DzV"]
|
live_view: [signing_salt: "SXtw7DzV"]
|
||||||
|
|
||||||
# Configures Elixir's Logger
|
|
||||||
config :logger, :console,
|
config :logger, :console,
|
||||||
format: "$time $metadata[$level] $message\n",
|
format: "$time $metadata[$level] $message\n",
|
||||||
metadata: [:request_id]
|
metadata: [:request_id]
|
||||||
|
|
||||||
# Use Jason for JSON parsing in Phoenix
|
|
||||||
config :phoenix, :json_library, Jason
|
config :phoenix, :json_library, Jason
|
||||||
|
|
||||||
# Import environment specific config. This must remain at the bottom
|
|
||||||
# of this file so it overrides the configuration defined above.
|
|
||||||
import_config "#{config_env()}.exs"
|
import_config "#{config_env()}.exs"
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import Config
|
import Config
|
||||||
|
|
||||||
# Configure your database
|
config :wabanex,
|
||||||
|
dns_cluster_query: :ignore,
|
||||||
|
dns_cluster_resolver: Wabanex.DevDNSClusterResolver
|
||||||
|
|
||||||
config :wabanex, Wabanex.Repo,
|
config :wabanex, Wabanex.Repo,
|
||||||
database: "wabanex_dev",
|
database: "wabanex_dev",
|
||||||
show_sensitive_data_on_connection_error: true,
|
show_sensitive_data_on_connection_error: true,
|
||||||
pool_size: 10
|
pool_size: 10
|
||||||
|
|
||||||
# For development, we disable any cache and enable
|
|
||||||
# debugging and code reloading.
|
|
||||||
#
|
|
||||||
# The watchers configuration can be used to run external
|
|
||||||
# watchers to your application. For example, we use it
|
|
||||||
# with webpack to recompile .js and .css sources.
|
|
||||||
config :wabanex, WabanexWeb.Endpoint,
|
config :wabanex, WabanexWeb.Endpoint,
|
||||||
http: [port: 4000],
|
http: [port: 4000],
|
||||||
debug_errors: true,
|
debug_errors: true,
|
||||||
@ -19,36 +16,8 @@ config :wabanex, WabanexWeb.Endpoint,
|
|||||||
check_origin: false,
|
check_origin: false,
|
||||||
watchers: []
|
watchers: []
|
||||||
|
|
||||||
# ## SSL Support
|
|
||||||
#
|
|
||||||
# In order to use HTTPS in development, a self-signed
|
|
||||||
# certificate can be generated by running the following
|
|
||||||
# Mix task:
|
|
||||||
#
|
|
||||||
# mix phx.gen.cert
|
|
||||||
#
|
|
||||||
# Note that this task requires Erlang/OTP 20 or later.
|
|
||||||
# Run `mix help phx.gen.cert` for more information.
|
|
||||||
#
|
|
||||||
# The `http:` config above can be replaced with:
|
|
||||||
#
|
|
||||||
# https: [
|
|
||||||
# port: 4001,
|
|
||||||
# cipher_suite: :strong,
|
|
||||||
# keyfile: "priv/cert/selfsigned_key.pem",
|
|
||||||
# certfile: "priv/cert/selfsigned.pem"
|
|
||||||
# ],
|
|
||||||
#
|
|
||||||
# If desired, both `http:` and `https:` keys can be
|
|
||||||
# configured to run both http and https servers on
|
|
||||||
# different ports.
|
|
||||||
|
|
||||||
# Do not include metadata nor timestamps in development logs
|
|
||||||
config :logger, :console, format: "[$level] $message\n"
|
config :logger, :console, format: "[$level] $message\n"
|
||||||
|
|
||||||
# Set a higher stacktrace during development. Avoid configuring such
|
|
||||||
# in production as building large stacktraces may be expensive.
|
|
||||||
config :phoenix, :stacktrace_depth, 20
|
config :phoenix, :stacktrace_depth, 20
|
||||||
|
|
||||||
# Initialize plugs at runtime for faster development compilation
|
|
||||||
config :phoenix, :plug_init_mode, :runtime
|
config :phoenix, :plug_init_mode, :runtime
|
||||||
|
@ -1,55 +1,7 @@
|
|||||||
import Config
|
import Config
|
||||||
|
|
||||||
# For production, don't forget to configure the url host
|
|
||||||
# to something meaningful, Phoenix uses this information
|
|
||||||
# when generating URLs.
|
|
||||||
#
|
|
||||||
# Note we also include the path to a cache manifest
|
|
||||||
# containing the digested version of static files. This
|
|
||||||
# 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 :wabanex, WabanexWeb.Endpoint,
|
config :wabanex, WabanexWeb.Endpoint,
|
||||||
url: [host: "example.com", port: 80],
|
url: [host: "example.com", port: 80],
|
||||||
cache_static_manifest: "priv/static/cache_manifest.json"
|
cache_static_manifest: "priv/static/cache_manifest.json"
|
||||||
|
|
||||||
# Do not print debug messages in production
|
|
||||||
config :logger, level: :info
|
config :logger, level: :info
|
||||||
|
|
||||||
# ## SSL Support
|
|
||||||
#
|
|
||||||
# To get SSL working, you will need to add the `https` key
|
|
||||||
# to the previous section and set your `:url` port to 443:
|
|
||||||
#
|
|
||||||
# config :wabanex, WabanexWeb.Endpoint,
|
|
||||||
# ...
|
|
||||||
# url: [host: "example.com", port: 443],
|
|
||||||
# https: [
|
|
||||||
# port: 443,
|
|
||||||
# cipher_suite: :strong,
|
|
||||||
# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
|
|
||||||
# certfile: System.get_env("SOME_APP_SSL_CERT_PATH"),
|
|
||||||
# transport_options: [socket_opts: [:inet6]]
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
# The `cipher_suite` is set to `:strong` to support only the
|
|
||||||
# latest and more secure SSL ciphers. This means old browsers
|
|
||||||
# and clients may not be supported. You can set it to
|
|
||||||
# `:compatible` for wider support.
|
|
||||||
#
|
|
||||||
# `:keyfile` and `:certfile` expect an absolute path to the key
|
|
||||||
# and cert in disk or a relative path inside priv, for example
|
|
||||||
# "priv/ssl/server.key". For all supported SSL configuration
|
|
||||||
# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1
|
|
||||||
#
|
|
||||||
# We also recommend setting `force_ssl` in your endpoint, ensuring
|
|
||||||
# no data is ever sent via http, always redirecting to https:
|
|
||||||
#
|
|
||||||
# config :wabanex, WabanexWeb.Endpoint,
|
|
||||||
# force_ssl: [hsts: true]
|
|
||||||
#
|
|
||||||
# Check `Plug.SSL` for all available options in `force_ssl`.
|
|
||||||
|
|
||||||
# Finally import the config/prod.secret.exs which loads secrets
|
|
||||||
# and configuration from environment variables.
|
|
||||||
import_config "prod.secret.exs"
|
|
||||||
|
@ -1,5 +1,35 @@
|
|||||||
import Config
|
import Config
|
||||||
|
|
||||||
|
# [warn] Conditional IPv6 support missing from runtime configuration.
|
||||||
|
#
|
||||||
|
# Add the following to your config/runtime.exs:
|
||||||
|
#
|
||||||
|
# maybe_ipv6 = if System.get_env("ECTO_IPV6") in ~w(true 1), do: [:inet6], else: []
|
||||||
|
#
|
||||||
|
# config :wabanex, Wabanex.Repo,
|
||||||
|
# ...,
|
||||||
|
# socket_options: maybe_ipv6
|
||||||
|
#
|
||||||
|
# [warn] Conditional server startup is missing from runtime configuration.
|
||||||
|
#
|
||||||
|
# Add the following to the top of your config/runtime.exs:
|
||||||
|
#
|
||||||
|
# if System.get_env("PHX_SERVER") do
|
||||||
|
# config :wabanex, WabanexWeb.Endpoint, server: true
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# [warn] Environment based URL export is missing from runtime configuration.
|
||||||
|
#
|
||||||
|
# Add the following to your config/runtime.exs:
|
||||||
|
#
|
||||||
|
# host = System.get_env("PHX_HOST") || "example.com"
|
||||||
|
#
|
||||||
|
# config :wabanex, WabanexWeb.Endpoint,
|
||||||
|
# ...,
|
||||||
|
# url: [host: host, port: 443]
|
||||||
|
|
||||||
|
config :wabanex, dns_cluster_query: System.get_env("DNS_CLUSTER_QUERY") || :ignore
|
||||||
|
|
||||||
config :wabanex, Wabanex.Repo,
|
config :wabanex, Wabanex.Repo,
|
||||||
username: System.get_env("POSTGRES_USER") || "postgres",
|
username: System.get_env("POSTGRES_USER") || "postgres",
|
||||||
password: System.get_env("POSTGRES_PASS") || "postgres",
|
password: System.get_env("POSTGRES_PASS") || "postgres",
|
||||||
|
@ -1,21 +1,13 @@
|
|||||||
import Config
|
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 :wabanex, Wabanex.Repo,
|
config :wabanex, Wabanex.Repo,
|
||||||
database: "wabanex_test#{System.get_env("MIX_TEST_PARTITION")}",
|
database: "wabanex_test#{System.get_env("MIX_TEST_PARTITION")}",
|
||||||
pool: Ecto.Adapters.SQL.Sandbox
|
pool: Ecto.Adapters.SQL.Sandbox
|
||||||
|
|
||||||
# We don't run a server during test. If one is required,
|
|
||||||
# you can enable the server option below.
|
|
||||||
config :wabanex, WabanexWeb.Endpoint,
|
config :wabanex, WabanexWeb.Endpoint,
|
||||||
http: [port: 4002],
|
http: [port: 4002],
|
||||||
server: false
|
server: false
|
||||||
|
|
||||||
# Print only warnings and errors during test
|
|
||||||
config :logger, level: :warning
|
config :logger, level: :warning
|
||||||
|
|
||||||
config :junit_formatter,
|
config :junit_formatter,
|
||||||
|
@ -7,59 +7,52 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: &db_user postgres
|
POSTGRES_USER: &db_user postgres
|
||||||
POSTGRES_PASSWORD: &db_pass postgres
|
POSTGRES_PASSWORD: &db_pass postgres
|
||||||
POSTGRES_DB: &db_name postgres
|
POSTGRES_DB: postgres
|
||||||
volumes:
|
volumes:
|
||||||
- './priv/docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql'
|
- './priv/docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql'
|
||||||
- 'db_data:/var/lib/postgresql/data'
|
- 'db_data:/var/lib/postgresql/data'
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
app:
|
app:
|
||||||
image: &app_image 'joaodubas/ex_trainer:${EX_TRAINER_TAG:-dev}'
|
image: 'joaodubas/ex_trainer:${EX_TRAINER_TAG:-dev}'
|
||||||
build:
|
build:
|
||||||
target: builder
|
target: builder
|
||||||
context: .
|
context: .
|
||||||
hostname: app
|
args:
|
||||||
|
BUILD_MIX_ENV: dev
|
||||||
|
hostname: &app_host ex_trainer
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
init: true
|
init: true
|
||||||
environment: &app_environment
|
develop:
|
||||||
|
watch:
|
||||||
|
- path: ./
|
||||||
|
ignore:
|
||||||
|
- ./build/
|
||||||
|
- ./deps/
|
||||||
|
target: /opt/app
|
||||||
|
action: sync
|
||||||
|
- path: ./config/
|
||||||
|
target: /opt/app
|
||||||
|
action: sync+restart
|
||||||
|
- path: ./lib/wabanex/application.ex
|
||||||
|
target: /opt/app
|
||||||
|
action: sync+restart
|
||||||
|
- path: ./mix.exs
|
||||||
|
target: /opt/app
|
||||||
|
action: sync+restart
|
||||||
|
- path: ./mix.lock
|
||||||
|
action: rebuild
|
||||||
|
environment:
|
||||||
|
DNS_CLUSTER_QUERY: *app_host
|
||||||
POSTGRES_HOST: *db_host
|
POSTGRES_HOST: *db_host
|
||||||
POSTGRES_USER: *db_user
|
POSTGRES_USER: *db_user
|
||||||
POSTGRES_PASS: *db_pass
|
POSTGRES_PASS: *db_pass
|
||||||
POSTGRES_NAME: wabanex_dev
|
POSTGRES_NAME: wabanex_dev
|
||||||
volumes: &app_volumes
|
|
||||||
- '.:/opt/app'
|
|
||||||
- 'app_build:/opt/app/_build'
|
|
||||||
- 'app_deps:/opt/app/deps'
|
|
||||||
working_dir: /opt/app
|
working_dir: /opt/app
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
entrypoint: sleep
|
scale: 3
|
||||||
command: infinity
|
entrypoint: ./priv/docker/service/docker-entrypoint.sh
|
||||||
db_setup:
|
command: local-cookie
|
||||||
image: *app_image
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
profiles:
|
|
||||||
- setup
|
|
||||||
environment: *app_environment
|
|
||||||
volumes: *app_volumes
|
|
||||||
restart: 'no'
|
|
||||||
command: |
|
|
||||||
mix ecto.setup \
|
|
||||||
&& MIX_ENV=test mix ecto.setup
|
|
||||||
db_migrate:
|
|
||||||
image: *app_image
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
profiles:
|
|
||||||
- migrate
|
|
||||||
environment: *app_environment
|
|
||||||
volumes: *app_volumes
|
|
||||||
restart: 'no'
|
|
||||||
command: |
|
|
||||||
mix ecto.migrate \
|
|
||||||
&& MIX_ENV=test mix.ecto.migrate
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
db_data: {}
|
db_data: {}
|
||||||
app_build: {}
|
|
||||||
app_deps: {}
|
|
||||||
|
@ -1,34 +1,25 @@
|
|||||||
defmodule Wabanex.Application do
|
defmodule Wabanex.Application do
|
||||||
# See https://hexdocs.pm/elixir/Application.html
|
|
||||||
# for more information on OTP Applications
|
|
||||||
@moduledoc false
|
@moduledoc false
|
||||||
|
|
||||||
use Application
|
use Application
|
||||||
|
|
||||||
def start(_type, _args) do
|
def start(_type, _args) do
|
||||||
children = [
|
children = [
|
||||||
# Start the PromEx supervisor
|
|
||||||
Wabanex.PromEx,
|
Wabanex.PromEx,
|
||||||
# Start the Ecto repository
|
|
||||||
Wabanex.Repo,
|
Wabanex.Repo,
|
||||||
# Start the Telemetry supervisor
|
|
||||||
WabanexWeb.Telemetry,
|
WabanexWeb.Telemetry,
|
||||||
# Start the PubSub system
|
|
||||||
{Phoenix.PubSub, name: Wabanex.PubSub},
|
{Phoenix.PubSub, name: Wabanex.PubSub},
|
||||||
# Start the Endpoint (http/https)
|
{DNSCluster,
|
||||||
|
query: Application.get_env(:wabanex, :dns_cluster_query) || :ignore,
|
||||||
|
log: :info,
|
||||||
|
resolver: Application.get_env(:wabanex, :dns_cluster_resolver) || DNSCluster.Resolver},
|
||||||
WabanexWeb.Endpoint
|
WabanexWeb.Endpoint
|
||||||
# Start a worker by calling: Wabanex.Worker.start_link(arg)
|
|
||||||
# {Wabanex.Worker, arg}
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
|
||||||
# for other strategies and supported options
|
|
||||||
opts = [strategy: :one_for_one, name: Wabanex.Supervisor]
|
opts = [strategy: :one_for_one, name: Wabanex.Supervisor]
|
||||||
Supervisor.start_link(children, opts)
|
Supervisor.start_link(children, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Tell Phoenix to update the endpoint configuration
|
|
||||||
# whenever the application is updated.
|
|
||||||
def config_change(changed, _new, removed) do
|
def config_change(changed, _new, removed) do
|
||||||
WabanexWeb.Endpoint.config_change(changed, removed)
|
WabanexWeb.Endpoint.config_change(changed, removed)
|
||||||
:ok
|
:ok
|
||||||
|
26
lib/wabanex/dev_dns_cluster_resolver.ex
Normal file
26
lib/wabanex/dev_dns_cluster_resolver.ex
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
defmodule Wabanex.DevDNSClusterResolver do
|
||||||
|
@moduledoc """
|
||||||
|
Local DNS resolver for cluster query.
|
||||||
|
"""
|
||||||
|
require Record
|
||||||
|
|
||||||
|
Record.defrecord(:hostent, Record.extract(:hostent, from_lib: "kernel/include/inet.hrl"))
|
||||||
|
|
||||||
|
def basename(node_name) when is_atom(node_name) do
|
||||||
|
[basename, _] = node_name |> to_string() |> String.split("@")
|
||||||
|
basename
|
||||||
|
end
|
||||||
|
|
||||||
|
def connect_node(node_name) when is_atom(node_name) do
|
||||||
|
Node.connect(node_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_nodes, do: Node.list(:visible)
|
||||||
|
|
||||||
|
def lookup(query, type) when is_binary(query) and type in [:a, :aaaa] do
|
||||||
|
case :inet_res.getbyname(~c"#{query}", type) do
|
||||||
|
{:ok, hostent(h_addr_list: addr_list)} -> addr_list
|
||||||
|
{:error, _} -> []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
28
lib/wabanex/release.ex
Normal file
28
lib/wabanex/release.ex
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
defmodule Wabanex.Release do
|
||||||
|
@moduledoc """
|
||||||
|
Used for executing DB release tasks when run in production without Mix
|
||||||
|
installed.
|
||||||
|
"""
|
||||||
|
@app :wabanex
|
||||||
|
|
||||||
|
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
|
1
mix.exs
1
mix.exs
@ -36,6 +36,7 @@ defmodule Wabanex.MixProject do
|
|||||||
{:credo, "~> 1.7.0", only: [:dev, :test], runtime: false},
|
{:credo, "~> 1.7.0", only: [:dev, :test], runtime: false},
|
||||||
{:crudry, "~> 2.4.0"},
|
{:crudry, "~> 2.4.0"},
|
||||||
{:dialyxir, "~> 1.4.0", only: [:dev, :test], runtime: false},
|
{:dialyxir, "~> 1.4.0", only: [:dev, :test], runtime: false},
|
||||||
|
{:dns_cluster, "~> 0.1.1"},
|
||||||
{:ecto_sql, "~> 3.12.0"},
|
{:ecto_sql, "~> 3.12.0"},
|
||||||
{:gettext, "~> 0.25.0"},
|
{:gettext, "~> 0.25.0"},
|
||||||
{:jason, "~> 1.4.0"},
|
{:jason, "~> 1.4.0"},
|
||||||
|
1
mix.lock
1
mix.lock
@ -11,6 +11,7 @@
|
|||||||
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
|
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
|
||||||
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
|
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
|
||||||
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
|
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
|
||||||
|
"dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"},
|
||||||
"ecto": {:hex, :ecto, "3.12.0", "9014a3ccac7f91e680b9d237d461ebe3d4e16d62ca8e355d540e2c6afdc28309", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "41e781a76e131093af8e1edf68b1319bf320878faff58da41ffa4b10fc6ff678"},
|
"ecto": {:hex, :ecto, "3.12.0", "9014a3ccac7f91e680b9d237d461ebe3d4e16d62ca8e355d540e2c6afdc28309", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "41e781a76e131093af8e1edf68b1319bf320878faff58da41ffa4b10fc6ff678"},
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"},
|
"ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"},
|
||||||
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
|
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
|
||||||
|
2
priv/docker/service/docker-entrypoint.sh
Executable file
2
priv/docker/service/docker-entrypoint.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
elixir --name ${HOSTNAME}@$(hostname -i | cut -d ' ' -f1) --cookie ${1} -S mix phx.server
|
2
priv/docker/service/docker-remote.sh
Executable file
2
priv/docker/service/docker-remote.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
iex --name ex_trainer_remote@127.0.0.1 --hidden --cookie local-cookie --remsh ${HOSTNAME}@$(hostname -i | cut -d ' ' -f1)
|
5
rel/overlays/bin/migrate
Executable file
5
rel/overlays/bin/migrate
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
cd -P -- "$(dirname -- "$0")"
|
||||||
|
exec ./wabanex eval Wabanex.Release.migrate
|
1
rel/overlays/bin/migrate.bat
Executable file
1
rel/overlays/bin/migrate.bat
Executable file
@ -0,0 +1 @@
|
|||||||
|
call "%~dp0\wabanex" eval Wabanex.Release.migrate
|
5
rel/overlays/bin/server
Executable file
5
rel/overlays/bin/server
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
cd -P -- "$(dirname -- "$0")"
|
||||||
|
PHX_SERVER=true exec ./wabanex start
|
2
rel/overlays/bin/server.bat
Executable file
2
rel/overlays/bin/server.bat
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
set PHX_SERVER=true
|
||||||
|
call "%~dp0\wabanex" start
|
Loading…
x
Reference in New Issue
Block a user