Docker 镜像管理:分层结构、构建优化与最佳实践

文章目录

docker镜像管理

镜像分层结构

如图是nginx的分层

镜像构建

docker commit

bash 复制代码
[root@server1 ~]# docker run -it --name demo busybox
/ # touch file1 file2 file3
/ # ls
bin    etc    file2  home   lib64  root   tmp    var
dev    file1  file3  lib    proc   sys    usr
ctrl+d: 退出容器后容器自动关闭
ctrl+pq: 退出容器后继续在后台运行

#显示所有容器
[root@server1 ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS                                   PORTS     NAMES
7b46fa695add   busybox   "sh"      38 seconds ago   Exited (0) 13 seconds ago                          demo

#提交容器变更到新的镜像
[root@server1 ~]# docker commit -m "add files" demo demo:v1
sha256:0c62baa3e9ad7ea0baabf26e80d915118f8612cb14644616ed0d0e0c94772571

#查看新镜像,有两层
[root@server1 ~]# docker history demo:v1
IMAGE          CREATED          CREATED BY                          SIZE      COMMENT
0c62baa3e9ad   17 seconds ago   sh                                  27B       add files
c6348fa86ba0   3 months ago     BusyBox 1.38.0 (glibc), Debian 13   4.45MB
这种方式看不到具体做了什么,不利于安全审计

Dockerfile

​ 镜像层(Image Layer)是构成 Docker 镜像的基本单位。每个镜像都是由一系列只读的层叠加而成的。这些层中的每一层都代表了文件系统的一个增量变更。当创建一个新的镜像时,Docker 会基于基础镜像添加新的层,每一层包含了对文件系统的修改,如添加、删除或修改文件。

镜像层特点:

  • 只读性:每个镜像层都是只读的,这意味着一旦创建了一个层,就不能再对其进行修改。这种设计保证了镜像的一致性和不可变性。

  • 增量更新:每个层只包含相对于前一层的差异部分。例如,如果一个层只是向文件系统中添加了一个新文件,那么这个层就只包含那个文件的信息,而不包含整个文件系统的完整副本。 • 共享性:多个镜像可以共享相同的底层。例如,如果你有两个不同的镜像,它们都是基于同一个基础镜像构建的,那么这两个镜像可以共享基础镜像的所有层,从而节省磁盘空间。

  • 联合挂载:Docker 使用一种称为联合文件系统(Union File System, UnionFS)的技术来将这些只读层合并成一个统一的文件系统视图。它们可以被组合在一起以形成一个完整的镜像。当对镜像进行修改时,实际上是在创建一个新的层,这个新层包含了所做的修改,而底层的层则保持不变。这种分层的设计使得容器镜像非常灵活和高效,因为它可以充分利用共享层来减少存储空间的占用,并且可以快速构建和分发新的镜像。

镜像层的工作原理:

  • 构建过程:当你使用 docker build 命令从 Dockerfile 构建镜像时,Docker 会逐条解析 Dockerfile 中的指令,并为每条指令创建一个新的层。例如,RUN,COPY, ADD等命令都会生成新的层。

  • 缓存机制:Docker在构建过程中会利用缓存来加速构建。如果 Dockerfile 中的某条指令之前已经执行过并且没有发生变化,Docker就可以直接使用之前的缓存层,而不需要重新执行该指令。

  • 容器运行:当启动一个容器时,Docker 会在所有只读层之上添加一个可写层(通常称为" 容器层 ")。任何对文件系统的修改都会写入这个可写层,而不是修改底层的只读层。这样即使容器停止或被删除,只读层仍然保持不变。

  • 存储优化:由于多个镜像和容器可以共享相同的底层,Docker 可以高效地管理磁盘空间。此外,只有实际发生变更的部分才会占用额外的空间,减少了存储需求。

常用参数:

  • FROM
bash 复制代码
指定base镜像,如果本地不存在会从远程仓库下载。	 
  • COPY 、ADD
bash 复制代码
把文件从build context复制到镜像
src必须指定build context中的文件或目录 
  • ENV
bash 复制代码
设置环境变量,变量可以被后续的指令使用
ENV HOSTNAME sevrer1.example.com 
  • EXPOSE
bash 复制代码
如果容器中运行应用服务,可以把服务端口暴露出去:
EXPOSE 80 
  • VOLUME
bash 复制代码
申明数据卷,通常指定的是应用的数据挂在点:
VOLUME ["/var/www/html"] 
  • WORKDIR
bash 复制代码
为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。 
  • RUN
bash 复制代码
在容器中运行命令并创建新的镜像层,常用于安装软件包
RUN yum install -y vim 
  • CMD 与 ENTRYPOINT
bash 复制代码
这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。
docker run后面的参数可以传递给ENTRYPOINT指令当作参数。
Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。 
  • Shell和exec格式的区别
bash 复制代码
# cat Dockerfile 
FROM busybox
ENV name world
ENTRYPOINT echo "hello, $name"
  • Shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而下面的exec格式不会:
bash 复制代码
# cat Dockerfile 
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo", "hello, $name"]	#这个不会出现解析
  • 需要改写成以下形式:
bash 复制代码
# cat Dockerfile 
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh", "-c", "echo hello, $name"]	#这样写才对
  • Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时ENTRYPOINT会忽略任何CMD或docker run提供的参数。
bash 复制代码
# cat Dockerfile 
FROM busybox
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]

