Node.js Сервис Docker Контейнерная практика применения

Node.js
Node.js Сервис Docker Контейнерная практика применения

Кто не отдыхает, тот не работает. - Ленин

В этой статье не будет объясняться использование, установка и т. д. команд Docker, потому что в предыдущей статьеСтатья с нуля, которая научит вас изучать Docker от начала до практики.Это также было объяснено очень подробно. Если вы не уверены, вы можете щелкнуть ссылку, чтобы вернуться и прочитать ее снова. В этой статье основное внимание уделяется тому, как выполнить контейнеризацию Docker и некоторую практическую оптимизацию проектов Node.js, а также некоторые общие проблемы.Конечно, если у вас есть другие вопросы об использовании, вы можете оставить сообщение в области комментариев.

об авторе: Май Джун, разработчик Nodejs, молодой человек после 90-х, который любит технологии и любит делиться, общедоступный аккаунт «Nodejs Technology Stack», проект с открытым исходным кодом Github.www.nodejs.red

Что можно узнать из этой статьи?

  • Узнайте, как контейнеризировать службу Node.js с помощью Docker.
  • Динамически задавайте переменные среды в Dockerfile для создания разных версий.
  • Как аутентифицируются частные пакеты NPM Node.js при создании образов
  • Egg.js framework Контейнеризация Docker должна обратить внимание на проблемы
  • Размер документа докера и оптимизация времени

Dockerize Node.js приложение

В начале этой статьи мы создадим простое приложение Node.js, затем создадим образ Docker для этого приложения, соберем и запустим его.

Создайте проект Node.js

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

const http = require('http');
const PORT = 30010;

const server = http.createServer((req, res) => {
    res.end('Hello Docker');
})

server.listen(PORT, () => {
    console.log('Running on http://localhost:', PORT, 'NODE_ENV', process.env.NODE_ENV);
});

Затем создаем файл package.json, здесь описание вашего приложения и необходимых зависимостей, с ним должны быть знакомы студенты, которые писали Node.js, здесь я добавил его в скриптыnpm run dev,npm run proДве команды, потому что я хочу рассказать здесь, как динамически устанавливать переменные среды, передавая параметры во время сборки.

{ 
    "name": "hello-docker", 
    "version": "1.0.2",
    "description": "", 
    "author": "May",
    "main": "app.js",   
    "scripts": {
      "dev": "NODE_ENV=dev node app.js",
      "pro": "NODE_ENV=pro node app.js"
    }
}

Файл Dockerfile

Это информация, содержащаяся в Dockerfile, команды находятся вНачало работы с Докеромтакже объясняется в

FROM node:10.0-alpine

RUN apk --update add tzdata \
    && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone \
    && apk del tzdata

RUN mkdir -p /usr/src/nodejs/

WORKDIR /usr/src/nodejs/

# add npm package
COPY package.json /usr/src/nodejs/package.json
RUN cd /usr/src/nodejs/
RUN npm i

# copy code
COPY . /usr/src/nodejs/

EXPOSE 30010

CMD npm run dev

Создайте файл .dockerignore на том же уровне, что и Dockerfile, чтобы не помещать локальные файлы отладки, node_modules и другие файлы в контейнер Docker.

.git
node_modules
npm-debug.log

На этом этапе вы можете создать образ Docker с помощью следующей команды

$ docker image build -t mayjun/hello-docker

Затем вы можете запустить контейнер Docker с помощью команды docker run -d -p 30010:30010 mayjun/hello-docker, но у меня есть вопрос по производству и тестированию.CMD npm run devТаким образом, вы можете упаковать только одну среду.Конечно, вы также можете создать файл для достижения этого или некоторых других методов.

Динамически устанавливаемые переменные среды

Чтобы разрешить вышеуказанные сомнения, моя идея состоит в том, чтобы динамически устанавливать переменные среды, передавая параметры при построении образа, и изменять файл Dockerfile, чтобы увидеть следующую реализацию:

EXPOSE 30010

ARG node_env # 新增加
ENV NODE_ENV=$node_env  # 新增加
CMD npm run ${NODE_ENV} # 修改

Ниже приведено объяснение приведенного выше кода.

  • Переменная определяется через директиву ARG, которую пользователь может передать сборщику во время сборки с помощью команды сборки docker с флагом --build-arg=.ARG node_env
  • Используйте ENV для ссылки на эту переменную в Dockerfile.ENV NODE_ENV=$node_env
  • Этот шаг заключается в использованииCMD npm run ${NODE_ENV}

