Docker进阶与实战上
华为Docker实践小组集大成之作,此文主要是摘录笔记,分为上下两部分,陆续更新,欢迎交流
简介
概念澄清
Docker
在LXC
基础上做了什么工作
LXC
含义
LXC
用户态工具Linux
Container
内核容器技术简称
通常指第二种,其特性为
- 跨主机部署
- 以应用为中心
- 自动构建
- 版本管理
- 组件重用
- 共享
- 工具生态链
Docker
容器与虚拟机
- 虚拟机:是用来进行硬件资源划分的完美解决方案,利用硬件虚拟化技术,通过一个
hypervisor
层来实现对资源的彻底隔离; - 容器:是操作系统级别的虚拟化,利用内核的
Cgroup
和Namespace
特性,通过软件实现虚拟化,仅仅是进程本身就可以与其他进程隔离开,不需要任何辅助
对比虚拟机的总结
特性 | 容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为MB |
一般为GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
关于容器技术
容器技术的前世今生
关于容器技术
容器技术主要包括Cgroup
和Namespace
Namespace
又称命名空间,主要做访问隔离。其原理是针对一类资源进行抽象,并将其封装在一起提供给一个容器使用,对这类资源每个容器都有自己的抽象并且彼此不可见,所以就可以做到访问隔离。Cgroup
是control
group
的简称,又称为控制组,主要是做资源控制。其原理是将一组进程放在一个控制组里,通过给这个控制组分配指定的可用资源,达到控制这一组进程可用资源的目的。
一分钟理解容器
容器的组成
容器 = 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
(traffic
controller
)限制网络带宽net
_piro
:设置进程的网络流量优先级huge
_tlb
:限制HugeTLB
的使用perf
_event
:允许Perf
工具基于Cgroup
分组做性能监测
Namespace
介绍
Namespace
是什么
Namespace
是将内核的全局资源做封装,使得每个Namespace
都有一份独立的资源,因此不同的进程在各自的Namespace
内对同一资源的使用不会互相干扰
目前Linux
内核总共实现了6种Namespace
IPC
:隔离System
V
IPC
和POSIX
消息队列Network
:隔离网络资源Mount
:隔离文件挂在系统PID
:隔离进程ID
UTS
:隔离主机名和域名User
:隔离用户ID
和组ID
理解Docker
镜像
Docker
image
概念介绍
Docker
image
是用来启动容器的只读模板,是容器启动所需要的rootfs
,类似于虚拟机所使用的镜像。
Docker
镜像的表示方法
Remote-dockerhub
.com
/namespace
/bar
:latest
Remote-dockerhub
.com
:Remote
image
hub
,集中存储镜像的Web
服务器地址(若缺少,则使用默认的镜像库,即Docker
官方镜像库)namespace
:Namespace
,类似于Github
中的命名空间,是一个用户或组织中所有镜像的集合bar
:Repository
,类似于Github
仓库,一个仓库可以有很多个镜像,不同镜像通过tag
来区分latest
:Tag
,类似于Git
仓库中的tag
,一般用来区分同一镜像的不同版本Layer
:镜像有一系列层组成,每层都用64位的十六进制,类似于Git
仓库中的commit
Image
ID
:镜像最上层的layer
ID
就是该镜像的ID
,Repo
:tag
提供了易于人类识别的名字,而ID
便于脚本处理、操作镜像
使用Docker
镜像
Docker
内嵌了一系列命令制作、管理、上传、下载镜像,可以调用REST
API
给Docker
daemon
发送相关命令,也可以使用client
端提供CLI
命令完成操作。
列出本机的镜像
docker images
Build
:创建镜像
- 直接下载
docker
pull
busybox
- 导入镜像
docker save -o busybox.tar busybox
导出busybox
为busybox.tar
docker load -i busybox.tar
导入该镜像
- 制作新镜像
docker
import
用于导入根文件系统的归档,并将之变成Docker
镜像。常用于制作Docker
基础镜像,与此相比,docker
export
则是把一个镜像导出为根文件系统的归档
Ship
:传输一个镜像
镜像传输是连接开发和部署的桥梁。可以使用Docker
镜像仓库做中转传输,还可以使用docker
export
/docker
save
生成的tar
包来实现,或者使用Docker
镜像的模板文件Dockerfile
做间接传输。
Run
:以image
为模板启动一个容器
启动容器时,使用docker
run
命令
- 命令间逻辑不一致,
docker
ps
列出容器,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
docker
push
localhost
:5000/official
/ubuntu
:14.04 向本地私有仓库上传镜像,如果不写服务器地址默认上传到官方Docker
Hub
docker
pull
ubuntu
:14.04 下载镜像,不写服务器地址默认从官方Docker
Hub
下载docker
search
localhost
:5000/ubuntu
查询镜像
再看Docker
Hub
Docker
Hub
优点
- 为开发者提供海量的
Docker
镜像,供免费下载学习和使用 - 拥有完善的账户管理系统,为用户提供付费扩容
- 服务器采用分布式部署,支持负载均衡
- 支持镜像上传、下载、查询、删除及属性设置等多种操作
- 支持在线编译镜像
- 后端采用分布式存储,可容灾备份
- 其核心是
Docker
distribution
,在开源社区上设计维护,会不断更新和完善 - 提供企业版
Docker
Hub
,为企业级用户提供一站式解决方案
账户管理系统
- 用户可以编辑自己的注册信息,如密码邮箱等
- 创建和删除用户下的镜像
- 收费用户可以创建和设置私有镜像
- 创建和维护组织,添加组员
- 用户之间可以互相关注
仓库服务
Registry
功能和架构
Registry
旨在实现镜像的创建、存储、分发和更新等功能
- 镜像存储 镜像数据存储在
Registry
后端,与本地镜像存储方式类似,它也分隔成多个镜像层,放置在各自的目录中,保存成tar
格式。还保留了清单文件(manifest
)和镜像签名文件(signature
)等 - 镜像创建、分发和更新 本地用户和
Registry
之间通过Registry
API
传输镜像。Registry
API
即一系列HTTP
/HTTPS
请求,用来发送用户请求到Registry
,并接收Registry
响应,请求响应中包含了镜像数据的交互
Registry
特点
- 快速上传和下载镜像
- 设计方案新颖且高性能
- 部署方便
- 有详细完整的
Registry
API
说明文档 - 后端支持多种分布式云存储方案(
s
3、azure
)和本地文件系统等,接口以插件方式存在,易于配置 - 清单文件(
Manifest
)作为元数据完整的记录镜像信息 - 以
Webhook
方式实现通知系统 - 实现了本地的
TLS
,支持HTTPS
安全访问 - 有可配置的认证模块
- 有健康检查模块
- 管理镜像的清单文件和摘要文件格式清晰,更清楚地为镜像打标签
- 拥有完善的镜像缓存机制,镜像下载更加快捷
Registry
API
API
描述:Registry
API
遵循REST
设计标准,用于Registry
和Docker
Engine
之间的通信,实现Registry
镜像分发,是Docker
Registry
的重要组成部分
API
传输的对象主要包括镜像layer
的块数据(blob
)和表单(Manifests
)
Manifest
是JSON
格式的文件,记录镜像的元数据信息,并兼容V
1版本镜像信息
{
"name": <name>,
"tag": <tag>,
"fsLayers": [
{
"blobSum": <tarsum>
},
...
],
"history": [...],
"signatures": [...]
}
鉴权机制
鉴权机制是Registry
V
2版本之后新增的功能,目的是校验用户请求权限。校验和控制访问权限的任务是由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
作用:
- 管理
Docker
Private
Hub
注册用户,认证用户访问权限 - 保存记录和更新用户信息,以及
token
等校验信息 Docker
元数据(metadata
)存储- 记录用户操作镜像的历史数据
- 提供操作界面
Web
UI
,用户可以方便的访问和更新资源
Index
主要由控制单元、鉴权模块、数据库、健康检查和日志系统组成
Docker
网络
Docker
网络现状
Libnetwork
提出新的容器网络模型(Container
Network
Model
,简称CNM
),定义了标准的API
用于为容器配置网络,其底层可以适配各种网络驱动。
CNM
三个重要概念
- 沙盒 是一个隔离的网络运行环境,保存了容器网络栈的配置,包括了对网络接口、路由表和
DNS
配置的管理。 Endpoint
将沙盒加入一个网络,Endpoint
的实现可以是一对veth
pair
或者OVS
内部端口,当前的Libnetwork
使用的是veth
pair
- 网络 网络包括一组能互相通信的
Endpoint
。网络实现可以是Linux
bridge
、vlan
等
从CNM
的概念角度讲,Libnetwork
的出现使得Docker
具备了跨主机多子网的能力,同一个子网内的不同容器可以运行在不同主机上
Libnetwork
五种驱动(driver
)
bridge
Docker
默认的容器网络驱动host
容器于主机共享同一Network
Namespace
,共享同一套网络协议栈、路由表及iptables
规则等,容器和主机看到的是相同的网络视图null
容器内网络配置为空,需要用户手动为容器配置网络接口及路由等remote
Docker
网络插件的实现,Remote
driver
使得Libnetwork
可以通过HTTP
RESTful
API
对接第三方的网络方案,
类似SocketPlane
的SDN
方案只要实现了约定的HTTP
URL
处理函数及底层的网络接口配置方法,就可以替换Docker
原生的网络实现overlay
Docker
原生的跨主机多子网网络方案
基本网络配置
Docker
网络初探
Docker
五种容器网络模式
none
不为容器配置任何网络功能container
与另一个运行中的容器共享Network
Namespace
,共享相同的网络视图host
与主机共享Root
Network
Namespace
,容器有完整的权限可以操纵主机的协议栈、路由表和防火墙等,所以被认为是不安全的bridge
Docker
设计的NAT
网络模型overlay
Docker
原生的跨主机多子网模型
网络解决方案进阶
Weave
Flannel
SocketPlane
容器卷管理
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
或其他容器- 镜像的安全性:用户如何确保下载下来的镜像是可信的、未被篡改的
Docker
daemon
的安全性:如何确保发送给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版可以私信我