1.什么是 Docker 镜像
Docker 镜像是由文件系统叠加而成的。最低端是一个引导文件系统,即 bootfs,这很像典型的Linux的引导文件系统。Docker 用户几乎永远不会
和引导文件系统有什么交互。实际上,当一个容器启动后,它会被移到内存中,而引导文件系统则会被卸载,以流出更多的内存供 initrd 磁盘镜像使用。
Docker 镜像的第二层是 root 文件系统 rootfs,它位于引导文件系统之上。rootfs 可以是一种或者多种操作系统(如 Debian 或者 Ubuntu 文件系统)
在传统的 Linux 引导过程中,root 文件系统会最先以只读的方式加载,当引导结束并完成了完整性检查之后,它才会被切换为读写模式。但是在 Docker 里面,
root 文件系统永远只会是只读状态,并且 Docker 利用联合加载(union mount)技术又会在root文件系统之上加载更多的只读文件系统。联合加载是指一次同时
加载多个文件系统,但是在外面看起来只能看到一个文件系统。联合加载会将各层文件系统叠加到一起,这样最终的文件系统会包含所有的底层的文件和目录。
Docker 将这样的文件系统成为镜像。一个镜像可以放到另外一个镜像的顶部。位于下面的镜像成为父镜像,以此类推,知道镜像栈的最底部,最底部的镜像被称为
基础镜像。当一个镜像启动容器时,Docker 会在该镜像的最顶层加载一个读写文件系统。我们想在 Docker 中运行的程序就是在这个读写层中执行的。
当 Docker 第一次启动一个容器时,初始的读写层是空的。当文件系统发生变化,这些变化会应用到这一层。如果,如果想修改一个文件,这个文件首先会从该读写
层下面的只读层复制到该读写层。该文件的只读版本依然存在,但是已经被读写层中的该文件副本所隐藏。
这种机制通常被称为写时复制,这也是 Docker 如此强大的技术之一,每个只读镜像层都是只读的,并且以后永远不会变化。当创建一个新容器时,Docker 会构建出
一个镜像栈,并在栈的最顶层添加一个读写层。这个读写层再加上其下面的镜像层以及一些配置数据,就构成了一个容器。容器是可以修改的,它们都有自己的状态,并且
是可以启动和停止的。容器的这种特点加上镜像分层架构,使得我们可以快速构建镜像并运行包含我们自己的应用程序和服务的容器。
Docker Hub 中有两种类型的仓库:用户仓库和顶层仓库
用户仓库的镜像都是由 Docker 用户创建的,用户仓库的命名是由用户名和仓库名2部分组成的,如 test/puppet。
而顶层仓库是由 Docker 内部人管理的,顶层仓库只包含仓库名。
2.构建镜像
1.docker commit container_id 用户名/镜像名
docker commit e803d8aec37e weidaodao/ubuntu
2.docker build -t 仓库/名称:标签 . // . 告诉去本地查找 Dockerfile
docker build -t 仓库/名称:标签 git@github.com:test/test // 去 git仓库下查找 Dockerfile
docker build -t 仓库/名称:标签 -f 文件路径
刷新一个构建用环境变量:
ENV REFRESHED_AT 2014-07-01 // 想刷新一个构建,只需要修改 ENV 指令中的日期,是的 Docker 在命令中 ENV 指令时开始重置这个缓存,并
运行后续指令而无需依赖该缓存。
3.Dockerfile 指令
1.CMD : 启动时的指令, RUN 是构建时的指令 // CMD ["/bin/true"], 和 docker run 命令启动容器时指定要运行的命令相似, docker run 可以覆盖 CMD
2.ENTRYPOINT : 该命令提供的命令则不容易被启动容器时被覆盖。实际上,docker run 命令中指定的任何参数都会被当作参数再次传递给 ENTRYPOINT 指令中指定的命令。
3.WORKDIR : 用来从镜像创建一个新容器时,在容器内部设置一个工作目录,ENTRYPOINT 和 / 或 CMD 指定的程序会在这个目录下执行。
4.ENV : 用来在镜像构建过程中设置环境变量 // ENV RVM_PATH /home/rvm, 新变量可以在后续的任何 RUN 命令中使用
5.USER : 该镜像会以什么样的用户去运行 // USER nginx, 该镜像启动的容器会以 nginx 用户的身份来运行
6.VOLUME : VOLUME ["/opt/project"] // 该命令会为基于此镜像的任何容器创建一个名为 /opt/project 的挂载点
用来向基于镜像创建的容器添加卷。一个卷是可以存在于一个或者多个容器内的特定的目录,这个目录可以绕过联合文件系统,并提供如下共享数据或者对数据进行
持久化的功能:
1.卷可以在容器间共享和重用
2.一个容器可以不说必须和其他容器共享卷
3.对卷的修改是立即生效的
4.对卷的修改不会对更新的镜像产生影响
5.卷会一直存在直到没有任何容器再使用它
卷功能让我们可以将数据(如源代码),数据库或者其他内容添加到镜像中,而不是将这些内容提交到镜像,并并且允许我们在多个容器之间共享这些内容。我们可以利用
此功能来测试容器和内部的应用程序代码,管理日志,或者处理容器内部的数据库。
7.ADD : 指令用来将构建环境下的文件和目录复制到镜像中
ADD software.lic /opt/application/software.lic // 这条指令将会将构建目录下的 software.lic 文件复制到 /opt/application/software.lic
ADD 文件时,可以通过目的参数末尾的字符来判断文件源是目录还是文件,如果以 / 结尾,那么Docker就认为源位置指向的是目录。
ADD 在处理本地归档文件时(tar archive)时,如果将归档文件作为源文件,那么 Docker 会自动将归档文件解开.
8.COPY : 类似于 ADD, 不同的是 COPY 只关心构建上下文中复制本地文件,而不会去做文件提取和解压的工作
COPY conf.d /etc/apache2/
源文件必须是一个与当前构建环境相对的文件或者目录,本地文件都放到 Dockerfile 同一个目录下。不能复制该目录之外的任何文件,因为构建环境会将上传到 Docker
守护进程,而复制是在 Docker 守护进程中进行的。任何位于构建之外的东西都是不可用的。COPY 指令的目的位置则必须是容器内部的一个绝对路径。
任何由该指令创建的文件或者目录的 UID 和 GID 都会设置为 0
9.LABEL : 用于为 Docker 镜像添加元数据。元数据以键值对的形式展示。
LABEL version="1.0"
10.STOPSIGNAL : 该指令用来设置停止容器时发送什么系统调用信号给容器。这个信号必须是内核系统调用表中的合法的数,如 9
11.ARG :
用来定义可以在 docker build 命令运行时传递给构建运行时的参数,我们只需要在构建时使用 --build-arg 标志即可。
ARG build
ARB webapp_user=user
12.ONBUILD :
该命令为镜像添加触发器。当一个镜像被用作其他镜像的基础镜像时(比如用户的镜像需要从某未准备好的位置添加源代码,或者用户需要执行特定于构建
镜像的环境的构建脚本),该镜像的触发器会被执行。
触发器会在构建过程中插入新指令,我们可以认为这些指令是紧跟在 FROM 之后指定的。触发器可以是任何构建指令。
ONBUILD ADD . /app/src
ONBUILD RUN cd /app/src && make
1.构建 docker 镜像
先用 docker login 登录到 docker hub 上:
1.用 docker commit 命令来构建
docker ps -l // 列出最后一个创建的容器
docker commit 容器id 作者名/库名:标签名
docker images // 查看,已经有新的
docker inspect REPOSITORY // 查看镜像信息
2.通过 Dockerfile 构建
1.先创建一个 static_web 的目录来保存 Dockerfile, 这个目录就是我们的构建环境,
docker 则称此环境为上下文或者构建的上下文。Docker 会在构建镜像时将构建上下文和该
上下文的文件和目录上传到 Docker 守护进程。这样 Docker 守护进程就能直接访问用户想
在镜像中存储的任何代码,文件或者其他数据。
# Version : 0.0.1
FROM ubuntu:14.04
MAINTAINER Wei daodao "test@qq.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 中的指令按顺序
从上到下执行。
每条指令都会创建一个新的镜像层并对镜像进行提交。Docker 大体上按照如下流程执行 Dockerfile 中的指令:
1.Docker 从基础镜像运行一个容器
2.执行一条指令,对容器进行修改
3.执行类似 docker commit 的操作,提交一个新的镜像层
4.Docker 在基于公共提交的镜像运行一个新的容器
5.执行 Dockerfile 中的下一条指令,直到所有的指令执行完毕
如果用户的 Dockerfile 由于某些原因失败了,那么用户将得到一个可以使用的镜像。这对调试很有帮助:可以基于
该镜像运行一个具备交互式功能的容器,使用最后创建的镜像对为什么用户的指令会失败进行调试。
每个 Dockerfile 的第一条指令必须是 FROM. FROM 指令指定一个已经存在的镜像,后续的指令都是基于这个镜像进行,
这个镜像被称为基础镜像。
指定 MAINTAINER 指令,这条指令会告诉 Docker 该镜像的作者是谁,以及作者的email.
RUN 指令会在当前的镜像中运行指定的命令。每条 RUN 指令都会创建一个新的镜像层,如果指令成功,就会将此镜像层提交。
之后继续执行 Dockerfile 中的下一条指令。
默认情况下, RUN 指令会在 shell 里使用命令包装器 /bin/sh -c 来执行。如果是在一个不支持 shell 的平台上运行或者
不希望在 shell 中运行,也可以使用 exec 格式发 RUN 命令。如:
RUN ["apt-get", "install", "-y", "nginx"]
EXPOSE 命令告诉 docker 该容器内的应用程序将会使用容器的指定端口。这并不意味着可以自动访问任何容器运行中的服务的端口。
2.基于 Dockerfile 构建新镜像
docker build -t weidaodao/static_web .
-t 设置仓库和名称
如果在构建上下文的根目录存在 .dockerignore 命名的文件的话,那么该文件内容会被按行进行切割,每一行都是一条文件过滤匹配模式。
这非常像 .gitignore 文件,该文件用来设置哪些文件不会被当作构建上下文的一部分。
3.构建失败了怎么办
基于最后成功步骤创建新容器进行调试:
1.docker run -t -i 容器_id /bin/bash
2.运行失败的命令,进行调试
3.成功后,修改 Dockerfile 文件,再次构建
4.Dockerfile 和构建缓存
由于每一步的构建过程都会将结果提交为镜像,所以 Docker 的构建过程就显得非常聪明。它会将之前的镜像层当作缓存。
有时候不需要缓存:
docker build --no-cache
5.基于构建缓存的 Dockerfile 模板
FROM ubuntu:14.04
MAINTAINER Wei daodao "test@qq.com"
ENV REFRESHED_AT 2014-07-01 # 设置环境变量, 用来表明该镜像模板最后的更新时间
RUN apt-get -qq update
有了这个模板,如果想刷新一个构建,只需要修改 ENV 指令中的日期。这使 docker 在命中 ENV 指令时开始重置这个缓存,
并运行后续指令而无需依赖该缓存。
docker history 镜像名 // 查看镜像如何构建的
8.运行自己的 Docker Registry
//从容器中运行 Registry
1.docker run -d -p 5000:5000 --name weidaodao-registry registry:2
2.测试新 Registry
docker tag 4ab4c602aa5e localhost:5000/weidaodao/hello-world // 给 镜像打上自己的标签
此命令使用 [REGISTRYHOST/]NAME[:TAG] 格式为 4ab4c602aa5e 重新打标。REGISTRYHOST 在此例中是 localhost。
在 Mac OSX 环境中,得把 localhost 换成 $(boot2docker ip):5000。
3.将镜像推送到本地 registry 中
docker push localhost:5000/weidaodao/hello-world
4.使用 curl 命令及 Docker Registry 服务 API v2 列出 Registry 中的镜像:
curl -v -X GET http://localhost:5000/v2/weidaodao/hello-world/tags/list
http://192.168.0.106:5000/v2/weidaodao/hello-world/tags/list // 浏览器访问
5.从你的本地环境中移除所有未使用的镜像
docker rmi -f $(docker images -q -a )
6.现在,尝试指定镜像的 Registry 来运行镜像:
docker run localhost:5000/hello-mine
http://dockone.io/article/324
https://docs.docker.com/registry/#basic-commands
构建镜像:
6.自动构建
7.删除镜像
8.运行自己的 Docker Registry