Кто не отдыхает, тот не работает. - Ленин
В этой статье не будет объясняться использование, установка и т. д. команд 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
...