将Webservice打包到Docker映像后无法正常工作

时间:2019-03-13 14:30:25

标签: ruby docker web

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

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

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

Web服务在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,我从阿尔卑斯山构建了一个轻量级的红宝石

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 image却没有。我运行命令:

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

3 个答案:

答案 0 :(得分:1)

之所以发生此问题,是因为默认情况下(开发环境)Sinatra会侦听127.0.0.1,在外部连接到容器的情况下无法正常工作

  

:绑定-服务器主机名或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

答案 1 :(得分:0)

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

用几句话-尝试通过-p参数发布暴露的端口。

例如:

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

答案 2 :(得分:0)

来自the documentation

  

标志值说明

     

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

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

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