2015-11-23 1 views
3

Я пробовал все, что я могу придумать. Я прочитал документы, блоги и попробовал следующие образцы на github.Окружающая среда Node.js dev в Docker на Windows

Но я не могу заставить его работать.

Что я хочу сделать, это просто. Я хочу написать свой код node.js на моем компьютере с Windows 8.1, и я также хочу запустить код из контейнера Docker без необходимости постоянно перестраивать контейнер. Поэтому я хочу сопоставить каталог на моем хосте Windows с каталогом внутри контейнера.

Я создал этот Dockerfile

FROM node:0.10.38 

RUN apt-get update -qq && apt-get install -y build-essential 

ENV ZMQ_VERSION 4.1.3 
ENV LIBSODIUM_VERSION 1.0.3 

RUN curl -SLO "https://download.libsodium.org/libsodium/releases/libsodium-$LIBSODIUM_VERSION.tar.gz" \ 
    && tar xvf libsodium-$LIBSODIUM_VERSION.tar.gz \ 
    && cd libsodium-$LIBSODIUM_VERSION \ 
    && ./configure \ 
    && make \ 
    && make install \ 
    && cd .. \ 
    && rm -r libsodium-$LIBSODIUM_VERSION \ 
    && rm libsodium-$LIBSODIUM_VERSION.tar.gz 
RUN curl -SLO "http://download.zeromq.org/zeromq-$ZMQ_VERSION.tar.gz" \ 
    && tar xvf zeromq-$ZMQ_VERSION.tar.gz \ 
    && cd zeromq-$ZMQ_VERSION \ 
    && ./configure \ 
    && make \ 
    && make install \ 
    && cd .. \ 
    && rm -r zeromq-$ZMQ_VERSION \ 
    && rm zeromq-$ZMQ_VERSION.tar.gz 
RUN ldconfig 

COPY entrypoint.sh /entrypoint.sh 
RUN chmod +x /entrypoint.sh 

ENTRYPOINT ["/entrypoint.sh"] 

RUN mkdir -p /usr/src/app 
ADD . /usr/src/app 
WORKDIR /usr/src/app 
RUN npm install 

EXPOSE 3000 
EXPOSE 35729 

CMD ["npm", "start"] 

У меня есть этот простой server.js файл

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

app.get('/', function (req, res) { 
    res.send('ZMQ: ' + zmq.version); 
}); 

var server = app.listen(3000, function() { 
    var host = server.address().address; 
    var port = server.address().port; 

    console.log('Example app listening at http://%s:%s', host, port); 
}); 

И этот простой package.json

{ 
    "name": "docker-node-hello-world", 
    "version": "1.0.0", 
    "description": "", 
    "main": "server.js", 
    "scripts": { 
    "start": "node server.js" 
    }, 
    "author": "", 
    "license": "ISC", 
    "dependencies": { 
    "express": "^4.13.3", 
    "zmq": "^2.14.0" 
    } 
} 

я установил последнюю Докер Toolbox, и можно запустить пример Docker Hello World. Я пытаюсь создать изображение своего докера таким образом, когда я нахожусь в каталоге, где находится мой файл Docker.

docker build -t dockernodetest:dockerfile .

Я затем попытаться запустить его, а также из того же места внутри Докер Quickstart терминала. Я использую хэш, поскольку тег не принимает по каким-либо причинам:

docker run -v //c/Bitbucket/docker-node-hello-world/:/usr/src/app -p 3000:3000 -i -t 9cfd34e046a5 ls ./usr/src/app

Результат этого является пустым каталогом. Я надеялся, что я мог бы просто вызвать

docker run -v //c/Bitbucket/docker-node-hello-world/:/usr/src/app -p 3000:3000 -i -t 9cfd34e046a5 npm start

Но поскольку каталог хост не доступен он выходит из строя. У меня такое ощущение, что я неправильно понял что-то очень основное. Я просто не знаю, что.

