所学的所有技术都为业务服务
Docker技术架构
Docker的进程模型
运行docker之后执行。虽然运行了5个docker容器,但却有10个进程
查看进程树,docker创建了很多进程
查看详细,共为这10个进程
查看bin目录下的docker相关shell
其中
- docker根进程
/usr/bin/dockerd-current 是docker的启动进程,是核心 - docker服务端server进程 docker-containerd-current
docker服务端的核心进程。负责与Docker客户端client、容器container进行通信
执行docker run命令,fork容器进程
其中 -l unix:///var/run/docker/libcontainerd/docker-containerd.sock 表示打开一个sock,实现所有的Docker容器和客户端通信 - docker运行具体镜像的容器进程 docker-containerd-shim-current
容器进程启动2种模式
- Docker容器内进程是宿主机独立进程
- 构建shell启动方式镜像
1.创建redisshell文件
FROM centos:latest
RUN yum -y install redis
EXPOSE 6379
CMD "/usr/bin/redis-server"
2.打包构建redisshell:1.0镜像
docker build -t redisshell:1.0 -f dockershell .
3.通过镜像创建容器并进入
其1号进程为/bredis进程,没有其他进程存在
- 构建利用exec启动方式镜像
1.创建redisexec文件
FROM centos:latest
RUN yum -y install redis
EXPOSE 6379
CMD ["/usr/bin/redis-server"]
2.打包构建redisexec:1.0镜像
docker build -t redisexec:1.0 -f dockerexec .
3.通过镜像创建容器并进入
因为docker stop只对docker容器内的1号进程发送退出信号。所以,为了优雅停机,官方建议采用exec模式启动线程并且每个docker只部署一个服务在1号线程
容器线程隔离
每个容器之间的线程都是隔离的如上图
容器的重启
docker run命令可以加入重启策略参数,具体可使用man docker run命令查阅。
重启策略有4种,为保证系统负载不过大,每次重启间隔时间从100ms开始以2的指数倍增大
- no 不自动重启,默认
- on-failure 1号进程退出非0时重启,可指定最大重启次数
- always:永远重启,当docker Daemon启动时就启动容器
- unless-stop 永远重启,当docker Daemon启动时,如果容器之前不为stop状态就启动容器
容器中的用户权限的隔离和传送
Docker安装的时候会自动创建Docker用户组,在启动Docker的时候需要较大的权限。
Docker用户组内执行命令的时候默认会添加sudo
Docker守护线程允许root和DOcker用户组访问docker。在使用相关容器的时候应谨慎,避免下载恶意镜像
Docker守护进程宕机的处理机制
由于Docker容器是Docker守护线程的子进程,所以守护线程挂掉的时候,所有Docker容器也会挂掉。
Docker 1.12版本增加live-restore宣传,去掉守护线程依赖。即使dockerd进程关闭,容器也可以运行。等待dockerd进程恢复后,重新管理容器。
可以在
/etc/docker/daemon.json中添加"live-restore":true 配置
/usr/lib/systemd/system/docker.service 添加 KillMode=process 配置
容器container的本质
container=CGroups+Namespace+Rootfs
Namespace
命名空间,很多中间件都有这种思想。其是内核级别的环境隔离的方法
在Linux下PID为1时超级父进程,对每个子进程而言,如果超级父进程PID为1即可以达到资源隔离。每个容器都有自己的1号进程
其实现基于
- clone
创建新的进程,实现进程的系统调用 - unshare
把进程脱离某个Namespace - setns
把进程加入某个Namespace
Rootfs
Rootfs即Docker容器启动时内部进程文件系统,即Docker的根目录
在/var/run/docker/libcontainerd 目录下的文件目录为每一个docker容器的根目录
CGroup
Control Group 把进程放到Group中统一管理控制,根据特定的行为把一系列任务及其子任务整合或分离到不同组类。实现不同用户层面的资源管理
- 资源限制
可对总资源进行限制,例如内存上线,超过则OOM - 优先级分配
对不同进程分配CPU时间片及I/O带宽 - 资源统计
统计系统资源使用量,CPU时长、内存用量 - 进程控制
对进程进行挂起、恢复
Docker是通过CGroup对容器资源限制和监控
例如docker run -m 512m 镜像:tag
即对镜像进行512m内存大小限制。如果此时在容器内设置JVM内存参数,则可能会和容器的内存参数有冲突
Docker启动总结
docker启动时利用fork命令从Docker-containerd进程中创建fork一个子进程,然后exec执行。
容器进程被fork之后创建Namespaec,再执行初始化
- dockerinit初始化网络栈
- ENTRYPOINT完成用户动态配置
- CMD负责启动入口
- Docker容器和Docker守护线程Daemon通过sock文件描述符进行痛惜
Docker体系架构
#官方说明
官方文档
https://docs.docker.com/get-started/overview/
Docker 使用客户端-服务器体系结构。
- Docker客户端与 Docker守护程序通信,守护程序负责构建、运行和分发 Docker 容器。Docker 客户端和守护程序可以在同一系统上运行,也可以将 Docker 客户端连接到远程 Docker 守护程序。
- Docker 客户端和守护程序使用 REST API、UNIX 套接字或网络接口进行通信。
- 另一个 Docker 客户端是 Docker Compose,它允许您使用由一组容器组成的应用程序。
Docker网络架构
Docker的网络模式较复杂的、默认有4种模式,可以通过docker run --network=="bridge" 来设置,默认为bridge桥接模式
Linux网桥时用一组代码模拟网络协议栈,类似交换机
Bridge模式
Docker默认的网络模式使用eth0虚拟网桥通信,在iptables上遵循了DNAT规则,实现端口转发功能
-
安装Docker之后会创建虚拟网桥
ip addr
网段为172.17.0.1/16
route
172.17.0.0网段的报文全部给docker0虚拟网桥
-
验证
1.启动一个centos镜像
2.查看容器内部ip
3.宿主机ping容器IP,可以ping通
Host模式
容器不会获得独立的Namespace,和宿主机共用Network Namespace。同时也不会虚拟出自己的网卡、IP。也是和宿主机共用
--privileged=true命令,容器会被允许直接配置主机的网络堆栈
如下图所示,所有的网络配置IP等和主机相同。
此时操作容器中的某些配置可能会影响到宿主机本身
Container模式
将Docker新建的容器进程放入一个已存在的网络栈中,虽然进程隔离,但是会和已经存在的容器共享IP、端口等网络信息
- 例如
再重新从镜像中启动一个容器和已有容器共享IP为172.17.0.2
如图所示ip及端口完全相同
None模式
新建隔离网络栈,不进行任何网络配置,可以自己手动配置
Docker集群网络模式
分布式环境下的集群网络通信系统,保证网络易管理、高容错
Bridge端口转发
集群环境下,Docker容器依然可以通过Bridge模式进行通信。
- 容器和宿主机之间通信
通过docker0网桥进行通信 - 宿主机和宿主机之间通信
通过物理网卡和网络进行通信
实现较简单,但是由于本机会维护路由表,性能不如直连。容器和宿主机暴露的IP、端口绑定(端口如果有冲突叫麻烦)。维护麻烦
交换机打通Docker网络和物理网络
- 实现
将物理网卡eth0插拔关联每个Docker容器上,为eth0
分配和物理网络同源IP地址。容器的IP地址就是物理网络同网段的IP地址。可直接给物理交换机转发 - 优势
性能优于NAT(Network Address Translation指网络地址转换) - 劣势
需要提前规划,IP地址可能会冲突,需要做好分配和回收。
新建虚拟网桥
新建一个虚拟网桥,将物理网卡插入该网桥中,将容器也插入虚拟网桥作为出口
Docker安全架构
Docker安全问题
- Docker和宿主机共内核
某个容器滥用宿主机资源导致宿主机崩溃会导致所有宿主机崩溃 - Docker自身漏洞
问题:Docker自身漏洞主要在代码执行、权限提升、信息泄露、绕过隔离
解决:将Docker升级最新版本 - Docker源问题
Docker Hub可以上传、下载镜像。也会有安全问题:
1.下载镜像被植入恶意代码(上传恶意镜像)、使用有漏洞软件(下载镜像后需要检查软件版本信息)
2.传输过程镜像被篡改(中间人攻击篡改镜像,MD5校验)
3.镜像搭建环境本身漏洞 - DDoS攻击资源耗尽
CGroups可以防止此类攻击,不为单一的容器分配过多的资源 - 共享root
如果以root权限运行容器,则容器内的root用户也拥有宿主机的root权限 - 未隔离文件系统
Docker有一些文件系统暂时未被隔离如/sys、/proc/sys、/proc/bus
Docker安全措施
- 内核级别
1.更新内核
2.将宿主机和Docker界限划分清晰(Namespace、CGroups) - 网络级别
1.禁止在容器上映射特权端口,容器只开放所需要的端口 - 镜像级别
1.创建本地镜像仓库服务
2.使用镜像扫描及签名 - 容器级别
1.容器以单一主线程方式进行
2.禁止容器运行ssh服务
3.限制容器中可用的进程数量,防止fork炸弹 - 其他设置
1.定期对容器进行安全审计
2.避免在同一宿主机上部署大量容器,维持一个能够管理的数量 - 容器最小化
- Docker Remote API
1.Docker远程调用API接口存在未授权访问漏洞 - 限制流量流向
1.使用iptables过滤器限制Docker容器的源IP地址泛微和流量流向 - 使用普通用户启动Docker服务
- 文件系统限制
挂载的容器根目录是绝对只读的,而且不同容器对应的文件目录权限分离,最好每个容器在宿主机上都有自己单独的分区 - 保证镜像安全
在镜像仓库客户端使用证书认证,对下载的镜像进行检查,并且不使用--insecure-registry= 参数 - 保证Docker Client与Daemon通信安全
防止链路劫持、会话劫持,通信的两端应该通过加密方式进行通信 - 资源限制
- 宿主机升级内核
- 避免Docker信息泄露
使用Dockerfile或者docker-compose文件创建容器时会有宿主机上的敏感信息在文件上 - 安全安全加固
- 限制系统命令调用
- SUID和GUID限制
- 能力限制
- 多租户环境
由于Docker容器内核共享,无法在多租户环境中安全实现责任分离。应将容器运行在没有其他目的且不用于敏感操作的宿主机上 - 完全虚拟化
使用完全虚拟化的解决方案来容纳Docker。防止漏洞从容器中扩大到宿主机上 - 日志分析
收集、归档Docker相关的安全日志。rsyslog或stdout+ELK进行日志收集、存储、分析
1.使用docker run -v 宿主机日志目录:容器日志目录 container /bin/bash
2.使用docker export导出为一个压缩包格式 - 漏洞扫描
Docker漏洞扫描的工具有Docker-slim、Docker Bench for Security - 端口扫描
Nmap和Masscan工具扫描端口
Comments | 0 条评论