docker学习笔记二

 

什么是docker镜像?

Docker镜像是由文件系统叠加而成。最底端是一个引导文件系统,即bootfs,这很像典型的Linux/Unix的引导文件系统。Docker用户几乎永远不会和引导文件系统有什么交互。实际上,当一个容器启动后,它将会被移到内存中,而引导文件系统则会被卸载(unmount),以留出更多的内存供initrd磁盘镜像使用。

实际上,Docker镜像的第二层是root文件系统rootfs,它位于引导文件系统之上。rootfs可以是一种或多种操作系统(如Debian或者Ubuntu文件系统)

在传统的Linux引导过程中,root文件系统会最先以只读的方式加载,当引导结束并完成了完整性检查之后,它才会被切换为读写模式。但是在Docker里,root文件系统永远只能是只读状态,并且Docker利用联合加载[1](union mount)技术又会在root文件系统层上加载更多的只读文件系统。联合加载指的是一次同时加载多个文件系统,但是在外面看起来只能看到一个文件系统。联合加载会将各层文件系统叠加到一起,这样最终的文件系统会包含所有底层的文件和目录。

  Docker将这样的文件系统称为镜像。一个镜像可以放到另一个镜像的顶部。位于下面的镜像称为父镜像(parent image),可以依次类推,直到镜像栈的最底部,最底部的镜像称为基础镜像(base image)。最后,当从一个镜像启动容器时,Docker会在该镜像的最顶层加载一个读写文件系统。我们想在Docker中运行的程序就是在这个读写层中执行的。

docker学习笔记二_第1张图片

当Docker第一次启动一个容器时,初始的读写层是空的。当文件系统发生变化时,这些变化都会应用到这一层上。比如,如果想修改一个文件,这个文件首先会从该读写层下面的只读层复制到该读写层。该文件的只读版本依然存在,但是已经被读写层中的该文件副本所隐藏。

 

         通常这种机制被称为写时复制(copy on write),这也是使Docker如此强大的技术之一。每个只读镜像层都是只读的,并且以后永远不会变化。当创建一个新容器时,Docker会构建出一个镜像栈,并在栈的最顶端添加一个读写层。这个读写层再加上其下面的镜像层以及一些配置数据,就构成了一个容器。在上一章我们已经知道,容器是可以修改的,它们都有自己的状态,并且是可以启动和停止的。容器的这种特点加上镜像分层框架(image-layering framework),使我们可以快速构建镜像并运行包含我们自己的应用程序和服务的容器

列出镜像

$docker images

docker学习笔记二_第2张图片

docker学习笔记二_第3张图片

镜像从仓库下载下来。镜像保存在仓库中,而仓库存在于Registry中。默认的Registry是由Docker公司运营的公共Registry服务,即Docker Hub

docker学习笔记二_第4张图片

