繁体   English   中英

如何使用 Phoenix Guides 中的示例在生产模式下运行 Elixir Phoenix Docker?

[英]How do I run Elixir Phoenix Docker in production mode using example from Phoenix Guides?

Elixir Phoenix Guides 上给出的示例 Dockerfile 似乎已经过时和损坏。 该示例可在此处找到: https://hexdocs.pm/phoenix/releases.html#containers

我创建了一个像这样的香草应用程序: mix phx.new hello_world

坏掉的Dockerfile:

# FROM elixir:1.9.0-alpine as build

# install build dependencies
RUN apk add --update git build-base nodejs yarn python

# prepare build dir
RUN mkdir /app
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 ./
COPY config config
RUN mix deps.get
RUN mix deps.compile

# build assets
COPY assets assets
RUN cd assets && npm install && npm run deploy
RUN mix phx.digest

# build project
COPY priv priv
COPY lib lib
RUN mix compile

# build release
COPY rel rel
RUN mix release

# prepare release image
FROM alpine:3.9 AS app
RUN apk add --update bash openssl

RUN mkdir /app
WORKDIR /app

COPY --from=build /app/_build/prod/rel/my_app ./
RUN chown -R nobody: /app
USER nobody

ENV HOME=/app

我正在尝试从 vanilla Phoenix 应用程序安装中运行 Dockerfile 并且遇到了许多问题,包括:

# FROM elixir:1.9.0-alpine as build
# Needs to be uncommented

RUN cd assets && npm install && npm run deploy
# npm install failed, had to add nodejs-npm

COPY rel rel
# errors here, there is no rel, should I remove?

More errors later because DATABASE_URL and SECRET_KEY_BASE are not declared

我不是专家,到目前为止 Dockerfile 现在看起来像这样:

FROM elixir:1.9.1-alpine as build

# install build dependencies
# modified: is this correct?
RUN apk add --update git build-base nodejs nodejs-npm yarn python

# prepare build dir
RUN mkdir /app
WORKDIR /app

# install hex + rebar
RUN mix local.hex --force && \
    mix local.rebar --force

# set build ENV
# modified: is this correct?
ENV DATABASE_URL=${DATABASE_URL} \
  SECRET_KEY_BASE=${SECRET_KEY_BASE} \
  MIX_ENV=prod

# install mix dependencies
COPY mix.exs mix.lock ./
COPY config config
RUN mix deps.get
RUN mix deps.compile

# build assets
COPY assets assets
RUN cd assets && npm install && npm run deploy

# build project
COPY priv priv
COPY lib lib
RUN mix compile

# build release
# removed next line, is that correct?
# COPY rel rel
RUN mix release

# prepare release image
FROM alpine:3.9 AS app
RUN apk add --update bash openssl

RUN mkdir /app
WORKDIR /app

COPY --from=build /app/_build/prod/rel/hello_world ./
RUN chown -R nobody: /app
USER nobody

ENV HOME=/app

ENTRYPOINT ["./bin/hello_world", "start"]

我尝试使用以下命令运行容器:

docker run -it -e DATABASE_URL='ecto://postgres:123456@localhost/hello_world_dev' -e SECRET_KEY_BASE='blargblargblarg' hello_world:latest

但我得到这个错误:

05:20:34.841 [error] GenServer #PID<0.1380.0> terminating
** (RuntimeError) connect raised KeyError exception: key :database not found. The exception details are hidden, as they may contain sensitive data such as database credentials. You may set :show_sensitive_data_on_connection_error to true when starting your connection if you wish to see all of the details
    (elixir) lib/keyword.ex:393: Keyword.fetch!/2
    (postgrex) lib/postgrex/protocol.ex:92: Postgrex.Protocol.connect/1
    (db_connection) lib/db_connection/connection.ex:69: DBConnection.Connection.connect/2
    (connection) lib/connection.ex:622: Connection.enter_connect/5
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil

..... repeat a lot

05:48:41.296 [info] Application hello_world exited: shutdown

这对我来说都是很新鲜的。 我已经轻松部署到 Heroku 但希望使用 Docker 部署到 AWS、GCP 等的快乐路径...

更新 1:这是config/prod.secret.exs文件。 我没有修改它。 请注意它正在加载环境变量:

# In this file, we load production configuration and secrets
# from environment variables. You can also hardcode secrets,
# although such is generally not recommended and you have to
# remember to add this file to your .gitignore.
use Mix.Config

database_url =
  System.get_env("DATABASE_URL") ||
    raise """
    environment variable DATABASE_URL is missing.
    For example: ecto://USER:PASS@HOST/DATABASE
    """

config :hello_world, HelloWorld.Repo,
  # ssl: true,
  url: database_url,
  pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")

secret_key_base =
  System.get_env("SECRET_KEY_BASE") ||
    raise """
    environment variable SECRET_KEY_BASE is missing.
    You can generate one by calling: mix phx.gen.secret
    """

config :hello_world, HelloWorldWeb.Endpoint,
  http: [:inet6, port: String.to_integer(System.get_env("PORT") || "4000")],
  secret_key_base: secret_key_base

# ## Using releases (Elixir v1.9+)
#
# If you are doing OTP releases, you need to instruct Phoenix
# to start each relevant endpoint:
#
#     config :hello_world, HelloWorldWeb.Endpoint, server: true
#
# Then you can assemble a release by calling `mix release`.
# See `mix help release` for more information.

更新 2:

