从零定制Docker镜像:基于CentOS 7.9配置Yum源并部署Nginx

📅 2026/7/28 19:24:37 👁️ 阅读次数 📝 编程学习
从零定制Docker镜像:基于CentOS 7.9配置Yum源并部署Nginx

在实际容器化开发和运维工作中,我们经常遇到一个核心需求:如何将一个标准的操作系统镜像,快速定制成一个包含特定软件和配置的、可直接部署服务的应用镜像。很多初学者会直接进入容器内部,通过yum install安装软件,但这种方式创建的容器状态是临时的,无法复用。Docker 的核心优势在于通过 Dockerfile 实现构建过程的自动化与版本化,从而生成可重复、可移植的镜像。

本文将以一个典型的 Linux 服务部署场景为例,手把手带你完成从零定制一个简单 Docker 镜像的全过程。我们将以 CentOS 7.9 为基础镜像,目标是在镜像内配置一个可用的 Yum 软件仓库,并成功安装并部署一个常用服务(例如 Nginx)。通过这个实践,你将清晰理解 Dockerfile 的编写逻辑、镜像构建的步骤,以及如何验证容器内的服务状态。无论你是刚开始接触 Docker,还是希望巩固镜像定制的基本功,这篇文章都将提供一条可复现的路径。

1. 理解 Docker 镜像定制:从容器临时操作到 Dockerfile 固化

在深入操作之前,必须厘清一个关键概念:我们最终要交付的是一个“镜像”(Image),而不是一个手动配置好的“容器”(Container)。容器是镜像的运行实例,你可以进入一个运行中的容器,随意安装软件、修改配置,但这些改动只存在于当前这个容器实例的生命周期内。一旦容器被删除,所有改动都会丢失。

Dockerfile 是解决这个问题的核心。它是一个文本文件,包含了一系列的指令(Instruction),每一条指令都会在镜像构建过程中创建一个新的“层”(Layer)。这些指令层叠起来,最终形成一个完整的、只读的镜像。当你运行docker build命令时,Docker 引擎会逐行执行 Dockerfile 中的指令,并缓存每一层的结果。这种分层机制使得镜像构建高效且可复用。

对于我们的目标——在 CentOS 镜像中配置 Yum 源并安装服务,如果只在容器内操作,步骤大致是:

  1. 启动一个基础 CentOS 容器。
  2. 进入容器,备份旧的 Yum 源配置文件。
  3. 下载并替换为国内镜像源(如阿里云、清华源)以加速下载。
  4. 执行yum install -y nginx安装服务。
  5. 配置服务并启动。

而使用 Dockerfile,我们需要将这些手动步骤翻译成 Dockerfile 指令,例如RUNCOPYWORKDIR等,从而实现自动化构建。最终,我们通过docker build -t my-nginx:1.0 .这样的命令,就能生成一个名为my-nginx、标签为1.0的镜像。任何人拿到这个 Dockerfile 和构建命令,都能生成一模一样的镜像,这就是“基础设施即代码”思想在容器领域的体现。

2. 环境准备与项目初始化

在开始编写 Dockerfile 之前,需要确保你的开发环境已经就绪。我们将在一个干净的目录中完成所有工作。

2.1 宿主机环境要求与验证

首先,你需要一台安装了 Docker 的 Linux 或 macOS 机器,Windows 用户可以使用 WSL2 或 Docker Desktop。通过以下命令验证 Docker 是否已正确安装并运行:

# 检查 Docker 客户端和服务端版本 docker --version docker-compose --version # 如果用到 Compose # 更详细地查看 Docker 系统信息,确认服务状态 docker info # 运行一个测试容器,验证 Docker 引擎功能是否正常 docker run hello-world

如果hello-world容器能成功运行并输出欢迎信息,说明 Docker 环境基本正常。接下来,为我们的镜像定制项目创建一个独立的工作目录,这有助于管理构建上下文(Build Context)。

# 创建一个项目目录并进入 mkdir -p ~/projects/custom-centos-nginx && cd ~/projects/custom-centos-nginx

2.2 规划镜像内容与 Dockerfile 结构

在动手写 Dockerfile 之前,先明确我们要构建的镜像包含哪些内容:

  1. 基础镜像:选择centos:7.9.2009。选择特定版本而非centos:latest是生产环境的最佳实践,可以避免因基础镜像版本自动升级带来的不可预测行为。
  2. Yum 仓库配置:将 CentOS 默认的国外源替换为国内镜像源(如阿里云),以大幅提升软件包下载速度。
  3. 目标服务:安装并配置 Nginx,这是一个轻量级 Web 服务器,非常适合作为演示。
  4. 容器行为:定义当容器启动时,自动运行 Nginx。

