Dockerfile: 制作精简镜像

发布时间:2024年01月06日

在这里插入图片描述

本文来自我的博客地址

写时复制

dockerfile 一条指令对应一层, 最多 127 层

从 busybox 入手理解 docker 镜像层的写时复制

dockerfile:

FROM busybox 

RUN mkdir -p /tmp/foo

# 新建一个 100M 的文件
RUN dd if=/dev/zero of=/tmp/foo/bar bs=1M count=100

# 删除文件
RUN rm /tmp/foo/bar 

一条指令对应 1 层: 4 层

$ docker build -t busybox:copy-on-write -f dockerfile1 .
$ docker images | grep busybox
busybox      copy-on-write   1f30f7a048eb   About a minute ago   106MB
busybox      latest          beae173ccac6   2 years ago          1.24MB

看得出来就算镜像删除的文件, 下层创建的不会消失, 删除指令创建的层只会叠加上去

使用 docker inspect 查看具体的层信息

busybox:latest

docker inspect busybox:latest

......
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:82ae998286b2bba64ce571578647adcabef93d53867748d6046cc844ff193a83"
            ]
        },
......

busybox:copy-on-write

docker inspect busybox:copy-on-write

......
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:82ae998286b2bba64ce571578647adcabef93d53867748d6046cc844ff193a83",
                "sha256:f70c1ce3ef10664a7aacf002afd20aa16f56bf98a83729b640c97363b10d329c",
                "sha256:3c38ae07f686f954897d06c4c56e65e17d1be5843f2c02e8f2d6734b4978dd83",
                "sha256:69d9b35636c7fa1f62c4bfe15f3c65f247553b122fe38af17dc34666f8cb2314"
            ]
        },
......

可以看到 busybox:copy-on-write 明显增加了层数

制作精简镜像方法:

  1. 串联 Dockerfile 指令
  2. 选用更小的镜像
  3. 压缩镜像

案例: 二进制部署 redis

多条命令构建

FROM ubuntu:trusty

ENV VER 7.2.3

# 安装依赖
RUN apt update
RUN apt install wget make gcc -y

# 获取源码包
RUN wget https://download.redis.io/releases/redis-$VER.tar.gz
RUN tar zxvf redis-$VER.tar.gz
WORKDIR redis-$VER

# 编译源码包
RUN make
RUN mkdir /usr/local/redis
RUN make install PREFIX=/usr/local/redis 

RUN apt-get clean && apt-get remove -y wget gcc make 

# 启动 redis
CMD ["/usr/local/redis/redis-server", "/usr/local/redis/redis.conf"]
构造镜像
docker build -t redis:many-lines-ubuntu -f dockerfile2 .
ROOTFS
......
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:f2fa9f4cf8fd0a521d40e34492b522cee3f35004047e617c75fadeb8bfd1e6b7",
                "sha256:30d3c4334a2379748937816c01f5c972a8291a5ccc958d6b33d735457a16196e",
                "sha256:83109fa660b2ed9307948505abd3c1f24c27c64009691067edb765bd3714b98d",
                "sha256:87c240db20b96e01aa53111dbf1a71b54095e95f2bb32076a7aee2de148aaaf1",
                "sha256:c45a2d4a77a5eb88bd2bfaaa691468eade520c8da9b3d39d30813e9882ff7b0b",
                "sha256:65faa09184aa345eeace30548ad9a337e4582f9b23d8a0871ad8a5be08fe6c09",
                "sha256:af54af5d0e940764f3cd2b78d5ab121b2dba5eb1f527e81f8c70c3deeddf15b9",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:1819a309db341aed9bc39e040a3695151d2b33c9d1d267069d6f3918f3871a1d",
                "sha256:e54f0072570654b50dd413197f5d921da283c90689d79336ed0c313112d3a591",
                "sha256:b6499beec6f2099e86807b4fee915170820834dfafae3ca324309db26e5660fb",
                "sha256:14a95f408690a544c45387595381902f921eb0356a53f8a73495198dc113b8a1",
                "sha256:a545e5b1525c37272eb70af26d8baab872f592c5f71ba934353a7104f0680e21"
            ]
        },
......

由于我们写了写多条 RUN 指令, 所以镜像 ROOTFS 极速增长

一条命令构建 ubuntu

FROM ubuntu:trusty

ENV VER 7.2.3

RUN apt update && \
    apt install wget make gcc -y && \
    wget https://download.redis.io/releases/redis-$VER.tar.gz && \
    tar zxvf  redis-$VER.tar.gz && cd redis-$VER && \
    make && mkdir /usr/local/redis && \
    make install PREFIX=/usr/local/redis && \
    mkdir -p /usr/local/redis/{conf,bin} && \
    cp redis.conf /usr/local/redis/conf && \
    apt-get clean && apt-get remove -y wget gcc make 

