目录

一、容器镜像结构

1、Linux 操作系统结构

2、容器镜像

3、base 镜像

4、容器镜像的分层结构

5、UnionFS 联合文件系统

6、容器 copy-on-write(写时复制) 特性

二、构建容器镜像

1、构建容器的两种方法

2、docker commit 构建镜像

1.docker命令补全

3、docker commit 示例

1. 运行一个centos 容器中运行 /sbin/init

2. 使用docker commit 命令将该容器保存为镜像“test1”

3. 使用docker images 查看新的镜像

4. 以test1 镜像运行一个容器

5. 使用docker history 命令查看镜像构建历史

3. Dockerfile

4、dockerfile 常用指令

5、Dockerfile 示例

1. 编辑一个dockerfile 文件,存放于/root/df 目录下

2. 使用docker build 命令用文件 dockerfile 构建一个镜像,并将镜像命名为 tests

6、容器镜像缓存特性

7、镜像命名

8、Registry

 9、Docker Hub

10、搭建私有Registry 示例


一、容器镜像结构

1、Linux 操作系统结构

Linux 操作系统由内核空间和用户空间构成

        kernel:Linux系统内核(/boot/vmlinuz-*)

        rootfs根文件系统): Linux系统中的用户空间文件系统。

             rootfs 是一个操作系统所包含的文件、配置和目录,但并不包括操作系统kernel

             

2、容器镜像

1. 容器镜像是容器的模板,容器时镜像的运行实例,runtime根据容器镜像创建容器

    

2. 容器镜像挂载在容器根目录,是为容器中的应用提供隔离后执行环境的文件系统

        ① 容器镜像打包了整个操作系统的文件和目录(rootfs),当然也包括应用本身。即,               应用及其运行所需的所有依赖,都在被封装在容器镜像中。

             保证了本地环境和云端环境的高度一致

3. 容器镜像采用分层结构:

        所有容器共享宿主机Kernel,并且不能修改宿主机Kernel。即,容器运行过程中使用               容器镜像里的文件,使用宿主机OS上的Kernel

3、base 镜像

1. scratch 空镜像

        ① 从 scratch 构建,不依赖其它镜像

                - scratch 本身是个空镜像

        其他镜像可在base 镜像上进行扩展,创建新的镜像

2. 最常用的 base 镜像是各 Linux 发行版的 Docker镜像,如 ubuntu、centos等

4、容器镜像的分层结构

1. Docker 镜像中引入层 layer 的概念。镜像制作过程中的每一步操作,都会生成一个新的镜像层 

2. 容器由若干只读镜像层和最上面的一个可写容器层构成

        分层结构使镜像共享、容器创建、分发非常高效

3. 使用 docker image inspect ubuntu 命令查看 ubuntu 镜像分层结构,回显如下

5、UnionFS 联合文件系统

1. UnionFS 主要功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下

        每一个镜像层都是Linux 操作系统文件与目录的一部分。在使用镜像时,docker 会                将所有的镜像层联合挂载到一个统一的挂载点上,表现为一个完整的Linux 操作系统              供容器使用

            

# docker images    #查看本地镜像

# docker history alpine:latest    #查看镜像制作历史

# docker pull ubuntu #从镜像仓库拉取镜像 ubuntu

# docker image inspect ubuntu:latest    #查看镜像相关信息

# docker run -itd ubuntu    #使用镜像运行容器

# docker ps    #查看运行中的容器

# docker exec -it dreamy_carson ls / #查看容器根目录

6、容器 copy-on-write(写时复制) 特性

1. 对容器的增、删、改、查操作:

操作具体执行
创建文件新文件只能被添加在容器层中
删除文件

依据容器分层结构由上往下依次查找。找到后,在容器层中记录该删除操作

具体实现是,UnionFS会在容器层创建一个"whiteout 文件"

将被删除的文件"遮挡"起来

修改文件

依据容器分层结构由上往下依次查找。

找到后,将镜像层中的数据复制容器层进行修改,

修改后的数据保存在容器层中。

(copy-on-write)

读取文件依据容器分层结构由上往下依次查找

二、构建容器镜像