对应的 Dockerfile 指令规划如下表:

步骤手动操作Dockerfile 指令目的与说明
1选择基础系统FROM centos:7.9.2009指定构建的起点
2配置 Yum 源RUN(执行命令备份和替换源文件)加速后续软件安装
3安装 NginxRUN yum install -y nginx安装主服务软件包
4暴露端口EXPOSE 80声明容器运行时监听的网络端口
5启动命令CMD ["nginx", "-g", "daemon off;"]定义容器启动时执行的默认命令

3. 编写 Dockerfile 定制镜像

现在,我们在项目目录中创建 Dockerfile 并逐步实现上述规划。

3.1 创建 Dockerfile 并指定基础镜像

使用文本编辑器(如 Vim、Nano 或 VS Code)创建名为Dockerfile的文件(注意没有后缀名)。

# Dockerfile # 使用官方 CentOS 7.9 特定版本作为基础镜像,确保环境一致性 FROM centos:7.9.2009 # 设置镜像的作者信息(元数据,非必需) LABEL maintainer="your-email@example.com"

FROM指令必须是 Dockerfile 的第一条有效指令(除了ARG)。它定义了构建过程的基础层。

3.2 配置国内 Yum 镜像源

CentOS 7 默认的 Yum 源速度可能较慢。我们将使用阿里云的镜像源进行替换。这一步需要在容器内执行 shell 命令,因此使用RUN指令。

# 配置 Yum 仓库为阿里云镜像,加速软件安装 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 \ && sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo \ && yum clean all \ && yum makecache

指令详解

  • RUN:在构建过程中,于当前镜像层之上执行命令并提交结果。每一条RUN都会创建一个新的镜像层。
  • &&:将多个命令串联在一个RUN指令中。这是一个重要的最佳实践。Docker 镜像的每一层都是只读的,减少RUN指令的数量可以有效减少镜像的层数,从而缩小最终镜像的体积。如果分多条RUN写,每条都会增加一层。
  • yum clean all && yum makecache:清理旧的缓存并生成新的元数据缓存,确保后续安装使用新的镜像源。

注意:网络搜索材料中提到了检查内核版本和下载 Yum 源,但那是在宿主机上安装 Docker 引擎的步骤,与我们在容器内配置 Yum 仓库是两件不同的事情,切勿混淆。本文的RUN指令是在构建镜像时,在未来的容器内部环境中执行的。

3.3 安装并初步配置 Nginx

配置好高速源后,安装 Nginx 就非常简单了。

# 安装 Nginx RUN yum install -y nginx # 可选:创建一个简单的自定义首页,替换 Nginx 默认页面 RUN echo '<h1>Hello, Docker! This is a custom CentOS with Nginx.</h1>' > /usr/share/nginx/html/index.html

第一个RUN使用yum install -y nginx安装软件包。-y参数表示自动确认安装,避免构建过程因等待用户输入而挂起。 第二个RUN创建了一个简单的 HTML 文件,覆盖 Nginx 的默认欢迎页,这样当我们访问容器时,能立刻看到定制化的内容,便于验证。

3.4 定义容器运行时行为

安装完成后,我们需要告诉 Docker 这个镜像运行时应该做什么。

# 声明容器运行时对外暴露的端口号 EXPOSE 80 # 设置容器启动时执行的默认命令 CMD ["nginx", "-g", "daemon off;"]

指令详解

  • EXPOSE 80:这是一个元数据指令,用于声明容器内的应用程序将监听 80 端口。它并不会自动在宿主机上打开端口映射,实际的端口映射需要在docker run时通过-p参数指定。
  • CMD ["nginx", "-g", "daemon off;"]:指定容器启动时的默认执行命令。这里以“前台进程”模式启动 Nginx(daemon off;)。这是关键点:Docker 容器需要有一个前台进程持续运行,如果进程退出,容器就会停止。Nginx 默认以守护进程(daemon)模式启动,会立即在后台运行并退出启动进程,这会导致 Docker 容器启动后立刻退出。使用-g "daemon off;"让 Nginx 保持在前台运行。

至此,一个完整的 Dockerfile 就编写完成了。完整内容如下:

