Docker - почему этот контейнер express.js с открытым / опубликованным портом отклоняет соединения? (используя boot2docker)

У меня есть простое приложение hello world express.js внутри контейнера докеров. Он настроен на работу на порту 8080, и файл докера предоставляет этот порт в образе. Кроме того, я публикую порт при запуске образа. Тем не менее, когда я пытаюсь сделать простой запрос на завиток, соединение отклоняется. Вот как я настроил этот тест:

Мой Dockerfile довольно прост:

FROM node

ADD ./src /src
WORKDIR /src

# install your application's dependencies
RUN npm install

# replace this with your application's default port
EXPOSE 8080

# replace this with your main "server" script file
CMD [ "node", "server.js" ]

А внутри моего каталога ./src у меня есть файл server.js, который выглядит так:

var express = require('express');
var app = express();

app.get('/', function(req, res){
  res.send('Hello World');
});

var server = app.listen(8080, function() {
    console.log('Listening on port %d', server.address().port);
});

а также базовый package.json, который выглядит так:

{
  "name": "hello-world",
  "description": "hello world test app",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "express": "4.7.2"
  }
}

Образ строится просто отлично:

→ docker build -t jimjeffers/hello-world .
Sending build context to Docker daemon 1.126 MB
Sending build context to Docker daemon 
Step 0 : FROM node
 ---> 6a8a9894567d
Step 1 : ADD ./src /src
 ---> 753466503fbf
Removing intermediate container 135dab70dfff
Step 2 : WORKDIR /src
 ---> Running in 12257ff3f990
 ---> 010ce4140cdc
Removing intermediate container 12257ff3f990
Step 3 : RUN npm install
 ---> Running in 1a9a0eb9d188
 ---> 5dc97c79281e
Removing intermediate container 1a9a0eb9d188
Step 4 : EXPOSE 8080
 ---> Running in abbaadf8709d
 ---> 9ed540098ed2
Removing intermediate container abbaadf8709d
Step 5 : CMD [ "node", "server.js" ]
 ---> Running in 63b14b5581cd
 ---> eababd51b50e
Removing intermediate container 63b14b5581cd
Successfully built eababd51b50e

И начинается просто отлично:

→ docker run -P -d jimjeffers/hello-world
ee5024d16a679c10131d23c1c336c163e9a6f4c4ebed94ad4d2a5a66a64bde1d

→ docker ps
CONTAINER ID        IMAGE                           COMMAND                CREATED             STATUS              PORTS                     NAMES
ee5024d16a67        jimjeffers/hello-world:latest   node server.js         About an hour ago   Up 11 seconds       0.0.0.0:49158->8080/tcp   jovial_engelbart    
5d43b2dee28d        mongo:2.6                       /usr/src/mongo/docke   5 hours ago         Up 3 hours          27017/tcp                 some-mongo          

Я могу подтвердить, что сервер работает внутри контейнера:

→ docker logs ee5024d16a67
Listening on port 8080

Но если я попытаюсь сделать запрос, в соединении будет отказано.

→ curl -i 0.0.0.0:49158
curl: (7) Failed connect to 0.0.0.0:49158; Connection refused

Что-то мне здесь не хватает? Если я запускаю приложение без использования докера, оно работает должным образом:

→ node src/server.js 
Listening on port 8080

→ curl -i 0.0.0.0:8080
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 11
ETag: W/"b-1243066710"
Date: Mon, 04 Aug 2014 05:11:58 GMT
Connection: keep-alive

Hello World

person Jim Jeffers    schedule 04.08.2014    source источник
comment
Блокирует ли это брандмауэр вашей хост-системы?   -  person Jonathan    schedule 04.08.2014


Ответы (2)


Я обнаружил источник путаницы. Моя машина работает на Mac OSX, поэтому я установил докер с помощью boot2docker.

Итак, снова повторяем процесс:

→ docker run -P -d jimjeffers/hello-world
28431b32b93dbecaa2a8a5b129cbd36eebe8a90f4c20ab10735455d82fa9de37

→ docker ps
CONTAINER ID        IMAGE                           COMMAND                CREATED             STATUS              PORTS                     NAMES
28431b32b93d        jimjeffers/hello-world:latest   node server.js         2 hours ago         Up 9 minutes        0.0.0.0:49159->8080/tcp   stoic_franklin      
5d43b2dee28d        mongo:2.6                       /usr/src/mongo/docke   6 hours ago         Up 4 hours          27017/tcp                 some-mongo   

Наконец, хитрость заключалась не в том, чтобы подключиться к моей машине, а в том, чтобы скручиваться с IP-адреса виртуальной машины:

→ boot2docker ip

The VM's Host only interface IP address is: 192.168.59.103

Итак, я наконец добился успеха, когда свернул виртуальную машину:

→ curl -i 192.168.59.103:49159
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 11
ETag: W/"b-1243066710"
Date: Mon, 04 Aug 2014 04:32:37 GMT
Connection: keep-alive

Все это подробно описано в руководстве по установке Docker, но я пропустил его, поскольку конец документа.

person Jim Jeffers    schedule 04.08.2014
comment
Наткнулся на это, а затем ударил себя по голове, осознав, что я уже читал документацию boot2docker, в которой говорится только об этом. Спасибо, Джим. +1 - person dooburt; 02.01.2015
comment
с новым набором инструментов это docker-machine ip, чтобы получить IP-адрес виртуальной машины докера. - person Kyle Falconer; 19.02.2016

После раскрытия порта в вашем файле докеров вы также должны указать Docker, как выполнить сопоставление из вашей хост-системы в ваш контейнер.

Попробуйте изменить команду запуска Docker на что-то вроде этого:

docker run -p 127.0.0.1:49158:8080 -d jimjeffers/hello-world

Тогда попробуйте: curl'ing:

curl -i 127.0.0.1:49158

person Jonathan    schedule 04.08.2014
comment
Привет, спасибо за ответ, Джонатан. Перезапуск контейнера с этим явным сопоставлением IP-адресов по-прежнему приводит к отклонению ответа. Может ли что-то еще блокировать это? - person Jim Jeffers; 04.08.2014
comment
Если вы не выполняете команды от имени пользователя root, он не сможет выполнить привязку к портам. Вы запускаете команды с sudo каждый раз? - person Jonathan; 04.08.2014
comment
Спасибо, Джонатан, ты не ответил на мой вопрос, но указал мне правильное направление. Я не могу запустить docker как sudo, так как использую boot2docker в OSX. Boot2Docker запускает легкую виртуальную машину. Итак, я публиковал свои открытые порты на виртуальной машине, а не на своей машине. - person Jim Jeffers; 04.08.2014
comment
Отлично. Рад, что ты это понял! - person Jonathan; 04.08.2014