运维实战 容器部分 Docker镜像
Posted 洛冰音
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了运维实战 容器部分 Docker镜像相关的知识,希望对你有一定的参考价值。
运维实战 容器部分 Docker镜像
镜像的分层结构
-
共享宿主机的
kernel
-
base
镜像提供的时最小的linux
系统 -
同一
docker
主机支持运行多种linux
发行版 -
采用分层结构的最大好处是: 共享资源
Copy-in-Write 可写容器层
-
容器层以下所有镜像层都是只读的
-
docker
从上往下依次查找文件 -
容器层保存镜像变化的部分,并不会对镜像本身进行任何修改
-
一个镜像最多只能有127层
镜像的构建
采用Dockerfile方式
##下载原始镜像busybox
docker pull busybox
##以交互式方式创建容器并简单测试
[root@Server1 ~]# docker run -it --name Busybox busybox
/ # ls
bin dev etc home proc root sys tmp usr var
/ # mkdir Test
/ # ls
Test bin dev etc home proc root sys tmp usr var
/ #
##退出交互式的方式
ctrl+ d 退出并关闭容器
ctrl+ pq 退出并将容器打入后台
##创建一个空目录用于存放Dockerfile
[root@Server1 ~]# cd /mnt/
[root@Server1 mnt]# mkdir Docker
[root@Server1 Docker]# vim Dockerfile
##文件内容
FROM busybox
RUN touch Test
RUN cd Test
RUN touch file{1..10}
##使用当前目录的Dockerfile构建镜像
[root@Server1 Docker]# docker build -t testbox .
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM busybox
---> 388056c9a683
Step 2/3 : RUN mkdir Test
---> Running in 0bbfb83c4a2f
Removing intermediate container 0bbfb83c4a2f
---> 2dd01c73369c
Step 3/3 : RUN touch file{1..10}
---> Running in 9c15b75bfdfe
Removing intermediate container 9c15b75bfdfe
---> aa4cd0b3c97a
Successfully built aa4cd0b3c97a
Successfully tagged testbox:latest
##查看本机镜像可以看到新构建的testbox
[root@Server1 Docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
testbox latest aa4cd0b3c97a 17 seconds ago 1.23MB
busybox latest 388056c9a683 2 weeks ago 1.23MB
##查看构建历史可以看到每一步操作都成为了新的一层
[root@Server1 Docker]# docker history testbox:latest
IMAGE CREATED CREATED BY SIZE COMMENT
aa4cd0b3c97a 43 seconds ago /bin/sh -c touch file{1..10} 0B
2dd01c73369c 44 seconds ago /bin/sh -c mkdir Test 0B
388056c9a683 2 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:8d57331dc331805f0… 1.23MB
Dockerfile
的方式可以看到基于busybox
后构建的新层的记录和操作内容.
而如果使用commit方式则会有略微不同.
采用Commit
方式
##删除刚才采用Dockerfile方式创建的容器
[root@Server1 Docker]# docker rmi testbox:latest
Untagged: testbox:latest
Deleted: sha256:aa4cd0b3c97a7fcf23834549a7a5a169c93b84e4f1b2cc4e77fd6deba2996a8a
Deleted: sha256:3961fc3b6ac0630016bbcab16b49c69294b7b12727995db5ec416b7d961c936e
Deleted: sha256:2dd01c73369c25ce7d6605e4f144a5660e30eef40368a1aece8b08ba5a6c5288
Deleted: sha256:80b97add01edb4a71fc8c4e3a11823cef75fb312d6ed0a74ac0f4dd5b8ff18a4
[root@Server1 Docker]# docker run -it --name Busybox busybox
/ # ls
bin dev etc home proc root sys tmp usr var
/ # mkdir Test
/ # cd Test/
/Test # touch file{1..10}
ctrl+p q退出交互模式并将容器打入后台
[root@Server1 Docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b38fd8cf7b9 busybox "sh" 31 seconds ago Up 31 seconds Busybox
##提交更新并生成新的镜像testbox
[root@Server1 Docker]# docker commit -m "V1" Busybox testbox:V1
sha256:1f68ffbebec57daf89e32b9e444679406651bb24817a84eb1e4c0cefb2bdc49e
[root@Server1 Docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
testbox V1 1f68ffbebec5 5 seconds ago 1.23MB
busybox latest 388056c9a683 2 weeks ago 1.23MB
##查看镜像构建的历史,可以看到新层的具体内容并没有显示出来
[root@Server1 Docker]# docker history testbox:V1
IMAGE CREATED CREATED BY SIZE COMMENT
1f68ffbebec5 12 seconds ago sh 41B V1
388056c9a683 2 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:8d57331dc331805f0… 1.23MB
因此还是推荐使用Dockerfile
的方式构建镜像
Dockerfile详解
-
FROM
指定base镜像,如果本地不存在则从网络拉取
-
MAINTAINER
设置镜像的作者,比如用户邮箱等等
-
Copy
- 从本机将文件从
build context
复制到镜像 - 支持两种形式:
COPY src dest
和COPY ["src", "dest"]
- 需要注意的是本机文件必须位于
build context
, 也就是Dockerfile
所在目录中
- 从本机将文件从
-
ADD
- 用法与
COPY
类似,不同的是src
可以是归档压缩文件,文件会被解压后放入容器内 - 本机文件并不需要位于
build context
中 - 也可以从网络下载文件并拷贝到镜像
- 用法与
-
ENV
设置环境变量,变量可以被后续的指令使用
- 举例
ENV HOSTNAME Server1.example.com
- 举例
-
EXPOSE
如果在容器中运行应用服务,需要把服务端口暴露出去的时候使用
EXPOSE 80
, 即对外暴露80端口
-
VOLUME
- 申明数据卷, 通常指定的是应用的数据挂载点
- 挂载目录的目的是为了持久化
- 举例
VOLUME ["/var/www/html"]
-
WORKDIR
- 为
RUN
,CMD
,ENTERPOINT
,ADD
,COPY
指令设置镜像中的当前工作目录 - 如果目录不存在则会自动创建
- 为
-
RUN
- 在容器中运行命令并创建新的镜像层, 常用于安装软件包
- 举例
RUN yum install -y vim
-
CMD和ENTRYPOINT
- 这两个指定都是用于设置容器启动后执行的命令
- 区别在于
CMD
会被RUN
后面的命令行覆盖, 而ENTRYPOINT
一定不会被忽略/一定会执行 docker run
后面的参数可以传递给ENTRYPOINT
指令作为参数- Dockerfile中只能指定一个
ENTRYPOINT
, 如果指定了很多个则只有最后一个有效
SHELL和EXEC格式的区别
FROM busybox
ENV name world
ENTRYPOINT echo "hello, $name"
Shell
格式底层会调用/bin/sh -c
来执行指令,可以解析变量,而下面的Exec
格式不会.
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo" "hello, $name"]
必须改写为如下形式才能正常解析变量.
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh" "-c" "echo hello, $name"]
Exec
格式时,ENTRYPOINT
可以通过CMD提供额外参数, CMD
的额外参数可以在容器启动时动态替换.
Shell
格式时,ENTRYPOINT
会忽略任何CMD
或docker run
提供的参数
操作过程
[root@Server1 Docker]# vim Dockerfile
[root@Server1 Docker]# touch index.html
[root@Server1 Docker]# echo Server1 > index.html
[root@Server1 Docker]# ls
Dockerfile index.html nginx-1.18.0.tar.gz
##Dockerfile内容
FROM busybox
RUN mkdir Test
RUN touch /Test/Testfile
COPY index.html /
ADD nginx-1.18.0.tar.gz /
RUN mv nginx-1.18.0 Nginx
ENV HOSTNAME Server1
EXPOSE 80
VOLUME ["/data"]
WORKDIR /Test
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
[root@Server1 Docker]# docker build -t demo .
Sending build context to Docker daemon 1.043MB
Step 1/12 : FROM busybox
---> 388056c9a683
Step 2/12 : RUN mkdir Test
---> Running in 939e77e989f6
Removing intermediate container 939e77e989f6
---> 9537fc624d09
Step 3/12 : RUN touch /Test/Testfile
---> Running in 2ce46791eec2
Removing intermediate container 2ce46791eec2
---> 169b8b8c81f7
Step 4/12 : COPY index.html /
---> 6abd12f14c62
Step 5/12 : ADD nginx-1.18.0.tar.gz /
---> 7fd946b03383
Step 6/12 : RUN mv nginx-1.18.0 Nginx
---> Running in 9ac35e723827
Removing intermediate container 9ac35e723827
---> a817a5a3b1eb
Step 7/12 : ENV HOSTNAME Server1
---> Running in 5a494de50eb1
Removing intermediate container 5a494de50eb1
---> eb900f03448c
Step 8/12 : EXPOSE 80
---> Running in 77affb4662d8
Removing intermediate container 77affb4662d8
---> e17a7d084fcb
Step 9/12 : VOLUME ["/data"]
---> Running in 4208622c722a
Removing intermediate container 4208622c722a
---> 281920256f8d
Step 10/12 : WORKDIR /Test
---> Running in 31f5db039dd2
Removing intermediate container 31f5db039dd2
---> 73b41cdf5a3c
Step 11/12 : ENTRYPOINT ["/bin/echo", "hello"]
---> Running in bb798ebc3335
Removing intermediate container bb798ebc3335
---> bb598d50bedf
Step 12/12 : CMD ["world"]
---> Running in 3ac90fc7965b
Removing intermediate container 3ac90fc7965b
---> bae4405b5d28
Successfully built bae4405b5d28
Successfully tagged demo:latest
[root@Server1 Docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo latest bae4405b5d28 6 seconds ago 13.7MB
busybox latest 388056c9a683 2 weeks ago 1.23MB
[root@Server1 Docker]# docker run --rm demo:latest
hello world
[root@Server1 Docker]# docker run --rm demo:latest linux
hello linux
--rm
参数常用于临时测试内容,当命令执行结束后临时生成的容器就会关闭并删除.
在其后跟着的参数会传递给容器使用.
因此不传递参数时根据Dockerfile
的内容,输出的内容是hello world
而当传递了linux
后,CMD
的参数被覆盖,输出的内容是hello linux
关于VOLUME的示例
[root@Server1 Docker]# docker run -it test
/Test # mount | grep data
/dev/mapper/rhel-root on /data type xfs (rw,relatime,attr2,inode64,noquota)
回到虚拟机,检测容器及其持久化路径
[root@Server1 volumes]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
df2e62b200ba test "sh" About a minute ago Up About a minute 80/tcp agitated_pasteur
[root@Server1 volumes]# docker inspect df2e62b200ba
[
{
"Id": "df2e62b200bafe221739f6535fc89264b9791e60aa698537619ded42b3686e9b",
"Created": "2021-04-27T03:01:58.831986169Z",
"Path": "sh",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 17440,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-04-27T03:01:59.097958403Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:73b41cdf5a3c2bc7251b046f768859cd633e02f19c6a61ce5dd6931ba026d3c4",
"ResolvConfPath": "/var/lib/docker/containers/df2e62b200bafe221739f6535fc89264b9791e60aa698537619ded42b3686e9b/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/df2e62b200bafe221739f6535fc89264b9791e60aa698537619ded42b3686e9b/hostname",
"HostsPath": "/var/lib/docker/containers/df2e62b200bafe221739f6535fc89264b9791e60aa698537619ded42b3686e9b/hosts",
"LogPath": "/var/lib/docker/containers/df2e62b200bafe221739f6535fc89264b9791e60aa698537619ded42b3686e9b/df2e62b200bafe221739f6535fc89264b9791e60aa698537619ded42b3686e9b-json.log",
"Name": "/agitated_pasteur",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Capabilities": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/59faba205ad3939e7a17f0127ae3c8cde7ff1360088c52df1e0793d66f39bf45-init/diff:/var/lib/docker/overlay2/6a304244cf9f7712409a6fa2c95c4c51d14a5085873e0d58457713dc772831d0/diff:/var/lib/docker/overlay2/ceaa36629aa9b33f4e898f8bb10797379487b746251e6da9773f36ec3addb809/diff:/var/lib/docker/overlay2/96cc89b932c5d43df2052ee68c93ddafd5aa3966018abc87f6111015b2b8e4a5/diff:/var/lib/docker/overlay2/e272c5d92a4906480fc601b600f6310f2c065f0c85a649d9d322db837aace931/diff:/var/lib/docker/overlay2/03d7b22fc476b81aac770b2be9f3d55db1a405a7e5e341ef7038e8c97c378edd/diff:/var/lib/docker/overlay2/04834c81f78ab1e77f9d2f32ab79e19b11ff34af47af0dca505824dd8b5805ad/diff",
"MergedDir": "/var/lib/docker/overlay2/59faba205ad3939e7a17f0127ae3c8cde7ff1360088c52df1e0793d66f39bf45/merged",
"UpperDir": "/var/lib/docker/overlay2/59faba205ad3939e7a17f0127ae3c8cde7ff1360088c52df1e0793d66f39bf45/diff",
"WorkDir": "/var/lib/docker/overlay2/59faba205ad3939e7a17f0127ae3c8cde7ff1360088c52df1e0793d66f39bf45/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "volume",
"Name": "30b75ff3583bd344cecbc68ba19a023a61c4b9be8e98332adba879f9ac78136c",
"Source": "/var/lib/docker/volumes/30b75ff3583bd344cecbc68ba19a023a61c4b9be8e98332adba879f9ac78136c/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "df2e62b200ba",
"Domainname": "",
"User": "",
"AttachStdin": true,
"AttachStdout": true,
"AttachStderr": true,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": true,
"OpenStdin": true,
"StdinOnce": true,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOSTNAME=Server1"
],
"Cmd": [
"sh"
],
"Image": "test",
"Volumes": {
"/data": {}
},
"WorkingDir": "/Test",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "c6391e8cdc95aaf864677d0d82f982093bca840a86de81f8565f9d4f29573cfa",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"80/tcp": null
},
"SandboxKey": "/var/run/docker/netns/c6391e8cdc95",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "d2a94cbedd95fdca62af4755c865f968077b498418df14f033ab238b08d2adc7",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "65b6bbdf4f1fc36862cd679fcc5fc6fc2c6b5326f8c9c7f76d1e4508975ae6c4",
"EndpointID": "d2a94cbedd95fdca62af4755c865f968077b498418df14f033ab238b08d2adc7",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
[root@Server1 volumes]# cd /var/lib/docker/volumes/30b75ff3583bd344cecbc68ba19a023a61c4b9be8e98332adba879f9ac78136c/_data
[root@Server1 _data]# ls
[root@Server1 _data]# touch Testfile
- 可以看到原本该路径下什么文件也没有
- 而当我们创建了测试文件后,该文件在测试容器中也可以看到了
/ # cd /data/
/data # ls
Testfile
- 同理,在任意一侧对该文件做修改/删除, 都会反映在另一侧
镜像的优化
优化逻辑
- 选择最精简的基础镜像
- 减少镜像的层数
- 清理镜像构建的中间产物
- 注意优化网络请求
- 尽量去用构建缓存
- 使用多阶段构建镜像
举例
- 首先尝试创建一个
Nginx
的镜像,这里使用精简版的RHEL7
作为base
镜像
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY NeuWings.repo /etc/yum.repos.d/NeuWings.repo
RUN rm -rf /etc/yum.repos.d/rhel7.repo
RUN rpmdb --rebuilddb
RUN yum install -y gcc pcre-devel zlib-devel > /dev/null
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN ./configure --prefix=/usr/local/nginx > /dev/null
RUN yum install -y make > /dev/null
RUN make > /dev/null
RUN make install > /dev/null
CMD ["/usr/local/nginx/sbin/nginx", "-g" "daemon off;"]
- 查看构建完成的大小:
346M
[root@Server1 Docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo latest 181d43b6a7dc 40 seconds ago 346MB
rhel7 latest 0a3eb3fde7fd 6 years ago 140MB
尝试精简
- 压缩镜像的层数,将可以放在同一条命令执行的都整合到同一条
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY NeuWings.repo /etc/yum.repos.d/NeuWings.repo
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN rm -rf /etc/yum.repos.d/rhel7.repo && rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make > /dev/null && /mnt/nginx-1.18.0/configure --prefix=/usr/local/nginx > /dev/null && yum install -y make > /dev/null && make > /dev/null && make install > /dev/null && yum clean all > /dev/null && rm -rf /mnt/nginx-1.18.0
CMD ["/usr/local/nginx/sbin/nginx", "-g" "daemon off;"]
- 查看构建完成的大小:
258M
[root@Server1 Docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo2 latest 7f186836d1d9 14 seconds ago 258MB
demo latest 181d43b6a7dc 8 minutes ago 346MB
rhel7 latest 0a3eb3fde7fd 6 years ago 140MB
已知其实我们需要的其实只是Nginx
的二进制文件, 中途为了编译而安装的依赖以及编译中产生的内容其实在服务中都没有用到
- 采用多阶段构建的方法,创建一个临时镜像用于编译,将编译好的二进制文件拷贝到最终要创建的镜像
FROM rhel7 as build
COPY NeuWings.repo /etc/yum.repos.d/NeuWings.repo
ADD nginx-1.18.0.tar.gz /mnt
RUN rm -rf /etc/yum.repos.d/rhel7.repo && rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make > /dev/null && cd /mnt/nginx-1.18.0 && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx > /dev/null && yum install -y make > /dev/null && make > /dev/null && make install > /dev/null && yum clean all > /dev/null && rm -rf /mnt/nginx-1.18.0 && rm -rf /var/cache/yum
FROM rhel7
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g" "daemon off;"]
- 首先构建一个镜像,镜像内编译安装
Nginx
- 再阶段性构建第二个镜像,将第一个镜像中的
Nginx
二进制文件复制过来 - 这种方式省去了中途安装的依赖和编译内容,镜像大小大大降低
[root@Server1 Docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo2 latest 94f2bf6f8c66 7 seconds ago 141MB
<none> <none> 56fe29ab9d19 8 seconds ago 258MB
demo latest 181d43b6a7dc 24 minutes ago 346MB
rhel7 latest 0a3eb3fde7fd 6 years ago 140MB
-
查看构建完成的大小:
141M
, 仅比base
镜像大了1m而已. -
如果还要继续压缩,就只能寻找更精简的
base
镜像了
FROM nginx as base
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG TIME_ZONE
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 /lib/x86_64-linux-gnu/libpcre.so.* /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 /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \\
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \\
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base-debian10
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]
- 操作过程
##获取最精简的基础镜像
[root@Server1 Docker]# docker load < base-debian10.tar
de1602ca36c9: Loading layer 3.041MB/3.041MB
1d3b68b6972f: Loading layer 17.77MB/17.77MB
Loaded image: gcr.io/distroless/base-debian10:latest
##构建需要的nginx镜像
[root@Server1 Docker]# docker build -t webserer:V1 -f Dockerfile2 .
##查看构建结果
[root@Server1 Docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
webserer V1 059742ab983d 6 seconds ago 31.9MB
<none> <none> 2cb570a37c5b 8 seconds ago 146MB
nginx latest 62d49f9bab67 13 days ago 133MB
gcr.io/distroless/base-debian10 latest d48fcdd54946 51 years ago 19.2MB
- 查看构建完成的大小:
31.9M
以上是关于运维实战 容器部分 Docker镜像的主要内容,如果未能解决你的问题,请参考以下文章