# 定制 CentOS 7.9 并部署 Nginx 的 Dockerfile FROM centos:7.9.2009 LABEL maintainer="dev@example.com" # 1. 配置国内 Yum 源 (阿里云) 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 \ && sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo \ && yum clean all \ && yum makecache # 2. 安装 Nginx 并创建自定义首页 RUN yum install -y nginx \ && echo '<h1>Hello, Docker! This is a custom CentOS with Nginx.</h1>' > /usr/share/nginx/html/index.html # 3. 声明暴露端口和定义启动命令 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]

4. 构建镜像与运行验证

有了 Dockerfile,我们就可以将其构建成真正的 Docker 镜像,并运行容器进行验证。

4.1 执行镜像构建命令

在包含 Dockerfile 的项目目录 (~/projects/custom-centos-nginx) 下,执行构建命令:

# 构建镜像,-t 参数用于给镜像打标签,格式为 name:tag # 最后的 `.` 表示构建上下文为当前目录,Docker 引擎会将该目录下的所有文件发送给守护进程(因此不要放无关大文件) docker build -t my-centos-nginx:v1.0 .

命令执行后,Docker 守护进程会逐行解析 Dockerfile,下载基础镜像(如果本地没有),并执行每一层指令。你会看到类似下面的输出:

Sending build context to Docker daemon 2.048kB Step 1/5 : FROM centos:7.9.2009 7.9.2009: Pulling from library/centos Digest: sha256:... Status: Downloaded newer image for centos:7.9.2009 ---> a6d4c6c1a6ec Step 2/5 : LABEL maintainer="dev@example.com" ---> Running in abcd1234 ---> bcde2345 Step 3/5 : RUN mv /etc/yum.repos.d/CentOS-Base.repo ... && yum makecache ---> Running in cdef3456 ... Complete! ---> 7890abcd Step 4/5 : RUN yum install -y nginx ... ---> Running in defg4567 ... Installed: nginx.x86_64 1:1.20.1-9.el7 Complete! ---> 8901bcde Step 5/5 : CMD ["nginx", "-g", "daemon off;"] ---> Running in efgh5678 ---> 9012cdef Successfully built 9012cdef Successfully tagged my-centos-nginx:v1.0

构建成功后,使用docker images查看本地镜像列表,应该能看到新构建的my-centos-nginx镜像。

docker images | grep my-centos-nginx

4.2 运行容器并验证服务

现在,从我们自定义的镜像启动一个容器。

# 运行容器 # -d: 后台运行 # -p 8080:80: 将宿主机的 8080 端口映射到容器的 80 端口 # --name my-web: 给容器起一个名字,便于管理 docker run -d -p 8080:80 --name my-web my-centos-nginx:v1.0

运行后,可以通过以下命令检查容器状态:

# 查看正在运行的容器 docker ps # 应该能看到 my-web 容器状态为 Up # 查看容器日志,确认 Nginx 启动无报错 docker logs my-web

最关键的一步是验证服务是否可达。Nginx 正在容器内的 80 端口监听,我们通过宿主机的 8080 端口访问。

# 方法1:使用 curl 命令(如果宿主机有) curl http://localhost:8080 # 方法2:直接在浏览器中访问 http://<宿主机IP>:8080

如果一切正常,curl命令会返回我们之前写入的 HTML 内容:<h1>Hello, Docker! This is a custom CentOS with Nginx.</h1>。浏览器访问也会显示这个标题。

4.3 进入容器内部检查

为了更深入地验证我们的构建结果,可以进入运行中的容器内部,检查 Yum 源和已安装的软件。

# 使用 exec 命令在运行中的容器内启动一个交互式 shell docker exec -it my-web /bin/bash

进入容器后,执行以下检查命令:

# 检查 Yum 源是否已替换为阿里云 cat /etc/yum.repos.d/CentOS-Base.repo | grep -i aliyun # 检查 Nginx 是否已安装且版本正确 nginx -v # 检查 Nginx 服务进程 ps aux | grep nginx # 检查我们创建的自定义首页 cat /usr/share/nginx/html/index.html

完成检查后,输入exit退出容器。

5. 常见问题排查与优化实践

在构建和运行自定义镜像的过程中,你可能会遇到一些问题。下面列出一些典型场景及其解决方法。

5.1 构建阶段常见问题

