云原生系列技术|云原生系列技术(二)(Docker 镜像详解)

?上一节我们主要讲了《Docker 介绍及实战》,这一节我们给大家重点讲下Docker镜像。
以实战为主,分三步走:使用别人的镜像 ——》制作自己镜像——》搭建自己的私有镜像仓库。
一、使用别人的镜像

  1. 配置国内镜像源 Docker 拉取(pull)镜像都是访问默认的Docker hub上的镜像,在国内网络环境下,下载镜像速度特别慢,所以建议国内用户使用Registry Mirror配置国内仓库镜像.方法如下:
    【云原生系列技术|云原生系列技术(二)(Docker 镜像详解)】首先,通过/etc/docker/daemon.json(系统如果没有这个文件,就新建一个)文件指定要使用的镜像源,这里以Docker官方提供的中国区镜像源为例:
    vi /etc/docker/daemon.json { "registry-mirrors":["https://registry.docker-cn.com"] }

    备注:大家也可以使用其他的镜像源,比如:
    ustc: https://docker.mirrors.ustc.edu.cn
    网易:http://hub-mirror.c.163.com
    腾讯:https://mirror.ccs.tencentyun.com //只有在腾讯云里面才可以访问到
    DaoCloud: http://{id}.m.daocloud.io //{id}需要自己注册账号后申请得到
    aliyun: https://{id}.mirror.aliyuncs.com // {id} 需要自己注册账号后申请得到
    接着,重新加载配置,重启docker:
    systemctl daemon-reload systemctl restart docker

    通过 docker info 看下配置是否生效:
    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

  2. 搜索镜像 使用别人的镜像,第一步应该是先搜索镜像,通常我们会去Docker官方镜像库(https://hub.docker.com/)里面找。下面通过docker search来搜索镜像。
    以busybox为例(BusyBox是一个集成了一百多个最常用Linux命令和工具【如cat、echo、grep、mount、telnet】的精简工具箱,它只有不到2MB的大小,很方便进行各种快速验证)
    首先通过以下命令看下帮助:
    docker search--help

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    接下来参考帮助来搜索busybox镜像:
    docker search busybox

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    通过上图,我们看到搜索到25个镜像(其实还有很多,只是默认返回25条记录),镜像按照stars(收藏数)从大到小排列。
    如果我们只想查找收藏数大于10的,可以通过-f来过滤:
    docker search -f stars=10 busybox

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    限制只返回2条,并且返回不截断输出结果:
    docker search -f stars=10 --limit=2 --no-trunc busybox

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    如果只想搜索官方镜像,可以这样:
    docker search -f is-official=true busybox

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

  3. 获取镜像 搜索到我们想要的镜像后,通过docker pull来拉取镜像:
    docker pull busybox

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    tip:不指定tag,则默认会拉取latest标签的镜像。
  4. 查看镜像信息 镜像pull下来后,我们通过以下命令查看下载的镜像:
    docker images

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    可以看到镜像来自哪个仓库,标签,镜像ID,创建时间,镜像大小。
    还可以通过以下命令查看镜像的详细信息:
    注:命令中的 af2f 为镜像的id,请根据实际情况替换;文中出现的类似命令都以此方法处理
    docker inspect af2f

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    通过以下命令查看镜像历史信息:
    docker history af2f

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    我们可以结合busybox的Dockerfile文件来看组成镜像的各个层的具体内容。
    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    上面看到的scratch镜像值得一说:
    scratch镜像:世界上最小的镜像,通常被用来制作第一个真正的镜像。
    scratch是这样做出来的:
    tar cv --files-from /dev/null | docker import - scratch

    如果尝试拉取镜像,会得到这样的提示:
    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    也就是说scratch是docker保留字,这个镜像神一样的存在,直接基于它做镜像就可以,不需要拉取。
  5. 标记镜像 我们在使用镜像的时候,一般都是通过name:tag的形式。tag相当于镜像的别名,通常标记为可识别的版本。比如我本地pull了busybox的三个版本(1.30/latest/1.29):
    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    通过docker tag给镜像添加任意标签:
    docker tag busybox:1.30 busybox:custom

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    通过上面的操作,我给镜像busybox:1.30添加了一个新标签:custom.
  6. 清理镜像 使用Docker一段时间后,系统中可能会遗留一些临时的镜像文件,以及一些没有被使用的镜像,就需要我们不定期的清理镜像。
    清理之前我们先看以下系统有哪些容器和镜像,其中tag为latest和custom的镜像正在使用:
    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    通过以下命令清理镜像:
    docker image prune -a -f

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    参数说明:
    ? -a 删除所有无用镜像,不光是临时镜像
    ? -f 强制删除镜像,而不是进行提示确认
    通过上面的命令,我们发现镜像只剩下tag为latest这一个了(因为这个被正在运行的容器使用,所以没有被清理)。
    需要注意的是,tag为custom的镜像也被删了,查看容器列表:
    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    通过容器列表可以看到,原来使用tag为custom镜像的容器,现在的image变为af2f…这个ID了。也就是说通过上面命令清理镜像的时候,除了没有被用到的镜像会被删除以外,同一个ID的镜像只会保留一个。
  7. 删除镜像 对于没有用到的镜像,我们还可以使用以下命令来删除镜像:
    docker rmi busybox:latest

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

  8. 传递镜像 很多时候,我们需要在内网的docker环境下使用外网的镜像,我们可以在外网环境下,通过docker pull把镜像拉下来,然后通过以下命令打包成tar文件:
    docker save -o busybox.tar busybox:latest

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

    然后把该tar文件拷贝到内网,在内网docker环境下执行以下命令导入镜像:
    docker load -i busybox.tar

    云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
    文章图片

二、制作自己的镜像
我们不可能一直使用别人的镜像,在容器时代,我们的业务也需要跑在容器里面,所以我们要学会自己制作镜像。
制作镜像的方式主要有两种:
  • 一是通过docker commit的方式,这种方式适合新手,或者镜像不需要经常更改的情况,制作过程就是启动一个已有镜像,然后在容器里面把自己的业务部署好,最后commit成镜像就ok了。
  • 二是通过Dockerfile文件build镜像,本人比较推荐使用这种方式,后续维护和更新镜像比较容易,前提就是需要掌握Dockerfile文件的编写。
下面重点介绍通过Dockerfile的方式来制作镜像,首先说一下Dockerfile中常用的指令:
  • FROM :指定构建镜像的基础源镜像。FROM一般是 Dockerfile 中非注释行的第一个指令。
  • LABEL : 以键值对的形式给镜像添加元数据。
  • MAINTAINER :指定创建/维护镜像的用户或组织,已过时,推荐使用LABEL
  • ADD :复制本地文件/目录、远程文件到容器指定路径中,还可以是一个tar文件(自动解压)
  • COPY :复制本地文件/目录到容器指定路径中
  • ENV :指定环境变量,会被后续RUN使用,并在容器运行时保留
  • WORKDIR :为后续的RUN、CMD、ENTRYPOINT配置工作目录
  • USER :指定运行容器时的用户名/UID,后续的RUN、CMD、ENTRYPOINT也会使用指定用户。
  • RUN :根据业务需要执行一些命令
  • VOLUME :创建一个挂载点
  • EXPOSE :指定容器要暴露的端口号
  • ONBUILD :当所创建的镜像被作为其它新创建镜像的基础镜像时,所执行的操作
  • CMD :配置容器启动后执行的命令,支持三种格式:
    • CMD [“executable” ,”Param1”, “param2”] 使用exec执行,推荐
    • CMD command param1 param2,在/bin/sh上执行
    • CMD [“Param1”, “param2”] 提供给ENTRYPOINT做默认参数。
  • ENTRYPOINT : 配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。支持两种格式:
    • ENTRYPOINT [“executable”, “param1”, “param2”]
    • ENTRYPOINT command param1 param2 (shell中执行)
从零开始制作一个“hello”镜像,让它 say: hello world
1.编写一个hello.c
#include int main(int argc, char ** argv){ printf("hello world\n"); for (int i=1; i < argc; i++){ printf("parameter %d is %s.\n", i, argv[i]); } return 0; }

2.编译 (使用静态编译,把所需依赖都包含进来):
gcc -static hello.c -o hello

3.编写Dockerfile
FROM scratch COPY hello / ENTRYPOINT ["/hello","p1","p2"]

4.构建镜像 (注意后面有个点 . ):
docker build -t hello .

5.运行(–rm:容器运行结束后自动删除):
docker run --rm hello p3 p4

输出:
hello world parameter 1 is p1. parameter 2 is p2. parameter 3 is p3. parameter 4 is p4.

三、搭建自己的私有镜像仓库
学会自己制作镜像后,要给自己镜像一个“家”。下面教大家以最快捷的方式搭建一个私有镜像仓库;
首先拉取仓库的镜像:
docker pull registry

然后运行:
docker run -d -p 5000:5000 --restart always --name registry -v /opt/registry:/var/lib/registry registry

这样我们的镜像仓库就搭建好了。下面我们验证下仓库是否可用,把busybox镜像tag后进行push到私有仓库:
云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
文章图片

然后把本地的busybox镜像全部删除,再从私有镜像仓库拉取。
云原生系列技术|云原生系列技术(二)(Docker 镜像详解)
文章图片

经过测试可以正常pull,证明我们的私有仓库没有问题。
总结
把上文提到的docker命令汇总下:
  • docker search :搜索镜像
  • docker pull : 拉取镜像
  • docker images : 列出本地镜像
  • docker inspect : 查看镜像元数据
  • docker history : 查看镜像历史信息
  • docker tag :给镜像添加标签
  • docker image prune :清理镜像
  • docker rmi :删除镜像
  • docker save :保存镜像为tar文件
  • docker load : 从tar文件加载镜像
  • docker commit : 从容器创建镜像
  • docker build : 从Dockerfile文件构建镜像
本节的Docker 镜像就介绍这些,我们下节给大家分享《微服务技术》

    推荐阅读