7.4 Docker:关于镜像 ==================== |image0| -------------- 一、镜像的基本内容 ------------------ :: # 查看本地已下载的镜像 $ docker images # 下载镜像 $ docker pull hello-world # 查看镜像信息 $ docker images hello-world 当我们下载镜像并执行一些命令的时候,docker实际上是记录下来的。 所有的命令都被转化成了bash命令存储在文件里。 这也就解释了为什么hello-world文件才1.5k 二、什么是Dockerfile -------------------- 如何构建镜像 我们可以从简单的分析:hello-world 每个镜像的创建都需要有一个Dockerfile,从docker hub下载的image可以在这里搜索\ `dockerfile `__\ ,包括后面我们自己构建也是一样。 现在分析一下hello-world的[Dockerfile] :: FROM scratch # 从0开始 COPY hello / # 将镜像里的hello可执行文件拷贝到容器根目录 CMD ["/hello"] # 当容器启动后执行hello文件内容 而hello的内容,也很简单就是打印这样一段内容 |image1| 三、理解base镜像 ---------------- :: 1. 不依赖其他镜像,从 scratch 构建。 2. 其他镜像可以之为基础进行扩展。 这个怎么理解呢?很重要。 比如说,我们下载的CentOS镜像 |image2| 你一定很纳闷。怎么才200M不到?我们平时下载的都几个G的。 这里就来解答一下 Linux 操作系统由内核空间和用户空间组成。 :: 内核空间是 kernel,Linux 刚启动时会加载 bootfs 文件系统,之后 bootfs 会被卸载掉。 用户空间的文件系统是 rootfs,包含我们熟悉的 /dev, /proc, /bin 等目录。 对于 base 镜像来说,【底层直接用 Host 的 kernel】,自己只需要提供 rootfs 就行了。 而对于一个精简的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了。相比其他 Linux 发行版,CentOS 的 rootfs 已经算臃肿的了,alpine 还不到 10MB。 我们平时安装的 CentOS 除了 rootfs 还会选装很多软件、服务、图形桌面等,需要好几个 GB 就不足为奇了。 照样来分析一下,Dockerfile:\ `地址 `__ :: FROM scratch MAINTAINER The CentOS Project ADD centos-7.2.1511-docker.tar.xz / CMD ["/bin/bash"] 对于容器来说,他底层使用的Host的kernel,所以假如我们的容器是CentOS的版本(内核是3.x),当我们把容器放到Ubuntu(内核是4.x)上使用是,他实际上使用的是Ubuntu的内核。 |image3| 容器只能使用 Host 的 kernel,并且不能修改。 所有容器都共用 host 的 kernel,在容器中没办法对 kernel 升级。如果容器对 kernel 版本有要求(比如应用只能在某个 kernel 版本下运行),则不建议用容器,这种场景虚拟机可能更合适。 四、镜像的分层结构 ------------------ 从上面我们知道,每个软件都信赖存活于一个base镜像,而每个base镜像都200M,是不是意味着我们每次都要重复下载base镜像呢? 肯定不是,这里就要说到镜像的分层结构,它使得多个容器,可以共用一个base镜像。 那么就产生一个问题,不同容器要是修改同一文件呢?该怎么办?会不会互相影响? 答案是不会。 因为,镜像层的文件都是只读的,如果容器层需要对文件进行操作,都要将文件进行拷贝,然后编辑,而容器会对这份文件进行管理,而这份文件只存在于当前容器层。不会对镜像层的文件产生影响,如果有新的容器以这个容器层做为基础镜像,那么这个文件将会被容器层所检索到。 :: 添加文件 在容器中创建文件时,新文件被添加到容器层中。 读取文件 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,打开并读入内存。 修改文件 在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。 删除文件 在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。 五、镜像的缓存特性 ------------------ 为了理解这个我们来构建个自己的容器。 第一步,先下载base镜像:centos :: $ docker pull centos 第二步,编辑Dockerfile :: FROM centos RUN yum install -y tree 第三步,创建容器,并命名为centos-tree :: $ docker build -t centos-tree . |image4| 第四步,在原始的Dockerfile上添加内容 :: FROM centos RUN yum install -y tree COPY testfile / 第五步,再创建一个容器 :: docker build -t centos-tree-testfile . |image5| 注意点,镜像的缓存要求构建的命令顺序要严格一致,只要有一行命令不同,缓存就会失效,即使最后的容器内容完全一致,也无法使用缓存。 比如,我们把第二次的Dockerfile改成如下,也是需要重新构建 :: FROM centos COPY testfile / RUN yum install -y tree 六、如何调试Dockerfile ---------------------- 当我们build一个新的镜像,也许会有很多的很复杂的步骤,如果一次性build很有可能遇到各种意外情况,导致build失败,这时候,我们就需要进行调试,找出失败原因,修改Dockerfile,最终成功。 那么如何调试?在我们build镜像的时候,每一步都会有一个镜像id,通过这个id我们就可以进入该层镜像。 |image6| 先来看看第二步的结果,\ ``/``\ 目录下没有testfile文件 :: $ docker run -it e316b390cf2a 再来看看第三步,\ ``/``\ 目录下已经有testfile文件 |image7| 友情提示 :: 进入容器后,如何退出 1. exit # 退出并关闭容器 2. ctl+d # 退出并关闭容器 3. ctl+p+q # 退出不关闭容器 退出后,可以使用 docker kill 手动关闭 七、Dockerfile常用指令 ---------------------- :: FROM 指定 base 镜像。 MAINTAINER 设置镜像的作者,可以是任意字符串。 COPY 将文件从 build context 复制到镜像。 COPY 支持两种形式: COPY src dest COPY ["src", "dest"] 注意:src 只能指定 build context 中的文件或目录。 ADD 与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest。 ENV 设置环境变量,环境变量可被后面的指令使用。例如: ENV MY_VERSION 1.3 RUN apt-get install -y mypackage=$MY_VERSION EXPOSE 指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。我们会在容器网络部分详细讨论。 VOLUME 将文件或目录声明为 volume。我们会在容器存储部分详细讨论。 WORKDIR 为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录,当我们进入容器时,即为工作目录。 RUN 在容器中运行指定的命令。 CMD 容器启动时运行指定的命令。 Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。CMD 可以被 docker run 之后的参数替换。 ENTRYPOINT 设置容器启动时运行的命令。 Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效。CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT。 八、理解CMD和ENTRYPOINT ----------------------- 这两个很容易混淆,但是又很重要。所以单独拿出来讲。 **相同的点**\ :都是容器启动后执行。相当于开机自启 **不同的点**\ :一个会被覆盖,一个不会被覆盖 CMD:两个功能 :: 1. 执行一些命令 - 若run时,没有指定其他命令,则会在启动容器的时候默认执行 - 若run时,指定了其他命令,则该命令会被覆盖,不被执行 - exec和bash格式都可以使用 exec:CMD ["/bin/echo", "hello world"] bash:CMD echo "hello world" |image8| :: 2. 给ENTRYPOINT传递参数 - 若run时,指定了参数,CMD传递的参数同样被覆盖,而ENTRYPOINT永远不会被覆盖。 - 注意:如果要传递参数,必须使用exec格式,诸如CMD [""] |image9| **推荐用法** :: 1. CMD:若想做开机启动命令,两种格式都可以;若想传递参数,则必须使用exec格式 2. ENTRYPOINT:同样也接受两种格式,但是请使用exec格式,即方便传递参数,实现定制,而且不容易出错。 九、上传镜像 ------------ 为了方便多台Host,使用同一Image,有如下三种方法。 :: 1. 在多台Host上,使用同一Dockerfile创建镜像; 2. 上传至Docker Hub,在需要的Host上下载 3. 搭建本地私有仓库。 使用Docker Hub :: 1. 需要联网,而且速度不快 2. 任何人都可以访问,不安全,可能不适合企业 使用方法 :: 1. 先到 Docker Hub 上注册一个账号 2. 在 Docker Host 上登录 $ docker login -u username 输入密码,登陆。 3. 修改镜像名字和tag:格式:[username]/name:tag $ docker tag hello wangbm/hello:v0.1 4. 上传 $ docker push wangbm/hello:v0.1 5. 下载,在其他Host $ docker pull wangbm/hello:v0.1 6. 若要删除,只能在网上删除,https://hub.docker.com 搭建本地仓库步骤 :: 1. 下载并启动Registry容器 $ docker -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2 参数说明 -d 后台运行 -p 将本机5000端口和容器的5000端口绑定 -v 将容器内的/var/lib/registry 和本机的 /myregistry 路径进行映射。 下载的是registry:2 版本 2. 重命令镜像 $ docker tag hello [host-ip]:5000/[username]/name:tag $ docker tag hello 192.168.2.55:5000/wangbm/hello:v0.1 3. 上传 $ docker push 192.168.2.55:5000/wangbm/hello:v0.1 4. 下载 $ docker pull 192.168.2.55:5000/wangbm/hello:v0.1 十、操作镜像 ------------ :: # 删除镜像必须先停止并删除容器 docker ps -a # 找到对应id docker stop docker rm docker rmi # 在容器内创建新镜像 docker commit # 给镜像打tag docker tag old_tag new_tag # 上传/下载镜像 docker push image docker pull image # 搜索Docker Hub中的镜像 docker search image # 从 Dockerfile 构建镜像 docker build -t image_tag . # 显示镜像构建历史 docker history image -------------- |image10| .. |image0| image:: http://image.iswbm.com/20200602135014.png .. |image1| image:: http://image.iswbm.com/17-12-23/49304868.jpg .. |image2| image:: http://image.iswbm.com/17-12-23/36753853.jpg .. |image3| image:: http://image.iswbm.com/17-12-23/70731434.jpg .. |image4| image:: http://image.iswbm.com/17-12-24/39646473.jpg .. |image5| image:: http://image.iswbm.com/17-12-24/85625734.jpg .. |image6| image:: http://image.iswbm.com/17-12-24/21127582.jpg .. |image7| image:: http://image.iswbm.com/17-12-24/42825662.jpg .. |image8| image:: http://image.iswbm.com/17-12-24/80077038.jpg .. |image9| image:: http://image.iswbm.com/17-12-24/98318652.jpg .. |image10| image:: http://image.iswbm.com/20200607174235.png