Docker - SuperProjectGit/super-repository GitHub Wiki
Docker是基于Go语言实现的云开源项目。Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或者数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。 Docker引擎的基础是Linux自带的容器(Linux Containers,LXC)技术。IBM对于容器技术的准确描述如下: 容器有效的将单个操作系统管理的资源划分到孤立的组中,以便更好的在孤立的组之间平衡有冲突的资源使用需求。与虚拟化相比,这样既不需要指令级模拟,也不需要即时编译。容器可以在核心CPU本地运行指令,而不需要任何专门的解释机制。此外,也避免了准虚拟化(paravirtualization)和系统调用替换中的复杂性。 我们可以将容器理解为一种沙盒。每个容器内运行一个应用,不同的容器相互隔离,容器之间可以建立通信机制。容器的创建和停止都十分快速(秒级),容器自身对资源的需求十分有限,远比虚拟机本身占用的资源少。
更快速的交付和部署:开发人员可以使用镜像快速的构建标准开发环境;开发完成后,测试和运维人员可以使用开发人员提供的docker镜像快速部署应用,可以避免开发和测试运维人员之间的环境差异导致的部署问题。 更高校的资源利用:Docker容器的运行不需要额外的虚拟化管理程序支持,它是内核级的虚拟化,在占用更少资源的情况实现更高的性能。 更方便的迁移和扩展:Docker容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、服务器等。这种兼容使得用户可以在不同的平台之间很方便的完成应用迁移。 更简单的更新管理:使用Dockerfile,只需要小小的配置修改,就可以替代以往大量的更新工作,并且所有修改都以增量方式进行分发和更新。
虚拟化的核心是对资源进行抽象,目标往往是为了在同一个机器上运行多个系统或应用,从而提高系统资源的利用率。虚拟化分为很多类型,比如常见的硬件辅助虚拟化(VMware workstation、 KVM等)。Docker所代表的容器虚拟化技术属于操作系统级虚拟化:内核通过创建多个虚拟的操作系统实例(内核和库)来隔离不同的进程。# 传统虚拟化和容器技术结构比较:传统虚拟化技术是在硬件层面实现虚拟化,增加了系统调用链路的环节,有性能损耗;容器虚拟化技术以共享Kernel的方式实现,几乎没有性能损耗。
Docker是Client/Server的架构,Docker客户端与Docker daemon进行交互,daemon负责构建、运行和发布Docker容器。客户端可以和服务端运行在同一个系统中,也可以连接远程的daemon。Docker的客户端的daemon通过RESTful API进行socket通信。 如上图,Docker守护进程(daemon)在主机上运行,用户不能直接和守护进程打交道,但是可以通过Docker客户端与其进行交互;Client是Docker的初始用户界面,它接收用户的命令并反馈,并且与Docker的守护进行交互。 Docker基于Linux容器技术(LXC),Namespace,Cgroup,UnionFS(联合文件系统)等技术实现:
命名空间是 Linux 内核一个强大的特性。每个容器都有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。docker实际上一个进程容器,它通过namespace实现了进程和进程所使用的资源的隔离。使不同的进程之间彼此不可见。
Docker用到的一些命名空间有: pid命名空间:用于隔离进程,容器都有自己独立的进程表和1号进程; net命名空间:用于管理网络,容器有自己独立的networkinfo; ipc命名空间:用于访问IPC资源(IPC:InterProcess Communication); mnt命名空间:用于管理挂载点,每个容器都有自己唯一的目录挂载; uts命名空间:用于隔离内核和版本标识(UTS:UnixTimeProcess System),每个容器都有独立的hostname和domain。
是 Linux 内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免当多个容器同时运行时的对系统资源的竞争。控制组技术最早是由 Google 的程序员 2006 年起提出,Linux 内核自 2.6.24 开始支持。控制组可以提供对容器的内存、CPU、磁盘 IO 等资源的限制和审计管理。
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对 文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。Docker 中使用的 AUFS(AnotherUnionFS)就是一种 Union FS。 AUFS 支持为每一个成员目录(类似 Git 的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限, 同时 AUFS 里有一个类似分层的概念, 对只读权限的分支可以逻辑上进行增量地修改(不影响只读部分的)。Docker 目前支持的 Union 文件系统种类包括 AUFS, btrfs, vfs 和 DeviceMapper。
Docker镜像类似于虚拟机镜像,是一个只读模板,并且包含了文件系统。一个镜像可以只包含一个操作系统环境(比如SUSE镜像),也可以安装了用户程序及其运行环境(比如eBackup镜像)。镜像其实就是一个文件,任何用户程序都可以成为镜像的一部分。 镜像=操作系统+软件运行环境+用户程序
如上图,一个layer就是一个image,多个image又可以打包成一个image。Image类似一个单链表系统,每个image包含一个指向parent image的指针,没有parent image的image是baseimage(image的指针靠sqlite数据库来保存)。 最上面的一层(不属于image)是可写的,上面的内容依赖于下面的内容,如果要修改下面的内容,先将下面的内容复制到上面再进行修改。 Image是创建container的基础。 关于image的一些命令: docker pull //从网络上下载镜像 docker images //查看本地主机已经存在的镜像
容器是从镜像创建的运行实例,可以将其启动、开始。停止、删除,而这些容器都是相互隔离(独立进程),互不可见的。
我们对Docker有了认识和了解,docker还有非常重要的一块,那就是docker镜像。提到docker镜像必不可少的一个文件是Dockerfile docker可以通过build命令自动从Dockerfile文件中读取并执行命令,最终生成docker镜像。使用Dockerfile非常简单,且重要!
Dockerfile命令详解
写文章时docker版本号为:1.8.2 目前Dockerfile中共包含14个命令,文章内容详细介绍每个一个命令的含义和用法
格式:INSTRUCTION arguments
instruction 不区分大小写,推荐用大写,以免和其他参数冲突
格式:
FROM \<image\>
FROM \<image\>:\<tag\>
FROM \<image\>@\<digest\>
Dockerfile中的第一条指令必须是FROM,FROM指令指定了构建镜像的base镜像
格式:MAINTAINER \<name\> \<Email\>
编写维护Dockerfile的作者信息
格式:
ENV \<key\>\<value\>
ENV \<key\>=\<value\>
为容器声明环境变量,环境变量在子镜像中也可以使用。可以直接使用环境变量$variable_name
运行容器指定环境变量:docker run --env <key>=<value>
格式:
-
RUN \<command\>
(类似/bin/sh -c
shell格式) -
RUN ["executable", "param1", "param2"]
(exec格式)
第一种 使用shell格式时,命令通过/bin/sh -c
执行;
第二种 使用exec
格式时,命令直接执行,容器不调用shell,并且exec
格式中的参数会看作是JSON
数组被Docker解析,所以要用(")双引号,不能用单引号(')。
举例:
RUN [ "echo", "$HOME" ]
$HOME变量不会被替换,如果你想运行shell程序,使用:RUN [ "sh", "-c", "echo", "$HOME" ]
格式:COPY <src><dest>
拷贝本地<src>目录下的文件到容器中<dest>目录。
格式:
- ADD <src><dest>
- ADD ["",... ""]
ADD hom* /mydir/
从<src>目录下拷贝文件,目录或网络文件到容器的<dest>目录。和COPY非常相似,但比COPY功能多,拷贝的文件可以是一个网络文件,并且ADD有解压文件得功能。
格式:
-
CMD \<commadn\> param1 param2
(shell格式) -
CMD ["executable", "param1", "param2"]
(exex格式) -
CMD ["param1", "param2"]
(为ENTRYPOINT命令提供参数)
虽然有三种格式,但在Dockerfile中如果有多个CMD命令,只有最后一个生效。
CMD
命令主要是提供容器运行时得默认值。默认值,可以是一条指令,也可以是参数(ENTRYPOINT),CMD
命令参数是一个动态值,信息会保存到镜像的JSON文件中。
举例:
ENTRYPOINT ["executable"]
CMD ["param1", "param2"]
启动容器执行:["executable", "param1", "param2"]
注意: 如果在命令行后面运行docker run
时指定了命令参数,则会把Dockerfile
中定义的CMD
命令参数覆盖
格式:
-
ENTRYPOINT \<command\>
(shell格式) -
ENTRYPOINT ["executable", "param1", "param2"]
(exec格式)
ENTRYPOINT
和CMD
命令类似,也是提供容器运行时得默认值,但它们有不同之处。同样一个Dockerfile中有多个ENTRYPOINT命令,只有最后一个生效。
-
当
ENTRYPOINT
命令使用<commmand>格式,ENTRYPOINT
会忽略任何CMD
指令和docker run
传来的参数,直接运行在/bin/sh -c
中;也就是说ENTRYPOINT
执行的进程会是/bin/sh -c
的子进程。所以进程的PID不会是1,而且也不能接受Unix信号。(执行docker stop $container_id的时候,进程接收不到SIGTERM信号) -
使用
exec
格式,docker run
传入的命令参数会覆盖CMD
命令,并附加到ENTRYPOINT
命令的参数中。推荐使用exec
方式
格式:ONBUILD [INSTRUCTION]
ONBUILD
指令的功能是添加一个将来执行触发器指令到镜像中。当Dockerfile中FROM
的镜像中包含ONBUILD
指令,在构建此镜像的时候会触发ONBUILD
指令。但如果当前Dockerfile中存在ONBUID
指令,不会执行就。ONBUILD
指令在生成应用镜像时用处非常大。
ONBUILD
如何工作
1.构建过程中,ONBUILD
指令会添加到触发器指令镜像元数据中。触发器指令不会在当前构建过程中生效
2.构建完后,触发器指令会被保存到镜像的详情中,主键是OnBuild
,可以使用docker inspect
命令查看到
3.之后此镜像可能是构建其他镜像的父镜像,在构建过程中,FROM
指令会查找ONBUILD
触发器指令,并按照之前定义的顺序执行;如果触发器指令执行失败,则构建新镜像失败并退出;如果触发器指令执行成功,则继续往下执行。
4.构建成功后ONBUILD
指令清除,固不会被孙子辈镜像继承。
格式:VOLUME ["/data"]
为docker主机和容器做目录映射,volume目录信息会保存到镜像的JSON文件中,在运行docker run
命令时指定$HOST_DIR
格式:LABEL <key>=<value> <key>=<value> <key>=<value> ...
LABEL指令,添加一个元数据到镜像中。一个镜像中可以有多个标签,建议写一个(因为没多个LABEL指令镜像会多一个layer
)LABEL
是一个键值对<key><value>,在一个标签值,包括空间使用引号和反斜杠作为您在命令行解析。
举例:
LABEL multi.label1="value1" multi.label2="value2" other="value3"
格式:EXPOSE <port> [<port>...]
在Dockerfile中定义端口,默认是不往外暴露,在运行docker run
-p
or -P
暴露
格式:USER daemon
设定一个用户或者用户ID,在执行RUN``CMD``ENTRYPOINT
等指令时指定以那个用户得身份去执行
格式:WORKDIR /path/to/workdir
当执行RUN``CMD``ENTRYPOINT``ADD``CMD
等命令,设置工作目录
如果在Dockerfile文件目录下有.dockerignore文件,docker在构建镜像的时候会把在.dockerignore文件中定义的文件排除出去
*/temp*
*/*/temp*
temp?
*.md
!LICENSE.md
- 系统要求 正在维护的Centos7以上版本, centos-extras被启用(默认是启用状态)启用centos-extras
- 卸载旧版本docker
旧版本被称为docker或者docker-engine,如果之前装有旧版本,需要卸载旧版本,相关依赖一同卸载。
$ sudo yum remove docker \ docker-common \ docker-selinux \ docker-engine
/var/lib/docker/路径下的内容将被保留,现在Docker-CE包统称docker-ce 3. 安装Docker-CE
- 使用repository安装,这种方式免除了安装和升级的任务,官方推荐的安装方式
- 下载RPM包手动安装和升级,适用于无外网的隔离环境
- 使用自动化的便捷脚本安装,适用于测试和开发环境
如果是第一次在一台新的机器上安装,则需要安装repository,之后就可以通过repository进行安装和升级
-
安装repository
- 安装依赖包,yum-utils包为yum-config-manager包提供了可用性,devicemapper的存储驱动则需要device-mapper-persistent-data和lvm2
$ sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2
- 安装 stable repository,即使要使用edge或者test repository,也需要stable repository的支持(docker-ce有两个更新通道 stablet提供可靠的版本,每个季度会更新一次,edge提供新版本,每个月更新一次)
$ sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo
- (可选) 开启edge或者test repository,默认是未启用的
$ sudo yum-config-manager --enable docker-ce-edge
$ sudo yum-config-manager --enable docker-ce-test
禁用edge或者test repository可以使用如下命令:
$ sudo yum-config-manager --disable docker-ce-edge $ sudo yum-config-manager --disable docker-ce-test
-
安装DOCKER CE
- 安装最新版本的docker ce
$ sudo yum install docker-ce
Note:如果启用了多个docker repository,则在使用yum install或者yum update没有指定版本时,总是会安装最高的版本,可能最高的版本并不是很稳定。
- 在生产环境,应该使用指定版本的docker,而不是使用最新的版本,查看可用版本
$ yum list docker-ce --showduplicates | sort -r
docker-ce.x86_64 17.09.ce-1.el7.centos docker-ce-stable
安装指定版本的docker ce
sudo yum install <FULLY-QUALIFIED-PACKAGE-NAME>
example:上面列表中的全称版本 docker-ce-17.06.1.ce
- 启动docker
$ sudo systemctl start docker
- 运行hello-world镜像检查docker是否正确安装
$ sudo docker run hello-world
这个命令会下载测试镜像,并且运行一个容器,当容器运行成功,会打印信息然后退出。