RooSoft
RooSoft

Reputation: 1501

Nginx seems to crash on Sinatra app in Docker

Dockerfile:

FROM ruby:2.3.1-slim
MAINTAINER Marc Lacoursiere <[email protected]>

RUN apt-get update && apt-get install -yq nginx

RUN rm /etc/nginx/sites-enabled/default
ADD docker/sinatra.conf /etc/nginx/sites-enabled/sinatra.conf

RUN adduser app --gecos "First Last,RoomNumber,WorkPhone,HomePhone" --disabled-password
RUN mkdir /home/app/webapp

WORKDIR /tmp
COPY app/Gemfile /tmp/
COPY app/Gemfile.lock /tmp/
RUN bundle install

COPY app /home/app/webapp
RUN chown -R app:app /home/app

CMD ["nginx", "-g", "daemon off;"]
CMD ["ruby", "/home/app/webapp/app.rb"]

Sinatra.conf:

upstream app {
    server 127.0.0.1:4000;
}

server {
    listen 80 default_server;
    server_name localhost;

    error_log /var/log/nginx/localhost.error_log info;

    location / {
        proxy_pass http://app;
    }
}

app.rb

require 'sinatra'
require 'sinatra/json'

set :port, 4000

get '/' do
  json 'Hello World!'
end

Gemfile:

source 'https://rubygems.org'

gem 'sinatra', '1.4.6'
gem 'sinatra-contrib', '~> 1.4.2'

How it gets executed in bash

docker run -p 4444:80 roosoft/sinatra-example

Simply said, I am supposed to get a sinatra app answering the container's port 4000. Nginx is listening to the container's port 80 and returns what it finds on port 4000, which is the sinatra app. The container's port 80 is redirected to the local port 4444. But port 4444 returns:

curl: (52) Empty reply from server

At that point, for some obscure reason, nginx is not running in the container. To fix it, I simply have to login into the container, type service nginx start and everything's fine. I can log out from the container and the local port 4444 returns what's expected.

If I comment out the last Dockerfile line, rebuild and restart the container, there is no sinatra app running in the container's port 4000, but nginx is running this time! Seems like nginx gets killed when I run sinatra.

What am I doing wrong? I obviously want both to run simultaneously...

Upvotes: 1

Views: 168

Answers (1)

Dirk Grappendorf
Dirk Grappendorf

Reputation: 3422

You can't have multiple CMD statements in a single Dockerfile (https://docs.docker.com/engine/reference/builder/#/cmd). If you look at the output of docker build, you can see that every CMD creates a new image. Each CMD overwrites the one specified in the previous image.

If you want to run multiple processes in a Docker container, you could use a process manager like supervisord. supervisord also helps you to automatically restart the processes in case of a failure. A tutorial on how this is done can be found here:

https://docs.docker.com/engine/admin/using_supervisord/

Another (and IMHO more cleaner) solution is to start two containers. One for the Sinatra app and one for Nginx. Simply link both containers together (docker create --link ...) or setup a network (docker network create ...) and connect both containers to it (docker create --network ...).

Upvotes: 1

Related Questions