容器将应用与环境打包整合,解决了应用外部依赖的痛点,打包后通过窗口可方便地部署到任意环境,用过就知道很香。

创建示例应用

NestJS 为例,先创建一个示例应用。

$ npm i -g @nestjs/cli
$ nest new my-app
$ cd my-app
$ yarn && yarn start
 

然后 app.controller.ts 中添加如下 action:

  @Get('ping')
async ping() {
return 'pong';
}
 

测试一把会得到如下返回,证明我们的 app 一切正常:

$ curl localhost:3000/ping
pong
 

Docker 介绍

先了解 Docker 的两个核心概念:

  • 镜像/image: 本质上是一个文件,里面包含创建容器的指令,可通过 docker images 查看已有的镜像。
  • 容器/container: 通过镜像创建出来运行中的实例即容器,可通过 docker ps 命令查看运行中的容器。

Docker 安装

$ brew install --cask docker
 

如果已经安装过,升级可使用如下命令:

$ brew install --cask docker
 

然后在程序目录或 Spotlight 中找到并启动 Docker,系统状态栏中会有个鲨鱼图标。

启动后命令行工具已经可用,检查安装:

$ docker —version
Docker version 20.10.6, build 370c289
 

使用

通过 docker help 查看帮助。

$ docker help
 

查看具体命令的帮助可在 help 后加上该命令:

$ docker help run
 

打包生成镜像

Docker 中打包后的应用存在于镜像中,其中便包含了应用及依赖的环境。将这个镜像文件进行分发就可以在其他地方加载运行,实现了在新环境中方便部署,无须再关心外部依赖。

创建 Dockerfile

使用 Docker 打包应用需先创建 Dockerfile,其中包含指导 Docker 如何打包的指令。

$ touch Dockerfile
 

一般我们会基于已有镜像来创建自己的镜像,比如这里打包 Node 应用,我们会使用一个已经包含 Node 环境的镜像作为源。通过如下 FROM 语句完成:

FROM node:14
 

创建应用所在的目录:

# Create app directory
WORKDIR /usr/src/app
 

将文件复制到目标路径,然后进行 npm 包依赖的安装:

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./ RUN npm install
# If you are building your code for production
# RUN npm ci --only=production
 

复制应用中的源码文件:

# Bundle app source
COPY . .
 

依赖和源码都好后,可以编译 Nest 应用,生成 dist 目录了:

npm run build
 

可以把镜像看作一个封闭环境,外界要与其中的应用进行交互,比如这里打包的是 Nest 服务,要能正常访问 Nest 中我们编写的 HTTP 接口,就需要 image 向外暴露端口。

因为默认 Nest 应用起的 3000 端口,这里就将其暴露,

EXPOSE 3000
 

最后一条指令,指导 Docker 启动 Nest 应用:

CMD [ "node", "dist/main" ]
 

所以完整的 Dockerfile 目前长这样了:

FROM node:14

# Create app directory
WORKDIR /usr/src/app # Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./ RUN npm install
# If you are building your code for production
# RUN npm ci --only=production
npm run build # Bundle app source
COPY . . EXPOSE 8080
CMD [ "node", "dist/main" ]
 

.dockerignore 文件

可创建 .dockerignore 文件,将日志,本地无用文件排除在复制的文件列表之外。

node_modules
npm-debug.log
 

生成镜像

通过如下命令根据前面创建的 Dockerfile 生成镜像:

$ docker build . -t wayou/my-app
 

其中 -t 指定镜像名称,一般为 <username>/<image_name> 形式,其中 username 与你在 Docker Hub 中的用户名一致。前面提到镜像可进行分发,当然也能分享,同时我们的 Dockerfile 也是基于名为 node:14 的镜像进行创建的,Docker Hub 则是官方一个分享 image 的平台。

生成镜像过程中如果出现如下错误:

Error response from daemon: dial unix docker.raw.sock: connect: connection refused
 

重启一下 Docker 服务即可。

查看镜像

正常的话,可通过如下命令查看到刚刚生成的镜像:

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wayou/my-app latest 6ba2f1f74d8b 7 hours ago 1.44GB
 

运行镜像

通过如下命令运行镜像:

$ docker run -p 8000:3000 -d wayou/my-app
 

