Mirrored hierarchy
-
Shared host kernel
-
base image provides the smallest linux system
-
The same docker host supports running multiple linux distributions
-
The biggest advantage of adopting hierarchical structure is to share resources
Copy in write writable container layer
-
All mirror layers below the container layer are read-only
-
docker looks for files from top to bottom
-
The container layer saves the changed part of the image without any modification to the image itself
-
A mirror can only have 127 layers at most
Construction of image
Dockerfile mode is adopted
##Download the original image busybox docker pull busybox ##Create containers interactively and simply test [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 / # ##Exit interactive mode ctrl+ d Exit and close the container ctrl+ pq Exit and drive the container into the background ##Create an empty directory to store Dockerfile [root@Server1 ~]# cd /mnt/ [root@Server1 mnt]# mkdir Docker [root@Server1 Docker]# vim Dockerfile ##Document content FROM busybox RUN touch Test RUN cd Test RUN touch file{1..10} ##Use the Dockerfile of the current directory to build the image [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 ##Viewing the native image, you can see the newly built 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 ##Looking at the construction history, you can see that each operation has become a new layer [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
Using Dockerfile, you can see the records and operation contents of the new layer built based on busybox
If you use the commit method, it will be slightly different
Commit mode is adopted
##Delete the container just created in Dockerfile mode [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 exits interactive mode and puts the container into the background
[root@Server1 Docker]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7b38fd8cf7b9 busybox "sh" 31 seconds ago Up 31 seconds Busybox ##Commit the update and generate a new image 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 ##Looking at the history of image construction, you can see that the specific content of the new layer is not displayed [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
Therefore, it is recommended to use Dockerfile to build images
Dockerfile details
-
FROM
Specify the base image. If it does not exist locally, it will be pulled from the network
-
MAINTAINER
Set the author of the image, such as user mailbox, etc
-
Copy
- Copy the file from the build context to the image from the local machine
- Two forms are supported: COPY src dest and COPY ["src", "dest"]
- It should be noted that the native file must be located in the build context, that is, the directory where the Dockerfile is located
-
ADD
- The usage is similar to that of COPY. The difference is that src can be an archive compressed file. The file will be decompressed and put into the container
- Native files do not need to be in the build context
- You can also download files from the network and copy them to the image
-
ENV
Set environment variables, which can be used by subsequent instructions
- For example, env hostname Server1 example. com
-
EXPOSE
If the application service is running in the container, it should be used when the service port needs to be exposed
- Export 80, i.e. exposed port 80
-
VOLUME
- Declare the data volume, which usually specifies the data mount point of the application
- The purpose of mounting directories is to persist
- Example VOLUME ["/var/www/html"]
-
WORKDIR
- Set the current working directory in the image for the run, CMD, entry, add and copy instructions
- If the directory does not exist, it is created automatically
-
RUN
- Run the command in the container and create a new mirror layer, which is often used to install software packages
- Example: RUN yum install -y vim
-
CMD and ENTRYPOINT
- Both of these specifications are used to set the commands to be executed after the container is started
- The difference is that CMD will be overwritten by the command line after RUN, and ENTRYPOINT will not be ignored / executed
- The parameters after docker run can be passed to the ENTRYPOINT instruction as parameters
- Only one entry point can be specified in Dockerfile. If many are specified, only the last one is valid
Differences between SHELL and EXEC formats
FROM busybox ENV name world ENTRYPOINT echo "hello, $name"
The bottom layer of Shell format will call / bin/sh -c to execute instructions, which can resolve variables, while the following Exec format will not
FROM busybox ENV name world ENTRYPOINT ["/bin/echo" "hello, $name"]
You must rewrite it to the following form to resolve variables normally
FROM busybox ENV name world ENTRYPOINT ["/bin/sh" "-c" "echo hello, $name"]
In Exec format, ENTRYPOINT can provide additional parameters through CMD, and the additional parameters of CMD can be dynamically replaced when the container is started
In Shell format, ENTRYPOINT will ignore any parameters provided by CMD or docker run
Operation process
[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 content 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 parameter is often used for temporary test content. When the command is executed, the temporarily generated container will be closed and deleted
The parameters that follow are passed to the container for use
Therefore, when parameters are not passed, the output content is hello world according to the content of Dockerfile
When linux is passed, CMD parameters are overwritten, and the output content is hello linux
Example of 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)
Back to the virtual machine, check the container and its persistence path
[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
- You can see that there are no files under the original path
- When we create a test file, the file can also be seen in the test container
/ # cd /data/ /data # ls Testfile
- Similarly, any modification / deletion of the file on either side will be reflected on the other side
Image optimization
Optimization logic
- Select the thinnest base image
- Reduce the number of mirror layers
- Clean up the intermediate products of image construction
- Pay attention to optimizing network requests
- Try to build a cache with
- Use multistage to build mirrors
give an example
- First, try to create an image of Nginx. Here, the reduced version of RHEL7 is used as the base image
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;"]
- View the size of the completed build: 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
Try to streamline
- The number of layers of compressed images, which can be executed in the same command, are integrated into the same image
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;"]
- View the size of the completed build: 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
It is known that what we need is only the binary files of Nginx. The dependencies installed in the middle of compilation and the contents generated during compilation are not used in the service
- Using the method of multi-stage construction, create a temporary image for compilation, and copy the compiled binary file to the final image to be created
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;"]
- First, build an image and compile and install Nginx in the image
- Build the second image in stages and copy the Nginx binary file in the first image
- In this way, the dependency of Midway installation and compilation content are omitted, and the image size is greatly reduced
[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
-
Check the size of the built image: 141M, which is only 1m larger than the base image
-
If you want to continue to compress, you can only find a leaner base image
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;"]
- Operation process
##Get the thinnest basic image [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 ##Build the required nginx image [root@Server1 Docker]# docker build -t webserer:V1 -f Dockerfile2 . ##View build results [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
- View the size of the completed build: 31.9M