+0

Возможно, вы захотите прочитать [Работа с контейнерами] (https://docs.docker.com/v1.8/userguide/usingdocker/), чтобы помочь вам понять, что произошло после каждого шага. Итак, каков вывод при запуске команды 'docker images'? – jeedo

+0

Также есть содержимое «entrypoint».sh' как 'ENTRYPOINT', аргументы будут переданы этому скрипту - см. [ENTRYPOINT] (https://docs.docker.com/v1.8/reference/builder/#entrypoint) – jeedo

ответ

4

Во-первых, давайте начнем с Dockerfile

FROM node:0.10.38-onbuild 

RUN apt-get update -qq && apt-get install -y build-essential 

ENV ZMQ_VERSION 4.1.3 
ENV LIBSODIUM_VERSION 1.0.3 

RUN curl -SLO "https://download.libsodium.org/libsodium/releases/libsodium-$LIBSODIUM_VERSION.tar.gz" \ 
    && tar xvf libsodium-$LIBSODIUM_VERSION.tar.gz \ 
    && cd libsodium-$LIBSODIUM_VERSION \ 
    && ./configure \ 
    && make \ 
    && make install \ 
    && cd .. \ 
    && rm -r libsodium-$LIBSODIUM_VERSION \ 
    && rm libsodium-$LIBSODIUM_VERSION.tar.gz 
RUN curl -SLO "http://download.zeromq.org/zeromq-$ZMQ_VERSION.tar.gz" \ 
    && tar xvf zeromq-$ZMQ_VERSION.tar.gz \ 
    && cd zeromq-$ZMQ_VERSION \ 
    && ./configure \ 
    && make \ 
    && make install \ 
    && cd .. \ 
    && rm -r zeromq-$ZMQ_VERSION \ 
    && rm zeromq-$ZMQ_VERSION.tar.gz 
RUN ldconfig 

EXPOSE 3000 35729 

От линии 1 Я использовал 0.10.38-onbuild тег, потому что я хочу, чтобы воспользоваться onbuild scripts, который будет работать для создания каталога /usr/src/app и запустить npm install

Тогда server.js и package.json, как вы их написали. Они находятся в том же рабочем каталоге, что и Dockerfile.

Далее мы строим образ

docker build -t dockernodetest . 

я опустил dockerfile тег, как это казалось ненужным. В любом случае клиент автоматически добавит тег latest. Чтобы увидеть, какие изображения у вас локально запущены docker images.

На данный момент мы должны иметь изображение, готовый бежать, но давайте сначала проверить, что файлы, которые мы хотели, чтобы загрузить затем и npm install создал node_modules каталог

$ docker run dockernodetest ls /usr/src/app 
Dockerfile 
node_modules 
package.json 
server.js 

Мы готовы на это пункт, чтобы запустить наше маленького nodejs приложения

$ docker run -it -p 8080:3000 dockernodetest 

> [email protected] start /usr/src/app 
> node server.js 

Example app listening at http://0.0.0.0:3000 

в данном случае я использовал -p 8080:3000 флаг на карту 3000 порта контейнера в порт 8080 на моем хосте-машине. Обратите внимание, что у меня не было никаких других команд в конце, потому что у меня получилось -onbuild изображение, которое вытащило форму: CMD [ "npm", "start" ], поэтому действие по умолчанию - запустить сценарий пакета start.

Итак, чтобы сделать цикл разработки еще быстрее вы хотите установить рабочую директорию в контейнер через -v вариант

$ docker run -it -p 8080:3000 -v "$PWD":/usr/src/app dockernodetest 

> [email protected] start /usr/src/app 
> node server.js 


module.js:340 
    throw err; 
     ^
Error: Cannot find module 'express' 
    at Function.Module._resolveFilename (module.js:338:15) 
    at Function.Module._load (module.js:280:25) 
    at Module.require (module.js:364:17) 
    at require (module.js:380:17) 
    at Object.<anonymous> (/usr/src/app/server.js:1:77) 
    at Module._compile (module.js:456:26) 
    at Object.Module._extensions..js (module.js:474:10) 
    at Module.load (module.js:356:32) 
    at Function.Module._load (module.js:312:12) 
    at Function.Module.runMain (module.js:497:10) 

npm ERR! Linux 4.1.7-15.23.amzn1.x86_64 
npm ERR! argv "node" "/usr/local/bin/npm" "start" 
npm ERR! node v0.10.38 
npm ERR! npm v2.11.1 
npm ERR! code ELIFECYCLE 
npm ERR! [email protected] start: `node server.js` 
npm ERR! Exit status 8 

Но что здесь произошло? Поскольку мы установили текущий рабочий каталог, он перезаписал то, что было ранее в /usr/src/app, включая наш каталог node_modules.

Итак, быстро исправить здесь, чтобы запустить npm install в нашем текущем рабочем каталоге и выполнить повторную команду docker run.

$ npm install 
[email protected] /home/ec2-user/dockernode 
└─┬ [email protected] 
    ├─┬ [email protected] 
    │ ├─┬ [email protected] 
... 
$ docker run -it -p 8080:3000 -v "$PWD":/usr/src/app dockernodetest 

> [email protected] start /usr/src/app 
> node server.js 

Example app listening at http://0.0.0.0:3000 

Теперь, если вы делаете обновление файла server.js просто нажмите Ctrl + с и перезапустить вы докер изображение, хотя вы можете использовать что-то вроде nodemon, чтобы сделать это еще более цельным.

+0

Вау, спасибо @jeedo , Очень тщательный ответ. Не могу дождаться, чтобы испытать тониту. БЛАГОДАРЯ –

0

Большое вам спасибо за ваш ответ. Это определенно привело меня на правильный путь. Мне потребовалось больше времени, чем я думал, но у меня все получилось.

Было несколько вещей, которые не сработали, но я наконец-то работал. Вот краткое изложение того, что я пережил.

  1. Я не смог использовать скрипты onbuild, как вы предлагали. Причина в том, что когда я основываю свое изображение на скрипте onbuild, он запускает npm install перед установкой ZeroMQ.

  2. Запуск npm install Внешний вид моего докера не был таким, как вы предлагали, когда я сопоставил диск. Одна из причин, по которой я хочу запустить это в Docker, - это то, что я хочу среду, в которой все зависимости (такие как ZeroMQ) установлены и доступны. Это то, что в некоторых средах сложно, и я хочу запустить это как на Windows, так и на Linux-хостах.

  3. Я действительно хочу использовать nodemon для разработки, поэтому мне также пришлось установить это глобально на изображении, а также вызвать nodemon при запуске контейнера. Поэтому мне пришлось расширить ваш пример, как вы предложили.

  4. У меня было много проблем с получением отображаемых томов для работы. Оказывается, что на хосте Windows вы должны быть в контексте C:\users\<username>, чтобы иметь возможность отображать тома на хосте из контейнера.Как только я понял это и распутывал все странные эксперименты, которые я провел, чтобы все это работало, я получил это на работу. Используя "$PWD", как вы предложили при вызове docker run, также странно на хосте Windows. Вы должны префикс с помощью косой черты следующим образом: /"$PWD".

  5. Когда я все понял, я начал смотреть на докер, отчасти потому, что не хотел, чтобы я печатал длинные команды запуска докеров (что я все время ошибался), а также потому, что в моих реальных проектах я хочу несколько контейнеров для моей базы данных и другие службы, которые мне нужны.

Так вот как оно выглядит сейчас. Он работает точно так, как я хочу, чтобы он работал. Теперь у меня есть контейнер, где все зависимости установлены внутри контейнера, и всякий раз, когда я запускаю свой контейнер, он сначала вызывает npm install и nodemon server.js. Все файлы, включая установленные модули npm, находятся на хосте, но отображаются внутри контейнера, из которого все выполняется.

Файл 1 - докер-compose.yml (заметьте, что я не нужен переменный $ PWD, но может просто использовать . относительный путь для главного пути)

web: 
    build: . 
    volumes: 
    - ".:/usr/src/app" 
    ports: 
    - "3000:3000" 

Файл 2 - Dockerfile

FROM node:0.10.40 

RUN mkdir /usr/src/app 
RUN mkdir /usr/src/node_modules 

RUN apt-get update -qq && apt-get install -y build-essential 

ENV ZMQ_VERSION 4.1.3 
ENV LIBSODIUM_VERSION 1.0.3 

RUN curl -SLO "https://download.libsodium.org/libsodium/releases/libsodium-$LIBSODIUM_VERSION.tar.gz" \ 
    && tar xvf libsodium-$LIBSODIUM_VERSION.tar.gz \ 
    && cd libsodium-$LIBSODIUM_VERSION \ 
    && ./configure \ 
    && make \ 
    && make install \ 
    && cd .. \ 
    && rm -r libsodium-$LIBSODIUM_VERSION \ 
    && rm libsodium-$LIBSODIUM_VERSION.tar.gz 
RUN curl -SLO "http://download.zeromq.org/zeromq-$ZMQ_VERSION.tar.gz" \ 
    && tar xvf zeromq-$ZMQ_VERSION.tar.gz \ 
    && cd zeromq-$ZMQ_VERSION \ 
    && ./configure \ 
    && make \ 
    && make install \ 
    && cd .. \ 
    && rm -r zeromq-$ZMQ_VERSION \ 
    && rm zeromq-$ZMQ_VERSION.tar.gz 
RUN ldconfig 

RUN npm install -g nodemon 
WORKDIR /usr/src/app 

CMD export NODE_PATH=/usr/src/node_modules && cp package.json /usr/src && npm install --prefix /usr/src && npm start 

EXPOSE 3000 35729 

Файл 3 - package.json (уведомление я использую -L флаг при вызове nodemon Это необходимо при работе внутри контейнера.)

{ 
    "name": "docker-node-hello-world", 
    "version": "1.0.0", 
    "description": "node hello world", 
    "main": "server.js", 
    "scripts": { 
    "start": "nodemon -L server.js" 
    }, 
    "author": "Author", 
    "license": "ISC", 
    "dependencies": { 
    "express": "^4.13.3", 
    "zmq": "^2.14.0" 
    } 
} 

File 4 - server.js

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

app.get('/', function (req, res) { 
    res.send('ZMQ Version: ' + zmq.version); 
}); 

var server = app.listen(3000, function() { 
    var host = server.address().address; 
    var port = server.address().port; 

    console.log('Example app listening at http://%s:%s', host, port); 
}); 

Для сборки используйте следующую команду

docker-compose build 

Для запуска используйте следующую команду

docker-compose up 

В это время я могу развивать мое приложение на моем хосте, и всякий раз, когда я меняю файл, мой сервер узлов перезапускается. Когда я добавляю новую зависимость к моему package.json, я должен перезагрузить свой контейнер, чтобы запустить npm install.

Единственное, что у меня пока нет, это то, как я делаю восстановление своего изображения плавным. Случается, что после создания нового изображения мне нужно удалить старый контейнер, прежде чем я смогу запустить новый контейнер. Отображение блокируется старым контейнером.

Я бы очень хотел дать вам кредит @jeedo. Я не смог бы достичь этого решения без вашей помощи. Я не знаю, как это сделать, и также отмечаю это как решение.

Редактировать: Я только что отредактировал это, чтобы добавить что-то в свой файл Dockerfile. Я переместил папку node_modules из файловой системы хоста. У меня были проблемы с слишком длинными путями в Windows. Эти изменения гарантируют, что node_modules всегда устанавливаются внутри контейнера.

Смежные вопросы