本文来自我的博客地址
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 明显增加了层数
案例: 二进制部署 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": {
"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 极速增长
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 .
docker inspect redis:one-line-ubuntu
......
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:f2fa9f4cf8fd0a521d40e34492b522cee3f35004047e617c75fadeb8bfd1e6b7",
"sha256:30d3c4334a2379748937816c01f5c972a8291a5ccc958d6b33d735457a16196e",
"sha256:83109fa660b2ed9307948505abd3c1f24c27c64009691067edb765bd3714b98d",
"sha256:72caaf8c025e80d97674e4d68ac4628b8dabab70dc9b73ef817c51b694c45daa"
]
},
......
可以看出指令数减少, ROOTFS 层数也明显减少
巨坑: debian 与 alpine 的镜像在切换国内时问题非常多, 建议直接使用原始镜像的软件源(确保能够访问外网)
问题概览:
- debian 低版本切换阿里源时, 不支持 https: 需要将 http 软连接为 https
- 显示 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
- 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 .
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
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
精简镜像方式:
参考:
- 容器化 | 使用 Alpine 构建 Redis 镜像 - RadonDB - 博客园 (cnblogs.com)
- 基于alpine用dockerfile创建的nginx镜像 - 一本正经的搞事情 - 博客园 (cnblogs.com)
- redis二进制安装_二进制安装redis-CSDN博客
- apt get - Debian 8 Jessie archive.debian.org GPG error KEYEXPIRED since 2022-11-19 (what now?) - Stack Overflow