其中 -p 部分前面为外部环境使用的端口,而 3000 为容器对外 暴露的端口。实际使用时则是使用外部这个 8000。

$ curl localhost:8000/ping
pong
 

通过 docker ps 查看运行中的实例。

镜像启动失败的排查

这里展示下如下 Debug 找出镜像启动失败的原因,即没有生成运行中的容器。

前面启动应用的指令是 CMD [ "node", "dist/main" ],而 dist 目录是通过 npm run build 而来,假如我们的 Dockerfile 中没有 build 这个步骤,很明显就没有 dist 目录所以会导致应用启动失败。

启动失败的话,docker ps 输出为空。

此时可加上 -a 参数,它会列出所有容器,包含停止的实例,以查看其状态。

$ docker ps -a
 

如果看到 STATUSExited,原因就是启动失败了。此时需要 Debug 一下看看启动失败的具体原因。

重新启动,并指定名称,方便后面查看日志:

$ docker run -p 8000:3000 -d --name test wayou/my-app
 

现在查看时可能看一个指定名称为 test 的容器:

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a9d187c0d665 wayou/my-app "docker-entrypoint.s…" 5 seconds ago Exited (1) 3 seconds ago test
 

然后通过 docker logs 查看其日志:

$ docker logs -t test
2021-05-21T09:58:56.706680291Z internal/modules/cjs/loader.js:888
2021-05-21T09:58:56.706727664Z throw err;
2021-05-21T09:58:56.706735472Z ^
2021-05-21T09:58:56.706739801Z
2021-05-21T09:58:56.706743086Z Error: Cannot find module '/usr/src/app/node dist/main'
2021-05-21T09:58:56.706746265Z at Function.Module._resolveFilename (internal/modules/cjs/loader.js:885:15)
2021-05-21T09:58:56.706751604Z at Function.Module._load (internal/modules/cjs/loader.js:730:27)
2021-05-21T09:58:56.706755609Z at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
2021-05-21T09:58:56.706759645Z at internal/main/run_main_module.js:17:47 {
2021-05-21T09:58:56.706762133Z code: 'MODULE_NOT_FOUND',
2021-05-21T09:58:56.706764372Z requireStack: []
2021-05-21T09:58:56.706766508Z }
 

从日志中就清晰地看到原因了。

修正后成功运行的话,通过 docker ps 看到正常运行的容器了。

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
743cb8b9d604 wayou/my-app "docker-entrypoint.s…" 5 seconds ago Up 3 seconds 0.0.0.0:8000->3000/tcp, :::8000->3000/tcp test
 

镜像及容器的清除

调试过程难免会生成很多无用的测试数据,可通过如下命令进行清除。

单个清除

通过各自对应的 rm 命令来完成。

镜像的删除

$ docker image rm [OPTIONS] IMAGE [IMAGE...]
 

容器的删除

$  docker rm [OPTIONS] CONTAINER [CONTAINER...] 
 

批量清除

也可通过 docker container prune 将全部容器清除掉。

进入容器内

通过如下命令可在容器中开启一个 shell,在 shell 中可查看其中的文件等。

$ docker exec -it <container id> /bin/bash
 

相关资源

The text was updated successfully, but these errors were encountered:

