作为一名开发者或DevOps工程师你一定经历过这样的场景Java应用要打包成Jar上传到Nexus再到服务器上用java -jar运行Node.js应用要打包成zip上传到服务器再npm install安装依赖Python应用要打包成tar还要确保服务器有正确的Python版本每种技术栈都有自己的制品格式、部署方式和环境要求管理起来简直是一场噩梦。而Docker的出现彻底改变了这一切。今天这篇文章我会带你初步了解Docker如何统一应用构建和部署流程并通过Node.js和Java的实际Dockerfile示例展示不同技术栈如何被Docker“收编”为同一种制品——Docker镜像。一、Docker带来的四大革命性改变1. 统一制品类型告别百花齐放在Docker之前每种技术栈都有自己的“专属制品”JavaJar/WarNode.jsZip/Tar外加package.jsonPythonEgg/Wheel/TarGo二进制可执行文件这意味着你需要为每种格式配置不同的制品仓库为每种格式编写不同的部署脚本为每种格式处理不同的环境依赖Docker之后一切皆镜像无论你用Java、Node.js、Python还是Go最终产出的都是Docker镜像。镜像包含了应用代码、依赖、运行时环境、配置文件——一切都在里面。你只需要一个支持Docker镜像的仓库如Docker Hub、Harbor就能管理所有应用的制品。2. 简化分发传输一个镜像搞定一切传统部署需要传输多个文件应用压缩包zip/tar依赖描述文件package.json、requirements.txt配置文件application.yml、.env启动脚本Docker将所有内容整合进镜像的文件系统只需要传输一个镜像。不再需要手动打包、解压、移动文件。3. 消除服务器环境依赖环境一致性成为现实传统部署最大的痛点环境不一致。开发环境Node版本18生产环境Node版本12本地能跑服务器跑不起来需要先安装Java、配置JAVA_HOME、安装Maven……Docker把依赖安装和运行环境都打包进镜像Node.js应用在镜像内执行npm installJava应用镜像内自带JREPython应用镜像内安装好所有pip包服务器只需要有Docker引擎不需要安装任何语言运行时。启动应用只需要一条命令docker run。4. 流程标准化让一切变得简单JavaScript生态的工具链尤其复杂Webpack、Grunt、Gulp、Rollup……构建方式五花八门。Docker帮助整合了这些流程“Docker让整合变得更容易因为你不再需要单独的zip文件和package.json你可以把所有事情都放在一个镜像里完成。”二、不同技术栈的Docker构建策略虽然Docker统一了最终制品但不同技术栈的构建过程仍有差异。Docker不会替代应用的原有构建步骤——你仍然需要JavaScript应用用Webpack做转译、压缩、混淆Java应用用Maven/Gradle构建出Jar包区别在于这些构建结果如何进入Docker镜像。1. Node.js应用源码进镜像内部装依赖Node.js应用的典型DockerfiledockerfileFROM node:13-alpine # 创建工作目录 RUN mkdir -p /usr/app # 复制依赖配置文件 COPY package*.json /usr/app/ # 复制应用代码 COPY app/* /usr/app/ # 设置工作目录 WORKDIR /usr/app # 在镜像内安装依赖 RUN npm install # 启动命令 CMD [node, server.js]特点直接复制源代码进镜像在镜像内部执行npm install安装依赖不需要提前打包成zip/tar所有依赖都成为镜像的一部分2. Java应用先构建Jar再进镜像Java应用的典型DockerfiledockerfileFROM openjdk:8-jre-alpine # 声明暴露端口 EXPOSE 8080 # 复制已构建好的Jar包 COPY ./build/libs/java-app-1.0-SNAPSHOT.jar /usr/app/ # 设置工作目录 WORKDIR /usr/app # 启动命令 ENTRYPOINT [java, -jar, java-app-1.0-SNAPSHOT.jar]特点必须先在镜像外用Maven/Gradle构建出Jar包只复制构建好的Jar包进镜像不复制源代码不需要在镜像内安装依赖依赖已在Jar包中镜像更轻量构建更快为什么有这种差异这是由两种技术栈的特性决定的Node.js依赖在运行时解析需要node_modules目录Java依赖已打包进Jar运行时不需要额外安装Docker尊重这种差异但提供了统一的交付物——镜像。三、Dockerfile核心指令解读指令作用示例FROM指定基础镜像FROM node:13-alpineRUN在构建时执行命令RUN npm installCOPY复制文件到镜像COPY app/* /usr/app/WORKDIR设置工作目录WORKDIR /usr/appCMD容器启动命令可被覆盖CMD [node, server.js]ENTRYPOINT容器入口命令不可被覆盖ENTRYPOINT [java, -jar, app.jar]EXPOSE声明容器暴露端口EXPOSE 8080注意CMD和ENTRYPOINT的区别ENTRYPOINT定义固定的启动命令CMD提供默认参数可以被docker run后面的命令覆盖四、Docker如何简化应用发布全流程传统流程以Node.js为例开发代码用Webpack构建转译、压缩打包成zip包含代码和package.json上传zip到服务器在服务器解压在服务器执行npm install安装依赖配置环境变量用pm2或node启动确保Node版本正确Docker化后的流程开发代码用Webpack构建转译、压缩编写Dockerfile构建Docker镜像包含所有步骤推送镜像到仓库在服务器拉取镜像运行容器第4步“构建镜像”已经包含了复制代码安装依赖配置环境第7步“运行容器”已经包含了使用正确的运行时应用启动命令服务器上只需要有Docker不需要Node、不需要npm、不需要配置环境变量。五、总结Docker的核心价值维度传统方式Docker方式制品类型Jar/War/Zip/Tar……Docker镜像制品仓库Nexus/Artifactory多种格式Harbor/Docker Hub单一格式服务器环境需安装Java/Node/Python等只需安装Docker依赖安装在服务器执行在镜像构建时执行配置管理环境变量、配置文件分开管理可整合进镜像或运行时注入启动命令各种不同命令docker runDocker镜像本身就是一种制品是所有其他制品类型的替代品。不管你用什么技术开发应用都可以统一使用Docker镜像作为通用制品整合所有应用的分发流程。后续的Docker模块我们会详细讲解Dockerfile语法和镜像构建流程带你深入掌握这项革命性技术。