Docker Hub(或者用户自己运营的Registry)中,镜像是保存在仓库中的。可以将镜像仓库想象为类似Git仓库的东西。它包括镜像、层以及关于镜像的元数据(metadata

拉取的镜像并不是一个完整的操作系统,只是一个裁剪版,只包含最低限度的支持系统运行的组件。

$ sudo docker run -t -i --name new_container ubuntu:12.04 /bin/bash 

这个例子会从镜像ubuntu:12.04启动一个容器,而这个镜像的操作系统则是Ubuntu 12.04

在构建容器时指定仓库的标签也是一个很好的习惯。这样便可以准确地指定容器来源于哪里

Docker Hub中有两种类型的仓库:用户仓库(user repository)和顶层仓库(top-level repository。用户仓库的镜像都是由Docker用户创建的,而顶层仓库则是由Docker内部的人来管理的。

  用户仓库的命名由用户名和仓库名两部分组成,如myhub/zjib

    用户名:myhub

仓库名:zjib

顶层仓库只包含仓库名部分,如ubuntu仓库。顶层仓库由Docker公司和由选定的能提供优质基础镜像的厂商(如Fedora团队提供了fedora镜像)管理,用户可以基于这些基础镜像构建自己的镜像。同时顶层仓库也代表了各厂商和Docker公司的一种承诺,即顶层仓库中的镜像是架构良好、安全且最新的

拉取镜像

docker run命令从镜像启动一个容器时,如果该镜像不在本地,Docker会先从Docker Hub下载该镜像。如果没有指定具体的镜像标签,那么Docker会自动下载latest标签的镜像

其实也可以通过docker pull命令先发制人地将该镜像拉取到本地。使用docker pull命令可以节省从一个新镜像启动一个容器所需的时间

$docker pull ……

 

查找镜像

通过docker search命令来查找所有Docker Hub上公共的可用镜像

docker学习笔记二_第5张图片

这条命令会完成镜像查找工作,并返回如下信息:

    仓库名;

    镜像描述;

    用户评价(Stars反应出一个镜像的受欢迎程度;

    是否官方(Official由上游开发者管理的镜像(如fedora镜像由Fedora团队管理);

    自动构建(Automated表示这个镜像是由Docker Hub的自动构建(Automated Build)流程创建的。

构建镜像

前面我们已经看到了如何拉取已经构建好的带有定制内容的Docker镜像,那么我们如何修改自己的镜像,并且更新和管理这些镜像呢?构建Docker镜像有以下两种方法。

    使用docker commit命令。

    使用docker build命令和Dockerfile文件

首次学习的时候那本书上说并不推荐使用docker commit命令,而应该使用更灵活、更强大的Dockerfile来构建Docker镜像docker学习笔记二_第6张图片

创建Docker Hub账号

官网注册,在linux上使用

$docker login        进行登录

Dockercommit命令创建镜像

创建Docker镜像的第一种方法是使用docker commit命令。可以将此想象为我们是在往版本控制系统里提交变更。我们先创建一个容器,并在容器里做出修改,就像修改代码一样,最后再将修改提交为一个新镜像

$docker commit

docker学习笔记二_第7张图片

我们启动了一个容器,并在里面安装了nginx。我们会将这个容器作为一个Web服务器来运行,所以我们想把它的当前状态保存下来。这样就不必每次都创建一个新容器并再次在里面安装nginx了。为了完成此项工作,需要先使用exit命令从容器里退出,之后再运行docker commit命令

docker学习笔记二_第8张图片

在这条命令里,我们指定了更多的信息选项。首先-m选项用来指定新创建的镜像的提交信息。同时还指定了--a选项,用来列出该镜像的作者信息。接着指定了想要提交的容器的ID。最后的myhub/nginx指定了镜像的用户名和仓库名,: 并为该镜像增加了一个webserver标签

可以用docker inspect命令来查看新创建的镜像的详细信息

docker学习笔记二_第9张图片

如果想从刚创建的新镜像运行一个容器,可以使用docker run命令

docker学习笔记二_第10张图片

⑳ 删除image

 docker images

 容器在运行中的话是没办法删除镜像的,所以删除镜像之前要先让容器停止运行

docker stop

docker  rmi  id/name   删除镜像

docker  rm  id/name  删除容器

 

2、用Dockerfile构建镜像

并不推荐使用docker commit的方法来构建镜像。相反,推荐使用被称为Dockerfile的定义文件和docker build命令来构建镜像。Dockerfile使用基本的基于DSL(Domain Specific Language))语法的指令来构建一个Docker镜像,我们推荐使用Dockerfile方法来代替docker commit,因为通过前者来构建镜像更具备可重复性、透明性以及幂等性

docker学习笔记二_第11张图片

 

wo创建了一个名为static_web的目录用来保存Dockerfile,这个目录就是我们的构建环境(build environment),Docker则称此环境为上下文(context)或者构建上下文(build context)。Docker会在构建镜像时将构建上下文和该上下文中的文件和目录上传到Docker守护进程。这样Docker守护进程就能直接访问用户想在镜像中存储的任何代码、文件或者其他数据

 

该Dockerfile由一系列指令和参数组成。每条指令,如FROM,都必须为大写字母,且后面要跟随一个参数:FROM centos。Dockerfile中的指令会按顺序从上到下执行,所以应该根据需要合理安排指令的顺序。

  每条指令都会创建一个新的镜像层并对镜像进行提交。Docker大体上按照如下流程执行Dockerfile中的指令

  •    Docker从基础镜像运行一个容器。
  • 执行一条指令,对容器做出修改。
  • 执行类似docker commit的操作,提交一个新的镜像层。
  • Docker再基于刚提交的镜像运行一个新容器。
  • 执行Dockerfile中的下一条指令,直到所有指令都执行完毕。

每个Dockerfile的第一条指令必须是FROM。FROM指令指定一个已经存在的镜像,后续指令都将基于该镜像进行,这个镜像被称为基础镜像(base iamge)

在前面的Dockerfile示例里,我们指定了centos作为新镜像的基础镜像。基于这个Dockerfile构建的新镜像将以centos操作系统为基础。在运行一个容器时,必须要指明是基于哪个基础镜像在进行构建。

  接着指定了MAINTAINER指令,这条指令会告诉Docker该镜像的作者是谁,以及作者的电子邮件地址。这有助于标识镜像的所有者和联系方式

  RUN指令会在当前镜像中运行指定的命令。在这个例子里,我们通过RUN指令更新了已经安装的APT仓库,安装了nginx包,之后创建了/usr/share/nginx/html/index.html文件,该文件有一些简单的示例文本。像前面说的那样,每条RUN指令都会创建一个新的镜像层,如果该指令执行成功,就会将此镜像层提交,之后继续执行Dockerfile中的下一条指令

默认情况下,RUN指令会在shell里使用命令包装器/bin/sh -c来执行。如果是在一个不支持shell的平台上运行或者不希望在shell中运行(比如避免shell字符串篡改),也可以使用exec格式的RUN指令

在这种方式中,我们使用一个数组来指定要运行的命令和传递给该命令的每个参数

EXPOSE指令,这条指令告诉Docker该容器内的应用程序将会使用容器的指定端口。这并不意味着可以自动访问任意容器运行中服务的端口(这里是80)。出于安全的原因,Docker并不会自动打开该端口,而是需要用户在使用docker run运行容器时来指定需要打开哪些端口。一会儿我们将会看到如何从这一镜像创建一个新容器

你可能感兴趣的:(docker学习笔记)