1、构建容器的两种方法

2、docker commit 构建镜像

1. docker commit 命令:可将一个运行中的容器保存为镜像。其运行过程可总结如下:

        运行一个容器

        修改容器内容

        将容器保存为镜像

1.docker命令补全

docker命令提供了bash-complete的脚本,在执行该命令时,敲tab可以自动补全参数

/usr/share/bash-completion/completions/docker 

# apt-get install bash-completion
# source /usr/share/bash-completion/completions/docker    #执行后出现如下问题
# docker pbash: _get_comp_words_by_ref: command not found
bash: [: : integer expression expected
bash: [: : integer expression expected
bash: [: : integer expression expected
q^C

'/usr/share/bash-completion/bash_completion 该文件中有上面缺少的命令'
# source /usr/share/bash-completion/bash_completion #此时就可正常进行docker子命令的补全

3、docker commit 示例

1. 运行一个centos 容器中运行 /sbin/init

# docker run -itd --privileged centos /sbin/init    #centos不加--privileged没有权限修改
# docker ps    #查看状态容器已经运行
CONTAINER ID   IMAGE                                               COMMAND                  CREATED          STATUS          PORTS     NAMES
736eae62b647   centos                                              "/sbin/init"             45 seconds ago   Up 44 seconds             inspiring_boyd
# docker exec -it 736e /bin/bash #进入容器

[root@736eae62b647 /]# yum -y install httpd    #安装web服务
Failed to set locale, defaulting to C.UTF-8
CentOS Linux 8 - AppStream                                                        73  B/s |  38  B     00:00    
Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist
'提示仓库源有问题'
[root@736eae62b647 /]# rm -rf /etc/yum.repos.d/CentOS-Linux-*
[root@736eae62b647 /]# cat /etc/redhat-release     #查看当前版本
CentOS Linux release 8.4.2105
[root@736eae62b647 /]#  curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo    #可以去阿里上查找对应版本https://developer.aliyun.com/mirror/
[root@736eae62b647 /]# yum repolist    #查看仓库是否架子啊
Failed to set locale, defaulting to C.UTF-8
repo id                              repo name
AppStream                            CentOS-8.5.2111 - AppStream - mirrors.aliyun.com
base                                 CentOS-8.5.2111 - Base - mirrors.aliyun.com
extras                               CentOS-8.5.2111 - Extras - mirrors.aliyun.com
[root@736eae62b647 /]# yum -y install httpd    #再次安装即可
[root@736eae62b647 /]# echo "hello world" > /var/www/html/index.html
[root@736eae62b647 /]# systemctl enable --now httpd
[root@736eae62b647 /]# curl localhost      #web服务正常开启
hello world
[root@736eae62b647 /]# exit #退出容器
# docker ps    #查看运行的容器状态
CONTAINER ID   IMAGE                                               COMMAND                  CREATED          STATUS          PORTS     NAMES
736eae62b647   centos                                              "/sbin/init"             27 minutes ago   Up 27 minutes             inspiring_boyd

2. 使用docker commit 命令将该容器保存为镜像“test1”

# docker commit inspiring_boyd test1    #将运行的容器做成镜像
sha256:18828b81510de014ea66b1ad3b505ba774fbc74ad2b25aa9168c584efced6924

3. 使用docker images 查看新的镜像

# docker images
REPOSITORY       TAG       IMAGE ID       CREATED         SIZE
test1            latest    18828b81510d   41 seconds ago     280MB

4. 以test1 镜像运行一个容器

# docker run -itd --privileged test1 /sbin/init
# docker exec -it interesting_vaughan /bin/bash    #进入容器
[root@09bf75ca5019 /]# curl localhost    #测试服务正常
hello world    

5. 使用docker history 命令查看镜像构建历史

对比镜像test1与centos,test1 比 centos 多了一个镜像层

3. Dockerfile

1. 文件指令集,描述如何自动创建 Docker 镜像

         是包含若干指令的文本文件,可以通过这些指令创建出 docker image

        文件中的指令执行后,会创建一个个新的镜像层

        文件中的注释以 “#” 开始

        一般由 4 部分组成

        

2. build context: 为镜像构建提供所需的文件或目录 

4、dockerfile 常用指令

指令作用命令格式
FROM指定base镜像FROM  <image>:<tag>
MAINTAINER注明镜像的作者MAINTAINER  <name>
RUN运行指定的命令RUN  <command>
ADD将文件从build context 复制到镜像中ADD  [--chown=<user>:<group>]<src>...<dest>
COPY将文件从build context复制到镜像中COPY  [--chown=<user>:<group>]<src>...<dest>
ENV设置环境变量ENV  <key><value>
EXPOSE指定容器中的应用监听的端口EXPOSE  <port>  [<port>/<protocol>...]
USER设置启动容器的用户USER  <user>[:<group>]
CMD设置在容器启动时运行指定的脚本或命令CMD command  param1 param2
ENTRYPOINT指定的是一个可执行的脚本或者程序的路径ENTRYPOINT  command  param1  param2
VOLUME将文件或目录声明为volume,挂载到容器中VOLUME  ["/data"]
WORKDIR设置镜像的当前工作目录WORKDIR  /path/to/workdir

参考资料: Dockerfile reference | Docker Documentation

5、Dockerfile 示例

1. 编辑一个dockerfile 文件,存放于/root/df 目录下

~# mkdir df
~# cd /root/df
~/df# echo haha > index.html
~/df# vim vim dockerfile
FROM httpd            #指定镜像
COPY index.html /     #将文件拷贝到镜像的根目录下
RUN echo haha         #运行一条命令

2. 使用docker build 命令用文件 dockerfile 构建一个镜像,并将镜像命名为 tests

~/df# docker build -t tests .    #-t指定镜像名 .为在当前目录中寻找dockerfile文件
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM httpd
 ---> a981c8992512
Step 2/3 : COPY index.html /
 ---> 9f026a199a7d
Step 3/3 : RUN echo haha
 ---> Running in 553668509bac
haha
Removing intermediate container 553668509bac
 ---> 3a9e4e5ee1bf
Successfully built 3a9e4e5ee1bf
Successfully tagged tests:latest

6、容器镜像缓存特性

1. Docker 会缓存已有镜像的镜像层,构建或下载镜像时,如果某镜像层已存在,则直接使用无须重新创建或下载

2. 编译 dockerfile 文件,增加在末尾声明作者的指令

~/df# vim dockerfile    
FROM httpd   
COPY index.html /
RUN echo haha
MAINTAINER *_花非人陌_*   #增加作者信息

3. 重新执行 docker build 构建镜像,新镜像命名为 tests2

~/df# docker build -t tests2 .    #重新建立镜像
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM httpd
 ---> a981c8992512
Step 2/4 : COPY index.html /
 ---> 'Using cache'    #使用了缓存
 ---> 9f026a199a7d
Step 3/4 : RUN echo haha
 ---> Using cache
 ---> 3a9e4e5ee1bf
Step 4/4 : MAINTAINER *_花非人陌_*
 ---> Running in 4f9ac93f1eb8
Removing intermediate container 4f9ac93f1eb8
 ---> 0bc362ff7331
Successfully built 0bc362ff7331
Successfully tagged tests2:latest

4. 交换dockerfile 文件中命令执行顺序,虽然在逻辑上这种改动对镜像的内容没有影响,但由于分层的结构特性,Docker 必须重建受影响的镜像层

~/df# vim dockerfile
FROM httpd
MAINTAINER *_花非人陌_*
COPY index.html /
RUN echo haha

5. 重新构建镜像test3,每一步均生成新的镜像层,未使用到 cache

~/df# docker build -t tests2 .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM httpd
 ---> a981c8992512
Step 2/4 : MAINTAINER *_花非人陌_*
 ---> Running in 2ab77293ccd7
Removing intermediate container 2ab77293ccd7
 ---> f1822a01898b
Step 3/4 : COPY index.html /
 ---> 3e7d474f3185
Step 4/4 : RUN echo haha
 ---> Running in 9dacd7052d95
haha
Removing intermediate container 9dacd7052d95
 ---> 456098bfd852
Successfully built 456098bfd852
Successfully tagged tests2:latest

7、镜像命名

镜像名称格式

         image name = repository:tag

        ② tag 一般用于描述镜像版本。若未指定tag,则默认为“latest”

8、Registry

1. Registry 是存放容器镜像的仓库,用户可进行镜像下载和访问,分为公有和私有两类

2. 公有镜像仓库

        Docker Hub 是 Docker 公司为公众提供的托管 Registry    Docker Hub

        Quay.io 现为 Red Hat 下的公共托管 Registry   Quay

        https://www.aliyun.com

        catalog.redhat.com

3. 私有仓库

        企业可以用 Docker Registry 构建私有的 Registry

                Registry 本身是一个开源项目,可以用于搭建私有 Registry

        Harbor,企业免费

        quay,收费

 9、Docker Hub

1. Docker Hub 是目前世界上最大的容器镜像仓库,由Docker公司维护。

    上面有Docker公司提供的镜像,及大量用户上传的镜像

10、搭建私有Registry 示例

1. 使用“registry” 镜像构建本地镜像仓库。registry 是 docker hub 上维护的镜像,其服务端        口是5000。 -v 参数将宿主机的/root/myregistry 目录映射到容器的 /var/lib/registry目录,用于存放镜像数据

root@k8s-master:~# mkdir /root/myregistry    
root@k8s-master:~# docker pull registry    #下载registry镜像
~# docker inspect registry | grep -A 1 Volume #查看容器数据挂载点
            "Volumes": {
                "/var/lib/registry": {}
--
            "Volumes": {
                "/var/lib/registry": {}
root@k8s-master:~# docker run -d -p 1000:5000 -v /root/myregistry:/var/lib/registry registry    #运行容器
# docker ps    #查看容器是否运行
CONTAINER ID   IMAGE        COMMAND                  CREATED              STATUS              PORTS                                       NAMES
45fa5baba5e8   registry     "/entrypoint.sh /etc…"   About a minute ago   Up About a minute   0.0.0.0:1000->5000/tcp, :::1000->5000/tcp   epic_heyrovsky

2. 使用docker tag 命令修改镜像名称,使其符合registry上的格式要求。

    若要将镜像上传到registry,镜像名称需要符合其命名格式要求:

     [Registry-host]:[port]/[username]/[repository:tag]

root@k8s-master:~# docker images    #查看镜像
REPOSITORY        TAG       IMAGE ID       CREATED         SIZE
tests2            latest    456098bfd852   2 hours ago     145MB
root@k8s-master:~# docker tag tests2:latest 192.168.5.100:1000/tests2:tests2

3.   上传容器镜像到私有 Registry

# docker push 192.168.5.100:1000/tests2:tests2    #默认无法推送成功
The push refers to repository [192.168.5.100:1000/tests2]
Get "https://192.168.5.100:1000/v2/": http: server gave HTTP response to HTTPS client
'默认无法推送,因为当前为https'

4. 在Linux下,若使用如“192.168.73.137:1000” 这样的内网地址作为私有仓库地址,则需要      在/etc/docker/daemon.json 中写入如下内容(如果文件不存在需新建该文件),

    然后重启Docker服务

root@k8s-master:~# vim /etc/docker/daemon.json    #编辑docker配置文件 
 },                                                
  "registry-mirrors": ["https://docker.nju.edu.cn/"],
  "insecure-registries": ["192.168.5.100:1000"]    #意思是不用证书服务地址和端口
}   
root@k8s-master:~# systemctl daemon-reload     #重新加载配置
root@k8s-master:~# systemctl restart docker    #重启docker服务
root@k8s-master:~# docker start epic_heyrovsky #启动容器

# ss -tunlp | grep 1000    #查看端口是否被监听,确保可以正常服务
tcp   LISTEN 0      4096         0.0.0.0:1000       0.0.0.0:*    users:(("docker-proxy",pid=1448928,fd=4))               
tcp   LISTEN 0      4096            [::]:1000          [::]:*    users:(("docker-proxy",pid=1448934,fd=4))               
'再次push成功,192.168.5.100:1000就是仓库地址'
root@k8s-master:~# docker push 192.168.5.100:1000/tests2:tests2 #上传镜像
The push refers to repository [192.168.5.100:1000/tests2]
462d767129cf: Pushed 
01597d537f57: Pushed 
c7c38e3c39ad: Pushed 
c672c6903747: Pushed 
34e2a1369fc5: Pushed 
6485bed63627: Pushed 
tests2: digest: sha256:6fad1afe9b257abc84994bb30ab12d3b63b44cbd6518c6a8b16a89507387daa0 size: 1573

# curl 192.168.5.100:1000/v2/_catalog    #访问后镜像已正常上传
{"repositories":["test2"]}

# curl http://192.168.147.102:1000/v2/test2/tags/list #查看镜像标签

# docker-registry-cli

将镜像分成了多层,放置在了不同目录当中

root@k8s-master:~# tree /root/myregistry/
/root/myregistry/
└── docker
    └── registry
        └── v2
            ├── blobs
            │   └── sha256
            │       ├── 15
            │       │   └── 152876b0d24a5561415915c652dceeb3bcd5080dc24c3994e77343a81f64b9f1
            │       │       └── data
            │       ├── 45
            │       │   └── 456098bfd852c3b85b0e7756273f8bbc085660225389066c6e9d7e0171ef8928
            │       │       └── data
            │       ├── 6b
            │       │   └── 6b29c2b62286e254216da297b4066a4bb79b918bc02811ba954bd7b8fd51360b
            │       │       └── data
            │       ├── 6c
            │       │   └── 6cc0f1e2dfdc6eb221cb7ad6e25e84544f19c87767e429a7ea683dfa5cbb257b
            │       │       └── data
            │       ├── 6f
            │       │   └── 6fad1afe9b257abc84994bb30ab12d3b63b44cbd6518c6a8b16a89507387daa0
            │       │       └── data
            │       ├── 7a
            │       │   └── 7a6db449b51b92eac5c81cdbd82917785343f1664b2be57b22337b0a40c5b29d
            │       │       └── data
            │       ├── b4
            │       │   └── b4effd428409f1da4dc8c896afb9818ef1ba24be5e7e5e3d86dea650ac3ed8bc
            │       │       └── data
            │       └── c2
            │           └── c2123effa3fcb96c62bf4d891147aef09029d429321bfb4c6a535fa3ca7e13d6
            │               └── data
            └── repositories
                └── tests2
                    ├── _layers
                    │   └── sha256
                    │       ├── 152876b0d24a5561415915c652dceeb3bcd5080dc24c3994e77343a81f64b9f1
                    │       │   └── link
                    │       ├── 456098bfd852c3b85b0e7756273f8bbc085660225389066c6e9d7e0171ef8928
                    │       │   └── link
                    │       ├── 6b29c2b62286e254216da297b4066a4bb79b918bc02811ba954bd7b8fd51360b
                    │       │   └── link
                    │       ├── 6cc0f1e2dfdc6eb221cb7ad6e25e84544f19c87767e429a7ea683dfa5cbb257b
                    │       │   └── link
                    │       ├── 7a6db449b51b92eac5c81cdbd82917785343f1664b2be57b22337b0a40c5b29d
                    │       │   └── link
                    │       ├── b4effd428409f1da4dc8c896afb9818ef1ba24be5e7e5e3d86dea650ac3ed8bc
                    │       │   └── link
                    │       └── c2123effa3fcb96c62bf4d891147aef09029d429321bfb4c6a535fa3ca7e13d6
                    │           └── link
                    ├── _manifests
                    │   ├── revisions
                    │   │   └── sha256
                    │   │       └── 6fad1afe9b257abc84994bb30ab12d3b63b44cbd6518c6a8b16a89507387daa0
                    │   │           └── link
                    │   └── tags
                    │       └── tests2
                    │           ├── current
                    │           │   └── link
                    │           └── index
                    │               └── sha256
                    │                   └── 6fad1afe9b257abc84994bb30ab12d3b63b44cbd6518c6a8b16a89507387daa0
                    │                       └── link
                    └── _uploads

11、搭建Harbor

1. 下载harbor

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