一、Docker概述
1. Docker是什么
- Docker是以Docker容器为资源分割和调度的基本单位,封装整个软件运行时环境,为开发者和系统管理员设计的,用于构建、发布和运行分布式应用的平台
- Docker是一个跨平台、可移植且简单易用的容器解决方案
- Docker可在容器内部快速自动化部署应用,并通过操作系统内核技术为容器提供资源隔离与安全保障
2. Docker的优点
- 持续部署与测试:使用镜像实现标准开发环境的构建,开发完成后通过封装着完整环境和应用的镜像进行迁移,测试人员可直接部署软件镜像来进行测试和发布。简化持续集成、测试和发布的过程
- 跨云平台支持
- 环境标准化和版本控制:可以对整个应用运行环境实现版本控制,一旦出现故障可以快速回滚
- 高资源利用率与隔离:容器没有管理程序的额外开销,与底层共享操作系统。容器有不错的资源与限制能力,可以精确地对应用分配CPU、内存等资源,保证了应用间不会相互影响
- 容器跨平台性与镜像
- 易于理解且易用
- 应用镜像仓库丰富
3. 容器云
容器云以容器为资源分割和调度的基本单位,封装整个软件运行时环境,为开发者和管理者提供用于构建、发布和运行分布式应用的平台
二、Docker基础
1. Docker命令
- docker info:docker配置信息
- docker run:docker run [OPTIONS] IMAGE [COMMAND][ARG…]
基于特定的镜像创建一个容器,如docker run ubuntu echo "Hello World"
-it :使用交互模式,分配一个伪终端,可在容器中利用打开的伪终端进行交互操作 - docker start/stop/restart:启动、停止、重启容器
- docker pull:从docker仓库拉取image
- docker images:列出主机上的镜像
- docker rmi/rm:删除容器/镜像(如果基于该镜像启动的容器存在,则无法直接删除,需要先删除容器)
- docker attach:连接到正在运行的容器,观察该容器的运行情况
- docker ps:查看容器相关信息,一般用来查看容器id
三、Docker核心原理
1. namespace资源隔离
namespace的6项隔离:
- UTS:主机名与域名隔离 。 系统调用参数:CLONE_NEWUTS
- IPC:信号量、消息队列和共享内存隔离 。系统调用参数:CLONE_NEWIPC
- PID:进程编号隔离。 系统调用参数:CLONE_NEWPID
- Network:网络设备、网络栈、端口隔离 。系统调用参数:CLONE_NEWNET
- Mount:挂载点(文件系统)隔离 。系统调用参数:CLONE_NEWNS
- User:用户和用户组。系统调用参数:CLONE_NEWUSER
clone()函数
使用clone()可创建一个独立的namespace进程,是Linux调用fork()的一种更通用的实现方式,调用方式:
int clone(int (*child_func)(void*), void *child_stack, int flags, void *arg)
- child_func:传入子进程运行的程序主函数
- child_stack:传入子进程使用的栈空间
- flags:表示使用哪些CLONE_*标志位,用来控制使用了哪些功能
- args:传入用户参数
setns()函数
通过setns()系统调用,进程从原先的namespace加入某个已存在的namespace。通常不为了影响进程的调用者,为了使新加入的pid namespace生效,会在setns()函数执行后使用clone()创建子进程继续执行命令,让原先的进程结束运行,调用方式:
int setns(int fd, int nstype)
- fd:要加入的文件描述符
- nstype:检查fd指向的namespace文件是否符合要求
PID namespace
PID namespace对进程PID进行重新标号,即两个不同namespace下的进程可以有相同的PID,每个PID namespace都有自己的计数程序。
内核为所有的PID namespace维护了一个树状结构,最顶层的是系统初始时创建的,被称为root namespace。它创建的新PID namespace 被称为 child namespace,而原先的PID namespace就是新创建的PID namespace的parent namespace。所属的父节点可以看到子节点中的进程,并可以通过信号等方式对子节点中的进程产生影响,但子节点不能看到父节点 PID namespace中的任何内容
- init进程
传统UNIX系统中,PID为1的进程是init,它作为所有进程的父进程,维护一张进程表,不断检查进程的状态,一旦某个子进程因为父进程错误成了“孤儿进程”,init就会回收该子进程的资源并结束进程。当系统中存在树状嵌套结构的PID namespace时,回收孤儿进程的任务就交给了该子进程所属的PID namespace中的 init 进程。
network namespace
network namespace主要提供关于网络资源的隔离,包括网络设备、IPv4和IPv6协议栈、IP路由表、防火墙、/proc/net目录、套接字(socket)等。
一个物理的网络设备最多存在于一个network namespace中,可以通过创建veth pair(虚拟网络设备对)在不同的network namespace间创建通道,以达到通信目的。veth pair一端放置在新的namespace中,通常命名为eth0,一端放在原先的namespace中连接物理网络设备,再通过把多个设备接入网桥或者进行路由转发,来实现通信的目的。
在Docker deamon完成veth pari的创建之前,init在管道的另一端循环等待,直到管道另一端传来Docker daemon关于veth设备的信息,并关闭管道。 init 才结束等待的过程,并把它的 "eth0"启动起来