Осталось только динамически передавать параметры при построении образа.

$ docker image build --build-arg node_env=dev -t mayjun/hello-docker:1.0.2 . # 构建测试环境
$ docker image build --build-arg node_env=pro -t mayjun/hello-docker:1.0.2 . # 构建生产环境

запустить контейнер

$ docker run -d -p 30010:30010 mayjun/hello-docker:1.0.2
$ docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                      NAMES
2bc6e62cd0e8        mayjun/hello-docker:1.0.2   "/bin/sh -c 'npm run…"   3 minutes ago       Up 3 minutes        0.0.0.0:30010->30010/tcp   elastic_bouman

Просмотр журналов контейнера

docker logs -f 2bc6e62cd0e8

> hello-docker@1.0.0 dev /usr/src/nodejs
> NODE_ENV=dev node app.js

Running on http://localhost: 30010 NODE_ENV dev

Я упаковал приведенный выше код в образ mayjun/hello-docker:1.0.2, который можно извлечь и просмотреть. docker pull mayjun/hello-docker:1.0.2

Частные пакеты Docker и Node.js NPM

Если вы используете частный пакет NPM в своем проекте, будет ошибка 404 установки частного пакета npm во время процесса создания образа Docker.Если он находится вне контейнера, мы можем npm войти в учетную запись с разрешениями частного пакета NPM на решить эту проблему Но вы не можете сделать это в Docker.

Создайте токен аутентификации

Для установки приватных пакетов нам понадобится "Создайте токен аутентификации», чтобы мы могли получить доступ к нашему частному пакету NPM в среде непрерывной интеграции и внутри контейнера Docker, как создать, можно обратиться кdocs.thathorseplus.com/creating-press…

Выполнение

Нам нужно добавить следующие две команды в процессе создания файла Dockerfile:

# 528das62-e03e-4dc2-ba67-********** 这个 Token 就为你创建的身份验证令牌 token
RUN echo "//registry.npmjs.org/:_authToken=528das62-e03e-4dc2-ba67-**********" > /root/.npmrc
RUN cat /root/.npmrc

Egg framework Контейнеризация Docker

Внутри яйца, если оноegg-scripts start --daemon,удалить --демонПросто запустите egg-скрипты напрямую, иначе контейнер Docker не запустится.

Посмотрите на следующий пример кода, измените package.json, файл Dockerfile такой же, как и первый выше.Докеризация приложения Node.jsэто то же самое

package.json

{
  "scripts": {
    "start": "egg-scripts start" // 去掉 --daemon
  }
}

Вы также можете обратиться к Egg Issues «Не удается запустить док-контейнер. Были ли у вас какие-либо проблемы?»GitHub.com/eggJS/яйцо/я…

Размер образа Docker и оптимизация времени сборки

Если изображение не оптимизировано, объем обычно очень большой Ниже приведены некоторые оптимизации, сделанные на практике.

ВЫПОЛНИТЬ/КОПИРОВАТЬ слои

Каждая инструкция в Dockerfile создает слой изображения, и каждый слой изображения можно повторно использовать и кэшировать без изменения инструкции Dockerfile или скопированного файла проекта.

Следующий код можно найти в зеркальном репозитории mayjun/hello-docker:latest.В следующем примере после изменения исходного кода модуль NPM будет переустановлен независимо от того, изменился ли package.json.Это явно не так. хорошо, так что мы будем улучшать

# ...

WORKDIR /usr/src/nodejs/hello-docker
COPY . /usr/src/nodejs/hello-docker

RUN npm install

# ...

Улучшенный код показан ниже.Мы делаем package.json заранее.Если package.json не модифицировать, пакет NPM не будет переустанавливаться, а время развертывания сократится.

# ...

WORKDIR /usr/src/nodejs/

# add npm package
COPY package.json /usr/src/app/package.json
RUN cd /usr/src/app/
RUN npm i

# copy code
COPY . /usr/src/app/

# ...

Оптимизация изображений Node.js Alpine

mayjun/hello-docker:1.0.0 Этот образ также доступен для поиска в репозитории Docker, около 688 МБ до оптимизации.

