华为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
的安全实践利用虚拟机软件或虚拟机中运行的软件漏洞进行攻击,以达到攻击或控制虚拟机宿主操作系统的目的
若文中有错误欢迎大家评论指出