热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

打包指令_NodeJSDocker打包优化

最近NodeJS后端工程的Docker打包优化工作总算告一段落了。其实去年12月份就开始试点改造,期间遇到了很难复现的间歇性sockethangup问题,
3b29f79e288c5acf7d0c13546f5f10a6.png

最近 NodeJS 后端工程的 Docker 打包优化工作总算告一段落了。其实去年 12 月份就开始试点改造,期间遇到了很难复现的间歇性 socket hang up 问题,不得不延后。上周终于抽出时间全力排查了下,发现是升级 NodeJS 到 6.15.0 后,其有一个 HTTP Keep-alive 连接超时的 Bug。不得不感慨:这小版本升级也要格外小心啊。

回到正题。在确认没有其他附带问题后,在试点的基础上,又增加了一些新的目标。总的目标大概如下:

  • 支持优雅停机,要求 Node 进程能够接收到 SIGTERM 软终止信号
  • 提升打包速度,充分利用 Docker Layer 缓存机制,降低 yarn install、node_modules 拷贝等高 IO 动作的运行频率
  • 保证源代码安全,不要将源代码打包到镜像里
  • 尽可能降低最终镜像大小,不要包含不必要的文件(如 node_modules 中的 devDependencies)

下面从各个目标一一介绍下我们的优化实践之路。

基础镜像设置

由于之前的基础镜像使用的是 FROM node:6,只有 major version,没有指定 minor version、patch version。当该基础镜像 minor 或 patch 版本更新后,如果本地的镜像缓存也被清除了,那么打包就会使用新版本的基础镜像。这也是上面不经意升级到 node 6.15.0 的原因。所以这里我们限定了基础镜像的全版本:FROM node:6.16.0。

我们的产品主要在国内使用,运维人员也都是在国内。为了更方便查看日志中的时间、方便程序中的日期计算,把时区调整为北京时区(即东八区):RUN rm /etc/localtime && echo "Asia/Shanghai" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata。注意,Debian Stretch 版本后需要 rm /etc/localtime,否则时区修改可能无法生效(被替换回原值)。

最后设置镜像的工作目录:WORKDIR /app。这样,我们新的基础镜像就完成了。

支持优雅停机

优雅停机(Gracefully Shutdown),就是当应用(进程)要被关闭时,首先会被发送一个软终止信号。应用在收到这个信号后,执行清理工作,然后自行退出。如果在指定的时间内没有自行退出,则会被强制关闭——这自然就不优雅了。这个软终止信号一般就是指 SIGTERM。NodeJS 进程默认会对 SIGTERM 信号进行响应,执行进程退出。但是默认的监听程序并不会执行清理工作。我们需要显式监听该信号,并在清理完毕后执行 process.exit(0) 以退出进程。

然而,在 Docker 容器里实现优雅停机会有一些新的问题需要面对。当使用 docker stop 停止一个容器时,docker 会首先发送一个 SIGTERM 信号给容器内的 PID=1 进程,也就是常说的 init 进程。如果 PID=1 进程没有在规定时间(一般 10 秒)内退出,则 docker 会发送 SIGKILL 信号强制退出容器内的所有进程。PID=1 进程比较特殊,在 linux 下,它会忽略所有默认的信号监听程序,也就是说收到 SIGTERM 默认不会退出。所以,我们的 PID=1 进程要求能显式监听 SIGTERM 并执行后续动作。

然而,当我们使用 shell form 的 ENTRYPOINT 或 CMD 指令时——如 CMD npm run start,Docker 容器会默认启用一个 Shell 来运行后面的指令。此时 PID=1 进程是 /bin/sh,完整的运行命令是 /bin/sh -c 'npm run start'。当 sh 收到 SIGTERM 信号时,它自身并不会退出。因为 sh 并没有显式监听 SIGTERM,默认的信号处理器被忽略了。自然 sh 内部也不会把信号转发给子进程。最后只会超时,继而被 SIGKILL 强制关闭。

Docker 推荐我们用 exec form 的 ENTRYPOINT 或 CMD 指令,如 CMD ["npm



推荐阅读
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • Node.js详细安装及环境配置
    1、下载安装根据自己电脑系统及位数选择,我这里选择windows64位.msi格式安装包(官网:https:odejs.orgzh-cndownload).msi和.zip格式区别 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了[从头学数学]中第101节关于比例的相关问题的研究和修炼过程。主要内容包括[机器小伟]和[工程师阿伟]一起研究比例的相关问题,并给出了一个求比例的函数scale的实现。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
author-avatar
另一种Xing福_290
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有