$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE mayjun/hello-docker 1.0.0 7217fb3e9daa 5 seconds ago 688MB

Оптимизировано с помощью Alpine

Alpine — это небольшой дистрибутив Linux.Также проще всего выбрать Alpine-версию Node.js, если вы хотите значительно уменьшить размер образа.Кроме того, часовой пояс -alpine по умолчанию не является домашним, и вам нужно настроить часовой пояс в Dockerfile.

FROM node:10.0-alpine

RUN apk --update add tzdata \
    && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone \
    && apk del tzdata

RUN echo "Asia/Shanghai" > /etc/timezone

RUN mkdir -p /usr/src/nodejs/

WORKDIR /usr/src/nodejs/

# add npm package
COPY package.json /usr/src/app/package.json
RUN cd /usr/src/app/
RUN npm i

# copy code
COPY . /usr/src/app/

EXPOSE 30010
CMD npm start

Переупаковал версию mayjun/hello-docker:1.1.0 Проверьте эффект еще раз, вы можете видеть, что файл образа уменьшен с 688 МБ до 85,3 МБ, эта оптимизация объема все еще очень велика.

$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
mayjun/hello-docker   1.1.0               169e05b8197d        3 minutes ago       85.3MB

Не упаковывайте пакет devDependencies в рабочей среде.

Некоторые пакеты, используемые в тестовой среде, не следует включать при зеркалировании рабочей среды, то есть объект devDependencies файла package.json, который фильтруется указанием параметра --production после npm i

Улучшения заключаются в следующем:

FROM node:10.0-alpine

# 省略 ...

# add npm package
COPY package.json /usr/src/app/package.json
RUN cd /usr/src/app/
RUN npm i --production # 改变在这了

# 省略 ...

Перепаковал версию mayjun/hello-docker:1.2.0 Проверьте эффект еще раз, вы можете увидеть, что файл образа уменьшился с 85,3 МБ до 72,3 МБ.

$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
mayjun/hello-docker   1.2.0               f018aa578711        3 seconds ago       72.3MB

Общая проблема

Question1

Следующая команда сообщает о следующей ошибке при удалении изображения:

$ docker rmi 6b1c2775591e
Error response from daemon: conflict: unable to delete 6b1c2775591e (must be forced) - image is referenced in multiple repositories

Если вы будете осторожны, вы можете обнаружить, что идентификатор образа 6b1c2775591e указывает на оба репозитория hello-docker и mayjun/hello-docker, что также является причиной сбоя удаления.

$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
mysql                 5.7                 383867b75fd2        6 days ago          373MB
hello-docker          latest              6b1c2775591e        7 days ago          675MB
mayjun/hello-docker   latest              6b1c2775591e        7 days ago          675MB

Укажите репозиторий и тег для удаления.После выполнения команды удаления снова проверьте хранилище mayjun/hello-docker.

$ docker rmi mayjun/hello-docker
$ docker images                 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mysql               5.7                 383867b75fd2        6 days ago          373MB
hello-docker        latest              6b1c2775591e        7 days ago          675MB

Question2

При выполнении команды удаления изображения сообщается о следующей ошибке:

$ docker rmi 9be467fd1285
Error response from daemon: conflict: unable to delete 9be467fd1285 (cannot be forced) - image is being used by running container 1febfb05b850

По подсказке есть запущенный контейнер, нужно сначала остановить контейнер, удалить контейнер, а потом удалить образ

$ docker container kill 1febfb05b850 # 停止容器
$ docker rm 1febfb05b850 # 删除容器
$ docker rmi 9be467fd1285 # 删除镜像

Question3

Установленный рабочий каталог (WORKDIR) должен соответствовать следующему

...
WORKDIR /usr/src/nodejs/

# add npm package
COPY package.json /usr/src/node/package.json # 目录不一致
RUN cd /usr/src/node/ # 目录不一致
RUN npm i
...

Например, приведенная выше конфигурация вызовет сообщение об ошибке, поскольку рабочий каталог не соответствует фактическому каталогу COPY:

图片描述

Затем измените его, чтобы он был последовательным, следующим образом

...
WORKDIR /usr/src/nodejs/

# add npm package
COPY package.json /usr/src/nodejs/package.json # 更改为一致
RUN cd /usr/src/nodejs/ # 更改为一致
RUN npm i
...