共计 5638 个字符,预计需要花费 15 分钟才能阅读完成。
Docker 镜像和仓库
什么是 Docker 镜像
docker 镜像是由文件系统系统叠加而成
, 最底层是一个引导文件系统,即bootfs
和 linux 引导文件系统很像,用户是不会和引导文件系统有什么交互,当一个容器启动后,它将会被移到内存中,docker 看起来很像一个典型的 linux 虚拟化栈,
docker 镜像第二层是 root 文件系统 rootfs
, 它位于引导文件系统之上,rootfs
可以是一种或多张操作系统,root
文件系统永远是能是只读状态,并且 docker 利用联合加载技术
又会在root
文件系统层上加载更多的只读文件系统,联合加载
是指一次同时加载多个文件系统,但是在外层看起来只能看到一个文件系统,联合文件系统会将各层文件系统叠加到一起,这样最终的文件系统会包含所有底层的文件和目录。
docker 将这样的文件系统称之为镜像,一个镜像可以放到另外一个镜像顶部,位于下面的镜像称之为
父镜像
,直到镜像栈的最底部,最底部的镜像称之为基础镜像
, 当启动容器时,Docker 会在该镜像的最顶层加载一个读写文件系统,我们运行的程序就是在就是在读写层中执行
当 docker 第一次启动一个容器时
,初始读写层是空的,当文件系统发生变化时,这些变化都会应用到这一层上
,当修改一个文件时,这个文件首先会从该读写层下面的只读层复制到该读写层
,只读版本依然存在
,但是已经被读写层中的该文件副本所隐藏
, 这种机制称为写时复制
, 每个只读镜像层都是只读的,并且以后永远不会变化,创建新容器时,docker 会构建初一个镜像栈,并在栈的最顶端添加一个读写层,这个读写层加上其下面的镜像层以及一些配置数据,就构成一个容器。
列出镜像
想要知道本机中有哪些镜像,可以使用
docker images
命令查看,本地镜像都保存在 Docker 宿主机的/var/lib/docker
目录下。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu latest c4ff7513909d 6 days ago 225.4 MB
docker 从仓库中下载下来,镜像保存在仓库中,而仓库位于
Registry
中,默认的Registry
是由Docker
公司运营的公共Registry
服务,Docker 提供一种标签功能(tag)
来区别镜像,这样可以使得同一个仓库中可以存储多个镜像,同一个镜像可以有多个标签
,在构建镜像的时候,建议指定标签,这样更容易来区分镜像
拉取镜像
启动容器时,如果镜像不在本地,Docker 会从 Docker hub 拉去镜像,没有指定镜像标签,会自动下载 latest 标签的镜像。也可以使用
docker pull
拉取镜像到本地,然后再启动容器,拉取指定标签的镜像为docker pull 镜像名: 标签名
查找镜像
可以通过
docker search
命令来查找所有 Docker hub 上公共可用的镜像
$ sudo docker search puppet
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
wfarr/puppet-module...
jamtur01/puppetmaster
. . .
查找镜像会返回该镜像的详细信息,
仓库名
,镜像描述
,用户评价 (stars)
,是否官方 (official)- 由上游开发这管理的镜像
,自动构建(Automated)- 表示镜像是由 Docker Hub 自动构建
构建镜像
在使用过程中我们需要修改,更新和管理这些镜像,可以自动构建镜像,构建镜像的方法有两种,
docker commit
命令和Dockerfile
文文件构建,在实际开发中,不推荐使用docker commit
方式构建,应该使用更灵活
,更强大
,的Dockerfile
来构建镜像
docker commit
docker commit
方式构建镜像,需要我们先创建一个容器,并在容器內做出修改,最后将修改提交为一个新的镜像
- 创建容器
$ sudo docker run -i -t ubuntu /bin/bash
root@4aab3ce3cb76:/#
- 安装软件
root@4aab3ce3cb76:/# apt-get -yqq update
. . .
root@4aab3ce3cb76:/# apt-get -y install nginx
. . .
- 构建镜像
$ sudo docker commit 4aab3ce3cb76 jamtur01/apache2
8ce0ea7a1528
docker commit 指定要提交的修改过的容器 ID, 以及一个目标镜像仓库,和镜像名,docker commit 提交的两个镜像的差异部分,使得构建镜像非常的轻量化
$ sudo docker commit -m"A new custom image" -a"James Turnbull" \
4aab3ce3cb76 jamtur01/apache2:webserver
f99ebb6fed1f559258840505a0f5d5b6173177623946815366f3e3acff01adef
还可以指定
-m
来指定新创建的镜像的提交信息,-a
来指定该镜像的作者信息
Dockerfile
并不推荐
docker commit
来构建镜像,推荐使用Dockerfile
定义文件,和docker build
命令来构建镜像,使用Dockerfile
的好处是构建镜像更具可重复性,透明性等好处。
Dockerfile 初体验
编写 Dockerfile 文件
- 创建一个目录,并初始化 Dockerfile 文件
$ mkdir static_web
$ cd static_web
$ touch Dockerfile
创建的目录
就是我们的构建环境
,Docker 称此环境为上下文
,或者构建上下文
,Docker 会在构建镜像时,将构建上下文和该上下文中的文件和目录上传到 Docker 守护进程
,这样 Docker 守护进程就能直接访问用户想要在镜像中存储的任何代码,文件,或者其他数据
。
- Dockerfile 文件内容
# Version: 0.0.1
FROM ubuntu:14.04
MAINTAINER James Turnbull "james@example.com"
RUN apt-get update && apt-get install -y nginx
RUN echo 'Hi, I am in your container' \
>/usr/share/nginx/html/index.html
EXPOSE 80
Dockerfile 由
一系列指令和参数组成
,指令都是大写字母
, 指令后面跟随一个参数,Dockerfile 会按照顺序,从上到下执行
,在书写 Dockerfile 时,需要合理安排指令的顺序。每条指令都会创建一个新的镜像层并对镜像进行提交
, 大致执行流程如下
- Docker 从基础镜像运行一个容器
- 执行一条指令,对容器作出修改
- 执行类似 docker commit 操作,提交一个新的镜像层
- Docker 再基于刚提交的镜像运行一个新容器,
- 执行 Dockerfile 中的下一条指令,直到所有指令都执行完毕
如果用户的
Dockerfile
由于某些原因(指令失败)
,没有正常结束,那么用户将得到一个可以使用的镜像
,方便用户调试,用户可以基于该镜像运行一个具备交互功能的容器,进行 失败指令调试。
Dockerfile 也支持注视,已
#
开始。
每个 Dockerfile
第一条指令必须是 FROM
, FROM 指定一个与存在的镜像,后续指令都将基于该镜像进行,这个镜像被称基础镜像
MAINTAINER
指令,指定该镜像的作者是谁,以及作者的电子邮件嘻,联系方式RUN
指令,会在当前镜像中运行指定的命令,每条RUN
指令都会创建一个新的镜像层,如果指令成功,就会将此镜像层提交,之后继续执行 Dockerfile 中的吓一条指令, 默认情况下,RUN
指令会在 shell 中使用命令包装器,/bin/sh -c 来执行,如果在一个不支持 shell 的平台上运行,或者不希望在 shell 中运行,可以使用 exec 格式的 run 命令
- exec 格式的
RUN
指令
RUN ["apt-get", "install", "-y", "nginx"]
EXPOSE
指令,告诉 Docker 该容器內额应用程序将会使用容器的指定端口,并不意味这可以自动访问任意容器运行中服务的端口,出于安全原因,Docker 并不会自动打开该端口,而是需要用户在使用 docker run 运行容器是来指定需要打开那些端口,可以指定多个 EXPOST 指令向外部公开多个端口
Dockerfile 构建新镜像
Dockerfile 编写完毕,需要使用
docker build
来构建镜像,执行docker build
命令时,Dockefile 中所有的指令都会被执行,并且提交,并且在该命令成功结束后返回一个新镜像
$ cd static_web
$ sudo docker build -t="jamtur01/static_web" .
Sending build context to Docker daemon 2.56 kB
Sending build context to Docker daemon
Step 0 : FROM ubuntu:14.04
---> ba5877dc9bec
Step 1 : MAINTAINER James Turnbull "james@example.com"
---> Running in b8ffa06f9274
---> 4c66c9dcee35
Removing intermediate container b8ffa06f9274
Step 2 : RUN apt-get update
---> Running in f331636c84f7
---> 9d938b9e0090
Removing intermediate container f331636c84f7
Step 3 : RUN apt-get install -y nginx
---> Running in 4b989d4730dd
---> 93fb180f3bc9
Removing intermediate container 4b989d4730dd
Step 4 : RUN echo 'Hi, I am in your container' >/usr/share/
nginx/html/index.html
---> Running in b51bacc46eb9
---> b584f4ac1def
Removing intermediate container b51bacc46eb9
Step 5 : EXPOSE 80
---> Running in 7ff423bd1f4d
---> 22d47c8cb6e5
Successfully built 22d47c8cb6e5
-t
参数,为新镜像设置了仓库和名称,也可以为过程中镜像设置一个标签,镜像名: 标签
$ sudo docker build -t="jamtur01/static_web:v1" .
自
Docker 1.5.0
开始,-f
标志指定一个区别与标准Dockerfile
的构建源的位置,这个文件可以不必命名为Dockerfile
但是必须要位于构建上下文中
docker build –t="jamtur01/static_web" -f path/to/file
构建失败
在构建过程中,指令失败,也会也会得到一个镜像,我们可以使用
docker run
命令来基于这个构建到目前为止已经成功的最后一步创建一个容器,方便调试指令
Dockerfile 和构建缓存
每一步构建过程都会将结果提交为镜像,Docker 会讲之前的镜像层看作缓存,构建起来额速度非常块,也可以在确保构建过程中不实用缓存, 可以使用
--no-cache
标志
$ sudo docker build --no-cache -t="jamtur01/static_web" .
查找新镜像
可以使用
docker images
可以查看到刚刚构建出来的镜像,也可以使用docker history
命令来查看镜像是如何构建出来的
$ sudo docker history 22d47c8cb6e5
IMAGE CREATED CREATED BY SIZE
22d47c8cb6e5 6 minutes ago /bin/sh -c #(nop) EXPOSE map[80/tcp:{}] 0 B
b584f4ac1def 6 minutes ago /bin/sh -c echo 'Hi, I am in your container' 27 B
93fb180f3bc9 6 minutes ago /bin/sh -c apt-get install -y nginx 18.46 MB
9d938b9e0090 6 minutes ago /bin/sh -c apt-get update 20.02 MB
4c66c9dcee35 6 minutes ago /bin/sh -c #(nop) MAINTAINER James Turnbull " 0 B
. . .
新镜像启动容器
我们可以使用新镜像,检查构建镜像是否一切正常
$ sudo docker run -d -p 80 --name static_web jamtur01/static_web \
nginx -g "daemon off;"
6751b94bb5c001a650c918e9a7f9683985c3eb2b026c2f1776e61190669494a8
-p
该标志用来控制Docker
在运行是应该公开那些网络端口给外部(宿主机),Docker
可以在宿主机随机选择一个位于 32768-61000 的一个较大的端口来映射到容器的 80 端口上,可以在宿主机指定一个具体的端口来映射到容器的 80 端口上
Docker 提供了一个更简单的方式,即-P
参数,该参数可以用来对外公开在Dockerfile 中通过 EXPOSE 指令公开的所有端口
$ sudo docker run -d -P --name static_web jamtur01/static_web \
nginx -g "daemon off;"
该命令会将容器內的
80 端口对本地宿主机公开
,并且绑定到宿主机的一个随机端口上
,该命令会将用来构建该镜像的Dockerfile
文件中的EXPOST
指令指定的其他端口也一并公开