问题现象可能原因检查与解决方式
docker build失败,提示Unable to find image ‘centos:7.9.2009’ locallyDocker 无法从配置的仓库拉取基础镜像。1. 检查网络连接。
2. 运行docker pull centos:7.9.2009手动拉取,看是否有更详细的错误信息。
3. 检查 Docker 守护进程是否运行 (systemctl status docker)。
docker buildRUN yum install步骤卡住或极慢。1. 容器内 Yum 源仍是国外源,网络慢。
2. Dockerfile 中配置国内源的命令执行失败。
1. 进入构建临时容器检查:在RUN指令前加RUN cat /etc/yum.repos.d/CentOS-Base.repo查看源文件内容。
2. 确保配置源的curl命令能成功下载.repo文件,网络搜索材料中提供的阿里云源地址是有效的。
构建成功,但镜像体积异常巨大。1. 每个RUN指令都产生一层,且未清理缓存。
2. 构建上下文 (.) 包含了大量不必要的文件。
1.合并 RUN 指令:将相关的yum installyum clean all等命令用&&连接在一个RUN中。
2.清理缓存:在安装命令最后加上&& yum clean all
3.使用.dockerignore文件:在项目根目录创建该文件,排除node_modules,.git, 日志等不参与构建的文件。
COPYADD指令失败(本文未使用,但常见)。要复制的文件在构建上下文中不存在。确保docker build命令最后的路径(构建上下文)包含了你要复制的文件。

5.2 运行阶段常见问题

问题现象可能原因检查与解决方式
容器启动后立即退出 (docker ps看不到)。最常见原因:容器内没有前台进程。例如,Nginx 以默认的守护进程模式启动后,主进程退出。1.docker logs my-web查看日志,通常无报错。
2. 确保 Dockerfile 的CMD是以前台模式启动应用,如 Nginx 使用nginx -g “daemon off;”
docker run时报错port is already allocated宿主机上 8080 端口已被其他程序占用。1. 更改映射端口,例如-p 8081:80
2. 在宿主机使用 `netstat -tlnp
访问http://localhost:8080连接被拒绝。1. 容器没有正常运行。
2. 端口映射错误。
3. 容器内防火墙或 SELinux 阻止(CentOS 镜像默认可能开启)。
1.docker ps确认容器状态为Up
2.docker port my-web查看容器的端口映射情况。
3. 在 Dockerfile 中安装服务后,可以尝试关闭防火墙:RUN yum install -y nginx && systemctl disable firewalld(仅用于学习环境,生产环境需谨慎)。
进入容器后无法使用systemctl命令。Docker 容器不是完整的操作系统,通常不运行 Systemd 这类初始化系统。在容器内直接使用服务的二进制命令启动,如nginx。这正是我们在CMD中直接调用nginx命令的原因。

5.3 镜像优化与生产环境建议

我们构建的镜像是一个可用的起点,但为了用于开发测试甚至生产环境,还需要考虑以下优化点:

  1. 使用更小的基础镜像centos:7.9.2009体积较大(约 200MB)。可以考虑使用alpine(仅 5MB)或debian:bullseye-slim等更精简的镜像作为基础,能显著减少镜像拉取时间和磁盘占用。但需要注意软件包管理命令(apkvsapt)和库的差异。
  2. 多阶段构建(Multi-stage Build):如果你的应用需要编译(如 Golang、Java),可以在一个大的“构建镜像”中完成编译,然后将编译好的二进制文件复制到一个干净的“运行镜像”中。这可以避免将编译工具、源代码等冗余文件打包进最终镜像。
  3. 非 root 用户运行:默认情况下,容器内的进程以 root 用户运行,存在安全风险。应在 Dockerfile 中创建并切换到一个非 root 用户来运行应用。
    RUN groupadd -r nginx-group && useradd -r -g nginx-group nginx-user USER nginx-user
  4. 健康检查(HEALTHCHECK):添加HEALTHCHECK指令,让 Docker 引擎能够判断容器内应用的健康状态,这对于编排工具(如 Kubernetes)非常重要。
    HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost/ || exit 1
  5. 环境变量与配置外置:不要将配置文件硬编码在镜像里。使用ENV指令定义环境变量,或通过docker run -e传入。对于配置文件,可以使用VOLUME指令挂载宿主机目录或配置卷,实现配置与镜像分离。

通过以上步骤,你不仅完成了一个从定制 Yum 源到安装服务的完整 Docker 镜像构建流程,还掌握了排查常见问题的方法和面向生产环境的优化思路。下次当你需要为一个简单的应用制作 Docker 镜像时,就可以遵循这个模式:明确需求、编写 Dockerfile、构建测试、优化调整。