Docker是一个开放源代码软件项目,项目主要代码在2013年开源于GitHub。它是云服务技术上的一次创新,让应用程序布署在软件容器下的工作可以自动化进行,借此在Linux操作系统上,提供一个额外的软件抽象层,以及操作系统层虚拟化的自动管理机制。
Docker利用Linux核心中的资源分脱机制,例如cgroups,以及Linux核心名字空间(name space),来创建独立的软件容器(containers),属于操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。Docker在容器的基础上进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护,使得其比虚拟机技术更为轻便、快捷。Docker可以在单一Linux实体下运作,避免因为创建一个虚拟机而造成的额外负担。
以下两张图分别介绍了虚拟机与Docker容器的结构。
对于虚拟机技术来说,传统的虚拟机需要模拟整台机器包括硬件,每台虚拟机都需要有自己的操作系统,虚拟机一旦被开启,预分配给他的资源将全部被占用。每一个虚拟机包括应用,必要的二进制和库,以及一个完整的用户操作系统。
容器技术和我们的宿主机共享硬件资源及操作系统,可以实现资源的动态分配。容器包含应用和其所有的依赖包,但是与其他容器共享内核。容器在宿主机操作系统中,在用户空间以分离的进程运行。容器内没有自己的内核,也没有进行硬件虚拟。
具体来说与虚拟机技术对比,Docker 容器存在以下几个特点:
Docker
是一家商业公司开发的容器技术,早期是容器内核是基于LXC(LinuX Container),来实现容器的创建和管理的。
LXC
: 早期有一种技术叫 jail(监狱,或叫沙盒),这种技术可让一个应用程序运行在一个沙箱中,该应用程序无论做出任何对系统的破坏都不会影响到真实的系统,仅仅只是沙箱中的虚拟环境。后来这种技术在Linux也引入了,叫vserver,即现在我们比较熟悉的chroot功能。但是在Linux系统中早期内核支持名称空间,是需要通过自己编写代码,调用系统调用来创建出UTS,Network,IPC,等不同的名称空间,结合chroot实现在一个操作系统上创建出一个用户空间,但这对普通用户来说,是很困难的,而LXC则提供了一组工具,将这些功能整合成工具,用户若需要创建容器,只需要使用lxc-create等命令行工具,就可以很轻松的创建容器,但是LXC在创建容器时,它需要借助于template(模板),当允许lxc-create来创建一个容器时,你可以在CentOS的系统上,创建一个Ubuntu的容器,或FreeBSD的容器等,都可以只有你提供相应的template和这些系统的软件包安装源即可; 但LXC这种方式带来的问题是使用上依然非常困难,应用模板的创建并不容易,而且又产生了很多冗余数据;如:我想创建两个Ubuntu的容器,我就需要安装两份相同的数据; 而且若我需要将一个容器迁移到另一台主机上,怎么做?LXC没有提供相应的工具。所以它并不适合大规模使用。Docker:它早期创建容器的内核是LXC,但它使用了比LXC更高效,更精巧的方式来创建容器,它不在使用模板来安装容器,而是将容器制作成镜像,当需要使用容器时,直接从镜像仓库中下载之前制作好的镜像到本地,直接启动容器即可。并且它的镜像采用一种叫做叠加镜像的方式解决数据冗余的问题,实际上它采用一种叫三层叠加镜像的方式来实现数据的高效利用 和 容器私有数据的保存。借助于共享存储来将容器的私有数据保存在宿主机的外部,当宿主机宕机时,只要在新的宿主机上下载镜像,启动容器,挂载数据即可恢复服务。具体如下图:
注: Docker为了管理容器方便,它定义一个容器中只能运行一个进程, 但实际上容器跟虚拟机类似,它是可运行多个进程的,只是为了管理方便,限制容器中只能运行一个进程。
CNCF
是Linux基金会旗下的基金会,可以理解为一个非盈利组织。当年谷歌内部一直用于编排容器的Borg项目开源了,为了该项目更好的发展,谷歌与Linux基金会一起创办了CNCF。同时,谷歌把Borg用Go语言重写,更名为Kubernetes并捐赠到CNCF。成立这个组织的初衷或者愿景,简单说:推动云原生计算可持续发展;帮助云原生技术开发人员快速地构建出色的产品;CNCF通过建立社区、管理众多开源项目等手段来推广技术和生态系统发展。云原生计算技术栈非常宽阔,与之相对应的开源项目就非常多。CNCF会管理和推广这些项目。比如,源于谷歌的Kubernetes(容器编排引擎)开源项目就被吸收到CNCF,Kubernetes也因此受到更多的人关注。再比如,源于华为的KubeEdge(边缘计算平台)开源项目也被CNCF吸纳,也吸引了很多人参与进来。很多公司很乐于把自已的项目贡献给CNCF,这样能吸引到更多的专家参与进来一起开发。只有足够优秀的项目CNCF才会接纳,源创公司会在该项目上保持技术上的领先,也能扩大技术影响力,所以公司愿意分享项目到CNCF。
Libcontainer
,又称为RunC,它是Docker官方提供的新Docker构建容器的核心程序,由于LXC在功能上,没有与时俱进,因此Docker官方,最终决定自己开发一个新的容器构建核心,它就是runC。
OCI(Open Container Initiative)
,它由Linux基金会主导于2015年6月创立,皆在围绕容器格式和运行时制定了一个开放的工业标准,它制定了两个规范标准:
OCF(Open Container Format)
,OCF开放容器格式就是OCI的倡导下产生的标准
Docker我们知道它是一家商业公司,早期Docker刚出现时,以下轰动世界,为了让Docker技术,能够有更大的发展,Docker将自己的产品分成商业版和社区开源版,但是Docker的商业版在商业领域上始终没能活动 大佬们的信赖,没能得到太多融资,但是社区开源版确始终火热的不行,Docker为了能获得更多商业利益,它最终决定将社区版的Docker更名为Moby,希望能吸引更多关注的目光到它的商业版上,但事与愿违。 而此时Google发现自己秘密使用了十几年的容器技术竟然被Docker给开源了,而且还发展的如此红火,尽人皆知,但Google不希望自己在容器技术上的话语权落到Docker手中,它决定扶持一家小容器公司,但这家公司的产品在Google大力扶植下,依然是名落孙山,不是Docker的对手,最后,Google发现Docker在编排工具的开发上,好无建树,而自己拥有十几年的容器使用经验(Google内部的容器叫Borg(博格)),因此就组织了工程师开发了Kubernetes,又鉴于Docker一家公司为了商业目的,随意更改Docker社区版,改变Docker的性质,因此Google将Kubernetes捐给了CNCF,而CNCF是容器标准化基金会组织,它是Google联合多家知名公司,如:IBM,微软,Facebook等联合成立的组织。向世人表态为不会左右Kubernetes的发展进程,加上Kubernetes从其诞生就是站在Bong的肩膀上成立的,所以它一经发布就成为世人聚焦的目标,短短3年,就已经从0.1发展到1.1版本,以每年4个版本迭代,2018年为止,其市场占有率达到80%以上。
对于开发人员来说,是天大的好处,因为Docker的出现真正解决代码一次编写到处运行,无论底层是什么系统,只要能运行docker,将镜像做好后,直接编排好,然后在宿主机上启动容器即可。对于运维人员来说,带来的问题是,系统构架更加复杂,原本的调试进程的方式,在容器时代变的异常困难,因为容器中很可能没有各种调试工具等。
如NMP环境的构建上, 通常我们需要先部署MySQL容器,接着是PHP容器,最后是Nginx容器,这样的顺序部署才能让环境都正常工作,否则可能出现Nginx代理PHP服务器,结果找不到PHP服务器,因为容器启动后,它的IP地址会改变,那通过DHCP根据MAC不是可以固定分配IP吗?但其实是不可以的,因为容器是没有固定MAC的,它的网卡是虚拟的,是通过Linux上的"虚拟网线”创建的两个虚拟网卡,一端接入容器,一端接入Docker0(默认桥)桥上,这样就实现了容器能接入网络中,因此每次启动容器时,是无法知道这一次创建的虚拟网卡的MAC地址是多少的,因此必须使用其它方法来获取启动完成后的容器的IP地址,这也就是为啥容器需要编排,对于LNMP环境,Nginx要依赖PHP,因为它要代理PHP,而PHP又依赖MySQL,因为PHP应用程序要从MySQL中获取数据,因此必须先启动MySQL容器,这样才能获取MySQL容器当前使用的IP,接着启动PHP容器,将MySQL容器的IP传入到PHP容器中,这样PHP容器就可以知道MySQL的IP,而Nginx也是一样,这样编排后,LNMP环境中每个容器就都能获取它所依赖的容器的IP,就可以正常通信了。
为了解决部署容器的顺序问题,容器技术,必须结合编排工具一起使用,才能实现大规模应用。目前比较知名的编排工具:
资源限制: 通常有两种,一种是弹性百分比限制能使用全部资源的百分比,另一种是决对资源限制。
实现资源限制的是Cgroups(Control Groups):
Docker主要包含三个基本概念,分别是镜像、容器和仓库,理解了这三个概念,就理解了 Docker 的整个生命周期。以下简要总结一下这三点:
pull
来获取镜像,然后执行run
命令来运行。当服务需要用到多种容器,容器之间又产生了各种依赖和连接的时候,部署一个服务的手动操作是令人感到十分厌烦的。docker-compose技术,就是通过一个.yml
配置文件,将所有的容器的部署方法、文件映射、容器连接等等一系列的配置写在一个配置文件里,最后只需要执行docker-compose up
命令就会像执行脚本一样的去一个个安装容器并自动部署他们,极大的便利了复杂服务的部署。
docker-machine 就是docker公司官方提出的,用于在各种平台上快速创建具有docker服务的虚拟机的技术,甚至可以通过指定driver来定制虚拟机的实现原理(一般是virtualbox)。
Docker按版本划分,可以区分为CE
和EE
。CE
即社区版(免费,支持周期三个月),EE
即企业版,强调安全,付费使用。
Registry: 在Docker中称为镜像仓库,Docker的镜像仓库有点类似与yum源仓库,但它的组织方式是这样的:官方提供的Docker镜像仓库地址: hub.docker.com
,当然国内也有很多docker镜像站,Docker镜像仓库的组织格式为:
以Nginx为例:
Nginx:为仓库名,nginx:1.15
这就是一个镜像名.同时一个镜像可能有多个名字,比如: 1.15是Nginx的最新发行版,则还会给它提供一个名字叫: nginx:lasted
即最新版,这个名字会随着Nginx发布的最新版而改变。nginx:1.14
另外我们知道,Nginx的发行版中,次号码为偶数表示,此版本为稳定版,
为奇数则为开发版,所以这种版本通常也会有一个名字: nginx:stated
即稳定版的nginx镜像。
状态图
Docker镜像包含了启动容器所需的文件系统及其内容,因此它用于创建并启动docker容器。docker镜像采用分层构建的机制,最底层为bootfs
,其上为rootfs
。
bootloader
和kernel
,容器启动完成后,bootfs会被卸载,以节省内存空间。如: docker exec -it nginx1 /bin/sh
,登录后,ls /
可以看到全部的根文件系统目录。
rootfs
时,为确保不会误删除文件,通常会先以只读模式挂载,完整性自检完成后,再重新以读写模式挂载rootfs
。Docker的镜像层级,从上到下分别为:
overlayfs:从kernel3.18以后被整合到Linux内核中了. 它叫 叠加文件系统, 再早期Docker实现叠加挂载是使用Aufs(Advanced multi-layered unification filesystem:高级多层统一文件系统), 而此文件系统是2006年开发,但因代码质量问题,一直未被整合到kernel中; 据说它的代码有3万行,而ext4这种文件系统总代码量4千多行。所以早期要使用docker有两种方式 一种手动给内核打aufs的补丁,另一种就是使用Ubuntu系统,因为它比较早的将Aufs整合到它的kernel中了。不过现在目前 CentOS系统已经能支持overlayfs的第2版了,所以可以直接使用docker即可。
最新稳定版安装包:Docker Desktop Installer.exe
双击桌面的Docker Desktop
图标运行它。
启动后,将在桌面右下角的状态栏出现一个Docker图标。
在图标上右键,点击Dashboard
图标,进入面板界面。
因为网络原因,直接请求默认官方镜像地址https://registry-1.docker.io
可能会因为网络问题失败。
国内有一些加速Docker镜像的源,其中包括:
https://hub-mirror.c.163.com
(网易节点)https://docker.mirrors.ustc.edu.cn
(科大节点)此外,阿里云还可以用账号创建专属的加速节点,地址:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
右键Docker Desktop在状态栏的图标,找到Settings
菜单。
在Docker Engine
菜单中,找到Json配置项的registry-mirrors
节点,添加我们需要配置的加速源地址,然后点击Apply & Restart
即可。
docker version
docker info
docker search $keyword
docker pull $imageName:tag
还可以直接指定镜像库来拉取,比如
docker pull $mirrorPath$imageName:tag
docker images
或者可使用:
docker image ls
docker image rm $imageName/$imageId
如果想要强制删除,可以加上-f
参数
docker image rm -f $imageName/$imageId
docker container create $imageName:tag
docker container run $imageName:tag
扩展格式:
docker container run [options] Image [Command] [参数...]
options:
-t
: 启动镜像时,给其添加一个终端访问接口,以便能够启动后,连接登录。-i
: 启动为交互模式。--rm
: 停止后,直接删除该容器。-d
: 运行到后台。--name <ImageName>
: 为启动的容器名一个名字。--network <NetName>
: 将容器加入一个指定的网络中。例如:
docker container run -it --name n1 nginx:latest
创建并后台运行一个容器-d
docker container run -itd --name n2 nginx:latest
docker container start $containerId
docker container stop $containerId
docker container kill $containerId
docker container top $containerId
docker network ls
可查看到,当docker安装完成后,它会自动创建一个bridge
的桥,这个桥是NAT桥,它是直接桥接在物理网卡上的,可直接和物理网络通信。
docker ps
docker ps -a
docker kill $containerName/$containerId
docker stop $containerName/$containerId
docker restart $containerName/$containerId
docker rm $containerId
注意:如果容器还在运行,将无法删除,需要先停止或者强制杀掉。
docker exec -it $containerName/$containerId /bin/sh
如需退出容器,使用命令exit
即可。
docker logs $containerName/$containerId
docker inspect $containerName/$containerId
通过此命令,还可以定制一些返回参数,例如获取容器IP
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $containerName/$containerId
docker stats
docker tag $sourceImage:$tag $targetImage:$tag
docker login
在Docker Desktop中默认就是登录docker.hub.com
官方镜像库。
如需指定第三方或者私有库,只需要定制可选参数即可。
docker login -u $userName -p $passWord $mirrorServerUrl
docker logout $mirrorServerUrl
docker push $imageName:tag
docker save -o $fileName $imageName:tag
该文件会保存到当前目录,通过ls
可查看。
docker load -i $fileName
docker build [OPTIONS] PATH|URL|-
docker build -t $tag $dockerFileName
docker export $containerId > $filename
cat $filename | docker import - $imageName:tag
docker commit -m $description $containerId $imageName:tag
定义和运行多个Docker容器的应用(Defining and running multi-container Docker applications)
Docker Compose是Docker官方的开源项目,使用Python编写,实现上调用了Docker服务的API进行容器管理,通过Compose,您可以使用YML
文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从YML
文件配置中创建并启动所有服务。
幸运的是,Docker Desktop For Windows已经自带了Docker Compose。
docker-compose version
rm /usr/local/bin/docker-compose
或者
pip uninstall docker-compose
Compose使用的三个步骤:
使用 Dockerfile 定义应用程序的环境。
使用docker-compose.yml
定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
最后,执行docker-compose up
命令来启动并运行整个应用程序。
docker-compose.yml
文件# yaml 配置
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
该Compose文件定义了两个服务:web
和redis
。
docker-compose up
# -d 是后台运行
docker-compose up -d
通过设定的端口,访问服务。
docker-compose ps
docker-compose stop
docker-compose start
docker-compose down
docker-compose logs
docker-compose build
docker-compose pull
docker-compose restart
docker-compose rm
–f
, –force,强制直接删除,包括非停止状态的容器-v
,删除容器所挂载的数据卷docker-compose run $seviceName $command
例如:docker-compose run ubuntu ping www.baidu.com
docker-compose scale $seviceName=$count
例如:docker-compose scale web=3 db=2
docker-compose pause
docker-compose pause $seviceName
docker-compose unpause
docker-compose kill
docker-compose kill $seviceName
docker-compose config
docker-compose create [options] [SERVICE...]
–force-recreate
:重新创建容器,即使配置和镜像没有改变,不兼容–no-recreate参数–no-recreate
:如果容器已经存在,不需要重新创建,不兼容–force-recreate参数–no-build
:不创建镜像,即使缺失–build
:创建容器前,生成镜像docker-compose exec [options] SERVICE COMMAND [ARGS...]
docker-compose exec –index=$serviceIndex $serviceName /bin/bash
-d
分离模式,后台运行命令。–privileged
获取特权。–user
USER 指定运行的用户。-T
禁用分配TTY,默认docker-compose exec分配TTY。–index=index
,当一个服务拥有多个容器时,可通过该参数登陆到该服务下的任何服务,例如:docker-compose exec –index=1 web /bin/bash
,web服务中包含多个容器docker-compose port $serviceName
–protocol=proto
,指定端口协议,TCP(默认值)或者UDP–index=index
,如果同意服务存在多个容器,指定命令对象容器的序号(默认为1)docker-compose push
Compose允许用户通过一个docker-compose.yml
模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
Compose模板文件是一个定义服务、网络和卷的YAML文件。Compose模板文件默认路径是当前目录下的docker-compose.yml,可以使用.yml或.yaml作为文件扩展名。
Docker-Compose标准模板文件应该包含version、services、networks 三大部分,最关键的是services和networks两个部分。
Compose目前有三个版本分别为Version 1,Version 2,Version 3,Compose区分Version 1和Version 2(Compose 1.6.0+,Docker Engine 1.10.0+)。Version 2支持更多的指令。Version 1将来会被弃用。
例如:
version: '2'
services:
web:
image: dockercloud/hello-world
ports:
- 8080
networks:
- front-tier
- back-tier
redis:
image: redis
links:
- web
networks:
- back-tier
lb:
image: dockercloud/haproxy
ports:
- 80:80
links:
- web
networks:
- front-tier
- back-tier
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
front-tier:
driver: bridge
back-tier:
driver: bridge
image是指定服务的镜像名称或镜像ID。如果镜像在本地不存在,Compose将会尝试拉取镜像。
services:
web:
image: dockercloud/hello-world
服务除了可以基于指定的镜像,还可以基于一份Dockerfile,在使用up启动时执行构建任务,构建标签是build,可以指定Dockerfile所在文件夹的路径。Compose将会利用Dockerfile自动构建镜像,然后使用镜像启动服务容器。
build都是一个目录,如果要指定Dockerfile文件需要在build标签的子级标签中使用dockerfile标签指定。
如果同时指定image和build两个标签,那么Compose会构建镜像并且把镜像命名为image值指定的名字。
services:
web:
build: .
services:
redis:
image: redis:alpine
web:
build:
context: F:\XXXXX\compose_hello
ports:
- published: 5000
target: 5000
version: '3'
context选项可以是Dockerfile的文件路径,也可以是到链接到git仓库的url,当提供的值是相对路径时,被解析为相对于撰写文件的路径,此目录也是发送到Docker守护进程的context
services:
web:
build:
context: F:\XXXXX\compose_hello
使用dockerfile文件来构建,必须指定构建路径
services:
web:
build:
context: .
dockerfile: Dockerfile-alternate
使用command可以覆盖容器启动后默认执行的命令。
services:
web:
command: bundle exec thin -p 3000
Compose的容器名称格式是:<项目名称><服务名称><序号>
可以自定义项目名称、服务名称,但如果想完全控制容器的命名,可以使用标签指定:container_name: app
在使用Compose时,最大的好处就是少打启动命令,但一般项目容器启动的顺序是有要求的,如果直接从上到下启动容器,必然会因为容器依赖问题而启动失败。例如在没启动数据库容器的时候启动应用容器,应用容器会因为找不到数据库而退出。depends_on标签用于解决容器的依赖、启动先后的问题。
下述YAML文件定义的容器会先启动redis和db两个服务,最后才启动web服务。
version: '2'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
ports用于映射端口的标签,使用HOST:CONTAINER
格式或者只是指定容器的端口,宿主机会随机映射端口。
当使用HOST:CONTAINER
格式来映射端口时,如果使用的容器端口小于60可能会得到错误得结果,因为YAML将会解析xx:yy这种数字格式为60进制。所以建议采用字符串格式。
ports:
- "3000"
- "8000:8000"
- "49100:22"
- "127.0.0.1:8001:8001"
添加主机名的标签,会在/etc/hosts文件中添加一些记录。
extra_hosts:
- "somehost:162.242.195.82"
- "otherhost:50.31.209.229"
启动后查看容器内部hosts:
162.242.195.82 somehost
50.31.209.229 otherhost
挂载一个目录或者一个已存在的数据卷容器,可以直接使用 [HOST:CONTAINER]格式,或者使用[HOST:CONTAINER:ro]格式,后者对于容器来说,数据卷是只读的,可以有效保护宿主机的文件系统。
Compose的数据卷指定路径可以是相对路径,使用.
或者..
来指定相对目录。
volumes:
// 只是指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)。
- /var/lib/mysql
// 使用绝对路径挂载数据卷
- /opt/data:/var/lib/mysql
// 以 Compose 配置文件为中心的相对路径作为数据卷挂载到容器。
- ./cache:/tmp/cache
// 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/)。
- ~/configs:/etc/configs/:ro
// 已经存在的命名的数据卷。
- datavolume:/var/lib/mysql
如果不使用宿主机的路径,可以指定一个volume_driver。
volume_driver: mydriver
自定义DNS服务器。可以是一个值,也可以是一个列表。
dns:8.8.8.8
dns:
- 8.8.8.8
- 9.9.9.9
暴露端口,但不映射到宿主机,只允许能被连接的服务访问。仅可以指定内部端口为参数
expose:
- "3000"
- "8000"
链接到其它服务中的容器。使用服务名称(同时作为别名),或者“服务名称:服务别名”(如 SERVICE:ALIAS)
links:
- db
- db:database
- redis
设置网络模式。
net: "bridge"
net: "none"
net: "host"
手机扫一扫
移动阅读更方便
你可能感兴趣的文章