banner
biuaxia

biuaxia

"万物皆有裂痕,那是光进来的地方。"
github
bilibili
tg_channel

[Reprint] Principles of Docker Images

title: 【转载】Docker Image Principles
date: 2021-08-16 09:24:01
comment: false
toc: true
category:

  • Docker
    tags:
  • 转载
  • Docker
  • Image
  • Principles

This article is reprinted from: Docker Image Principles


Docker Image Principles#

An image is a lightweight, executable, standalone software package used to package the software runtime environment and the software developed based on the runtime environment. It contains everything needed for a particular software, including code, runtime libraries, environment variables, and configuration files.

UnionFs (Union File System)#

UnionFS (Union File System): The Union file system (UnionFS) is a layered, lightweight, and high-performance file system that supports modifications to the file system as a single commit layered on top of each other, while also allowing different directories to be mounted under the same virtual file system (unite several directories into a single virtual filesystem). The Union file system is the foundation of Docker images. Images can inherit through layers, and various specific application images can be created based on a base image (which has no parent image). Features: Multiple file systems can be loaded simultaneously, but from the outside, only one file system is visible. The union loading will overlay the various layers of the file system, so the final file system will contain all the underlying files and directories.

When downloading a Docker image layer by layer, it is actually a manifestation of the union file system.

Docker Image Loading Principles#

Docker images are actually composed of layers of file systems, which is a hierarchical file system called UnionFS. The bootfs (boot file system) mainly contains the bootloader and kernel. The bootloader is primarily responsible for loading the kernel. When Linux starts, it loads the bootfs file system, and at the bottom layer of the Docker image is the bootfs. This layer is the same as in a typical Linux/Unix system, containing the bootloader and kernel. Once the boot process is complete, the entire kernel is in memory, and at this point, the memory usage rights have been transferred from bootfs to the kernel, and the system will also unload bootfs.

The rootfs (root file system) is above the bootfs. It includes the standard directories and files in a typical Linux system, such as /dev, /proc, /bin, /etc, etc. The rootfs consists of various different operating system distributions, such as Ubuntu, CentOS, etc.

image

Usually, the CentOS we install on virtual machines is several gigabytes, while Docker is only a few hundred megabytes.

For a streamlined OS, the rootfs can be very small, only needing to include the most basic commands, tools, and libraries, because the underlying kernel is directly used from the host, and it only needs to provide the rootfs. Thus, for different Linux distributions, the bootfs is basically consistent, while the rootfs will differ, allowing different distributions to share the bootfs.

Understanding Layers#

When downloading a Docker image layer by layer, it is the most intuitive manifestation of layering (already downloaded layers will not be downloaded again).

$ docker pull redis  
Using default tag: latest  
latest: Pulling from library/redis  
33847f680f63: Already exists  
26a746039521: Pull complete  
18d87da94363: Pull complete  
5e118a708802: Pull complete  
ecf0dbe7c357: Pull complete  
46f280ba52da: Pull complete  
Digest: sha256:cd0c68c5479f2db4b9e2c5fbfdb7a8acb77625322dd5b474578515422d3ddb59  
Status: Downloaded newer image for redis:latest  
docker.io/library/redis:latest  

We can also use the inspect command mentioned in the previous article.

docker image inspect redis:latest  

We can see the specific layering information of the image, with 6 layers corresponding to the 6 layers when the image was downloaded.

"RootFS": {  
    "Type": "layers",  
    "Layers": [  
        "sha256:814bff7343242acfd20a2c841e041dd57c50f0cf844d4abd2329f78b992197f4",  
        "sha256:dd1ebb1f5319785e34838c7332a71e5255bda9ccf61d2a0bf3bff3d2c3f4cdb4",  
        "sha256:11f99184504048b93dc2bdabf1999d6bc7d9d9ded54d15a5f09e36d8c571c32d",  
        "sha256:e461360755916af80821289b1cbc503692cf63e4e93f09b35784d9f7a819f7f2",  
        "sha256:45f6df6342536d948b07e9df6ad231bf17a73e5861a84fc3c9ee8a59f73d0f9f",  
        "sha256:262de04acb7e0165281132c876c0636c358963aa3e0b99e7fbeb8aba08c06935"  
    ]  
},  

Benefits of Layering:

The biggest benefit is - resource sharing.

For example, if multiple images are built from the same base image, then the Docker Host only needs to save one copy of the base image on disk; at the same time, only one copy of the base image needs to be loaded into memory to serve all containers. Moreover, each layer of the image can be shared.

