目录html
上一篇文章中,咱们学习了包括 docker run 在内的许多对容器进行操做的基本指令,那么在本节中,咱们主要探讨 Docker 镜像的一些概念,好比什么是镜像,如何对镜像进行管理,如何修改镜像,如何建立、存储、共享本身建立的镜像等,那么就开始咱们的学习nginx
Docker 镜像是由文件系统叠加而成,最底端是一个引导文件系统,也就是bootfs
,这很像典型的 Linux/Unix 的引导文件系统。Docker 用户永远不会和引导文件系统有什么交互。实际上,一个容器启动后,它就会被移入内容,而引导文件系统则会被卸载,从而留出更多的空间。(感受有点像古代的餐馆招待?负责引导顾客进入餐馆,本身的工做就算是完成了)git
传统的Linux 引导过程当中,root文件系统最早以只读的方式加载,当引导结束后,会切换为读写模式。可是在Docker 中,root文件系统永远只是只读状态,而且使用联合加载的技术一次同时加载多个文件系统。联合加载会将各层系统文件叠加在一块儿,最终的文件系统包含底层的文件和目录。web
联合加载:联合加载指的是一次同时加载多个文件系统,可是外面看起来只有一个文件系统。docker
Docker 将这样的文件系统成为镜像。一个镜像能够放到另外一个镜像的顶部。位于下面的镜像称为父镜像,一次类推,知道镜像栈的最底部,最底部的镜像称为基础镜像。最后,当一个镜像启动容器时,Docker会在镜像的最顶层加载一个文件系统。咱们想在 Docker 中运行的程序就是在这个读写层中执行的。shell
用一幅图来表示一下:apache
咱们先从如何列出系统中的 Docker 镜像来开始,可使用 docker images 命令来实现,以下ubuntu
能够看到,咱们已经获取了一个镜像列表。那么,这些镜像是从哪来的呢?咱们执行 docker run 命令时,同时进行了镜像下载数组
镜像从仓库下载下来。镜像保存在仓库中,而仓库存在于 Registry 中。默认的 Registry 是由 Docker 公司运行的公共 Registry 服务,即 Docker Hub。须要进行ID的注册缓存
Docker Registry 的代码是开源的,你也能够拥有本身的Registry。
在 Docker Hub (或者是你本身运营的 Docker Registry)中,镜像是保存在仓库中的,能够将镜像仓库想象成相似于Git 仓库的东西。它包括镜像、层、以及包括镜像的元数据。
仓库能够包含不少镜像,你可使用docker pull
来拉取仓库中的镜像,以下
Git 拉取代码的指令是 git pull ,这样就很类似了。
再来使用 docker images 看一下如今有哪些镜像
由于个人 Docker Hub 仓库中只有一个 ubuntu 的镜像,因此图中标红的这个镜像是咱们刚从 Docker Hub 上下载下来的。
为了区分同一个仓库中的不一样镜像,Docker 为咱们提供了 tag 这个标签,每一个镜像在列出来的时候都带有一个标签,如12.十、 12.04等,这种标签机制使得一个仓库中容许存储多个镜像。
咱们能够在仓库后面加一个冒号:标签名
的方式来指定该仓库中的某一个镜像,例如 docker run -t -i --name new_container ubuntu:12.04 /bin/bash
Docker 会自动帮咱们切换到 Ubuntu 的环境下,固然,这种方式建立了一个交互式任务。
在构建容器时指定仓库的标签也是一个好习惯,这样即可以准确的指定容器来源于哪里。
Docker Hub 有两种仓库,一种是用户仓库,一种是顶层仓库。用户仓库是由开发人员本身建立的,顶层仓库是由Docker Hub 内部人员管理。
用户仓库的命名由两部分构成,如 cxuan/ubuntu
相对的,顶层仓库的命名就比较严谨,如 ubuntu 仓库。顶层仓库由 Docker 公司和选定的优质基础镜像厂商来管理,用户能够基于这些镜像构建本身的镜像。
用户镜像都是由爱好者社区本身提供的,没有通过 Docker 公司的认证,因此须要本身承担相应的风险。
还记得docker run 的启动过程吗?再来一下这张图回顾一下
其实也能够经过 docker pull 命令先预先拉取镜像到本地,使用 docker pull 命令能够节省从一个新镜像启动一个容器所须要的时间。下面就来领取一下fedora
基础镜像( fedora 是 Fedora 优质厂商提供的基础镜像 )
可使用 docker images 查看新镜像是否拉取到本地,不过咱们此次只但愿看到 fedora 的镜像,那么你可使用这个命令: docker images fedora
能够看到咱们已经把 fedora 镜像拉取到了本地
咱们能够经过 docker search 命令来查找全部 Docker Hub 上公共可用的镜像,以下
下面还有不少镜像,咱们主要看一下每条镜像都返回了哪些内容
从上面查询的结果中选择一个镜像进行拉取,docker pull jamtur01/puppetmaster
这条命令将会下载 jamtur01/puppetmaster镜像到本地。
接下来就可使用这个镜像来构建一个容器,下面就用 docker run 命令构建一个容器。
...
查看版本号
上面咱们看到如何拉取而且构建好带有定制内容的 Docker 镜像,那么咱们如何修改本身的镜像,而且管理和更新这些镜像呢?
如今咱们不推荐使用 docker commit 命令,相反应该使用更灵活更强大的 Dockerfile 来构建镜像。不过,为了对 Docker 又一个更深的了解,咱们仍是会先介绍一下 docker commit 构建镜像。以后,咱们重点介绍Docker 所推荐的构建方法:编写 Dockerfile 以后使用 docker build
命令。
构建镜像中很重要的一环就是如何共享和发布镜像。能够将镜像推送到 Docker Hub中或者本身的私有 Registry 中。为了完成这项工做,须要在 Docker Hub上建立一个帐号
若是你尚未Docker 通行证,在 hub.docker.com 注册一个,记下你的用户名,登陆本地计算机上的Docker公共注册表。使用docker login
,输入用户名和密码进行登陆
你的我的信息会保存在 $HOME/.dockercfg 文件中
建立 Docker镜像的第一种方式是使用 docker commit 命令。能够将此想象为咱们是在版本控制系统里面提交变动,毕竟这和 git commit 命令真是太像了。
咱们先从建立一个容器开始,这个容器基于咱们前面见过的 ubuntu 镜像。以下
接下来,咱们在 ubuntu 中安装 apache 服务器,使用apt-get -yqq update
和 apt-get -y install apache2
命令。
咱们启动了一个容器,并安装了 Apache 服务器,咱们会将这个服务器做为 Web 服务器运行,因此咱们想把它当前状态保存起来。这样下次启动就不用从新安装了。为了完成这项工做,须要先使用 exit 从 ubuntu 中退出,以后再运行 docker commit 命令。以下
咱们看到,在上图所示的 docker commit 命令中,指定了要提交修改过的容器ID(能够经过 docker ps -l -q 命令获得刚刚建立的容器 ID),以及一个镜像仓库和镜像名,这里是 jamtur01/puppetmaster
可使用 docker images jamtur01/puppetmaster
命令查看刚刚建立的镜像。
能够在提交时指定更多的数据,就和 git 的命令是同样的,使用 docker commit -m
命令
这条命令中咱们使用 -m(message) 指定提交信息,同时指定了 --authro 选项,列出镜像做者信息。接着列出了想要提交的容器ID, 最后指定了 jamtur01/puppetmaster ,并为其打上了 webserver 的tag 标签。
可使用 docker inspect
命令来查看新建立的镜像的详细信息。
咱们并不推荐使用 docker commit 方法来构建镜像。相反,咱们推荐使用 Dockerfile
和 docker build
的命令来构建镜像。Dockerfile 使用基于 DSL 语法的指令来构建一个 Docker 镜像,以后使用 docker build 命令基于 Dockerfile 中的指令构建一个新的镜像。
下面咱们建立一个目录并初始化 Dockerfile,咱们建立一个包含简单web服务器的Docker镜像
如上图所示,咱们在 /usr/local/docker 目录下建立了一个 static_web
的目录,再建立了一个 Dockerfile 文件。那么这个 static_web 目录就是咱们的构建环境。Docker 称此环境为上下文(context)
或者 构建上下文(build context)
,Docker 会在构建镜像时将构建上下文和该上下文中的文件和目录上传到 Docker 守护进程。这样 Docker 守护进程就能够直接访问你镜像中的 代码、文件和数据。
下面是一个经过 Dockerfile 来构建 web 服务器的 Docker 镜像
# Version: 0.0.1 FROM ubuntu:14.04 MAINTAINER James Turnbull "james@example.com" RUN apt-get update RUN apt-get install -y nginx RUN echo 'Hi, I am in your container' \ >/usr/share/nginx/html/index.html EXPOSE 80
该 Dockerfile 由一系列指令和参数组成。每条指令,如FROM,都必须为大写字母,并且后面要跟随一个参数: FROM ubuntu:14.04。Dockerfile 中的指令会按照顺序由上向下
执行,因此编写 Dockerfile 时,请注意它的顺序。
若是不能使用
:wq
来进行保存的话,请首先使用sudo su
切换到管理员模式,而后就能够保存啦。
每条指令都会建立一个新的镜像层并对镜像进行提交。Docker 大致按照以下流程执行 Dockerfile 指令
从上面能够看出,若是你的Dockerfile 因为某些缘由(例如指令失败了)没有正常结束,那么你将获得了一个可使用的镜像。这对调试颇有帮助: 能够基于镜像运行一个具有交互功能的容器,使用最后建立的镜像对你最后失败的指令作出调试
Dockerfile 也支持中文注释,以 # 开头的行都会被认为是注释。Dockerfile 中的第一行就是注释的例子
每一个 Dockerfile 的第一行指令都应该是 FROM。FROM指令指定一个已经存在的镜像,后续指令都将基于该镜像进行,这个镜像被称为基础镜像(base image)。
在上面的示例中,咱们使用了 ubuntu:14.04
做为新镜像基础镜像。基于这个 Dockerfile 构建的新镜像以 Ubuntu 14.04 操做系统为基础。再运行一个容器时,必需要指明基于哪一个基础镜像进行构建。
接着指定了 MAINTAINER
指令,这条指令会告诉 Docker 该镜像的做者是谁,以及做者的电子邮件地址,这有助于标示镜像的全部者以及联系方式。
在这些指令以后,咱们指定了三条 RUN
指令。RUN指令会在当前的镜像中运行指定的命令。在这个例子中,咱们经过 RUN 指令更新了已经安装的 APT 仓库,安装了 nginx 包,以后建立了 /usr/share/nginx/html/index.html 文件,该文件由一些简单的示例文本。像前面说的那样,每条RUN指令都会建立一个新的镜像层,若是该命令执行成功,就会将此镜像提交,继续执行下一条指令。
默认状况下,RUN指令会在shell里使用命令包装器 /bin/sh -c 来执行。若是是在一个不支持 shell 的平台上运行或者不但愿在 shell 中运行,也可使用 exec 格式的 RUN 指令
以下 : RUN["apt-get", "install", "-y", "nginx"]
在这种方式中,咱们使用数组的方式来指定要运行的命令和要传递的参数。
接着设置了 EXPOSE
命令,这条执行告诉 Docker 容器内的应用程序将会使用容器的指定接口。这并不意味着能够自动访问任意容器运行中的服务端口,能够指定多个 EXPOSE 指令向外公开多个端口。
执行 docker build
命令时,Dockerfile 中的全部指令都会被执行而且提交,而且在命令成功结束后返回一个新镜像,下面就来看看如何构建一个新镜像。
必定不要忘记最后面有个空格 和.
,也能够在构建镜像的过程当中为镜像设置一个标签: 使用方法为“镜像名 : 标签”,以下所示
以前大体介绍了一下指令失败时的执行过程,下面来看一个例子: 假设咱们在上面的 Dockerfile 中把 nginx 拼成了 ngnx ,再来构建一遍
咱们能够看到,程序出错了,这个时候咱们但愿去调试一下此次失败。咱们使用 docker run 命令来基于此次构建到目前为止已经成功的最后一步建立一个容器,这里它的ID 是 dee85a65a396
,咱们可使用以下命令
docker run -t -i dee85a65a396 /bin/bash
,来恢复到出错以前的镜像,而后从新运行出错的指令apt-get install -y ngnx
,能够看到哪里出错了
可是感受这个步骤是多余了一些,若是 Dockerfile 中出现了错误,那么 Docker 就会给你提示,用不着从新运行命令来找出问题缘由。
因为每一步的结果都会做为下一步的基础镜像,因此Docker 构建镜像的过程很是聪明,它会将以前的镜像层做为缓存。
正如上面 Dockerfile 来举例,好比,在咱们调试过程当中,不须要在第一步和第三步之间作任何修改,所以 Docker 会将以前构建时建立的镜像看成缓存并做为新的开始点。再次构建时,Docker 会直接从第四步开始。当以前的构建步骤没有变化时,这会节省大量的时间。若是第一步到第三步之间有什么变化,则回到第一步开始。
然而,有的时候不但愿有缓存的功能,这个时候你须要使用 apt-get update
,那么 Docker 将不会刷新 APT 包的缓存,要想略过缓存,可使用 docker build
的 --no-cache 标志。
构建缓存的一个好处就是,咱们能够实现简单的 Dockerfile 模版,通常会在 Dockerfile 文件顶部使用相同的指令集模版,好比对 ubuntu ,使用下面的模版
FROM ubuntu:14.04 MAINTAINER James Turnbull "james@example.com" ENV REFRESHED_AT 2019-08-15 RUN apt-get -qq update
咱们来分析一下这个新的 Dockerfile :
如今来看一下新构建的镜像,使用 docker images 命令来完成
若是想要了解镜像是如何构建出来的,可使用 docker history 命令,以下
从结果能够看出镜像构建的每一层都是哪些指令构成的
咱们能够基于新构建的镜像启动新容器,来检查咱们的构建工做是否正常
在这里,咱们使用 docker run 命令,启动一个 static_web 的容器, -d
表示的是以分离(detached) 的方式在后台运行。这种方式适合 nginx守护进程 这种须要长时间运行的进程。咱们也指定了须要在 容器中运行的命令: nginx -g "daemon off;"
,将之前台方式运行 nginx 做为咱们的服务器。
咱们这里也使用了一个新的 -p 标志,用来控制 Docker 再运行时应该给外部开放哪些端口
使用 docker ps
查看一下端口分配状况
Docker 把 32769 端口映射到了 80 端口上
也能够经过 docker port
查看端口的映射状况
Dockerfile 指令比较多,这里咱们会对 Dockerfile 单独列一个章节进行说明
镜像构建完毕以后,咱们也能够将它上传到 Docker Hub 上面去,这样其余人就能使用这个镜像了。
Docker Hub 的私有仓库是须要收费的
咱们可使用 docker push 命令将镜像推送至 Docker Hub。命令以下
为何推送不上去?
网上搜索了一下,大概是镜像标签的问题,从新为镜像设置一个标签
而后把这个标签推送上去,至关于就是把镜像推送上去
咱们能够在 Docker Hub 上看到咱们推送的镜像了
若是再也不须要一个镜像了,也能够将它删除,使用 docker rmi
命令来删除一个镜像
该操做只能删除本地镜像,若是你已经推送至 Docker Hub 上,那么你还须要在 Docker Hub 上将其删除
登陆 Docker Hub ,直接点下面的连接删除
docker rmi 删除多个容器的方式直接在后面枚举容器便可,中间用空格隔开
本篇文章主要讲述了 Docker 中的镜像和仓库的一些概念和基本用法,那么你是否能回顾起来下面这些内容呢?