Я написал приложение node, используя синтаксис ES6, то есть import express from 'express';
. После этого, чтобы упростить жизнь, я хотел использовать Docker для размещения приложения. Поэтому я погуглил свой запрос, как и вы, и нашел кучу руководств о том, как создать Dockerfile и docker-compose.yml.
Мила, давайте!
TL;DR
Вы можете найти весь код на GitHub @ https://github.com/Tabofa/demo-app
После того, как я написал все инструкции, я запустил его, создал образ, и docker-compose запустил контейнер. К моему большому разочарованию, я получил ошибки. Он не признавал импорт и громко жаловался на это.
После того, что казалось вечностью гугления, я наконец обнаружил, что есть две вещи, о которых я не знал.
- Мне пришлось добавить
{ "type": "module" }
как поле верхнего уровня в package.json. - И мне нужен был Node 13 или новее.
Итак, имея эту информацию под рукой, я наконец смог создать свой новый образ.
Если вы хотите продолжить, я создал очень простое приложение узла для тестирования, если нет, прокрутите вниз до The Dockerfile.
mkdir demo-app cd demo-app npm init npm install express npm install pm2 # I want pm2 to host my app in the container later touch Dockerfile touch docker-compose.yml mkdir src cd src touch index.js
Если вы будете следовать, у вас должна быть файловая структура, подобная следующей
demo-app | src | index.js | Dockerfile | docker-compose.yml | package.json | package-lock.json
Первый трюк, чтобы заставить node читать мое приложение как es6, а не CommonJs, заключался в том, что мне пришлось немного изменить файл package.json
. Добавление поля type
{ "name": "demo-app", "version": "1.0.0", "description": "", "type": "module", "main": "src/index.js", "script": { ... } }
В ./src/index.js
я написал простое приложение, которое будет предоставлять порт и конечную точку, которая при вызове будет отвечать «hello world». Используя экспресс, который мы установили в начале здесь.
# src/index.js import express from 'express' const app = express() const PORT = 3000 app.get('/', (req, res) => { res.send('hello world') }) app.listen(PORT, () => { console.log(`listening on port ${PORT}`) })
Как только я попробовал это с node ./src/index.js
, я мог приступить к созданию Dockerfile.
Докерфайл
# Dockerfile FROM node:14-alpine
Это был еще один трюк: используя базовый образ с узлом 13 или более поздней версии, я решил использовать 14, так как это была последняя основная версия на момент написания.
Я продолжил добавлять обычные команды в Dockerfile
# Dockerfile # Base image to use FROM node:14-alpine #Create the directory we're going to use RUN mkdir -p /usr/src/app # Set it as work directory WORKDIR /usr/src/app # Copy all the code to our work directory COPY . . # Install all our dependencies sRUN npm install # Expose the port we want to communicate on EXPOSE 3000 # Start the container CMD [ "npx", "pm2-runtime", "start", "src/index.js" ]
В последней строке Dockerfile я указываю команду для выполнения после создания образа. в этом случае мы используем pm2-runtime
согласно документации для pm2, это способ сделать это в контейнере докера, иначе докер может подумать, что процесс завершен, и закрыть его, мы этого не хотим.
Я также использую npx
здесь, поэтому мы используем pm2 из наших node_modules, что дает нам роскошь не указывать это как глобальную установку в Dockerfile, мы могли бы, если бы мы хотели запустить RUN npm install -g pm2
после нашего оператора RUN npm install
, установив его глобально . Но зачем заморачиваться.
Файл docker-compose.yml
Перейдем к следующей части, нашему docker-compose.yml, он не нужен, но, на мой взгляд, упрощает жизнь.
# docker-compose.yml version: '3' services: demo-app: build: context: . ports: - "3000:3000"
Теперь вы сможете запустить docker-compose up
в окне терминала, и если вы откроете браузер и перейдете к http://localhost:3000
, вы увидите на экране слова «hello world».
Удачного кодирования!