diff --git a/config/runtime.exs b/config/runtime.exs index 10474812..28143f6e 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -129,6 +129,20 @@ if config_env() == :prod do ]} ] + config :libcluster, + topologies: [ + k8s: [ + strategy: Cluster.Strategy.Kubernetes, + config: [ + mode: :ip, + kubernetes_ip_lookup_mode: :pods, + kubernetes_node_basename: "microwaveprop", + kubernetes_selector: "app=prop", + kubernetes_namespace: "prop" + ] + ] + ] + config :microwaveprop, :email_from, {"NTMS Propagation", "graham@w5isp.com"} config :microwaveprop, hrrr_base_url: System.get_env("HRRR_BASE_URL", "http://skippy.w5isp.com:8080") config :microwaveprop, srtm_tiles_dir: "/srtm" diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 762a2566..d4f2a660 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -30,6 +30,7 @@ spec: matchLabels: app: prop topologyKey: topology.kubernetes.io/physical-host + serviceAccountName: prop imagePullSecrets: - name: forgejo-registry securityContext: @@ -43,6 +44,10 @@ spec: image: git.mcintire.me/graham/prop:main-1775486348-7654146 # {"$imagepolicy": "flux-system:prop"} imagePullPolicy: IfNotPresent env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP - name: PHX_SERVER value: "true" - name: PHX_HOST diff --git a/k8s/kustomization.yaml b/k8s/kustomization.yaml index 52241e5c..19b3c375 100644 --- a/k8s/kustomization.yaml +++ b/k8s/kustomization.yaml @@ -3,5 +3,6 @@ kind: Kustomization resources: - namespace.yaml - secret.yaml + - rbac.yaml - deployment.yaml - service.yaml diff --git a/k8s/rbac.yaml b/k8s/rbac.yaml new file mode 100644 index 00000000..c802b7ad --- /dev/null +++ b/k8s/rbac.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prop + namespace: prop +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: prop-pod-reader + namespace: prop +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: prop-pod-reader + namespace: prop +subjects: + - kind: ServiceAccount + name: prop + namespace: prop +roleRef: + kind: Role + name: prop-pod-reader + apiGroup: rbac.authorization.k8s.io diff --git a/lib/microwaveprop/application.ex b/lib/microwaveprop/application.ex index 71708f97..c30aa7f6 100644 --- a/lib/microwaveprop/application.ex +++ b/lib/microwaveprop/application.ex @@ -7,9 +7,12 @@ defmodule Microwaveprop.Application do @impl true def start(_type, _args) do + topologies = Application.get_env(:libcluster, :topologies, []) + children = [ MicrowavepropWeb.Telemetry, Microwaveprop.Repo, + {Cluster.Supervisor, [topologies, [name: Microwaveprop.ClusterSupervisor]]}, {Phoenix.PubSub, name: Microwaveprop.PubSub}, {Oban, Application.fetch_env!(:microwaveprop, Oban)}, Microwaveprop.RepoListener, diff --git a/lib/microwaveprop_web/router.ex b/lib/microwaveprop_web/router.ex index 7bc12d41..7980ff32 100644 --- a/lib/microwaveprop_web/router.ex +++ b/lib/microwaveprop_web/router.ex @@ -47,19 +47,19 @@ defmodule MicrowavepropWeb.Router do # pipe_through :api # end - # Enable LiveDashboard and Swoosh mailbox preview in development - if Application.compile_env(:microwaveprop, :dev_routes) do - # If you want to use the LiveDashboard in production, you should put - # it behind authentication and allow only admins to access it. - # If your application does not have an admins-only section yet, - # you can use Plug.BasicAuth to set up some basic authentication - # as long as you are also using SSL (which you should anyway). - import Phoenix.LiveDashboard.Router + import Phoenix.LiveDashboard.Router + scope "/" do + pipe_through :browser + + live_dashboard "/dashboard", metrics: MicrowavepropWeb.Telemetry + end + + # Enable Swoosh mailbox preview in development + if Application.compile_env(:microwaveprop, :dev_routes) do scope "/dev" do pipe_through :browser - live_dashboard "/dashboard", metrics: MicrowavepropWeb.Telemetry forward "/mailbox", Plug.Swoosh.MailboxPreview end end diff --git a/mix.exs b/mix.exs index 0ce5a0a6..116564ae 100644 --- a/mix.exs +++ b/mix.exs @@ -70,7 +70,8 @@ defmodule Microwaveprop.MixProject do {:axon, "~> 0.7", only: [:dev, :test]}, {:exla, "~> 0.9", only: [:dev, :test]}, {:polaris, "~> 0.1", only: [:dev, :test]}, - {:tidewave, "~> 0.5", only: :dev} + {:tidewave, "~> 0.5", only: :dev}, + {:libcluster, "~> 3.4"} ] end diff --git a/mix.lock b/mix.lock index 4da4e355..d88a0e59 100644 --- a/mix.lock +++ b/mix.lock @@ -23,6 +23,7 @@ "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "lazy_html": {:hex, :lazy_html, "0.1.10", "ffe42a0b4e70859cf21a33e12a251e0c76c1dff76391609bd56702a0ef5bc429", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.9.0", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:fine, "~> 0.1.0", [hex: :fine, repo: "hexpm", optional: false]}], "hexpm", "50f67e5faa09d45a99c1ddf3fac004f051997877dc8974c5797bb5ccd8e27058"}, + "libcluster": {:hex, :libcluster, "3.5.0", "5ee4cfde4bdf32b2fef271e33ce3241e89509f4344f6c6a8d4069937484866ba", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.3", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ebf6561fcedd765a4cd43b4b8c04b1c87f4177b5fb3cbdfe40a780499d72f743"}, "live_stash": {:hex, :live_stash, "0.1.1", "d6a715708d0d281608de62a15ee8aca63427046daaa6333a235aa9e55f2cccb2", [:mix], [{:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:uniq, "~> 0.6", [hex: :uniq, repo: "hexpm", optional: false]}], "hexpm", "96341ebd35513f6e71b4e268ef4d413b1e21048a3d759cafe0cd8378ad8df908"}, "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, diff --git a/rel/env.sh.eex b/rel/env.sh.eex new file mode 100644 index 00000000..264ac5c4 --- /dev/null +++ b/rel/env.sh.eex @@ -0,0 +1,8 @@ +#!/bin/sh + +# Set the release node name from the pod IP for Erlang clustering +if [ -n "$POD_IP" ]; then + export RELEASE_DISTRIBUTION=name + export RELEASE_NODE=microwaveprop@${POD_IP} + export RELEASE_COOKIE="${ERLANG_COOKIE:-microwaveprop_cookie}" +fi