Docker镜像定制实战:从Dockerfile编写到Nginx服务部署

发布时间:2026/7/25 2:02:35
Docker镜像定制实战:从Dockerfile编写到Nginx服务部署 在容器化部署的实践中我们常常会遇到一个核心需求如何将一个标准的操作系统镜像快速定制成符合我们业务需求的专属镜像并在其中部署和配置服务。很多新手在初次接触 Docker 时会止步于拉取和使用官方镜像一旦需要修改内部环境比如安装特定软件、配置Yum源就感到无从下手要么选择进入容器手动操作但容器重启后修改会丢失要么觉得编写 Dockerfile 过于复杂。本文将彻底解决这个问题手把手带你从零开始完成“定制镜像 - 配置容器内部环境 - 部署服务”的完整闭环。你将掌握如何通过 Dockerfile 构建一个包含自定义 Yum 仓库的 CentOS 镜像并在此镜像基础上在容器内成功部署一个 Nginx 服务。整个过程代码完整、步骤清晰你可以完全跟着操作一遍彻底理解 Docker 镜像定制的核心逻辑。1. 核心概念与目标拆解在开始动手之前我们需要明确几个关键概念和本次实战的最终目标。Docker 镜像是一个轻量级、可执行的独立软件包它包含运行某个软件所需的所有内容代码、运行时、库、环境变量和配置文件。你可以把它理解为一个应用程序的“模板”或“快照”。Docker 容器是镜像的运行实例。当你运行一个镜像时你就创建了一个容器。容器是隔离的、资源可控的进程空间。我们通常说的“进入容器操作”指的是在一个正在运行的容器实例内部进行操作。Dockerfile是一个文本文件里面包含了一条条的指令每一条指令构建镜像的一层。Docker 通过读取 Dockerfile 中的指令来自动构建镜像。它是实现镜像定制化、自动化的核心。Yum 仓库是 CentOS/RedHat 系列 Linux 发行版中用于软件包管理的源。在容器内默认的仓库可能无法访问或速度慢配置一个本地或国内的镜像仓库是提升构建速度和确保软件包可用的关键。本次实战目标定制简单镜像编写一个 Dockerfile从官方 CentOS 镜像开始定制我们自己的基础镜像。为容器配置 Yum 仓库在定制镜像的过程中将默认的 Yum 源替换为国内高速镜像源如阿里云镜像源确保后续安装软件的速度和稳定性。容器内安装部署服务在基于定制镜像启动的容器内安装并配置一个 Nginx Web 服务器验证服务部署成功。最终我们将得到一个名为mycentos:nginx的自定义镜像运行它即可直接启动一个提供了 Nginx 服务的容器。2. 环境准备与项目结构在开始编写代码前请确保你的实验环境已就绪。2.1 基础环境要求操作系统任何支持 Docker 的 Linux 发行版如 Ubuntu 20.04 CentOS 7、macOS 或 Windows 10/11需安装 WSL2。本文以 Linux 环境为例进行演示。Docker 引擎已安装并启动 Docker Daemon。你可以通过运行docker --version和systemctl status dockerLinux来验证。网络连接需要能够访问互联网以下载基础镜像和软件包。2.2 创建项目目录为了保持工作区整洁我们创建一个专属目录来存放所有相关文件。mkdir -p ~/docker-custom-image cd ~/docker-custom-image2.3 项目最终文件结构预览在开始前我们先了解最终会生成哪些文件~/docker-custom-image/ ├── Dockerfile # 镜像构建的蓝图 ├── nginx.conf # 可选自定义的 Nginx 配置文件 └── README.md # 可选项目说明我们主要操作的文件是Dockerfile。3. 编写 Dockerfile定制镜像与配置 Yum 仓库这是整个流程的核心。我们将通过一个 Dockerfile 完成所有步骤。3.1 创建并编辑 Dockerfilevim Dockerfile或者使用你喜欢的文本编辑器如nano,vscode。3.2 Dockerfile 内容详解将以下内容完整复制到 Dockerfile 中每一行都有详细注释。# 第一行指定基础镜像。我们使用 CentOS 7 的官方镜像作为起点。 # 使用特定版本标签而非 latest可以确保构建环境的一致性。 FROM centos:7.9.2009 # 作者信息元数据非必需 LABEL maintaineryour-emailexample.com # 第一步配置 Yum 仓库为国内阿里云镜像加速软件安装。 # 1. 备份原有的仓库配置文件一个好习惯 RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup # 2. 下载阿里云的 CentOS 7 仓库配置文件 RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo # 3. 清理旧的缓存并生成新缓存 RUN yum clean all yum makecache # 第二步安装必要的系统工具和 Nginx。 # -y 参数表示自动确认安装避免构建过程因交互提示而中断。 RUN yum install -y wget vim net-tools nginx # 第三步配置 Nginx 服务一个简单的自定义示例。 # 创建一个简单的自定义首页覆盖 Nginx 默认首页。 RUN echo h1Hello, Docker Custom Image!/h1pThis Nginx is running inside a container built from a custom image./p /usr/share/nginx/html/index.html # 第四步暴露 Nginx 默认的 HTTP 端口 80。 # 这只是一个声明告诉用户这个镜像中的应用程序会使用哪些端口。 EXPOSE 80 # 第五步设置容器启动时自动执行的命令。 # 使用 nginx -g daemon off; 在前台运行 Nginx这是容器化应用的最佳实践。 # 容器需要有一个前台进程持续运行否则它会认为任务结束而自动退出。 CMD [nginx, -g, daemon off;]关键指令解析FROM: 所有 Dockerfile 都必须以FROM指令开始。它指定了构建新镜像所基于的父镜像。RUN: 在镜像构建过程中执行命令。每一条RUN指令都会在当前镜像顶部创建一个新的层。我们通过多条RUN命令完成了换源、安装、配置等操作。EXPOSE: 声明运行时容器提供服务的端口。这只是一个元数据方便使用者了解实际的端口映射需要在docker run时通过-p参数指定。CMD: 指定容器启动时默认执行的命令。一个 Dockerfile 中只能有一条CMD指令如果有多条则只有最后一条生效。这里我们让 Nginx 在前台运行。4. 构建自定义镜像有了 Dockerfile我们就可以使用docker build命令来构建镜像。4.1 执行构建命令在Dockerfile所在的目录~/docker-custom-image下运行docker build -t mycentos:nginx .命令参数解释docker build: 构建镜像的命令。-t mycentos:nginx:-t参数用于给镜像打标签Tag。格式为name:tag。这里我们将镜像命名为mycentos标签为nginx。.: 这个点.表示当前目录是构建上下文Build Context。Docker 守护进程会将当前目录下的所有文件除非被.dockerignore排除发送给 Docker 引擎用于构建。它也是 Dockerfile 所在的位置。4.2 观察构建过程执行命令后Docker 会逐行执行 Dockerfile 中的指令。你会看到类似下面的输出Sending build context to Docker daemon 2.048kB Step 1/9 : FROM centos:7.9.2009 7.9.2009: Pulling from library/centos Digest: sha256:... Status: Downloaded newer image for centos:7.9.2009 --- 8652b9f0cb4c Step 2/9 : LABEL maintaineryour-emailexample.com --- Running in abc123def456 --- 8e7f1a2b3c4d Step 3/9 : RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup --- Running in def456abc123 --- 5a6b7c8d9e0f ... Step 8/9 : EXPOSE 80 --- Running in 789012ghi345 --- bcde456fgh789 Step 9/9 : CMD [nginx, -g, daemon off;] --- Running in 234567jkl890 --- 1234567890ab Successfully built 1234567890ab Successfully tagged mycentos:nginx每一行Step对应 Dockerfile 中的一条指令或一个层。--- Running in ...表示在一个临时容器中执行该指令--- ...后面的一串字符是执行后生成的新镜像层的 ID。最后两行表示构建成功并打上了我们指定的标签。4.3 验证镜像是否创建成功构建完成后使用docker images命令查看本地镜像列表docker images | grep mycentos你应该能看到类似下面的输出REPOSITORY TAG IMAGE ID CREATED SIZE mycentos nginx 1234567890ab 2 minutes ago 450MB至此我们的自定义镜像mycentos:nginx已经构建完成。它包含了 CentOS 7.9 系统、配置好的阿里云 Yum 源、安装好的 Nginx 以及我们自定义的首页。5. 运行容器并验证服务部署镜像只是静态的模板我们需要运行它来创建容器并验证 Nginx 服务是否成功部署。5.1 基于自定义镜像运行容器docker run -d --name my-nginx-container -p 8080:80 mycentos:nginx命令参数解释docker run: 运行容器的命令。-d: 让容器在后台运行Detached mode。--name my-nginx-container: 给容器起一个名字方便后续管理如停止、查看日志。-p 8080:80: 端口映射。将宿主机的8080端口映射到容器的80端口。这样我们通过访问宿主机的8080端口就能访问容器内的 Nginx 服务。mycentos:nginx: 指定用于创建容器的镜像名称和标签。5.2 检查容器运行状态docker ps你应该能看到一个名为my-nginx-container的容器正在运行状态为Up并且端口映射为0.0.0.0:8080-80/tcp。5.3 验证 Nginx 服务现在Nginx 服务已经在容器内运行。我们可以通过几种方式验证方式一在宿主机上使用curl命令访问curl http://localhost:8080如果一切正常你将看到我们之前在 Dockerfile 中写入的 HTML 内容h1Hello, Docker Custom Image!/h1pThis Nginx is running inside a container built from a custom image./p方式二通过浏览器访问打开你的浏览器输入地址http://你的宿主机IP:8080。如果你的宿主机就是本地机器可以直接访问http://localhost:8080。你应该能看到显示 “Hello, Docker Custom Image!” 的简单页面。方式三进入容器内部查看我们也可以进入容器内部确认服务进程和配置。# 进入正在运行的容器 docker exec -it my-nginx-container /bin/bash # 进入容器后检查 Nginx 进程 ps aux | grep nginx # 输出应包含 nginx master 和 worker 进程 # 检查我们创建的首页文件 cat /usr/share/nginx/html/index.html # 检查 Yum 仓库配置是否已更换为阿里云源 cat /etc/yum.repos.d/CentOS-Base.repo | head -5 # 输出中应包含 mirrors.aliyun.com # 退出容器 exit5.4 查看容器日志如果服务没有如期运行查看容器日志是首要的排查手段。docker logs my-nginx-container这将输出容器内 Nginx 服务的标准输出和错误日志对于排查启动问题非常有用。6. 深入理解镜像分层与构建优化通过上面的实践我们已经成功完成了目标。但为了写出更高效、更专业的 Dockerfile我们需要理解背后的原理。6.1 镜像分层LayeringDocker 镜像由一系列只读层Layer堆叠而成每一层代表 Dockerfile 中的一条指令。例如我们的Dockerfile创建了大约 9 层每条RUN、COPY、ADD等指令都会生成新层。优点共享与复用如果多个镜像基于同一基础层如centos:7.9.2009它们可以共享这一层节省磁盘空间。构建缓存Docker 会缓存已构建的层。当你修改 Dockerfile 并重新构建时只有发生变化的指令及其之后的指令会重新执行这大大加快了构建速度。查看镜像分层可以使用docker history mycentos:nginx命令查看镜像的构建历史和每层大小。6.2 Dockerfile 构建优化建议基于分层原理我们可以优化 Dockerfile合并 RUN 指令减少层数。将相关的RUN命令用连接并用\换行保持可读性。优化前RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo RUN yum clean all yum makecache RUN yum install -y wget vim net-tools nginx优化后RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup \ curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \ yum clean all \ yum makecache \ yum install -y wget vim net-tools nginx这样将 4 层合并为 1 层使镜像更紧凑。清理缓存在安装软件包的同一层中清理不必要的缓存文件减小镜像体积。在yum install后添加 yum clean all。对于apt-getDebian/Ubuntu使用 rm -rf /var/lib/apt/lists/*。使用.dockerignore文件在构建上下文目录中创建.dockerignore文件列出不需要发送给 Docker 守护进程的文件或目录如.git,node_modules, 日志文件等可以加速构建过程并避免将敏感文件意外打入镜像。选择合适的基础镜像如果对镜像大小极其敏感可以考虑使用alpine等更小的基础镜像但需要注意软件包管理和兼容性差异。7. 常见问题与排查思路在实际操作中你可能会遇到以下问题。这里提供排查思路。问题现象可能原因排查与解决思路docker build失败提示Unable to find image ‘centos:7.9.2009’ locallyDocker 无法从仓库拉取指定标签的基础镜像。1. 检查网络连接。2. 确认镜像标签是否存在可以访问 Docker Hub 网站查询。3. 尝试使用更通用的标签如centos:7。docker build过程中yum install失败提示Cannot retrieve metalink for repository: epel/x86_64或下载超时。Yum 仓库配置未生效或网络问题。1. 检查 Dockerfile 中配置 Yum 源的RUN指令是否执行成功查看构建日志。2. 进入构建失败的临时容器检查/etc/yum.repos.d/下的文件内容。3. 尝试在 Dockerfile 中使用其他国内镜像源如清华源、华为云源。docker run后容器立即退出docker ps看不到容器。容器内没有前台进程持续运行。1. 检查 Dockerfile 中的CMD或ENTRYPOINT指令是否正确。2. 使用docker logs 容器ID查看退出前的日志。3. 对于 Nginx确保使用nginx -g ‘daemon off;’在前台运行。4. 可以先用docker run -it mycentos:nginx /bin/bash交互式启动手动测试命令。宿主机访问localhost:8080连接被拒绝。端口映射失败或容器内服务未监听正确端口。1. 确认docker run时使用了-p 8080:80参数。2. 使用docker ps确认端口映射已建立 (0.0.0.0:8080-80/tcp)。3. 进入容器 (docker exec) 检查 Nginx 进程是否运行 (ps aux | grep nginx)。4. 在容器内使用curl localhost:80测试服务是否正常。镜像体积过大。构建过程中引入了不必要的文件或层数过多。1. 参考第6节优化 Dockerfile合并RUN指令并清理缓存。2. 使用多阶段构建multi-stage builds来分离构建环境和运行环境这是减少镜像体积的终极利器。如何修改已构建镜像的配置镜像一旦构建完成就是只读的。不要进入运行中的容器修改正确做法是1. 修改 Dockerfile。2. 重新执行docker build -t mycentos:nginx-v2 .构建新版本镜像。3. 停止旧容器用新镜像启动新容器。8. 进阶使用多阶段构建优化镜像对于更复杂的应用如需要编译的 Go、Java 程序多阶段构建是官方推荐的最佳实践。它允许你在一个 Dockerfile 中使用多个FROM语句每个FROM开始一个新的构建阶段。你可以将前一阶段的构建产物复制到后一阶段而丢弃不需要的中间文件和工具从而得到非常小的最终镜像。这里给出一个概念性示例展示如何为一个简单的 Go 应用构建极小的镜像# 第一阶段构建阶段 (builder)使用包含完整Go编译器的镜像 FROM golang:1.19-alpine AS builder WORKDIR /app COPY . . # 编译Go程序生成静态链接的可执行文件适合alpine环境 RUN go build -o myapp -ldflags -s -w main.go # 第二阶段运行阶段使用极小的基础镜像 FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ # 从上一阶段builder仅复制编译好的可执行文件不复制源代码和编译器 COPY --frombuilder /app/myapp . # 运行程序 CMD [./myapp]通过这种方式最终的生产镜像只包含运行程序必需的alpine系统和可执行文件myapp体积可能只有十几MB而构建阶段的中间产物编译器、源代码等完全不会出现在最终镜像中。9. 工程实践与总结通过本次从 Dockerfile 编写、镜像构建到容器运行的全流程实践你应该已经掌握了 Docker 镜像定制的核心技能。回顾一下关键点Dockerfile 是蓝图它是定义镜像构建过程的脚本务必精心编写。分层构建是核心机制理解镜像分层有助于优化构建速度和镜像大小。配置容器内部环境像配置 Yum 源这类操作必须在 Dockerfile 的RUN指令中完成以确保环境被固化到镜像里。服务前台运行容器内应用必须以前台模式运行否则容器会退出。端口映射是访问桥梁通过-p参数将容器端口映射到宿主机是实现外部访问的标准方式。迭代方式永远通过修改 Dockerfile 并重建镜像来更新应用而不是直接修改运行中的容器。将这套流程应用到你的实际项目中无论是部署一个 Python Flask 应用、一个 Java Spring Boot 的 JAR 包还是一个 Node.js 服务思路都是一致的——编写 Dockerfile定义基础环境、安装依赖、复制代码、配置服务、设置启动命令最后构建和运行。你可以尝试修改本次的 Dockerfile比如安装不同的软件如mysql,python3部署不同的服务如httpd,tomcat或者将你的应用程序代码通过COPY指令添加到镜像中。多动手实践几次你就能熟练地将任何应用容器化。