Docker进阶与实战上

华为Docker实践小组集大成之作,此文主要是摘录笔记,分为上下两部分,陆续更新,欢迎交流

简介

概念澄清

DockerLXC基础上做了什么工作

LXC含义

  • LXC用户态工具
  • Linux Container内核容器技术简称

通常指第二种,其特性为

  • 跨主机部署
  • 以应用为中心
  • 自动构建
  • 版本管理
  • 组件重用
  • 共享
  • 工具生态链

Docker容器与虚拟机

  • 虚拟机:是用来进行硬件资源划分的完美解决方案,利用硬件虚拟化技术,通过一个hypervisor层来实现对资源的彻底隔离;
  • 容器:是操作系统级别的虚拟化,利用内核的CgroupNamespace特性,通过软件实现虚拟化,仅仅是进程本身就可以与其他进程隔离开,不需要任何辅助

对比虚拟机的总结

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为MB 一般为GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般几十个

关于容器技术

容器技术的前世今生

关于容器技术

容器技术主要包括CgroupNamespace

  • Namespace 又称命名空间,主要做访问隔离。其原理是针对一类资源进行抽象,并将其封装在一起提供给一个容器使用,对这类资源每个容器都有自己的抽象并且彼此不可见,所以就可以做到访问隔离。
  • Cgroupcontrol 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,创建了一个新的子进程,该进程拥有自己的pidmountusernetipcuts 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系统调用,在新的NamespaceCgrouprootfs中执行"/bin/bash"程序

Cgroup介绍

Cgroup是什么

Cgroupcontrol group的简写,属于Linux内核提供的一个特性,用于限制和隔离一组进程对系统资源的使用,也就是做资源的Qos,这些资源主要包括CPU、内存、block I/O和网络带宽。

Cgroup中实现的子系统及其作用如下:

  • devices:设备权限控制
  • cpuset:分配指定的CPU和内存节点
  • cpu:控制CPU占用率
  • cpuacct:统计CPU使用情况
  • memory:限制内存的使用上限
  • freezer:冻结(暂停)Cgroup中的进程
  • net_cls:配合tctraffic controller)限制网络带宽
  • net_piro:设置进程的网络流量优先级
  • huge_tlb:限制HugeTLB的使用
  • perf_event:允许Perf工具基于Cgroup分组做性能监测

Namespace 介绍

Namespace是什么

Namespace是将内核的全局资源做封装,使得每个Namespace都有一份独立的资源,因此不同的进程在各自的Namespace内对同一资源的使用不会互相干扰

目前Linux内核总共实现了6种Namespace

  • IPC:隔离System V IPCPOSIX消息队列
  • 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就是该镜像的IDRepo:tag提供了易于人类识别的名字,而ID便于脚本处理、操作镜像

使用Docker镜像

Docker内嵌了一系列命令制作、管理、上传、下载镜像,可以调用REST APIDocker daemon发送相关命令,也可以使用client端提供CLI命令完成操作。

列出本机的镜像

docker images

Build:创建镜像

  • 直接下载 docker pull busybox
  • 导入镜像
    • docker save -o busybox.tar busybox 导出busyboxbusybox.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说明文档
  • 后端支持多种分布式云存储方案(s3、azure)和本地文件系统等,接口以插件方式存在,易于配置
  • 清单文件(Manifest)作为元数据完整的记录镜像信息
  • Webhook方式实现通知系统
  • 实现了本地的TLS,支持HTTPS安全访问
  • 有可配置的认证模块
  • 有健康检查模块
  • 管理镜像的清单文件和摘要文件格式清晰,更清楚地为镜像打标签
  • 拥有完善的镜像缓存机制,镜像下载更加快捷

Registry API

API描述:Registry API遵循REST设计标准,用于RegistryDocker Engine之间的通信,实现Registry镜像分发,是Docker Registry的重要组成部分

API传输的对象主要包括镜像layer的块数据(blob)和表单(Manifests

ManifestJSON格式的文件,记录镜像的元数据信息,并兼容V1版本镜像信息

{
  "name": <name>,
  "tag": <tag>,
  "fsLayers": [
    {
	  "blobSum": <tarsum>
	},
	...
  ],
  "history": [...],
  "signatures": [...]
}

鉴权机制

鉴权机制是Registry V2版本之后新增的功能,目的是校验用户请求权限。校验和控制访问权限的任务是由Docker EngineRegistryAuth 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 bridgevlan

CNM的概念角度讲,Libnetwork的出现使得Docker具备了跨主机多子网的能力,同一个子网内的不同容器可以运行在不同主机上

Libnetwork五种驱动(driver

  • bridge Docker默认的容器网络驱动
  • host 容器于主机共享同一Network Namespace,共享同一套网络协议栈、路由表及iptables规则等,容器和主机看到的是相同的网络视图
  • null 容器内网络配置为空,需要用户手动为容器配置网络接口及路由等
  • remote Docker网络插件的实现,Remote driver 使得Libnetwork可以通过HTTP RESTful API对接第三方的网络方案,
    类似SocketPlaneSDN方案只要实现了约定的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就会用发布者的公钥来校验该镜像是否和发布者所发布的镜像一致,是否被篡改,是否是最新版

日志审计

目前支持的类型nonejson-filesysloggelffluentd,默认为json-file

监控

在使用容器时,应该注意监控容器的信息,若发现异常,就能采取措施及时补救

文件系统级防护

Docker可以设置容器的根文件系统为只读模式,只读模式的好处是即使容器与host使用的是同一文件系统,也不用担心会影响甚至破坏host的根文件系统

capability

打破了Linux操作系统中超级用户/普通用户的概念,让普通用户也可以做只有超级用户才能完成的工作

SELinux

Security-Enhanced Linux 美国国家安全局对于强制访问控制的实现,在这种访问控制体系下,进程只能访问那些在它的任务中所需要的文件

AppArmor

其主要作用是设置某个可执行程序的访问控制权限

Seccomp

Seccompsecure computing mode)是一种Linux内核提供的安全特性,可以实现应用程序的沙盒机制,以白名单或黑名单的方式限制进程进行系统调用

grsecurity

可以用来控制资源访问权限

几个与Docker安全相关的项目

  • Notary 保证serverclient之间的交互使用可信任的连接
  • docker-bench-security 检测用户的生产环境是否符合Docker的安全实践

安全加固

主机逃逸

利用虚拟机软件或虚拟机中运行的软件漏洞进行攻击,以达到攻击或控制虚拟机宿主操作系统的目的

后记

本书链接 Docker进阶与实战

若文中有错误欢迎大家评论指出,或者加我微信好友一起交流gm4118679254,如果有需要此书pdf版可以私信我

posted @ 2021-12-06 17:08  蟹丸  阅读(101)  评论(0编辑  收藏  举报