首页/新闻资讯/正文详情

【Docker深入浅出】【四】单体应用容器化与Dockerfile怎么写

发布时间:2026/11/3 9:14:56 来源:云帆数科 栏目:资讯中心
【Docker深入浅出】【四】单体应用容器化与Dockerfile怎么写
文章目录一. 应用的容器化——简介二. 单体应用容器化1. 获取代码与分析Dockfile2. 容器化当前应用构建具体的镜像3推送镜像到仓库4. 运行应用程序5. 小结三. 生产环境中的多阶段构建四. 应用容器化命令本文介绍了如何容器化Docker化一个应用。介绍了Dockerfile基本的工作机制并用docker image build命令创建了一个新的镜像。镜像创建后基于该镜像启动了一个容器。多阶段构建提供了一种简单的方式能够构建更加精简的生产环境镜像。Dockerfile是一个将应用程序文档化的有力工具首先编写应用代码然后创建一个Dockerfile来定义这个应用最后使用docker image build命令构建镜像。一. 应用的容器化——简介完整的应用容器化过程主要分为以下几个步骤。创建Dockerfile其中包括当前应用的描述、依赖以及该如何运行这个应用。创建镜像对Dockerfile执行docker image build命令构建镜像应用容器化完成即应用被打包为一个Docker镜像​就能以镜像的形式交付并以容器的方式运行了。二. 单体应用容器化1. 获取代码与分析Dockfile代码地址https://github.com/nigelpoulton/psweb.git 。如下代码结构$ cd psweb $ ls-l total28-rw-r--r--1root root341Sep2916:26app.js-rw-r--r--1root root216Sep2916:26circle.yml-rw-r--r--1root root338Sep2916:26Dockerfile 。。。Dockerfile包含了对当前应用的描述并且能指导Docker完成镜像的构建。在Docker当中包含应用文件的目录通常被称为构建上下文Build Context​。通常将Dockerfile放到构建上下文的根目录下。有一点是必须的文件开头字母是大写D这里是一个单词。像“dockerfile”或者“Docker file”这种写法都是不允许的。$ cat Dockerfile FROM alpine# 以alpine镜像作为当前镜像基础LABEL maintainernigelpoultonhotmail.com# 维护者maintainerRUN apk add--update nodejs nodejs-npm# 安装Node.js和NPMCOPY./src# 将应用的代码复制到镜像当中设置新的工作目录安装依赖包WORKDIR/src RUN npm install EXPOSE8080# 网络端口ENTRYPOINT[node,./app.js]# 将app.js设置为默认运行的应用。Dockerfile主要包括两个用途描述当前应用指导Docker完成应用的容器化创建一个包含当前应用的镜像​Dockerfile能实现开发和部署两个过程的无缝切换、帮助新手快速熟悉这个项目。如下Dockerfile配置描述配置说明基础镜像层1. 每个Dockerfile文件第一行都是FROM指令。FROM指定的镜像会作为当前镜像的基础镜像层当前应用的剩余内容会作为新增镜像层添加到基础镜像层之上。2. 本例中的应用基于Linux操作系统所以在FROM指令当中引用Linux基础镜像label标签1. 一种描述信息沟通方式。每个标签是一个键值对Key-Value​在一个镜像当中可以通过增加标签的方式来为镜像添加自定义元数据。2. 通过标签LABEL方式指定了当前镜像的维护者为“nigelpoultonhotmail. com”​。安装镜像层1. RUN apk add --update nodejs npm 指令使用alpine的apk包管理器将nodejs和nodejs-npm安装到当前镜像之中。2. RUN指令会在FROM指定的alpine基础镜像之上新建一个镜像层来存储这些安装内容。工作目录Dockerfile通过WORKDIR指令为Dockerfile中尚未执行的指令设置工作目录。该目录与镜像相关并且会作为元数据记录到镜像配置中但不会创建新的镜像层。安装相关依赖1. run npm install指令会根据package.json中的配置信息使用npm来安装当前应用的相关依赖包。2. npm命令会在工作目录中执行并且在镜像中新建镜像层来保存相应的依赖文件。暴露端口通过EXPOSE 8080设置应用端口指定程序入口1. 通过ENTRYPOINT指令来指定当前镜像的入口程序。2. ENTRYPOINT指定的配置信息也是通过镜像元数据的形式保存下来而不是新增镜像层。如下产生了四个镜像2. 容器化当前应用构建具体的镜像如下命令会构建并生成一个名为web:latest的镜像。命令最后的点.表示Docker在进行构建的时候使用当前目录作为构建上下文。docker image build -t web:latest . [] Building 55.2s (10/10) FINISHED docker:desktop-linux [internal] load build definition from Dockerfile transferring dockerfile: 400B [internal] load metadata for docker.io/library/alpine:latest [internal] load .dockerignore transferring context: 2B CACHED [1/5] FROM docker.io/library/alpine:latest [internal] load build context transferring context: 7.65kB [2/5] RUN apk add --update nodejs npm curl [3/5] COPY . /src [4/5] WORKDIR /src [5/5] RUN npm install exporting to image exporting layers writing image sha256:673850491a21f99a0f063f9e69f6649ba5dcdc naming to docker.io/library/web:latest View build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/b80dnc9ketudf6y5nyoiob5vs命令执行结束后检查本地Docker镜像库是否包含了刚才构建的镜像。$ docker image ls REPO TAG IMAGE ID CREATED SIZE web latest fc69fdc4c18e 10 seconds ago 64.4MB恭喜应用容器化已经成功了可以通过docker image inspect web:latest来确认刚刚构建的镜像配置是否正确。3推送镜像到仓库Docker Hub是一个开放的公共镜像仓库服务并且这也是docker image push命令默认的推送地址。在推送镜像之前需要先使用Docker ID登录Docker Hub。除此之外还需要为待推送的镜像打上合适的标签。登录docker login Authenticatingwithexisting credentials...Login Succeeded# 或docker login Loginwith**your**Docker ID to pushandpull imagesfromDocker Hub...Username:nigelpoulton Password:Login SucceededDocker在镜像推送的过程中需要如下信息● Registry镜像仓库服务​● Repository镜像仓库​● Tag镜像标签​。当Registry和Tag不指定值时Docker会默认Registrydocker.io、Taglatest。但是Docker并没有给Repository提供默认值而是从被推送镜像中的REPOSITORY属性值获取。push执行docker image push命令会尝试将镜像推送到docker.io/web:latest中。二级命名空间gaoliang00这个用户并没有web这个镜像仓库的访问权限所以只能尝试推送到gaoliang00这个二级命名空间Namespace之下。因此需要使用这个ID为当前镜像重新打一个标签。额外的标签docker image tag web:latest gaoliang00/web:latest docker imagelistREPOSITORY TAG IMAGE ID CREATED SIZE gaoliang00/web latest 673850491a2117minutes ago94.9MB web latest 673850491a2117minutes ago94.9MB为镜像打标签命令的格式是docker image tag current-tag new-tag其作用是为指定的镜像添加一个额外的标签并且不需要覆盖已经存在的标签。docker image push gaoliang00/web Using default tag: latest The push refers to repository [docker.io/gaoliang00/web] 744f820bd5f4: Pushed 。。。 9110f7b5208f: Pushed latest: digest: sha256:4c822e80a71c328a1f2aeaf11221c6c724dca7bd88822da35bb9160925823f56 size: 13664. 运行应用程序从app.js这个文件内容中可以看出这其实就是一个在8080端口提供Web服务的应用程序。下面的命令会基于web:latest这个镜像启动一个名为c1的容器。docker container run -d --name c1 -p 81:8080 web:latest docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9d9b6776cbe9 web:latest node ./app.js About a minute ago Up About a minute 0.0.0.0:8888-8080/tcp c2 49ccc5e94a9a web:latest node ./app.js 3 minutes ago Up 3 minutes 0.0.0.0:81-8080/tcp c1这样应用程序已经容器化并成功运行了如果没有出现这样的界面尝试执行下面的检查来确认原因所在。使用docker container ls指令来确认容器已经启动并且正常运行。容器名称是c1并且从输出内容中能看到0.0.0.0:81-8080/tcp。确认防火墙或者其他网络安全设置没有阻止访问Docker主机的80端口。5. 小结1.如何区分命令是否会新建镜像层一个基本的原则是如果指令的作用是向镜像中增添新的文件或者程序那么这条指令就会新建镜像层如果只是告诉Docker如何完成构建或者如何运行应用程序那么就只会增加镜像的元数据。2.查看构建镜像过程中执行了哪些指令docker image history web:latest IMAGE CREATED BY SIZE fc6..18e/bin/sh-c#(nop) ENTRYPOINT [node ./a... 0B334.bf0/bin/sh-c#(nop) EXPOSE 8080/tcp 0Bb27..eae/bin/sh-c npm install14.1MB932.749/bin/sh-c#(nop) WORKDIR /src 0B052.2dc/bin/sh-c#(nop) COPY dir:2a6ed1703749e80... 22.5kBc1d..81f/bin/sh-c apk add--update nodejs nodejs-npm46.1MB336.b92/bin/sh-c#(nop) LABEL maintainernigelp... 0B3fd..f02/bin/sh-c#(nop) CMD [/bin/sh] 0B/bin/sh-c#(nop) ADD file:093f0723fa46f6c... 4.15MB可以观察到只有4条指令会新建镜像层就是那些SIZE列对应的数值不为零的指令其他指令只在镜像中新增了元数据信息。docker image inspect指令来确认确实只有4个层被创建了。docker image inspect web:latestSnip},RootFS:{Type:layers,Layers:[sha256:cd7100...1882bd56d263e02b6215,sha256:b3f88e...cae0e290980576e24885,sha256:3cfa21...cc819ef5e3246ec4fe16,sha256:4408b4...d52c731ba0b205392567]},3.了解镜像构建的过程运行临时容器在该容器中运行Dockerfile中的指令将指令运行结果保存为一个新的镜像层删除临时容器。 Step3/8:RUN apk add--update nodejs nodejs-npm---Runningine690ddca785fRun inside of temp container fetch http://dl-cdn...APKINDEX.tar.gz fetch http://dl-cdn...APKINDEX.tar.gz(1/10)Installing ca-certificates(20171114-r0)SnipOK:61MiBin21packages---c1d31d36b81fCreate new layer Removing intermediate containerRemove temp container Step4/8:COPY./src三. 生产环境中的多阶段构建在传统的 Docker 构建中你可能会将所有构建依赖和工具保留在最终镜像中。这通常会导致镜像体积较大。多阶段构建允许你在多个阶段中进行构建最终只将所需的部分复制到最终镜像中。这可以显著减少镜像的体积。多阶段构建方式使用一个Dockerfile其中包含多个FROM指令。每一个FROM指令都是一个新的构建阶段Build Stage并且可以方便地复制之前阶段的构件。使用仓库如下来举例说明https://github.com/david-gao1/atsea-sample-shop-app/blob/master/app/DockerfileFROM node:latest AS storefront WORKDIR/usr/src/atsea/app/react-app COPY react-app.RUN npm install RUN npm run build FROM maven:latest AS appserver WORKDIR/usr/src/atsea COPY pom.xml.RUN mvn-B-f pom.xml-s/usr/share/maven/ref/settings-docker.xml dependency \:resolve COPY..RUN mvn-B-s/usr/share/maven/ref/settings-docker.xml package-DskipTests FROM java:8-jdk-alpine AS production RUN adduser-Dh/home/gordon gordon WORKDIR/static COPY--fromstorefront/usr/src/atsea/app/react-app/build/.WORKDIR/app COPY--fromappserver/usr/src/atsea/target/AtSea-0.0.1-SNAPSHOT.jar.ENTRYPOINT[java,-jar,/app/AtSea-0.0.1-SNAPSHOT.jar]CMD[--spring.profiles.activepostgres]首先注意到Dockerfile中有3个FROM指令。每一个FROM指令构成一个单独的构建阶段。● 阶段0叫作storefront。● 阶段1叫作appserver。● 阶段2叫作production。storefront阶段拉取了大小超过600MB的node:latest镜像然后设置了工作目录复制一些应用代码进去然后使用2个RUN指令来执行npm操作。这会生成3个镜像层并显著增加镜像大小。appserver阶段拉取了大小超过700MB的maven:latest镜像。然后通过2个COPY指令和2个RUN指令生成了4个镜像层。production阶段拉取java:8-jdk-alpine镜像这个镜像大约150MB明显小于前两个构建阶段用到的node和maven镜像。这个阶段会创建一个用户设置工作目录从store front阶段生成的镜像中复制一些应用代码过来。之后设置一个不同的工作目录然后从appserver阶段生成的镜像中复制应用相关的代码。最后production设置当前应用程序为容器启动时的主程序。重点在于COPY --from指令它从之前的阶段构建的镜像中仅how复制生产环境相关的应用代码而不会复制生产环境不需要的构件。可见它明显比之前阶段拉取和生成的镜像要小。最终无须额外的脚本仅对一个单独的Dockerfile执行docker image build命令就创建了一个精简的生产环境镜像。多阶段构建是随Docker 17.05版本新增的一个特性用于构建精简的生产环境镜像。四. 应用容器化命令docker image build 。命令会读取Dockerfile并将应用程序容器化。使用-t参数为镜像打标签使用-f参数指定Dockerfile的路径和名称使用-f参数可以指定位于任意路径下的任意名称的Dockerfile。构建上下文是指应用文件存放的位置可能是本地Docker主机上的一个目录或一个远程的Git库。Dockerfile中的FROM指令用于指定要构建的镜像的基础镜像。它通常是Dockerfile中的第一条指令。Dockerfile中的RUN指令用于在镜像中执行命令这会创建新的镜像层。每个 RUN指令创建一个新的镜像层。Dockerfile中的COPY指令用于将文件作为一个新的层添加到镜像中。通常使用 COPY指令将应用代码赋值到镜像中。Dockerfile中的EXPOSE指令用于记录应用所使用的网络端口。Dockerfile中的ENTRYPOINT指令用于指定镜像以容器方式启动后默认运行的程序。其他的Dockerfile指令还有LABEL、ENV、ONBUILD、HEALTHCHECK、CMD等。

