Dockerized Phoenix/Elixir 应用程序拒绝所有 HTTP/socket 请求

Dockerized Phoenix/Elixir App Rejects All HTTP/socket requests

我正在尝试按照本教程进行操作,以在 docker 中获得我的(在本地主机上运行)elixir/phoenix 应用程序 运行ning 容器,我 运行 陷入困境。

https://pspdfkit.com/blog/2018/how-to-run-your-phoenix-application-with-docker/

这是我的错误:

[info] JOIN "room:lobby" to AlbatrossWeb.RoomChannel
phoenix_1  |   Transport:  Phoenix.Transports.WebSocket (2.0.0)
phoenix_1  |   Serializer:  Phoenix.Transports.V2.WebSocketSerializer
phoenix_1  |   Parameters: %{}
phoenix_1  | inside room:lobby channel handler
phoenix_1  | [info] Replied room:lobby :ok
phoenix_1  | [error] Ranch protocol #PID<0.403.0> of listener AlbatrossWeb.Endpoint.HTTP (cowboy_protocol) terminated
phoenix_1  | ** (exit) exited in: Phoenix.Endpoint.CowboyWebSocket.resume()
phoenix_1  |     ** (EXIT) an exception was raised:
phoenix_1  |         ** (Protocol.UndefinedError) got FunctionClauseError with message "no function clause matching in Poison.Encoder.__protocol__/1" while retrieving Exception.message/1 for %Protocol.UndefinedError{description: "", protocol: Poison.Encoder, value: ["127", "127", "room:lobby", "phx_reply", %{response: %{}, status: :ok}]}
phoenix_1  |             (poison) lib/poison/encoder.ex:66: Poison.Encoder.impl_for!/1
phoenix_1  |             (poison) lib/poison/encoder.ex:69: Poison.Encoder.encode/2
phoenix_1  |             (poison) lib/poison.ex:41: Poison.encode!/2
phoenix_1  |             (phoenix) lib/phoenix/transports/v2/websocket_serializer.ex:22: Phoenix.Transports.V2.WebSocketSerializer.encode!/1
phoenix_1  |             (phoenix) lib/phoenix/transports/websocket.ex:197: Phoenix.Transports.WebSocket.encode_reply/2
phoenix_1  |             (phoenix) lib/phoenix/endpoint/cowboy_websocket.ex:77: Phoenix.Endpoint.CowboyWebSocket.websocket_handle/3
phoenix_1  |             (cowboy) /app/deps/cowboy/src/cowboy_websocket.erl:588: :cowboy_websocket.handler_call/7
phoenix_1  |             (phoenix) lib/phoenix/endpoint/cowboy_websocket.ex:49: Phoenix.Endpoint.CowboyWebSocket.resume/3
phoenix_1  |             (cowboy) /app/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
phoenix_1  | [info] JOIN "room:lobby" to AlbatrossWeb.RoomChannel
<....repeat forever....>

我不确定发生了什么。

我的房间大厅只是一个简单的套接字通道,定义 room_channel.ex 为:

###room_channel.ex###
defmodule AlbatrossWeb.RoomChannel do
  use Phoenix.Channel

  def join("room:lobby", _message, socket) do
    IO.puts "inside room:lobby channel handler"
    {:ok, socket}
  end

  def join("room:" <> _private_room_id, _params, _socket) do
    {:error, %{reason: "unauthorized"}}
  end

  def handle_in("updated_comments", %{"payload"=>payload}, socket) do
    IO.puts("inside updated_comments handle_in")
    broadcast! socket, "updated_comments", payload
    # ArticleController.retrieve(socket)
    {:noreply, socket}
  end
end
###room_channel.ex###

当我 运行 没有我的 docker 文件时,它 运行 没问题 - 我添加的是以下内容:


###run.sh###
docker-compose up --build
###run.sh###

###Dockerfile###
FROM elixir:latest

RUN apt-get update && \
  apt-get install -y postgresql-client

# Create app directory and copy the Elixir projects into it
RUN mkdir /app
COPY . /app
WORKDIR /app

# Install hex package manager
RUN mix local.hex --force

# Compile the project
RUN mix do compile

CMD ["/app/entrypoint.sh"]
###Dockerfile###

###docker-compose###
# Version of docker-compose
version: '3'

# Containers we are going to run
services:
  # Our Phoenix container
  phoenix:
    # The build parameters for this container.
    build:
      # Here we define that it should build from the current directory
      context: .
    environment:
      # Variables to connect to our Postgres server
      PGUSER: postgres
      PGPASSWORD: postgres
      PGDATABASE: db
      PGPORT: 5432
      # Hostname of our Postgres container
      PGHOST: db
    ports:
      # Mapping the port to make the Phoenix app accessible outside of the container
      - "4000:4000"
    depends_on:
      # The db container needs to be started before we start this container
      - db
  db:
    # We use the predefined Postgres image
    image: postgres:9.6
    environment:
      # Set user/password for Postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      # Set a path where Postgres should store the data
      PGDATA: /var/lib/postgresql/data/pgdata
    restart: always
    volumes:
      - pgdata:/var/lib/postgresql/data
# Define the volumes
volumes:
  pgdata:
###docker-compose###

###entrypoint.sh###
#!/bin/bash

while ! pg_isready -q -h $PGHOST -p $PGPORT -U $PGUSER
do
  echo "$(date) - waiting for database to start"
  sleep 2
done

