zoukankan      html  css  js  c++  java
  • Docker 镜像篇

    镜像是 Docker 容器的基石,容器是镜像的运行实例,有了镜像才能启动容器。

    docker两个跟镜像有关的命令:

    hello-world - 最小的镜像

    hello-world 是 Docker 官方提供的一个镜像,通常用来验证 Docker 是否安装成功。

    我们先通过 docker pull 从 Docker Hub 下载它。

    查看

    运行hello-world

    Base 镜像

    base 镜像有两层含义:

    1. 不依赖其他镜像,从 scratch 构建。

    2. 其他镜像可以之为基础进行扩展。

    所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。

    从镜像仓库pull一个CentOS镜像下来:

    Linux 操作系统由内核空间和用户空间组成。如下图所示:

     

    bootfs

    kernel是内核空间,Linux 刚启动时会加载 bootfs 文件系统,之后 bootfs 会被卸载掉

    rootfs

    rootfs是用户空间的文件系统,包含我们熟悉的 /dev, /proc, /bin 等目录。

    对于 base 镜像来说,底层直接用 Host 的 kernel,自己只需要提供 rootfs 就行了;而对于一个精简的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了。

    base 镜像提供的是最小安装的 Linux 发行版

    下面是 CentOS 镜像的 Dockerfile 的内容:

    FROM scratch
    ADD centos-7-docker.tar.xz /
    
    LABEL name="CentOS Base Image" 
        vendor="CentOS" 
        license="GPLv2" 
        build-date="20170406"
    
    CMD ["/bin/bash"]

    Kernel

    通过uname -a 可以看到我们运行的Centos kernel是直接调用宿主机Ubuntu的 kernel.

    容器只能使用 Host 的 kernel,并且不能修改。
    所有容器都共用 host 的 kernel,在容器中没办法对 kernel 升级。如果容器对 kernel 版本有要求(比如应用只能在某个 kernel 版本下运行),则不建议用容器,这种场景虚拟机可能更合适。

    构建镜像

    Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如我们现在构建一个新的镜像,Dockerfile 如下:

    59.png

    ① 新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。
    ② 安装 emacs 编辑器。
    ③ 安装 apache2。
    ④ 容器启动时运行 bash。

    构建过程如下图所示:

    可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

    问什么 Docker 镜像要采用这种分层结构呢?

    最大的一个好处就是 - 共享资源

    比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享,我们将在后面更深入地讨论这个特性。

    这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?

    答案是不会!
    修改会被限制在单个容器内。
    这就是我们接下来要学习的容器 Copy-on-Write 特性。

    可写的容器层

    当容器启动时,一个新的可写层被加载到镜像的顶部。
    这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

    所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。

    只有容器层是可写的,容器层下面的所有镜像层都是只读的

    创建镜像

    对于 Docker 用户来说,最好的情况是不需要自己创建镜像。几乎所有常用的数据库、中间件、应用软件等都有现成的 Docker 官方镜像或其他人和组织创建的镜像,我们只需要稍作配置就可以直接使用。

    使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用那些官方镜像,因为 Docker 的工程师知道如何更好的在容器中运行软件。

    当然,某些情况下我们也不得不自己构建镜像,比如:

    1. 找不到现成的镜像,比如自己开发的应用程序。

    2. 需要在镜像中加入特定的功能,比如官方镜像几乎都不提供 ssh。

    Docker 提供了两种构建镜像的方法:

    1. docker commit 命令

    2. Dockerfile 构建文件

    docker commit

    docker commit 命令是创建新镜像最直观的方法,其过程包含三个步骤:

      1. 运行容器

      2. 修改容器

      3. 将容器保存为新的镜像

    举个例子:在 Centos base 镜像中安装 vi 并保存为新镜像

    1、运行容器:docker run -it centos

    2、安装vim:

      

      确认 vim 没有安装。

      

    3、将容器保存为新的镜像

    在另外一台host查看我们刚才安装了vim Container的name或id

    通过commit来打包

    查看新的镜像

    总结:以上演示了如何用 docker commit 创建新镜像。然而,Docker 并不建议用户通过这种方式构建镜像。原因如下:

    1. 这是一种手工创建镜像的方式,容易出错,效率低且可重复性弱。比如要在 debian base 镜像中也加入 vi,还得重复前面的所有步骤。

    2. 更重要的:使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审计,存在安全隐患。

    Dockerfile创建镜像

    dockerfile内容:

    FROM centos
    RUN yum install -y vim

    build完成后即可在本地仓库查看到刚才打包的centos-with-vim-dockerfile image

    调试 Dockerfile

    包括 Dockerfile 在内的任何脚本和程序都会出错。有错并不可怕,但必须有办法排查,所以本节讨论如何 debug Dockerfile。

    先回顾一下通过 Dockerfile 构建镜像的过程:

    1. 从 base 镜像运行一个容器。

    2. 执行一条指令,对容器做修改。

    3. 执行类似 docker commit 的操作,生成一个新的镜像层。

    4. Docker 再基于刚刚提交的镜像运行一个新容器。

    5. 重复 2-4 步,直到 Dockerfile 中的所有指令执行完毕。

    从这个过程可以看出,如果 Dockerfile 由于某种原因执行到某个指令失败了,我们也将能够得到前一个指令成功执行构建出的镜像,这对调试 Dockerfile 非常有帮助。我们可以运行最新的这个镜像定位指令失败的原因

    我们来看一个调试的例子。Dockerfile 内容如下:

    执行 docker build

    Dockerfile 在执行第三步 RUN 指令时失败。我们可以利用第二步创建的镜像 22d31cc52b3e 进行调试,方式是通过 docker run -it 启动镜像的一个容器。

    80.png

    手工执行 RUN 指令很容易定位失败的原因是 busybox 镜像中没有 bash。虽然这是个极其简单的例子,但它很好地展示了调试 Dockerfile 的方法。

  • 相关阅读:
    Git: git tag 使用小结(给发布版本打标记,切换并修改某个历史版本)
    android: Android水波纹点击效果
    Flutter: 运行新项目报错
    FFmpeg编译:mac下编译iOS平台的FFmpeg库(支持armv7, arm64, i386, x86_64)
    Xcode: Xcode中Command Line Tools的安装方法
    win10: windows+E 改回打开我的电脑
    DialogFragment: DialogFragment的一些理解
    Android Studio: 查看SDK源代码
    HandlerThread: HandlerThread的理解
    Looper: Looper,Handler,MessageQueue三者之间的联系
  • 原文地址:https://www.cnblogs.com/vincenshen/p/6841635.html
Copyright © 2011-2022 走看看