Docker进阶与实战上
华为Docker实践小组集大成之作,此文主要是摘录笔记,分为上下两部分,陆续更新,欢迎交流
简介
概念澄清
Docker在LXC基础上做了什么工作
LXC含义
LXC用户态工具LinuxContainer内核容器技术简称
通常指第二种,其特性为
- 跨主机部署
- 以应用为中心
- 自动构建
- 版本管理
- 组件重用
- 共享
- 工具生态链
Docker容器与虚拟机
- 虚拟机:是用来进行硬件资源划分的完美解决方案,利用硬件虚拟化技术,通过一个
hypervisor层来实现对资源的彻底隔离; - 容器:是操作系统级别的虚拟化,利用内核的
Cgroup和Namespace特性,通过软件实现虚拟化,仅仅是进程本身就可以与其他进程隔离开,不需要任何辅助
对比虚拟机的总结
| 特性 | 容器 | 虚拟机 |
|---|---|---|
| 启动 | 秒级 | 分钟级 |
| 硬盘使用 | 一般为MB |
一般为GB |
| 性能 | 接近原生 | 弱于 |
| 系统支持量 | 单机支持上千个容器 | 一般几十个 |
关于容器技术
容器技术的前世今生
关于容器技术
容器技术主要包括Cgroup和Namespace
Namespace又称命名空间,主要做访问隔离。其原理是针对一类资源进行抽象,并将其封装在一起提供给一个容器使用,对这类资源每个容器都有自己的抽象并且彼此不可见,所以就可以做到访问隔离。Cgroup是controlgroup的简称,又称为控制组,主要是做资源控制。其原理是将一组进程放在一个控制组里,通过给这个控制组分配指定的可用资源,达到控制这一组进程可用资源的目的。
一分钟理解容器
容器的组成
容器 = cgroup + namespace + rootfs + 容器引擎(用户态工具)
Cgroup:资源控制Namespace: 访问隔离rootfs: 文件系统- 容器引擎:生命周期控制
容器的创建原理
代码一:
pid = clone(fun, stack, flags, clone_arg);
(flags: CLONE_NEWPID | CLONE_NEWNS |
CLONE_NEWUSER | CLONE_NEWNET |
CLONE_NEWIPC | CLONE_NEWUTS |
...)
通过clone系统调用,并传入各个Namespace对应的clone flag,创建了一个新的子进程,该进程拥有自己的pid、mount、user、net、ipc、uts namespace
代码二:
echo $pid > /sys/fs/cgroup/cpu/tasks
echo $pid > /sys/fs/cgroup/cpuset/tasks
echo $pid > /sys/fs/cgroup/blkio/tasks
echo $pid > /sys/fs/cgroup/memory/tasks
echo $pid > /sys/fs/cgroup/devices/tasks
echo $pid > /sys/fs/cgroup/freezer/tasks
将代码一中产生的进程pid写入各个Cgroup子系统中,这样该进程就可以受到相应的Cgroup子系统的控制
代码三:
fun()
{
...
pivot_root("path_of_rootfs/", path);
...
exec("/bin/bash");
...
}
该fun函数由上面生成的新进程执行,在fun函数中,通过pivot_root系统调用,使进程进入一个新的rootfs,之后通过exec系统调用,在新的Namespace、Cgroup、rootfs中执行"/bin/bash"程序
Cgroup介绍
Cgroup是什么
Cgroup是control group的简写,属于Linux内核提供的一个特性,用于限制和隔离一组进程对系统资源的使用,也就是做资源的Qos,这些资源主要包括CPU、内存、block I/O和网络带宽。
Cgroup中实现的子系统及其作用如下:
devices:设备权限控制cpuset:分配指定的CPU和内存节点cpu:控制CPU占用率cpuacct:统计CPU使用情况memory:限制内存的使用上限freezer:冻结(暂停)Cgroup中的进程net_cls:配合tc(trafficcontroller)限制网络带宽net_piro:设置进程的网络流量优先级huge_tlb:限制HugeTLB的使用perf_event:允许Perf工具基于Cgroup分组做性能监测
Namespace 介绍
Namespace是什么
Namespace是将内核的全局资源做封装,使得每个Namespace都有一份独立的资源,因此不同的进程在各自的Namespace内对同一资源的使用不会互相干扰
目前Linux内核总共实现了6种Namespace
IPC:隔离SystemVIPC和POSIX消息队列Network:隔离网络资源Mount:隔离文件挂在系统PID:隔离进程IDUTS:隔离主机名和域名User:隔离用户ID和组ID
理解Docker镜像
Docker image概念介绍
Docker image是用来启动容器的只读模板,是容器启动所需要的rootfs,类似于虚拟机所使用的镜像。
Docker镜像的表示方法
Remote-dockerhub.com/namespace/bar:latest
Remote-dockerhub.com:Remoteimagehub,集中存储镜像的Web服务器地址(若缺少,则使用默认的镜像库,即Docker官方镜像库)namespace:Namespace,类似于Github中的命名空间,是一个用户或组织中所有镜像的集合bar:Repository,类似于Github仓库,一个仓库可以有很多个镜像,不同镜像通过tag来区分latest:Tag,类似于Git仓库中的tag,一般用来区分同一镜像的不同版本Layer:镜像有一系列层组成,每层都用64位的十六进制,类似于Git仓库中的commitImageID:镜像最上层的layerID就是该镜像的ID,Repo:tag提供了易于人类识别的名字,而ID便于脚本处理、操作镜像
使用Docker镜像
Docker内嵌了一系列命令制作、管理、上传、下载镜像,可以调用REST API给Docker daemon发送相关命令,也可以使用client端提供CLI命令完成操作。
列出本机的镜像
docker images
Build:创建镜像
- 直接下载
dockerpullbusybox - 导入镜像
docker save -o busybox.tar busybox导出busybox为busybox.tardocker load -i busybox.tar导入该镜像
- 制作新镜像
dockerimport用于导入根文件系统的归档,并将之变成Docker镜像。常用于制作Docker基础镜像,与此相比,dockerexport则是把一个镜像导出为根文件系统的归档
Ship:传输一个镜像
镜像传输是连接开发和部署的桥梁。可以使用Docker镜像仓库做中转传输,还可以使用docker export/docker save生成的tar包来实现,或者使用Docker镜像的模板文件Dockerfile做间接传输。
Run:以image为模板启动一个容器
启动容器时,使用docker run命令
- 命令间逻辑不一致,
dockerps列出容器,docker images列出镜像 docker inspect查看容器和镜像的详细信息
Docker image的组织结构
Docker image包含着数据及必要的元数据。数据由一层层的image layer组成,元数据则是一些JSON文件,用来描述数据(image layer)之间的关系以及容器的一些配置信息。
写时复制
当父进程fork子进程时,内核并没有为子进程分配内存(当然基本的进程控制块、堆栈还是需要的),而是让父子进程共享内存。当两者之一修改共享内存时,会触发一次缺页异常导致真正的内存分配。这样既加速了子进程的创建速度,又减少了内存的消耗。
仓库
什么是仓库
仓库(repository)是用来集中存储Docker镜像,支持镜像分发和更新
仓库的组成
仓库的名字通常是由两部分组成,中间以斜线分开,斜线之前是用户名,斜线之后是镜像名。
仓库镜像
仓库下面包含一组镜像,镜像之间用标签(tag)区分,一个完整的镜像路径通常由服务器地址、仓库名称和标签组成
registry.hub.docker.com/official/ubuntu:14.04
它代表Docker Hub上的Ubuntu官方镜像,发行版本是14.04
dockerpushlocalhost:5000/official/ubuntu:14.04 向本地私有仓库上传镜像,如果不写服务器地址默认上传到官方DockerHubdockerpullubuntu:14.04 下载镜像,不写服务器地址默认从官方DockerHub下载dockersearchlocalhost:5000/ubuntu查询镜像
再看Docker Hub
Docker Hub优点
- 为开发者提供海量的
Docker镜像,供免费下载学习和使用 - 拥有完善的账户管理系统,为用户提供付费扩容
- 服务器采用分布式部署,支持负载均衡
- 支持镜像上传、下载、查询、删除及属性设置等多种操作
- 支持在线编译镜像
- 后端采用分布式存储,可容灾备份
- 其核心是
Dockerdistribution,在开源社区上设计维护,会不断更新和完善 - 提供企业版
DockerHub,为企业级用户提供一站式解决方案
账户管理系统
- 用户可以编辑自己的注册信息,如密码邮箱等
- 创建和删除用户下的镜像
- 收费用户可以创建和设置私有镜像
- 创建和维护组织,添加组员
- 用户之间可以互相关注
仓库服务
Registry功能和架构
Registry旨在实现镜像的创建、存储、分发和更新等功能
- 镜像存储 镜像数据存储在
Registry后端,与本地镜像存储方式类似,它也分隔成多个镜像层,放置在各自的目录中,保存成tar格式。还保留了清单文件(manifest)和镜像签名文件(signature)等 - 镜像创建、分发和更新 本地用户和
Registry之间通过RegistryAPI传输镜像。RegistryAPI即一系列HTTP/HTTPS请求,用来发送用户请求到Registry,并接收Registry响应,请求响应中包含了镜像数据的交互
Registry特点
- 快速上传和下载镜像
- 设计方案新颖且高性能
- 部署方便
- 有详细完整的
RegistryAPI说明文档 - 后端支持多种分布式云存储方案(
s3、azure)和本地文件系统等,接口以插件方式存在,易于配置 - 清单文件(
Manifest)作为元数据完整的记录镜像信息 - 以
Webhook方式实现通知系统 - 实现了本地的
TLS,支持HTTPS安全访问 - 有可配置的认证模块
- 有健康检查模块
- 管理镜像的清单文件和摘要文件格式清晰,更清楚地为镜像打标签
- 拥有完善的镜像缓存机制,镜像下载更加快捷
Registry API
API描述:Registry API遵循REST设计标准,用于Registry和Docker Engine之间的通信,实现Registry镜像分发,是Docker Registry的重要组成部分
API传输的对象主要包括镜像layer的块数据(blob)和表单(Manifests)
Manifest是JSON格式的文件,记录镜像的元数据信息,并兼容V1版本镜像信息
{
"name": <name>,
"tag": <tag>,
"fsLayers": [
{
"blobSum": <tarsum>
},
...
],
"history": [...],
"signatures": [...]
}
鉴权机制
鉴权机制是Registry V2版本之后新增的功能,目的是校验用户请求权限。校验和控制访问权限的任务是由Docker Engine、Registry 和Auth Service 协作完成
部署私有仓库
运行私有仓库
Docker私有服务(private registry)用来建设私有仓库、管理私有Docker镜像。
部署私有服务的有点:
- 可独立开发和运维私有仓库
- 节省带宽资源
- 有独立的账户管理系统
- 增加了定制化功能
搭建私有仓库的前提是部署Docker Private Registry。命令如下
docker run -d --hostname localhost --name registry-v2 -v /opt/data/distribution:/var/lib/registry/docker/registry/v2 -p 5000:5000 registry:2.0
构建反向代理
在实际使用中,暴露主机端口的方法是不安全的,如果Registry没有配置访问代理,任何用户都可以直接通过端口访问,因此,设计时需要为其加上HTTPS反向代理。
该方式会用代理服务器来接受用户的HTTPS请求,然后将请求转发给内部网络上的Registry服务器,并将Registry响应结果返回给用户。
Index及仓库高级功能
Index作用和组成
Index作用:
- 管理
DockerPrivateHub注册用户,认证用户访问权限 - 保存记录和更新用户信息,以及
token等校验信息 Docker元数据(metadata)存储- 记录用户操作镜像的历史数据
- 提供操作界面
WebUI,用户可以方便的访问和更新资源
Index主要由控制单元、鉴权模块、数据库、健康检查和日志系统组成
Docker网络
Docker网络现状
Libnetwork提出新的容器网络模型(Container Network Model,简称CNM),定义了标准的API用于为容器配置网络,其底层可以适配各种网络驱动。
CNM三个重要概念
- 沙盒 是一个隔离的网络运行环境,保存了容器网络栈的配置,包括了对网络接口、路由表和
DNS配置的管理。 Endpoint将沙盒加入一个网络,Endpoint的实现可以是一对vethpair或者OVS内部端口,当前的Libnetwork使用的是vethpair- 网络 网络包括一组能互相通信的
Endpoint。网络实现可以是Linuxbridge、vlan等
从CNM的概念角度讲,Libnetwork的出现使得Docker具备了跨主机多子网的能力,同一个子网内的不同容器可以运行在不同主机上
Libnetwork五种驱动(driver)
bridgeDocker默认的容器网络驱动host容器于主机共享同一NetworkNamespace,共享同一套网络协议栈、路由表及iptables规则等,容器和主机看到的是相同的网络视图null容器内网络配置为空,需要用户手动为容器配置网络接口及路由等remoteDocker网络插件的实现,Remotedriver使得Libnetwork可以通过HTTPRESTfulAPI对接第三方的网络方案,
类似SocketPlane的SDN方案只要实现了约定的HTTPURL处理函数及底层的网络接口配置方法,就可以替换Docker原生的网络实现overlayDocker原生的跨主机多子网网络方案
基本网络配置
Docker网络初探
Docker五种容器网络模式
none不为容器配置任何网络功能container与另一个运行中的容器共享NetworkNamespace,共享相同的网络视图host与主机共享RootNetworkNamespace,容器有完整的权限可以操纵主机的协议栈、路由表和防火墙等,所以被认为是不安全的bridgeDocker设计的NAT网络模型overlayDocker原生的跨主机多子网模型
网络解决方案进阶
WeaveFlannelSocketPlane
容器卷管理
Docker卷管理基础
增加新数据卷
docker run -d -v /tmp/data --name busyboxtest busybox
其中-v参数会在容器的/tmp/data目录下创建一个新的数据卷,用户可以通过docker inspect 命令查看数据卷所在主机中的位置
将主机目录挂载为数据卷
-v参数除了可以用于创建数据卷外,还可以用来将Docker daemon所在主机上的文件或文件夹挂载在容器中
docker run -d -v /host/data:/data --name busyboxtest busybox
上述命令是将主机的/host/data目录挂载在容器的/data目录
还可以只读的方式挂载
docker run -d -v /host/data:/data:ro --name busyboxtest busybox
如果容器中的/
data路径已经存在,Docker会使用/host/data的内容覆盖该目录,与mount命令行为一致
数据卷的备份、转储和迁移
使用如下命令将数据卷中的数据打包,并将打包后的文件拷贝到主机当前目录中
docker run --rm --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf
上述命令创建了一个容器,该容器挂载了
dbdata数据卷,并将主机的当前目录挂载到容器的/backup目录中;然后在容器中使用tar命令将dbdata数据卷中的内容打包存放到/backup目录的backup.tar文件中。
待容器执行结束后,备份文件就出现在主机的当前目录。之后可以将备份文件恢复到当前容器或者新创建的容器中,完成数据的备份和迁移工作
Docker卷管理的问题
- 只支持本地数据卷
- 缺乏对数据卷生命周期的有效管理
使用卷插件
卷插件简介
开发者可以根据自己的需要开发卷插件,可以更方便、更灵活地将本机或远端的存储卷挂载到本机的容器中,提供比Docker自身的卷管理更丰富的功能(如快照、备份等)
已有的卷插件
Convoy一种基于本地存储的单机版插件Flocker支持多种后台存储驱动
Docker API
关于Docker API
REST简介
REST Representational State Transfer 一般来说只要一个架构设计满足REST,就可以称之为RESTful架构
Docker安全
深入理解Docker的安全
Docker的安全性
Docker安全性主要体现如下几个方面
Docker容器的安全性:这是指容器是否会危害到host或其他容器- 镜像的安全性:用户如何确保下载下来的镜像是可信的、未被篡改的
Dockerdaemon的安全性:如何确保发送给daemon的命令是可信用户发起的。
Docker容器的安全性
安全策略
Cgroup
Docker如何使用Cgroup
- 限制
CPU - 限制内存
- 限制块设备
I/O
ulimit
Linux系统中有一个ulimit指令,可以对一些类型的资源起到限制作用,包括core dump文件的大小、进程数据段的大小、可创建文件的大小、常驻内存集的大小、打开文件数量、进程栈的大小、CPU时间、单个用户的最大线程数、进程的最大虚拟内存等
容器组网
在接入容器隔离不足的情况下,将受信任的和不受信任的容器组网在不同的网络中,可以减少危险
容器+全虚拟化
如果将容器运行在全虚拟化环境中(例如在虚拟机中运行容器),这样就算容器被攻破,也有虚拟机的保护作用
镜像签名
当发布者将镜像push到远程仓库时,Docker会对镜像用私钥进行签名,之后其他人pull镜像时,Docker就会用发布者的公钥来校验该镜像是否和发布者所发布的镜像一致,是否被篡改,是否是最新版
日志审计
目前支持的类型none、json-file、syslog、gelf、fluentd,默认为json-file
监控
在使用容器时,应该注意监控容器的信息,若发现异常,就能采取措施及时补救
文件系统级防护
Docker可以设置容器的根文件系统为只读模式,只读模式的好处是即使容器与host使用的是同一文件系统,也不用担心会影响甚至破坏host的根文件系统
capability
打破了Linux操作系统中超级用户/普通用户的概念,让普通用户也可以做只有超级用户才能完成的工作
SELinux
Security-Enhanced Linux 美国国家安全局对于强制访问控制的实现,在这种访问控制体系下,进程只能访问那些在它的任务中所需要的文件
AppArmor
其主要作用是设置某个可执行程序的访问控制权限
Seccomp
Seccomp(secure computing mode)是一种Linux内核提供的安全特性,可以实现应用程序的沙盒机制,以白名单或黑名单的方式限制进程进行系统调用
grsecurity
可以用来控制资源访问权限
几个与Docker安全相关的项目
Notary保证server和client之间的交互使用可信任的连接docker-bench-security检测用户的生产环境是否符合Docker的安全实践
安全加固
主机逃逸
利用虚拟机软件或虚拟机中运行的软件漏洞进行攻击,以达到攻击或控制虚拟机宿主操作系统的目的
后记
本书链接 Docker进阶与实战
若文中有错误欢迎大家评论指出,或者加我微信好友一起交流
gm4118679254,如果有需要此书pdf版可以私信我

浙公网安备 33010602011771号