使用 Docker 部署 Node 应用的更多相关文章

  1. 使用 Docker 部署 Node 应用 - 镜像文件尺寸的优化

    前面 使用 Docker 部署 Node 应用 一文中完成了镜像的创建和运行,不过生成的镜像还有些粗糙,需要进一步优化. 镜像的优化 通过 docker images 看到简单的一个 node 服务端 ...

  2. docker部署node.js

    1.dockerfile FROM node:14.16.0 RUN mkdir -p /var/log/lily/ RUN mkdir -p /opt/node # 工作目录 WORKDIR /op ...

  3. docker部署nodejs项目应用

    之前笔者弄了一套nestjs项目放在自己服务器上,并用pm2管理进程. 现在要把pm2停止,尝试一下用docker容器,那么首先要安装docker 一.安装docker 由于笔者服务器的系统是cent ...

  4. Docker部署Elasticsearch集群

    http://blog.sina.com.cn/s/blog_8ea8e9d50102wwik.html Docker部署Elasticsearch集群 参考文档: https://hub.docke ...

  5. docker 部署cassandra

    摘要 本文主要介绍在redhat7 平台,利用docker 部署cassandra 集群,除了介绍基本的部署步骤,另外主要 讨论类似于cassandra 这种分布式集群系统部署 docker如何进行网 ...

  6. 【原创】运维基础之Docker(2)通过docker部署zookeeper nginx tomcat redis kibana/elasticsearch/logstash mysql kafka mesos/marathon

    通过docker可以从头开始构建集群,也可以将现有集群(配置以及数据)平滑的迁移到docker部署: 1 docker部署zookeeper # usermod -G docker zookeeper ...

  7. 一步步学会用docker部署应用(nodejs版)

    一步步学会用docker部署应用 docker是一种虚拟化技术,可以在内核层隔离资源.因此对于上层应用而言,采用docker技术可以达到类似于虚拟机的沙盒环境.这大大简化了应用部署,让运维人员无需陷入 ...

  8. 教你使用docker部署淘宝rap2服务

    什么是rap2 先来说说起因,在上一个星期的分享会上,谈到前后端联调上,有同事提到了rap2,特意去了解了一下,觉得使用这个东西来进行前后端的接口联调来真是太方便了,对比我们之前公司内部开发的API ...

  9. 【Docker江湖】之docker部署与理解

    转载请注明出处:http://blog.csdn.net/gamer_gyt 博主微博:http://weibo.com/234654758 Github:https://github.com/thi ...

随机推荐

  1. spring泛型注入

    泛型依赖注入 Spring 4.0版本中更新了很多新功能,其中比较重要的一个就是对带泛型的Bean进行依赖注入的支持. 泛型依赖注入允许我们在使用spring进行依赖注入的同时,利用泛型的优点对代码进 ...

  2. Day008 下标越界及小结

    数组的四个基本特点 其长度是确定的.数组一旦被创建,它的大小就是不可以改变的. 其元素必须是相同类型,不允许出现混合类型. 数组中的元素可以是任何数据类型,包括基本类型和引用类型. 数组变量属于引用类 ...

  3. Day003 数据类型拓展

    数据类型拓展 整数拓展 进制 ​ 通常我们使用的都是10进制的整数,java中可以表示不同进制的整数 进制 表示方法 二进制 0b 八进制 0 十进制 默认 十六进制 0x 看看下面这个例子吧 int ...

  4. 手写Spring MVC框架(一) 实现简易版mvc框架

    前言 前面几篇文章中,我们讲解了Spring MVC执⾏的⼤致原理及关键组件的源码解析,今天,我们来模仿它⼿写⾃⼰的mvc框架. 先梳理一下需要实现的功能点: tomcat加载配置文件web.xml: ...

  5. SQL Server 查看进程阻塞及处理

    修改或删除数据前先备份,先备份,先备份(重要事情说三遍)! 1.首先,查看线程,分析是否存在阻塞进程,blocked>0都是当前被阻塞的进程  SELECT * FROM sysprocesse ...

  6. CRM助力企业迎接数字化浪潮

    去年,国家发展改革委官网发布'数字化转型伙伴行动'倡议.倡议政府和社会各界联合起来,共同构建多元化的联合推荐机制,带动全行业数字化转型,构建数字化产业链,培育数字化生态,形成"数字引领.抗击 ...

  7. [Django框架之视图层]

    [Django框架之视图层] 视图层 Django视图层, 视图就是Django项目下的views.py文件,它的内部是一系列的函数或者是类,用来专门处理客户端访问请求后处理请求并且返回相应的数据,相 ...

  8. 使用gulp搭建项目

    项目源码地址 前期准备工作 首先确保本机安装了 node gulp中文文档 安装 gulp 命令行工具 npm install --global gulp-cli 在项目目录下创建 package.j ...

  9. vmware安装ubuntu ,一直处于end kernel panic - not syncing : corrupted stack end detected inside scheduler

    vmware安装ubuntu ,一直处于end kernel panic - not syncing : corrupted stack end detected inside scheduler y ...

  10. Linux上使用iSCSI概述

    iSCSI简介 1. scsi和iscsi SCSI技术是存储设备最基本的标准协议,通常需要设备互相靠近并用SCSI总线连接,因此受到物理环境的限制 iSCSI(Internet Small Comp ...