At this point, someone might ask: If multiple containers share a base image, when one container modifies the contents of the base image, such as files under /etc, will the /etc of other containers also be modified? The answer is: No! Because modifications are confined to a single container.

This is the Copy-on-Write feature of containers that we will learn next.

Writable Layer of Containers#

When a container starts, a new writable layer is loaded on top of the image. This layer is commonly referred to as the "container layer," while everything below the "container layer" is called "image layers." All operations are performed on the container layer, which is the only writable layer; all image layers below the container layer are read-only.

image

Commit Image#

docker commit  Submit the container as a new copy  

Let's illustrate this with an example.

I previously downloaded the Tomcat image.

$ docker images  
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE  
tomcat       latest    710ec5c56683   7 days ago     668MB  
redis        latest    aa4d65e670d6   3 weeks ago    105MB  
mysql        latest    c60d96bd2b77   3 weeks ago    514MB  
centos       centos7   8652b9f0cb4c   9 months ago   204MB  

Start Tomcat.

-- Run the image and map the port to the host port  
docker run  -it -p 8080:8080 tomcat  

In another terminal, check the currently running containers; Tomcat is running.

$ docker ps  
CONTAINER ID   IMAGE            COMMAND             CREATED          STATUS          PORTS                                       NAMES  
8b294cd7074e   tomcat           "catalina.sh run"   29 seconds ago   Up 28 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   zealous_cohen  
f42ae22e4b72   centos:centos7   "/bin/bash"         3 weeks ago      Up 46 hours                                                 centos-test  

Then we enter the Tomcat container.

docker exec -it 8b294cd7074e /bin/bash  
$ docker exec -it 8b294cd7074e /bin/bash  
root@8b294cd7074e:/usr/local/tomcat# ls  
BUILDING.txt  CONTRIBUTING.md  LICENSE	NOTICE	README.md  RELEASE-NOTES  RUNNING.txt  bin  conf  lib  logs  native-jni-lib  temp  webapps  webapps.dist  work  

Next, we check the webapp (project file location), and as shown, the webapp is empty.

root@8b294cd7074e:/usr/local/tomcat# cd webapps  
root@8b294cd7074e:/usr/local/tomcat/webapps# ls  
root@8b294cd7074e:/usr/local/tomcat/webapps#  

Then we access Tomcat; a 404 indicates that Tomcat has started normally but cannot find the corresponding page, which is understandable since the webapp is empty.

image

Now let's try to create an image with content in the webapp.

We will copy the files from webapps.dist to webapps.

root@8b294cd7074e:/usr/local/tomcat# cp -r webapps.dist/* webapps  
root@8b294cd7074e:/usr/local/tomcat# cd webapps  
root@8b294cd7074e:/usr/local/tomcat/webapps# ls  
ROOT  docs  examples  host-manager  manager  

After modification, Tomcat can be accessed normally.

image

$ docker ps  
CONTAINER ID   IMAGE            COMMAND             CREATED          STATUS          PORTS                                       NAMES  
8b294cd7074e   tomcat           "catalina.sh run"   27 minutes ago   Up 27 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   zealous_cohen  

Now that we have made simple modifications to this Tomcat, I think my version is slightly better than the official one, so I will submit my image.

$ docker commit -a="cb" -m "add init file" 8b294cd7074e newtomcat:1.0  
sha256:44cf4d44be664d9704a3fc38ddef1f03fa7f113ad83f4049cced322a14dc216b  

By using docker images, we can see that a new image has been created. Upon careful observation, we can find that our submitted newtomcat is slightly larger than the official tomcat.

$ docker images  
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE  
newtomcat    1.0       44cf4d44be66   46 seconds ago   673MB  
tomcat       latest    710ec5c56683   7 days ago       668MB  
redis        latest    aa4d65e670d6   3 weeks ago      105MB  
mysql        latest    c60d96bd2b77   3 weeks ago      514MB  
centos       centos7   8652b9f0cb4c   9 months ago     204MB  

Later, we can directly use our own image and also share it with others; we will discuss this later.

Through this example, we can review the layering concept mentioned above. The newtomcat is the image generated after we made modifications in the previous container layer, which is similar to a snapshot of a virtual machine image.

That's all for Docker images. Now we have a simple understanding of Docker, and we will continue to learn more about Docker-related content. Let's keep up the good work!

Day by day, there is no end; efforts will not be in vain and will eventually pay off.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.