【问题标题】:Webservice does not work after being packaged into a Docker imageWebservice打包成Docker镜像后不工作
【发布时间】:2019-03-15 01:21:51
【问题描述】:

我用 sinatra 用 ruby​​ 编写了一个简单的 web 服务。如果我运行ruby app.rb,它将在 localhost:4567 上运行。我写了一个 Dockerfile 来制作镜像并暴露 4567 端口。

但是,当我运行 docker 映像时,Web 服务会运行,但如果我尝试(使用 curl 和浏览器)连接到端口 4567,它会显示 Connection reset by peer

有人有什么建议吗?因为我不知道在这种情况下要检查什么。我尝试了一些模糊的东西,但仍然..

webservice 在 docker 外正常运行。

编辑 1:

我已将图片推送至eivor/ruby。如果你运行它并去浏览器检查它会说connection reset。是的,我在发布问题之前尝试了docker run -p 4567:4567 eivor/ruby

编辑 2:这是app.rb

require 'sinatra'
require 'referal' # this is the gem that calculate reward points to users
require 'json'
require 'byebug'

get '/' do
  'hello, world!'
end

# inside docker image, even get / returns connection reset by peer
# not to mention post data to it

post '/' do
  data = JSON.parse(request.body.read)
  input = []
  data.each do | key, value |
    input << value
  end
  invs, users = input.reduce([[],[]]) do | results, instruction |
    results = classify(instruction, results[0], results[1])
    results
  end
  res = export(users)
  # byebug
  puts res
end

post '/text' do
  @data = request.body.readlines
  #byebug
  @processed = @data.map{ |s| process(s) }
  @invs, @users = @processed.reduce([[],[]]) do | results, instruction |
    results = classify(instruction, results[0], results[1])
    results
  end
  @jsn = export(@users)
  puts @jsn
end

这里是 Dockerfile,我用 alpine 构建了一个轻量级的 ruby​​

FROM alpine:3.5
ENV BUILD_PACKAGES bash curl-dev ruby-dev build-base git libstdc++ tzdata ca-certificates
ENV RUBY_PACKAGES ruby>2.3 ruby-irb ruby-rake ruby-io-console ruby-bigdecimal ruby-json

RUN apk update && apk upgrade
RUN apk add $BUILD_PACKAGES && apk add $RUBY_PACKAGES
RUN apk add ruby-bundler>1.17

RUN echo 'gem: --no-document' > /etc/gemrc && rm -rf /var/cach/apk/*

RUN gem install bundler

RUN mkdir /usr/app
WORKDIR /usr/app
RUN git init

COPY . /usr/app

RUN bundle install

RUN bundle exec rake install

EXPOSE 4567

CMD ["ruby", "./app.rb"]

如果我使用命令 ruby app.rbbundle exec rerun app.rb 在 docker 外部运行,它可以正常工作。但是使用 docker 镜像,它没有。我运行命令:

docker run -p 4567:4567 eivor/ruby

服务器运行,

[2019-03-14 16:59:59] INFO  WEBrick 1.3.1
[2019-03-14 16:59:59] INFO  ruby 2.3.8 (2018-10-18) [x86_64-linux-musl]
== Sinatra (v2.0.5) has taken the stage on 4567 for development with backup from WEBrick
[2019-03-14 16:59:59] INFO  WEBrick::HTTPServer#start: pid=1 port=4567

但是当我尝试使用浏览器或 curl 访问时,它显示connection reset by peer。如果我尝试使用 curl 发布,数据实际上已发送但它没有响应,而是挂断了我。

curl -v localhost:4567 --data-binary @test/input
* Rebuilt URL to: localhost:4567/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 4567 (#0)
> POST / HTTP/1.1
> Host: localhost:4567
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Length: 369
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 369 out of 369 bytes
* Recv failure: Connection reset by peer
* stopped the pause stream!
* Closing connection 0
curl: (56) Recv failure: Connection reset by peer

【问题讨论】:

  • 请查看如何提供MVCE。在这种情况下,Dockerfile 的副本和用于启动容器的命令行参数会很有帮助。
  • 对不起,我已经推送了docker镜像并给出了我的命令行。
  • 请在此处发布您的Dockerfileapp.rb,以便我们更好地为您提供帮助。
  • 你好,我放了app.rbDockerfile,服务器日志和curl日志。当我使用 curl 发布数据时,数据实际上已发送,但服务器挂断了我。

标签: ruby docker web


【解决方案1】:

发生此问题是因为 Sinatra 默认情况下(开发环境)在 127.0.0.1 上侦听,这在外部连接到容器的情况下不起作用

:bind - 服务器主机名或 IP 地址

字符串,指定启用 :run 设置时要侦听的接口的主机名或 IP 地址。开发环境中的默认值是'localhost',这意味着服务器只能从本地机器获得。在其他环境中,默认值为“0.0.0.0”,这会导致服务器侦听所有可用接口。

所以如果要继续在开发模式下运行,则需要将其改为0.0.0.0,例如:

docker run -p 4567:4567 --name stack eivor/ruby bash -c 'ruby ./app.rb -o 0.0.0.0'

在 Dockerfile 中可以用作:

CMD ["ruby", "./app.rb", "-o", "0.0.0.0"]

或者您可以在脚本中使用以下内容:

set :bind, '0.0.0.0'

然后从容器外部可以得到结果:

curl -v localhost:4567
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 4567 (#0)
> GET / HTTP/1.1
> Host: localhost:4567
> User-Agent: curl/7.64.0
> Accept: */*
> 
< HTTP/1.1 200 OK 
< Content-Type: text/html;charset=utf-8
< Content-Length: 13
< X-Xss-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< Server: WEBrick/1.3.1 (Ruby/2.3.8/2018-10-18)
< Date: Thu, 14 Mar 2019 17:17:20 GMT
< Connection: Keep-Alive
< 
* Connection #0 to host localhost left intact
hello, world!

有关更多配置,请查看以下内容:CONFIGURING SETTINGS

【讨论】:

  • 好的,这适用于 get / 方法。不过,我仍然无法向其发布数据。将不得不进一步检查。但这回答了问题。在生产中,你使用 Puma 吗?
  • 是的,你可以依赖 puma、unicorn、passenger 任何适合你的东西,你也可以在你的应用程序前面使用nginx。对于POST 方法,我无法尝试,但这将是与代码相关的问题,而不是您的主机和 docker 之间的通信
【解决方案2】:

看看这篇文章:https://docs.docker.com/config/containers/container-networking/

简而言之 - 尝试通过 -p 参数发布您的公开端口。

例如:

$ docker run -it -p 4567 my-local-image

【讨论】:

  • 是的,我试过了。如果您在此步骤后有更多建议,我想听听。
  • 尝试查看服务是否已启动或通过以下方式监听您的连接: - docker ps -a - docker logs {my-container-id}
【解决方案3】:

来自the documentation

标志值说明

-p 8080:80 将容器中的TCP 80端口映射到Docker主机上的8080端口。

您需要将容器中的 TCP 端口 4567 映射到 Docker 主机上的端口。例如,将其映射到端口 8080:

$ docker run -it -p 8080:4567 image-goes-here

【讨论】:

  • 谢谢,但我确实试过了。试过这个之后,你知道我还能检查什么其他提示吗?
猜你喜欢
  • 2020-03-23
  • 2022-08-26
  • 2015-03-14
  • 1970-01-01
  • 2020-12-20
  • 1970-01-01
  • 1970-01-01
  • 2014-05-21
  • 2022-08-03
相关资源
最近更新 更多