相关推荐

解决LTX-Best-Face-ID常见问题:从安装错误到人脸模糊的完整解决方案
解决LTX-Best-Face-ID常见问题:从安装错误到人脸模糊的完整解决方案

解决LTX-Best-Face-ID常见问题:从安装错误到人脸模糊的完整解决方案 LTX-Best-Face-ID是一款基于LTX-2.3模型的身份保留参考视频生成LoRA插件,它能通过一张参考照片和文本提示生成保持人物身份的视频。本文将针对使用过程中可能遇到的安装错误、人脸模糊… · 2026/11/3 9:14:56

AndroidGen-GLM-4-9B自定义扩展指南:打造专属Android智能助手
AndroidGen-GLM-4-9B自定义扩展指南:打造专属Android智能助手

AndroidGen-GLM-4-9B自定义扩展指南:打造专属Android智能助手 AndroidGen-GLM-4-9B是一款由智谱AI开发的强大Android智能生成模型,通过自定义扩展,开发者可以打造完全符合自身需求的Android智能助手。本文将详细介绍如何通过配置文件修改、令… · 2026/11/3 9:14:56

【python基础】类的继承、类导入、类的编写规范
【python基础】类的继承、类导入、类的编写规范

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 9:13:55

【大数据框架】Calcite 基础概念:从 SQL 到执行计划的思维路径
【大数据框架】Calcite 基础概念:从 SQL 到执行计划的思维路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 9:51:56

