Linux中自定义镜像的制作讲解

一、自定义镜像docker commit

1.1 镜像构建原因

在现代软件开发和运维中,Docker 已成为一种非常流行的工具,它通过容器化应用程序来简化部署过程。

然而,默认的官方镜像往往只能满足基础需求,无法涵盖所有特定项目的具体要求。因此,构建自己的 Docker 镜像是非常必要的。

你负责维护一个线上服务,使用的是基于 nginx 的镜像,运行着一个前端静态站点,并配置了复杂的 Nginx 路由、HTTPS 证书和访问控制策略。

现在公司要进行一次 灾备演练,要求你在不依赖线上环境的情况下,在测试集群中快速还原出一个“与生产几乎一致”的服务实例,用于模拟故障切换。

在某些场景下,确实不需要构建镜像

尤其是满足以下条件时:

  • 所有配置文件都通过 volume 挂载

  • 应用数据也通过 volume 存储

  • 容器本身只是运行时环境,没有额外的修改

镜像存在的意义,是在什么情况下不可替代?

你负责一个部署内部服务,该服务基于 nginx:1.21-alpine 运行,但为了满足公司安全合规要求,你需要:

  • 在容器中安装审计工具(如 auditd, syslog, osquery

  • 修改默认 root 用户为非 root 用户

  • 设置 SELinux 或 AppArmor 策略

  • 删除一些不必要的系统命令(如 telnet, nc, tcpdump

  • 强化日志输出格式并集成到统一日志平台

这些操作不能通过 volume 实现,因为它们涉及到:

  • 容器内系统组件的变更

  • 用户权限、安全策略等底层设置

  • 系统二进制文件的删除或替换

完成这些操作后,希望把当前容器的状态保存下来,用于后续所有节点统一部署。

原因说明
系统级改动无法通过 volume 实现修改用户、删除命令、安装系统组件等只能在镜像层完成
安全加固要求可复制、可验证你不能让每个节点手动执行一遍加固脚本,必须统一标准
合规性要求可追溯构建镜像可以打标签、记录作者和时间,方便审计和版本管理

镜像 vs Volume 的适用场景对比表

场景是否需要构建镜像使用 Volume 是否足够
修改系统组件(如安装包、删命令)必须构建镜像不够
用户权限、安全策略调整必须构建镜像不够
日志配置、访问控制等应用级配置可以用 volume足够
数据持久化、网站静态资源可以用 volume足够
安全合规、标准化部署必须构建镜像不够

Volume 是用来存放“可变的业务数据”,而镜像则是用来固化“不变的运行环境”。

构建 Docker 镜像的方式

编号构建方式说明
1docker commit(容器提交)基于运行中的容器状态生成镜像
2Dockerfile + docker build通过编写 Dockerfile 文件定义镜像内容,并使用 docker build 构建

1.2 docker commit

docker commit 是一个用于将容器的当前状态保存为新镜像的命令。

这种方法非常适合快速测试或对现有镜像进行小范围的修改。

然而,它不推荐用于复杂的或需要长期维护的应用场景,因为它的透明度较低、不可重复性高,并且难以版本控制和团队协作。

1.3 自定义 HTTP 镜像

在 CentOS 7 容器中安装 httpd,并提交为新镜像 my-httpd-image

启动容器并进入交互式 shell

docker run -it --name my-httpd-container centos:7 /bin/bash

这会创建一个名为 my-httpd-container 的容器,并进入它的 bash 环境。

在容器内安装 httpd

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 httpd

退出容器

exit

提交容器为新镜像

docker commit [容器名] 镜像名:[版本号]

1.4 自定义 Nginx 镜像

在 CentOS 7 容器中安装 nginx,并提交为新镜像 my-nginx-image

启动容器并进入交互式 shell

docker run -it --name v1 yum:1.0 /bin/bash

添加 EPEL 仓库并安装 nginx

CentOS 7 默认仓库中没有 nginx,需要先添加 EPEL 仓库:

yum install -y epel-release
yum install -y nginx

修改默认页面

同样地,可以修改默认首页内容:

echo "Hello from Nginx in Docker" > /usr/share/nginx/html/index.html

提交容器为新镜像

docker commit v1 mynginx:1.0

二、自定义镜像dockerfile

2.1 基础知识

Dockerfile 是一个文本文件,包含了一系列用于构建 Docker 镜像的 指令(Instructions)。

它类似于 shell 脚本,但不是直接运行命令,而是告诉 Docker 如何一步步构建出一个定制化的镜像。

一个完整的 Dockerfile 通常包含以下几个部分:

  1. 基础镜像

  2. 元数据信息

  3. 安装与配置

  4. 工作目录设置

  5. 文件复制

  6. 环境变量设置

  7. 端口暴露

  8. 启动命令

  9. 入口点

  10. 其他高级指令

2.2 指令详解

FROM —— 指定基础镜像

作用:指定当前镜像构建所依赖的基础镜像。

格式

FROM <image>:[版本号]

说明

必须是 Dockerfile 中的第一个有效指令(除非是多阶段构建)。

可以选择官方镜像(如 nginx, python, alpine)或你自己定义的镜像。

示例

FROM ubuntu:20.04
FROM centos:7

LABEL —— 添加元数据标签

作用:为镜像添加描述性信息,比如作者、版本等。 格式

LABEL <key>=<value> ...

说明

替代已废弃的 MAINTAINER 指令。

可以多次使用,也可以一次写多个键值对。

示例

LABEL maintainer="john@example.com" \					所属者
      version="1.0" \									版本
      description="This is a custom Nginx image"		描述这个镜像是用来做什么的
RUN —— 构建时执行命令

作用:在构建过程中执行命令,通常用于安装软件包等操作。

格式

Shell 形式(隐式调用 /bin/sh -c):

RUN command arg1 arg2

Exec 形式(推荐):

RUN ["command", "arg1", "arg2"]

说明

每个 RUN 指令都会生成一个新的镜像层(layer)。

建议将多个命令合并到一行中,减少层数。

示例

RUN yum update && \
    yum install -y nginx

WORKDIR —— 设置工作目录

作用:设置后续指令(如 COPY, ADD, CMD, ENTRYPOINT)的工作目录。

格式

WORKDIR /path/to/workdir

说明

如果目录不存在,会自动创建。

推荐使用绝对路径。

示例

WORKDIR /app

COPYADD —— 复制文件到镜像中

COPY

作用:从本地主机复制文件/目录到镜像中。

优点:简单、安全、推荐使用。

格式

COPY <src>... <dest>

示例

COPY ./index.html /usr/share/nginx/html/index.html

ADD

作用:功能类似 COPY,但还能自动解压 tar 文件、支持远程 URL 下载。

示例

ADD app.tar.gz /opt/app/
ADD https://example.com/file.txt /tmp/

推荐:优先使用 COPY,只有必要时才用 ADD

ENV —— 设置环境变量

作用:设置容器内使用的环境变量。

格式

ENV <key>=<value> ...

说明

在后续指令中可以通过 $VAR_NAME 引用。

容器启动后也会保留这些变量。

示例

ENV APP_HOME=/var/www/app \
	NODE_ENV=production

EXPOSE —— 声明容器监听端口

作用:声明容器在运行时会监听哪些端口。

格式

EXPOSE <port>[/<protocol>]...

说明

不会自动映射宿主机端口,只是文档性质的说明。

实际映射需在 docker run 时通过 -p 参数指定。

示例

EXPOSE 80/tcp
EXPOSE 8000

示例运行时映射:

docker run -d -p 8080:80 my-nginx-image

CMD —— 容器启动时默认执行的命令

作用:定义容器启动时默认执行的命令。

格式

Exec 形式(推荐):

CMD ["command", "arg1", "arg2"]

Shell 形式(隐式调用 /bin/sh -c):

CMD command arg1 arg2

说明

可以被 docker run 命令覆盖。

一个 Dockerfile 中只能有一个有效的 CMD(如果有多个,最后一个生效)。

示例

CMD ["nginx", "-g", "daemon off;"]

ENTRYPOINT —— 容器入口点(固定命令)

作用:设置容器启动时必须运行的命令,比 CMD 更“固定”。 格式

ENTRYPOINT ["command", "param1", "param2"]

说明

CMD 配合使用时,CMD 的内容作为参数传递给 ENTRYPOINT

不能轻易被 docker run 覆盖(除非加 --entrypoint)。

示例

ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
指令是否可省略是否影响运行是否可覆盖典型用途
FROM指定基础镜像
LABEL添加元数据
RUN安装软件
CMD设置默认启动命令
ENTRYPOINT❌(需特殊参数)固定入口命令
EXPOSE声明监听端口
ENV设置环境变量
COPY复制文件
ADD类似 COPY,支持 tar 和 URL
WORKDIR设置工作目录

2.3 构建 httpd 镜像

mkdir /test

cd /test

vim dockerfile

-- 将下面的内容放入
# 使用官方 CentOS 7 镜像作为基础镜像
FROM centos:7

# 添加元数据信息
LABEL maintainer="admin" \
      description="CentOS 7"

# 备份原始的 CentOS-Base.repo
RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak

# 使用 curl 下载阿里云的 CentOS Base.repo 文件
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

# 清理并重建缓存
RUN yum clean all && yum makecache

# 安装一个httpd
RUN yum install -y httpd

EXPOSE 80

# 设置容器启动命令(示例)
CMD ["httpd", "-D", "FOREGROUND"]

构建 Docker 镜像

打开终端或命令行工具,导航到包含 Dockerfile 的目录,然后运行以下命令来构建 Docker 镜像。

请将 <your-image-name> 替换为你想要给这个镜像起的名字:

docker build -t <your-image-name> .

2.4 构建 nginx 镜像

# 使用官方 CentOS 7 镜像作为基础镜像
FROM centos:7

# 添加元数据信息
LABEL maintainer="admin" \
      description="CentOS 7"

# 备份原始的 CentOS-Base.repo
RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak

# 使用 curl 下载阿里云的 CentOS Base.repo 文件
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

# 清理并重建缓存
RUN yum clean all && yum makecache

# 安装 EPEL 源(Nginx 在 EPEL 中)
RUN yum install -y epel-release && \
    yum clean all && \
    yum makecache

# 安装 Nginx
RUN yum install -y nginx && \
    yum clean all

# 创建存放网页内容的目录
RUN mkdir -p /var/www/html

# 将HTML压缩包复制到容器中
COPY html.zip /tmp/html.zip

# 安装 unzip 工具
RUN yum install -y unzip && \
    yum clean all

# 解压HTML内容到指定目录
RUN unzip /tmp/html.zip -d /var/www/html/ && \
    rm /tmp/html.zip

# 修改 Nginx 默认配置文件,将根目录改为 /var/www/html
RUN sed -i 's|/usr/share/nginx/html|/var/www/html|g' /etc/nginx/nginx.conf

# 暴露80端口
EXPOSE 80

# 启动 Nginx 服务(前台模式)
CMD ["nginx", "-g", "daemon off;"]

测试:

docker run -d name n1 my-nginx

docker inspect n1                   看它的ip

curl ip

2.5 构建服务镜像

FROM centos:7

LABEL maintainer="xyz" \
      description="CentOS 7 with Java application"

WORKDIR /usr/local/java

ADD jre-8u221-linux-x64.tar.gz ./
COPY msg.jar ./app.jar

ENV JAVA_HOME=/usr/local/java/jre1.8.0_221
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH=$JAVA_HOME/bin:$PATH

EXPOSE 8080

CMD ["java", "-jar", "app.jar"]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值