示例

bash 复制代码
[root@server1 ~]# mkdir docker
[root@server1 ~]# cd docker/
[root@server1 docker]# vim Dockerfile
FROM busybox
RUN touch file1 file2 file3
COPY os.sql /
[root@server1 docker]# cp /root/os.sql .
[root@server1 docker]# ls
Dockerfile os.sql
[root@server1 docker]# docker build -t demo:v2 .
[root@server1 docker]# docker images demo:v2
[root@server1 docker]# docker history demo:v2

清理测试用例

bash 复制代码
[root@server1 docker]# ls
Dockerfile  os.sql
[root@server1 docker]# rm -f *
[root@server1 docker]# ls
[root@server1 docker]# docker images demo
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
demo         v2        fe1649903f38   13 minutes ago   6.03MB
demo         v1        0c62baa3e9ad   3 hours ago      4.45MB
demo         v4        ae7fe0f39606   3 months ago     4.45MB
demo         v3        22edc42c18c0   3 months ago     4.45MB
[root@server1 docker]# docker rmi fe1649903f38 0c62baa3e9ad ae7fe0f39606 22edc42c18c0
[root@server1 docker]# docker images demo
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

封装nginx

官网下载安装包:nginx: download,并拖入目录

bash 复制代码
[root@server1 docker]# docker pull docker.1ms.run/centos:7
[root@server1 docker]# docker images centos
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
centos       7         eeb6ee3f44bd   4 years ago   204MB
#复制yum源
[root@server1 docker]# cd /etc/yum.repos.d/
[root@server1 yum.repos.d]# ls
CentOS-Base.repo  docker-ce.repo
[root@server1 yum.repos.d]# cp CentOS-Base.repo ~/docker/
#编辑dockerfile文件
[root@server1 yum.repos.d]# cd /root/docker/
[root@server1 docker]# vim Dockerfile
FROM centos:7
RUN rm -f /etc/yum.repos.d/*.repo
COPY CentOS-Base.repo /etc/yum.repos.d/
RUN yum install -y gcc make pcre-devel openssl-devel
ADD nginx-1.30.4.tar.gz /mnt/
WORKDIR /mnt/nginx-1.30.4
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc
RUN ./configure --with-http_ssl_module --with-http_stub_status_module
RUN make
RUN make install
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
#确保资源文件都在当前目录
[root@server1 docker]# ls
CentOS-Base.repo  Dockerfile  nginx-1.30.4.tar.gz
#构建镜像
[root@server1 docker]# docker build -t webserver:v1 .
[root@server1 docker]# docker images webserver
REPOSITORY   TAG       IMAGE ID       CREATED              SIZE
webserver    v1        e983577bf2ce   About a minute ago   553MB
#启动容器
[root@server1 docker]# docker run -d --name web1 webserver:v1
85f2872a5680e772647108014ce610db7bfcb7af4a591fea0ebd24361d61b7f2
[root@server1 docker]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS     NAMES
85f2872a5680   webserver:v1   "/usr/local/nginx/sb..."   4 minutes ago   Up 4 minutes   80/tcp    web1

查看容器详情

bash 复制代码
[root@server1 docker]# docker inspect  web1

验证部署是否成功

bash 复制代码
[root@server1 docker]# curl 172.17.0.2

镜像优化

缩减镜像层

bash 复制代码
#拷贝nginx.conf文件并修改日志路径到终端,便于docker抓取
[root@server1 docker]# vim nginx.conf
error_log  /dev/stderr notice;
    access_log  /dev/stdout  main;
    
[root@server1 docker]# vim Dockerfile
FROM centos:7
RUN rm -f /etc/yum.repos.d/*.repo
COPY CentOS-Base.repo /etc/yum.repos.d/
ADD nginx-1.30.4.tar.gz /mnt/
RUN yum install -y gcc make pcre-devel openssl-devel && cd /mnt/nginx-1.30.4 && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx-1.30.4 && yum clean all
COPY nginx.conf /usr/local/nginx/conf/
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

[root@server1 docker]# ls
CentOS-Base.repo  Dockerfile  nginx  nginx-1.30.4.tar.gz  nginx.conf
[root@server1 docker]# docker build -t webserver:v2 .

[root@server1 docker]# docker images webserver
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
webserver    v2        13992a2a16de   54 seconds ago   319MB
webserver    v1        e983577bf2ce   42 minutes ago   553MB

[root@server1 docker]# docker run -d --name web1 webserver:v2
a7f6d72d89b9f8894029ff1ec6cd851d47bcb133f0f50d1f21840b1ca3fa919c

[root@server1 docker]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS     NAMES
a7f6d72d89b9   webserver:v2   "/usr/local/nginx/sb..."   22 seconds ago   Up 21 seconds   80/tcp    web1

[root@server1 docker]# docker rm -f web1
web1

多阶段构建

bash 复制代码
[root@server1 docker]# vim Dockerfile
FROM centos:7 as build
RUN rm -f /etc/yum.repos.d/*.repo
COPY CentOS-Base.repo /etc/yum.repos.d/
ADD nginx-1.30.4.tar.gz /mnt/
RUN yum install -y gcc make pcre-devel openssl-devel && cd /mnt/nginx-1.30.4 && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx-1.30.4 && yum clean all
COPY nginx.conf /usr/local/nginx/conf/

FROM centos:7
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

[root@server1 docker]# docker build -t webserver:v3 .

[root@server1 docker]# docker images webserver
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
webserver    v3        70105c1ba69a   20 seconds ago   205MB
webserver    v2        13992a2a16de   6 minutes ago    319MB
webserver    v1        e983577bf2ce   47 minutes ago   553MB

[root@server1 docker]# docker run -d --name web1 webserver:v3
53c55976b539716dd9d777b2ade38065c87434f8b506e9bba21b4edec4a515f8

[root@server1 docker]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS     NAMES
53c55976b539   webserver:v3   "/usr/local/nginx/sb..."   38 seconds ago   Up 37 seconds   80/tcp    web1

使用最精简的基础镜像

bash 复制代码
#导入基础镜像
[root@server1 docker]# ls
base-debian12.tar  CentOS-Base.repo  Dockerfile  nginx  nginx-1.30.4.tar.gz  nginx.conf
[root@server1 docker]# docker load -i base-debian12.tar

[root@server1 docker]# mkdir new
[root@server1 docker]# cd new/
[root@server1 new]# vim Dockerfile
FROM nginx:latest as base

RUN mkdir -p /opt/var/cache/nginx && \
    cp -a --parents /usr/lib/nginx /opt && \
    cp -a --parents /usr/share/nginx /opt && \
    cp -a --parents /var/log/nginx /opt && \
    cp -aL --parents /var/run /opt && \
    cp -a --parents /etc/nginx /opt && \
    cp -a --parents /etc/passwd /opt && \
    cp -a --parents /etc/group /opt && \
    cp -a --parents /usr/sbin/nginx /opt && \
    cp -a --parents /usr/sbin/nginx-debug /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libpcre* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
    cp -a --parents /lib/x86_64-linux-gnu/libzstd* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
    cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt

FROM gcr.io/distroless/base-debian12:latest

COPY --from=base /opt /

EXPOSE 80 443

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

[root@server1 new]# docker build -t webserver:v4 .

[root@server1 new]# docker images  webserver
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
webserver    v4        990537d3b63f   12 seconds ago   62.3MB
webserver    v3        70105c1ba69a   6 minutes ago    205MB
webserver    v2        13992a2a16de   12 minutes ago   319MB
webserver    v1        e983577bf2ce   53 minutes ago   553MB

[root@server1 new]# docker rm -f web1
web1

[root@server1 new]# docker run -d --name web1  webserver:v4

[root@server1 new]# curl  172.17.0.2
相关推荐
harmony&16 分钟前
Docker 容器技术从入门到实战:生态系统、安装部署与架构详解
docker·容器·架构
vipxieliang21 分钟前
收货地址验证完整方案:省市区与详细地址
java·spring boot
Json____29 分钟前
java-宿舍安全卫生检查系统项目源码
java·前端·javascript·课程设计·it学习·wwwoop.com
天天喝旺仔36 分钟前
Docker 镜像瘦身实战:多阶段构建把体积缩小 90%
运维·后端·ci/cd·docker·云原生·容器·性能优化
zzzll111142 分钟前
LangChain4j:Java 生态的 AI 应用开发利器
java·开发语言·人工智能
NJCloud1 小时前
Docker 私有仓库部署:Registry、加密传输与认证鉴权
运维·网络·docker·云原生·容器
w200512241 小时前
K8S控制器管理
linux·云原生·容器·kubernetes
2601_967338711 小时前
尚硅谷2026尚硅谷Java全栈+Python智能体教程
java·人工智能
用户3126874877201 小时前
HashMap 到底怎么扩容的?源码级链路拆解
java