Qwen3-Omni:多模态AI实时交互全攻略
Qwen3-Omni:多模态AI实时交互全攻略

Qwen3-Omni:多模态AI实时交互全攻略 导语 Qwen3-Omni-30B-A3B-Instruct正式发布,作为一款原生支持文本、图像、音视频输入并实时生成语音的多语言全模态模型,它标志着AI交互从单一模态向"感知-理解-响应"全链路智能化的跨越。 行… · 2026/11/3 9:51:56

三环境测试全覆盖:OpenRouter ai-sdk-provider Node、Edge与E2E测试体系解析
三环境测试全覆盖:OpenRouter ai-sdk-provider Node、Edge与E2E测试体系解析

【免费下载链接】ai-sdk-provider The OpenRouter provider for the Vercel AI SDK contains support for hundreds of models through the OpenRouter chat and completion APIs. 项目地址: https://gitcode.com/gh_mirrors/ai/ai-sdk-provider 点击查看 免费下载 … · 2026/11/3 9:51:56

RLPR-Qwen2.5:无验证器也能玩转推理?
RLPR-Qwen2.5:无验证器也能玩转推理?

RLPR-Qwen2.5:无验证器也能玩转推理? 导语:OpenBMB团队推出基于Qwen2.5-7B-Base优化的RLPR-Qwen2.5-7B-Base模型,采用创新的RLPR框架,无需外部验证器即可提升大模型推理能力,为通用领域推理任务提供新范式。… · 2026/11/3 9:51:56

Folia PWA 手机端安装指南:3 步装好歌词动画播放器
Folia PWA 手机端安装指南:3 步装好歌词动画播放器

Folia PWA 手机端安装指南:3 步装好歌词动画播放器 【免费下载链接】folia-major 专注于绚丽的歌词动画效果的本地音乐/navidrome/第三方多平台在线音乐播放器 项目地址: https://gitcode.com/GitHub_Trending/fo/folia-major Folia 歌词动画播放器可以以 PW… · 2026/11/3 9:51:56

【44】苹果数据集(有v5/v8模型)/YOLO苹果检测
【44】苹果数据集(有v5/v8模型)/YOLO苹果检测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 9:50:51

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46

STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码