我从config/prod.exs中删除import_config "config/prod.secret.exs"我将config/prod.secret.exs重命名为config/releases.exs并在我更改的文件中use Mix.Config import Config和未注释的config:hello_world, HelloWorldWeb.Endpoint, server: true

现在,当我尝试使用端口映射和 --network="host" 运行容器时

docker run -it -e DATABASE_URL='ecto://postgres:123456@localhost/hello_world_dev' -e SECRET_KEY_BASE='blargblargblarg' -p 5432:5432 --network="host" hello_world:latest

我明白了

23:21:48.635 [error] Postgrex.Protocol (#PID<0.2615.0>) failed to connect: ** (DBConnection.ConnectionError) tcp connect (localhost:5432): connection refused - :econnrefused
23:21:48.635 [error] Postgrex.Protocol (#PID<0.2619.0>) failed to connect: ** (DBConnection.ConnectionError) tcp connect (localhost:5432): connection refused - :econnrefused
23:21:48.639 [info] Running HelloWorldWeb.Endpoint with cowboy 2.6.3 at :::4000 (http)
23:21:48.640 [info] Access HelloWorldWeb.Endpoint at http://example.com
23:21:49.938 [error] Postgrex.Protocol (#PID<0.2623.0>) failed to connect: ** (DBConnection.ConnectionError) tcp connect (localhost:5432): connection refused - :econnrefused

更新 3:我尝试更改DATABASE_URL但没有成功。

# adding port
DATABASE_URL='ecto://postgres:123456@localhost:5432/hello_world_dev'

# changing hostname to 127.0.0.1
DATABASE_URL='ecto://postgres:123456@127.0.0.1/hello_world_dev'

# changing hostname to 127.0.0.1 and adding port
DATABASE_URL='ecto://postgres:123456@127.0.0.1:5432/hello_world_dev'

# changing hostname to 0.0.0.0
DATABASE_URL='ecto://postgres:123456@0.0.0.0/hello_world_dev'

# changing hostname to 0.0.0.0 and adding port
DATABASE_URL='ecto://postgres:123456@0.0.0.0:5432/hello_world_dev'

# changing ecto to postgresql
DATABASE_URL='postgresql://postgres:123456@localhost/hello_world_dev'

# changing ecto to postgresql and localhost to 127.0.0.1
DATABASE_URL='postgresql://postgres:123456@127.0.0.1/hello_world_dev'

# changing ecto to postgresql and localhost to 127.0.0.1 with port
DATABASE_URL='postgresql://postgres:123456@127.0.0.1:5432/hello_world_dev'

# changing ecto to postgresql and localhost to 0.0.0.0
DATABASE_URL='postgresql://postgres:123456@0.0.0.0/hello_world_dev'

# changing ecto to postgresql and localhost to 0.0.0.0 with port
DATABASE_URL='postgresql://postgres:123456@0.0.0.0:5432/hello_world_dev'

¯\_(ツ)_/¯

为生产就绪的构建和部署周期配置了一个很好的示例存储库 它包含一个 ansible 设置,它将维护 docker 映像,在 docker 映像中构建 phoenix 应用程序,并在您的生产服务器上执行自动版本化发布。

我建议您阅读博客文章指南

从 ENV 变量定义数据库 url

config :hello_world, HelloWorld.Repo,
  url: "${DATABASE_URL}"

然后将数据库pool_size与 pool_size 一起使用,并将其传递给容器

DATABASE_URL=ecto://postgres@db/hello_world?pool_size=10

ENV REPLACE_OS_VARS=true添加到您的Dockerfile (可能仅适用于 Distillery,否则用正确的形式替换"${DATABASE_URL}"在运行时获取 ENV 变量,而不是在编译阶段)。

以下是如何使用 Distillery 创建简单构建的示例:

FROM elixir:1.9.0-alpine

RUN mix local.hex --force && \
    mix local.rebar --force && \
    mix archive.install --force hex phx_new 1.4.8

RUN apk add --update nodejs nodejs-npm

ENV MIX_ENV=prod

WORKDIR /srv/app

COPY ./platform/ /srv/app/

# install dependencies (production only)
RUN mix local.rebar --force
RUN mix deps.get --only prod
RUN mix compile

# RUN npm install --global webpack
RUN cd assets && npm install && ./node_modules/webpack/bin/webpack.js --mode production
RUN mix phx.digest

RUN mix distillery.release

# alpine version should be the same as build
FROM alpine:3.9
RUN apk add --update bash
ENV REPLACE_OS_VARS=true
WORKDIR /srv/app
COPY --from=0  /srv/app/_build/prod/ .
CMD rel/platform/bin/platform migrate && rel/platform/bin/platform foreground

另外,请记住,由于您在本地运行postgres (与容器不在同一网络上),您需要将其纳入帐户并使用docker.for.mac.localhost作为postgres的主机名或--net=host docker runlocalhost作为postgres的主机。

看起来问题出现是因为您没有正确设置配置。

异常:键:找不到数据库

为了使用您使用环境变量注入的数据库,您需要显式获取它。 根据您组织配置的方式,您应该为您的 Repo 配置一个配置。 默认情况下,repo 的配置是:

config :yourserver_api, YourServer.Repo,
  username: "postgres",
  password: "postgres",
  database: "yourserver_api_prod",
  hostname: "localhost",
  pool_size: 10

如果您确定将注入例如数据库,那么您需要将其更改为:

database: System.get_env("DATABASE_URL") 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM