Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造

镜像存储位置:
  • Linux Docker 主机 本地镜像仓库通常位于/var/lib/docker/
  • Windows Docker 主机则是C:\\ProgramData\\docker\\windowsfilter。

docker镜像采用层级结构,一个镜像最多拥有127层UnionFS(联合文件系统)。

一、base镜像

有两层含义:
  • 不依赖其它镜像,从scratch构建;
  • 其它镜像可以以它为基础进行扩展
能称作base镜像的通常是最小安装的、各种Linux发行版的Docker镜像,比如Ubuntu、Debian、Centos等。

二、Linux操作系统由内核空间与用户空间组成

Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第1张图片
内核空间是kernel,Linux刚启动时会加载bootfs文件系统,之后bootfs会被卸载掉;
用户空间的文件系统是rootfs,包含我们熟悉的/dev、/proc等目录。
base镜像,底层直接用Host的kernel,自己只需提供rootfs(包括最基本的命令、工具、程序库)。

三、构建镜像

3.1、docker commit命令构建镜像   

-----不建议(易出错、效率低、重复性差、无法对镜像进行审计)

是创建镜像最直观的方法,包含三步:
1、运行容器
2、修改容器
3、将容器保存为新镜像
比如:在ubuntu base镜像里安装vi并保存为新镜像
1、在宿主机上运行容器:docker run -it ubuntu
2、在容器内安装vi:apt-get install -y vim    # 可能需要配置源 Docker镜像apt-get提示:E: Unable to locate package vim_最爱喝酸奶的博客-CSDN博客
3、在宿主机上保存为新镜像:
    3.1 在宿主机上查看当前运行的容器 ,名称为 jovial_noyce
    3.2 执行docker commit将容器保存为新镜像
         docker commit  jovial_noyce  ubuntu-with-vi   # 新镜像ubuntu-with-vi
4、在宿主机上从新镜像ubuntu-with-vi启动容器,验证vi
docker run -it ubuntu-with-vi

3.2、Dockerfile构建镜像

概念:
    Dockerfile是镜像的描述文件,定义了如何构建Docker镜像。
Dockerfile中每一个指令都会创建一个镜像层,上层依赖于下层,只要某一层发生变化,其上面的所有层的缓存都会失效。
构建镜像过程:
1、从base镜像运行一个容器;
2、执行一条指令,对容器修改;
3、执行docker commit的操作,生成新的镜像层;
4、Docker再基于步骤3生成的新的镜像运行一个新的容器;
5、重复2~4步骤,直到Dockerfile中的所有指令执行完毕。

调试Dockfile:

    若执行Dockerfile失败了,可根据之前一个指定成功构建的镜像查出问题:运行最新的这个镜像定位问题。
1、在宿主机上创建Dockerfile文件,内容如下:
[root@syslog docker_test]# ll
total 4
-rw-r--r-- 1 root root 57 Oct 15 16:55 Dockerfile  #手工创建
[root@syslog docker_test]# cat Dockerfile
FROM ubuntu                                                                     # 将ubuntu作为base镜像
RUN apt-get update && apt-get install -y vim

2、[root@syslog docker_test]# docker build -t ubuntu-with-vim-dockerfile .       # ubuntu-with-vim-dockerfile新镜像的名称

3、查看镜像
4、docker history会显示镜像的构建历史,也就是Dockerfile的执行过程
[root@syslog docker_test]# docker history  ubuntu-with-vim-dockerfile
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
2375dae36592        8 minutes ago       /bin/sh -c apt-get update && apt-get install…   93.9MB
9140108b62dc        2 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
           2 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B
           2 weeks ago         /bin/sh -c [ -z "$(apt-get indextargets)" ]     0B
           2 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   811B
           2 weeks ago         /bin/sh -c #(nop) ADD file:da80f59399481ffc3…   72.9MB 

ubuntu-with-vim-dockerfile与ubuntu镜像相比,只多了顶部的一层2375dae36592,由apt-get命令创建,大小93.9MB,(93.9+72.9=167M)

表示无法获取IMAGE ID,通常从Docker Hub下载的镜像会有这个问题。

四、镜像命名

一个特定镜像的名字有两部分组成:repository与tag(用于描述版本信息)
[image name] = [repository]:[tag]
若执行docker build时未指定tag,会使用默认值latest,等同于:docker build -t ubuntu-with-vi:latest
docker tag image-name  [repository]:[tag]      # 给镜像image-name重命名
例如:docker tag httpd https-1.2:1.2
Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第2张图片

五、保存/发布镜像

5.1、使用公共registry

使用Docker Hub、quary.io
    1、在Docker Hub注册一个账号
    2、在Dock Host(宿主机)上登录
Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第3张图片
    3、修改镜像的repository与Docker Hub账号匹配( Docker Hub为了区分不同用户的同名镜像,镜像的repository要包含用户名,完整格式:[username]/xxx:tag
[root@syslog ~]# docker tag httpd 1162886013/https-1.3:1.3
[root@syslog ~]# docker images 1162886013/https-1.3
REPOSITORY             TAG                 IMAGE ID            CREATED             SIZE
1162886013/https-1.3   1.3                 3dd970e6b110        3 days ago          138MB

    4、docker push 将镜像上传到Docker Hub:Docker会上传镜像的每一层,若Docker Hub上已经有了的镜像层则不会上传;如果想上传同一个repository中所有镜像,省略tag部分即可

[root@syslog ~]# docker push 1162886013/https-1.3:1.3
The push refers to repository [docker.io/1162886013/https-1.3]
850c0c904ff3: Pushed
c264370aa736: Pushed
e6f7f192bbc8: Mounted from library/httpd
6d80bc0bd923: Pushed
d0fe97fa8b8c: Pushed
1.3: digest: sha256:60b82a0c2599b217d5231d3a54eb9f691ac8bc15b66f8f5f79f383f87c9c51ce size: 1366

     5、在Docker Hub的Repositories可以看到上传的镜像

Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第4张图片
  6、这个新上传的镜像可以被其他DockerHost下载使用:docker pull 1162886013/https-1.3:1.3

5.2、搭建本地registry

Docker Hub上有官方的镜像registry,我们在自己的Docker中运行registry
    1、 首先, Http: server gave HTTP response to HTTPS client 解决方法_兔子不会武功的博客-CSDN博客,解决docker push报错: http: server gave HTTP response to HTTPS client
           Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第5张图片
    2、启动registry容器:
docker run -d -p 5000:5000 -v /home/myregistory:/var/lib/registry registry:2

    -d: 后台启动容器

    -p: 将容器的5000端口映射到Host的5000端口,5000是registry服务端口

    -v: 将容器的/var/lib/registry目录映射到Host的/home/myregistory(手动创建该目录),用于存放镜像数据

         Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第6张图片
    3、docker tag重命名镜像,使之与registry匹配
         [root@syslog ~] docker tag httpd:1.1    10.21.144.111 :5000/1162886013/httpd:1.1
        在新镜像的前面加了运行registry的主机名称和端口
        repository完整格式:[registry-host]:[port]/[username]]/xxx,只有Docker Hub上的镜像可以省略[registry-host]:[port]
         Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第7张图片
  4、docker push上传镜像  docker push   10.21.144.111:5000/1162886013/httpd:1.1
         Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第8张图片

六、多层架构的镜像

在不同的平台上拉取镜像,需要考虑镜像是否与当前运行环境的架构(Windows、ARM..)匹配。
多架构镜像(Multi-architecture Image)的出现解决了这个问题!某个镜像仓库标签下的镜像可以同时支持64位Linux、Windows、ARM等多种架构
为了实现这个特性,镜像仓库服务API支持两种重要的结构:Manifest列表(新)和Manifest。
Manifest列表指某个镜像标签支持的架构列表其支持的每种架构,都有自己的Mainfest定义,其中列举了该镜像的构成。
Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第9张图片
原理:
假设要在ARM架构的linux上运行docker,拉取镜像时,Docker客户端调用Docker hub镜像仓库服务相应的API完成拉取。若该镜像有Mainfest列表,且存在Linux on ARM一项,则Docker Client会找到ARM架构对应的Mainfest并解析出该镜像的镜像层加密ID,然后从Docker Hub二进制存储中拉取每个镜像层。
所有官方镜像支持Mainfest列表。在没有Manifest列表的情况下,镜像仓库服务返回普通的Manifest.
示例:go version命令输出Go的版本和主机OS/CPU架构信息
Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第10张图片

七、多阶段构造

多阶段构造能在不增加复杂性的前提下优化构造过程。
多阶段构建方式使用一个Dockerfile,其中包含多个FROM 指令。每一个FROM 指令都是一个新的构建阶段(Build Stage),并且可以方便地复制之前阶段的构件。
Dockerfile文件如下:
Docker- 5、构建镜像/镜像命名/保存发布镜像/多阶段构造_第11张图片
重点在于 COPY --from 指令,它从之前的阶段构建的镜像中仅复制生产环境相关的应用代码,而不会复制生产环境不需要的构件。

八、构建镜像最佳实践

8.1、镜像缓存

一旦有指令在缓存中未命中(没有该指令对应的镜像层),则后续的整个构建过程将不再使用缓存。在编写Dockerfile 时须特别注意这一点,尽量将易于发生变化的指令置于Dockerfile 文件的后方执行。这意味着缓存未命中的情况将直到构建的后期才会出现,从而构建过程能够尽量从缓存中获益。通过对docker image build命令加入--nocache=true 参数可以强制忽略对缓存的使用。还有一点也很重要,那就是COPY 和ADD 指令会检查复制到镜像中的内容自上一次构建之后是否发生了变化。例如,有可能Dockerfile 中的COPY . /src 指令没有发生变化,但是被复制的目录中的内容已经发生变化了。为了应对这一问题,Docker 会计算每一个被复制文件的Checksum 值,并与缓存镜像层中同一文件的checksum 进行对比。如果不匹配,那么就认为缓存无效并构建新的镜像层。

8.2、合并镜像

总体来说,Docker 会遵循正常的方式构建镜像,但之后会增加一个额外的步骤,将所有的内容合并到一个镜像层中。当镜像中层数太多时,合并是一个不错的优化方式。例如,当创建一个新的基础镜像,以便基于它来构建其他镜像的时候,这个基础镜像就最好被合并为一层。缺点是,合并的镜像将无法共享镜像层。这会导致存储空间的低效利用,而且push 和pull  操作的镜像体积更大。执行docker image build 命令时,可以通过增加--squash 参数来创建一个合并的镜像。

8.3、使用no-install-recommends

在构建Linux 镜像时,若使用的是APT 包管理器,则应该在执行apt-get install 命令时增加no-install-recommends 参数。这能够确保APT 仅安装核心依赖(Depends 中定义)包,而不是推荐和建议的包。这样能够显著减少不必要包的下载数量。

你可能感兴趣的:(k8s+docker,docker,构建镜像)