# 启动 redis
CMD ["/usr/local/redis/bin/redis-server", "/usr/local/redis/conf"]
构造镜像
docker build -t redis:one-line-ubuntu -f dockerfile2 .
ROOTFS
docker inspect redis:one-line-ubuntu

......
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:f2fa9f4cf8fd0a521d40e34492b522cee3f35004047e617c75fadeb8bfd1e6b7",
                "sha256:30d3c4334a2379748937816c01f5c972a8291a5ccc958d6b33d735457a16196e",
                "sha256:83109fa660b2ed9307948505abd3c1f24c27c64009691067edb765bd3714b98d",
                "sha256:72caaf8c025e80d97674e4d68ac4628b8dabab70dc9b73ef817c51b694c45daa"
            ]
        },
......

可以看出指令数减少, ROOTFS 层数也明显减少

更改基础镜像为 debian

巨坑: debian 与 alpine 的镜像在切换国内时问题非常多, 建议直接使用原始镜像的软件源(确保能够访问外网)

问题概览:

  1. debian 低版本切换阿里源时, 不支持 https: 需要将 http 软连接为 https
  2. 显示 gpg key 错误时: wget http://http.us.debian.org/debian/pool/main/d/debian-archive-keyring/debian-archive-keyring_2023.4_all.deb && dpkg -i debian-archive-keyring_2023.4_all.deb
  3. alpline 与 debian 安装的 gcc 可能会出现版本问题, 需要你更换 gcc 版本
FROM debian

ENV VER 7.2.3

RUN apt-get update && \
    apt-get install wget make gcc -y && \
    wget https://download.redis.io/releases/redis-$VER.tar.gz && \
    tar zxvf  redis-$VER.tar.gz && cd redis-$VER && \
    make && mkdir /usr/local/redis && \
    make install PREFIX=/usr/local/redis && \
    mkdir -p /usr/local/redis/{conf,bin} && \
    cp redis.conf /usr/local/redis/conf && \
    apt-get clean && apt-get remove -y wget gcc make 

# 启动 redis
CMD ["/usr/local/redis/bin/redis-server", "/usr/local/redis/conf"]
构造镜像
docker build -t redis:one-line-debian -f dockerfile2 .
ROOTFS
docker inspect redis:one-line-debian

......
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:ae134c61b154341a1dd932bd88cb44e805837508284e5d60ead8e94519eb339f",
                "sha256:98547bcc9e3b713c48a4f5ca069fd442eaa71bc61b68c9a3c00a4af0d73cbe2d"
            ]
        },
......

可以看出将多条指令合并书写能够有效减少 ROOTFS 层数

使用分段构造

多段构造, 在到最后一段, 有小镜像承接, 前面段的内容不会保留下来

推荐镜像:

镜像说明
scrach空镜像, 不带任何调试工具
busybox小镜像, 带有基础调试工具

因为我们需要解压 tar 包, scrath 没有解压工具, 我们使用 busybox 演示

使用 busybox 作为基础镜像

FROM ubuntu:trusty as builder

ENV VER 7.2.3

RUN apt update && \
    apt install wget make gcc -y && \
    wget https://download.redis.io/releases/redis-$VER.tar.gz && \
    tar zxvf  redis-$VER.tar.gz && cd redis-$VER && \
    make && mkdir /usr/local/redis && \
    make install PREFIX=/usr/local/redis && \
    cp redis.conf /usr/local/redis/conf && \
    apt-get clean && apt-get remove -y wget gcc make 

RUN tar cvf /123.tar /usr/local/redis/

FROM busybox

COPY --from=builder /123.tar /

RUN tar xvf /123.tar -C /usr/local/

# 启动 redis
CMD ["/usr/local/redis/bin/redis-server", "/usr/local/redis/conf"]
构造镜像

补充: 如果你遇到 Dockerfile 构造时的错误时, 可以加上 --progress=plain --no-cache查看详细构建日志

docker build -t redis:with-busybox -f dockerfile7 . --progress=plain
ROOTFS
docker inspect redis:with-busybox

......
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:82ae998286b2bba64ce571578647adcabef93d53867748d6046cc844ff193a83",
                "sha256:335bc67496eb30fe68fe25e6c8f97cb6b74d9989a1c6b24012971097bf22a1a3",
                "sha256:abf10e66d6bddcb7e00f41707d71515b1927b1984889aa13ca6b232f9fb78b27"
            ]
        },
......

镜像压缩

了解即可 docker squash已不在维护

安装
wget https://github.com/jwilder/docker-squash/releases/download/v0.2.0/docker-squash-linux-amd64-v0.2.0.tar.gz 

