华为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:隔离进程IDUTS:隔离主机名和域名User:隔离用户ID和组IDDocker镜像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仓库中的commitImage ID:镜像最上层的layer ID就是该镜像的ID,Repo:tag提供了易于人类识别的名字,而ID便于脚本处理、操作镜像Docker镜像Docker内嵌了一系列命令制作、管理、上传、下载镜像,可以调用REST API给Docker daemon发送相关命令,也可以使用client端提供CLI命令完成操作。
docker images
Build:创建镜像docker pull busyboxdocker save -o busybox.tar busybox 导出busybox为busybox.tardocker 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 Hubdocker pull ubuntu:14.04 下载镜像,不写服务器地址默认从官方Docker Hub下载docker search localhost:5000/ubuntu 查询镜像Docker HubDocker Hub优点Docker镜像,供免费下载学习和使用Docker distribution,在开源社区上设计维护,会不断更新和完善Docker Hub,为企业级用户提供一站式解决方案Registry功能和架构Registry旨在实现镜像的创建、存储、分发和更新等功能
Registry后端,与本地镜像存储方式类似,它也分隔成多个镜像层,放置在各自的目录中,保存成tar格式。还保留了清单文件(manifest)和镜像签名文件(signature)等Registry之间通过Registry API传输镜像。Registry API 即一系列HTTP/HTTPS请求,用来发送用户请求到Registry,并接收Registry响应,请求响应中包含了镜像数据的交互Registry特点
Registry API说明文档s3、azure)和本地文件系统等,接口以插件方式存在,易于配置Manifest)作为元数据完整的记录镜像信息Webhook方式实现通知系统TLS,支持HTTPS安全访问Registry APIAPI描述: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作用:
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 pairEndpoint。网络实现可以是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原生的跨主机多子网模型WeaveFlannelSocketPlaneDocker卷管理基础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 APIDocker APIREST简介REST Representational State Transfer 一般来说只要一个架构设计满足REST,就可以称之为RESTful架构
Docker安全Docker的安全Docker的安全性Docker安全性主要体现如下几个方面
Docker容器的安全性:这是指容器是否会危害到host或其他容器Docker daemon的安全性:如何确保发送给daemon的命令是可信用户发起的。Docker容器的安全性CgroupDocker如何使用Cgroup
CPUI/OulimitLinux系统中有一个ulimit指令,可以对一些类型的资源起到限制作用,包括core dump文件的大小、进程数据段的大小、可创建文件的大小、常驻内存集的大小、打开文件数量、进程栈的大小、CPU时间、单个用户的最大线程数、进程的最大虚拟内存等
在接入容器隔离不足的情况下,将受信任的和不受信任的容器组网在不同的网络中,可以减少危险
如果将容器运行在全虚拟化环境中(例如在虚拟机中运行容器),这样就算容器被攻破,也有虚拟机的保护作用
当发布者将镜像push到远程仓库时,Docker会对镜像用私钥进行签名,之后其他人pull镜像时,Docker就会用发布者的公钥来校验该镜像是否和发布者所发布的镜像一致,是否被篡改,是否是最新版
目前支持的类型none、json-file、syslog、gelf、fluentd,默认为json-file
在使用容器时,应该注意监控容器的信息,若发现异常,就能采取措施及时补救
Docker可以设置容器的根文件系统为只读模式,只读模式的好处是即使容器与host使用的是同一文件系统,也不用担心会影响甚至破坏host的根文件系统
capability打破了Linux操作系统中超级用户/普通用户的概念,让普通用户也可以做只有超级用户才能完成的工作
SELinuxSecurity-Enhanced Linux 美国国家安全局对于强制访问控制的实现,在这种访问控制体系下,进程只能访问那些在它的任务中所需要的文件
AppArmor其主要作用是设置某个可执行程序的访问控制权限
SeccompSeccomp(secure computing mode)是一种Linux内核提供的安全特性,可以实现应用程序的沙盒机制,以白名单或黑名单的方式限制进程进行系统调用
grsecurity可以用来控制资源访问权限
Docker安全相关的项目Notary 保证server和client之间的交互使用可信任的连接docker-bench-security 检测用户的生产环境是否符合Docker的安全实践利用虚拟机软件或虚拟机中运行的软件漏洞进行攻击,以达到攻击或控制虚拟机宿主操作系统的目的
若文中有错误欢迎大家评论指出