# Create, migrate, and seed database if it doesn't exist.
if [[ -z `psql -Atqc "\list $PGDATABASE"` ]]; then
  echo "Database $PGDATABASE does not exist. Creating..."
  createdb -E UTF8 $PGDATABASE -l en_US.UTF-8 -T template0
  echo "1"
  mix do ecto.drop, ecto.create
  echo "2"
  mix phx.gen.schema Binarys binary postnum:integer leftchild:integer rightchild:integer downvotes:integer message:string parent:string upvotes:integer
  echo "3"
  mix phx.gen.schema Comments comment postnum:integer children:map downvotes:integer message:string parent:string upvotes:integer identifier:uuid
  echo "4"
  mix ecto.migrate
  echo "5"
  mix run priv/repo/seeds.exs
  echo "Database $PGDATABASE created."
fi

exec mix phx.server
###entrypoint.sh###

我还像这样更改了 dev.exs 文件中的配置:

###dev.exs###
config :albatross, Albatross.Repo,
  adapter: Ecto.Adapters.Postgres,
  username: "postgres",
  password: "postgres",
  hostname: "db",
  database: "db",
  # port: 5432,
  pool_size: 10
###dev.exs###

有趣的是,所有这些错误似乎都是在我的前端启动时产生的,但没有发出请求(除了连接到套接字)。如果我尝试发出 http 请求,我会得到:

phoenix_1  | [info] POST /addComment
phoenix_1  | inside addComment
phoenix_1  | [debug] Processing with AlbatrossWeb.PageController.addComment/2
phoenix_1  |   Parameters: %{"payload" => %{"message" => "sf", "parent" => "no_parent", "postnum" => 6, "requestType" => "post", "urlKEY" => "addComment"}}
phoenix_1  |   Pipelines: [:browser]
phoenix_1  | [error] Failure while translating Erlang's logger event
phoenix_1  | ** (Protocol.UndefinedError) got FunctionClauseError with message "no function clause matching in Plug.Exception.__protocol__/1" while retrieving Exception.message/1 for %Protocol.UndefinedError{description: "", protocol: Plug.Exception, value: %Protocol.UndefinedError{description: "", protocol: Plug.Exception, value: %Protocol.UndefinedError{description: "", protocol: Plug.Exception, value: %Protocol.UndefinedError{description: "", protocol: String.Chars, value: %Postgrex.Query{columns: nil, name: "", param_formats: nil, param_oids: nil, param_types: nil, ref: nil, result_formats: nil, result_oids: nil, result_types: nil, statement: ["INSERT INTO ", [34, "comment", 34], [], [32, 40, [[[[[[[[[[], [34, "children", 34], 44], [34, "downvotes", 34], 44], [34, "identifier", 34], 44], [34, "message", 34], 44], [34, "parent", 34], 44], [34, "postnum", 34], 44], [34, "upvotes", 34], 44], [34, "inserted_at", 34], 44], 34, "updated_at", 34], ") VALUES ", [], 40, [[[[[[[[[[], [36 | "1"], 44], [36 | "2"], 44], [36 | "3"], 44], [36 | "4"], 44], [36 | "5"], 44], [36 | "6"], 44], [36 | "7"], 44], [36 | "8"], 44], 36 | "9"], 41], [], " RETURNING ", [], 34, "id", 34], types: nil}}}}}
phoenix_1  |     (plug) lib/plug/exceptions.ex:4: Plug.Exception.impl_for!/1
phoenix_1  |     (plug) lib/plug/exceptions.ex:19: Plug.Exception.status/1
phoenix_1  |     (plug) lib/plug/adapters/translator.ex:79: Plug.Adapters.Translator.non_500_exception?/1
phoenix_1  |     (plug) lib/plug/adapters/translator.ex:49: Plug.Adapters.Translator.translate_ranch/5
phoenix_1  |     (logger) lib/logger/erlang_handler.ex:104: Logger.ErlangHandler.translate/6
phoenix_1  |     (logger) lib/logger/erlang_handler.ex:97: Logger.ErlangHandler.translate/5
phoenix_1  |     (logger) lib/logger/erlang_handler.ex:30: anonymous fn/3 in Logger.ErlangHandler.log/2
phoenix_1  |     (logger) lib/logger.ex:861: Logger.normalize_message/2
phoenix_1  |     (logger) lib/logger.ex:684: Logger.__do_log__/3
phoenix_1  |     (kernel) logger_backend.erl:51: :logger_backend.call_handlers/3
phoenix_1  |     (kernel) logger_backend.erl:38: :logger_backend.log_allowed/2
phoenix_1  |     (ranch) /app/deps/ranch/src/ranch_conns_sup.erl:167: :ranch_conns_sup.loop/4
phoenix_1  |     (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
phoenix_1  | 

所以你可以看到它看到了请求并且它似乎在操纵它。它就是不能 return 它。我的 Docker 和 docker-compose 文件中都暴露了我的端口,我真的看不出还有什么问题,因为当我 运行 它在外面时我让这个应用程序工作docker 个容器。

出了什么问题?

我认为问题出在您的 Dockerfile 上。

你没有暴露任何端口。

为了能够发布端口,您需要先公开 post。

尝试在您的 Dockerfile 中添加 EXPOSE 4000

没有足够的声誉来回复其他答案,但我想通知潜在的读者,EXPOSE 指令只是文档。发布之前不需要公开端口。

来自official docker documentation

The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.