tar xzvf docker-squash-linux-amd64-v0.2.0.tar.gz -C /usr/local/bin/
使用
root@MKT:~/goproject/httppod/tmp# docker save redis:many-lines-ubuntu | docker-squash -verbose -t redis:squash | docker load
Loading export from STDIN using /tmp/docker-squash272131964 for tempdir
Loaded image w/ 13 layers
  -  redis (1 tags)
Extracting layers...
  -  /tmp/docker-squash272131964/72c5745a74e809afa1c8bbb09164a25a99971cd6ebb60bf9a3c7c399932e2d92/layer.tar
  -  /tmp/docker-squash272131964/e0d139e2e59aa8505f205730d7bd8924bf1289034504be42b618c284420cb9c2/layer.tar
  -  /tmp/docker-squash272131964/10bc199db63a91cf1c3d75fddb1083740e09115320801e0e34f517f8160bd326/layer.tar
  -  /tmp/docker-squash272131964/228aa3e189d788785b2d8c129b6bbf1553ad34e141608706f2d0459d5a1be035/layer.tar
  -  /tmp/docker-squash272131964/42f6beebfd61e1ff415ab2237fdb49bd34dee9f319a1d49e2ca525dc18823e5d/layer.tar
  -  /tmp/docker-squash272131964/45ce59804d1f796310cf5ba3e5878be2e63d644ba271c8d33a315230e737324f/layer.tar
  -  /tmp/docker-squash272131964/462272b123320a876d404d41dac9f20ecf24140f22d979896cc2d0bfa487bae2/layer.tar
  -  /tmp/docker-squash272131964/63b9671bfe8674a1e65dfbb88881ddb1c214eabf89f6ed98e3f0e1deaca9bd8f/layer.tar
  -  /tmp/docker-squash272131964/075972677a1d485c0ba03f4d3b2fb6e3c39f273628f6f0d702149faa4e2831bd/layer.tar
  -  /tmp/docker-squash272131964/88f0016636d34b6a24606c2db4d7ea26c0a02d830383e46aee831c2e1db897a9/layer.tar
  -  /tmp/docker-squash272131964/a8626ef4bd7f2ec2fde454e5263f09eea4d369983ef770abb470f1688baa6681/layer.tar
  -  /tmp/docker-squash272131964/a8ea63a42a3c2e60d8738e8bd81be0502d4bc6ecc827c8e472e171d4abf7e5cf/layer.tar
  -  /tmp/docker-squash272131964/b795b8b69dcd58cbf17a234cba5e8d1de61da850032d781ae92b3ba9eb0fdb69/layer.tar
Inserted new layer 2619184f193f after 228aa3e189d7
  -  228aa3e189d7
  -> 2619184f193f /bin/sh -c #(squash) from 228aa3e189d7
  -  075972677a1d
  -  10bc199db63a
  -  a8626ef4bd7f
  -  88f0016636d3
  -  e0d139e2e59a
  -  63b9671bfe86
  -  45ce59804d1f
  -  462272b12332
  -  b795b8b69dcd
  -  42f6beebfd61
  -  a8ea63a42a3c
  -  72c5745a74e8
Squashing from 2619184f193f into 2619184f193f
  -  Deleting whiteouts for layer 075972677a1d
  -  Deleting whiteouts for layer 10bc199db63a
Removing extracted layers
Tagging 2619184f193f as redis:squash
Tarring new image to STDOUT
Done. New image created.
  -  228aa3e189d7 54.036378 years  206.1 MB
  -  2619184f193f 17 seconds /bin/sh -c #(squash) from 228aa3e189d7 370.1 MB
Removing tempdir /tmp/docker-squash272131964
Loaded image: redis:many-lines-ubuntu

总结

镜像大小

root@MKT:~/goproject/httppod/tmp# docker images
REPOSITORY   TAG                 IMAGE ID       CREATED             SIZE
redis        with-busybox        a26dc68d9da9   17 minutes ago      65.1MB
busybox      copy-on-write       e71e45a955a2   26 minutes ago      109MB
redis        many-lines-ubuntu   cf3ded3f5a5f   43 minutes ago      565MB
redis        one-line-debian     ac157643d4a6   About an hour ago   669MB
redis        one-line-ubuntu     86be0695bcf2   2 hours ago         562MB

精简镜像方式:

  1. 使用单条指令替换多条指令
  2. 使用更小的基础镜像
  3. 使用镜像压缩工具

参考:

  1. 容器化 | 使用 Alpine 构建 Redis 镜像 - RadonDB - 博客园 (cnblogs.com)
  2. 基于alpine用dockerfile创建的nginx镜像 - 一本正经的搞事情 - 博客园 (cnblogs.com)
  3. redis二进制安装_二进制安装redis-CSDN博客
  4. apt get - Debian 8 Jessie archive.debian.org GPG error KEYEXPIRED since 2022-11-19 (what now?) - Stack Overflow
文章来源:https://blog.csdn.net/m0_51964671/article/details/135325237
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。