容器(docker&k8s)技术简述

容器技术简述

1、容器是什么

容器技术:有效的将单个操作系统的资源划分到孤立的组中,以便更好的在孤立的组之间平衡有冲突的资源使用需求,这种技术就是容器技术。

2、容器的历史和发展

  • 2008年,容器的概念就已经基本定型了,并不是后面Docker造出来的。讲到容器,就不得不讲到它的前生LXC(Linux Container)。LXC是Linux内核提供的容器技术,能提供轻量级的虚拟化能力,能隔离进程和资源。

  • 2009年,Cloud Foundry(业界第一个开源PaaS云平台)基于LXC(Linux Container)实现了对容器的操作,该项目取名为Warden。

  • 2010年,dotCloud公司同样基于LXC技术,使用Go语言实现了一款容器引擎,也就是现在的Docker。那时,dotCloud公司还是个小公司,出生卑微的Docker没什么热度,活得相当艰难。

  • 2013年,dotCloud公司决定将Docker开源。开源后,项目异常火爆,直接驱动dotCloud公司更名为Docker公司。Docker也快速成长,干掉了CoreOS公司的rkt容器和Google的lmctfy容器,直接变成了容器的事实标准。以致于后来人一提到容器就认为是Docker。

3、为什么使用容器

3.1 虚拟化技术演历路径
  1. 物理机(多个应用程序可能跑在一台物理机器上)
    物理机
  2. 虚拟机(一台物理机器启动多个虚拟机实例,一个虚拟机跑多个应用程序)
    虚拟机
  3. 容器(一台物理机上启动多个容器实例,一个容器跑多个应用程序)
    容器
3.2 容器 VS 虚拟机
  • 虚拟机:虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程。
    虚拟机底层

容器:容器的应用进程则直接运行于宿主机的内核,容器内没有自己的内核,也没有进行硬件虚拟。
在这里插入图片描述

容器与虚拟机对比

特性容器虚拟机
启动速度秒级分钟级
体量极小(MB)较大(GB)
性能近似物理机性能损耗大
系统支持量单机支持上千个容器一般支持几十个
交付/部署开发、测试、生成环境一致易受操作系统、环境变量等限制
迁移/扩展易迁移、易扩展易受操作系统、资源等限制

4、容器解决了什么

  1. 运行环境一致性:容器打包了程序必需的所有依赖以及操作系统,可创建与其他应用相隔离的环境,彻底解决了环境的一致性问题。

  2. 各环境灵活迁移:Docker镜像可在所有主流 Linux 发行版、Microsoft 平台灵活迁移,极大减轻了开发和部署工作量。

  3. 资源消耗和冲突:MB级别的空间占用、秒级的启动速度可大大减少资源的消耗;同时容器会将应用相互隔离,我们可以为每个应用设置明确的资源限制,不必担心依赖项冲突或资源争用。

  4. 提高生产力:容器不是直接在主机操作系统运行,可减少调试和诊断环境差异所需的时间,提高了开发生产效率。

  5. 版本控制:每个容器的镜像都有版本控制,可以对历史版本进行追踪和差异比较。

  6. 安全隔离:容器会在操作系统级别虚拟化 CPU、内存、存储和网络资源,为开发者提供在逻辑上与其他应用相隔离的沙盒化操作系统接口。

5、容器原理

容器技术两大知识点Cgroups(Linux Control Group)和Linux Namespace。掌握它们,容器技术就基本了解了。

5.1 Namespace
  • Namespace重点在“隔离”,是Linux内核用来隔离资源的方式。

  • 每个Namespace下的资源对于其他Namespace都是不透明,不可见的。

  • 简单来说,容器和容器之间不要相互影响,容器和宿主机之间不要相互影响。
    NameSpace

Linux 的Namespace机制提供了七种不同的命名空间:

namespace系统调用参数隔离内容
UTSCLONE_NEWUTS主机名和域名
IPCCLONE_NEWIPC信号量、消息队列和共享内存
PIDCLONE_NEWPID进程编号
NetworkCLONE_NEWNET网络设备、网络栈、端口等
MountCLONE_NEWNS挂载点(文件系统)
UserCLONE_NEWUSER用户和用户组
CgroupCLONE_NEWCGROUP控制进程对系统资源的支配调度
5.2 Cgroups

CGroups(Control Groups) 重点在“限制”。限制资源的使用,包括CPU、内存、磁盘的使用,体现出对资源的管理能力。

  1. 控制组(CGroup) 一个 CGroup 包含一组进程,并可以在这个 CGroup 上增加 Linux Subsystem 的各种参数配置,将一组进程和一组 Subsystem 关联起来。

  2. Subsystem 子系统 是一组资源控制模块,比如 CPU 子系统可以控制 CPU 时间分配,内存子系统可以限制 CGroup 内存使用量。可以通过lssubsys -a命令查看当前内核支持哪些 Subsystem。

  3. Hierarchy 层级树 主要功能是把 CGroup 串成一个树型结构,使 CGruop 可以做到继承,每个 Hierarchy 通过绑定对应的 Subsystem 进行资源调度。

  4. Task 在 CGroups 中,task 就是系统的一个进程。一个任务可以加入某个 CGroup,也可以从某个 CGroup 迁移到另外一个 CGroup。

6、认识Dokcer

6.1 Docker的构成

Docker 由镜像、镜像仓库、容器三个部分组成:

  • 镜像: 封装了应用所需依赖和操作系统的跨平台可移植程序包

  • 镜像仓库: 镜像的存储位置(云端仓库或本地仓库)

  • 容器: 资源隔离的镜像运行时环境

6.2 Dockerfile、Docker镜像、Docker容器的关系
  • Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
  • Docker镜像是由一系列只读的层组成的,Dockerfile中每一个命令都会在已有的只读层上再创建一个新的只读层。
FROM lhl-docker-java8:1.0
COPY app.jar /app/app.jar
WORKDIR /app
CMD ["java","-jar","/app/app.jar"]
  • 容器中的每一层命令只对当前容器进行非常小的修改,上面的Dockerfile会构建一个拥有4层layer的镜像:
    docker构建
  • 当镜像被创建时会在镜像的最上层添加一层可读写层,也就是容器层,所有对于运行时容器的修改其实是对于镜像读写层的修改。因此,镜像和容器的区别就在于:所有的镜像都是只读的,而容器等于镜像加上一层读写层,也就是说同一个镜像可以对应多个容器。
  • 一句话概括三者关系:Docker镜像由Dockerfile构建,Docker容器是Docker镜像的运行时状态。
6.3 Docker的进程隔离
  • 当我们在宿主机运行 Docker,通过docker run或docker start创建新容器进程时,会传入 CLONE_NEWPID 实现进程上的隔离;接着在方法createSpec的setNamespaces中完成除进程命名空间之外与用户、网络、IPC(信号量、消息队列和共享内存) 以及 UTS(主机名和域名) 相关的命名空间的设置。
    Docker实现原理
6.4 Docker的网络通信
  • 当 Docker 容器完成命名空间的设置,其网络也变成了独立的命名空间,与宿主机的网络通信便产生了限制,这就导致外部很难访问到容器内的应用程序服务。因此,Docker 提供了 4 种网络模式,通过–net参数指定。
  1. host, 与宿主机共用一个Network Namespace,容器不会虚拟出自己的网卡、配置自己的IP等,而是使用宿主机的IP和端口。

  2. container,指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。

  3. none,容器拥有自己的Network Namespace,但是并不为Docker容器进行任何网络配置。即容器没有网卡、IP、路由等信息,需要手动添加配置。

  4. bridge,Docker默认的网络设置,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上。

由于Docker常用bridge模式,一下着重介绍该模式:

  • 虚拟网桥:当Docker Server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器都会连接到这个虚拟网桥上。

  • 分配容器IP:Docker会选择一个与宿主机不同的IP地址和子网分配给docker0,连接docker0的容器都会从该子网中选择一个未占用的IP使用。

  • 容器间通信:连在同一网桥上的容器可以相互通信,也可以出于安全考虑禁止通信。

  • 容器与外界通信:IP包首先从容器发往默认网关docker0(IP包到达docker0也就是到达了主机),然后查询主机路由表,发现包应该有eth0发往主机网关,接着IP包会转给eth0由eth0发出。对于外界看来,IP包是由主机eth0发出的,Docker容器对外是不可见的。bridge模式

6.5 Docker的文件系统隔离

上述解决了进程和网络等隔离的问题,但是 Docker 容器中的进程仍然能够访问或者修改宿主机器上的其他目录,这是我们不希望看到的。

  • 在新的进程中创建隔离的挂载点命名空间需要在 clone 函数中传入 CLONE_NEWNS,这样子进程就能得到父进程挂载点的拷贝,如果不传入这个参数子进程对文件系统的读写都会同步回父进程以及整个主机的文件系统。
  • 当一个容器需要启动时,它一定需要提供一个根文件系统(rootfs),容器需要使用这个文件系统来创建一个新的进程,所有二进制的执行都必须在这个根文件系统中,并建立一些符号链接来保证 IO 不会出现问题。
  • 通过 Linux 的chroot命令能够改变当前的系统根目录结构,通过改变当前系统的根目录,我们能够限制用户的权利,在新的根目录下并不能够访问旧系统根目录的结构个文件,也就建立了一个与原系统完全隔离的目录结构。
    docker文件隔离
6.6 Docker的Cgroup
  • Docker 安装目录下有一个 docker 目录,当启动一个容器时,就会创建一个与容器标识符相同的 CGroup,大概的层级关系:
    Docker Cgroup

  • 每一个 CGroup 下面都有一个 tasks 文件,其中存储着属于当前控制组的所有进程的 pid,作为负责 cpu 的子系统,cpu.cfs_quota_us 文件中的内容能够对 CPU 的使用作出限制。

  • 当我们 Docker 关闭掉正在运行的容器时,Docker 的子控制组对应的文件夹也会被 Docker 进程移除。

6.7 Docker命令大全

7、K8s应运而生

7.1 K8s是什么

kubernetes,简称K8s,是用8代替8个字符“ubernete”而成的缩写。
Kubernetes是Google开源的一个容器编排引擎,它具有完备的集群管理能力,支持自动化部署、服务滚动升级和在线扩容、可扩展的资源自动调度机制、多实例负载均衡等。

7.2 为什么使用K8s

虽然Docker已经为容器提供了开放标准,但随着容器不断增加也出现了一系列问题:

  • 单机支持容器到达上限,怎么办?
  • 分布式环境下容器之间如何通信?
  • 如何协调和管理数量庞大的容器?
  • 容器的运行状况如何监控?
  • 应用升级版本如何做到不中断?
  • 如何做到批量启动容器?
7.3 K8s学习之路

Kubernetes 项目庞大复杂,文章不能面面俱到,因此这个部分将向读者提供一种主线学习思路:

  • Kubernetes 的设计理念

  • Kubernetes 的核心技术概念和API对象

  • Kubernetes 提供的组件及适用场景

  • Kubernetes 的架构

  • Kubernetes 架构模块实现原理

  • 更多学习资料请查看 Kubernetes中文社区 | 中文文档

8、参考资料

https://cloud.google.com/containers/?hl=zh-cn
https://www.zhihu.com/question/267624901/answer/2013602482
https://blog.csdn.net/qq_42046105/article/details/119193314
https://blog.csdn.net/laotianv5/article/details/81475051
https://blog.csdn.net/volcano1995/article/details/90668085
https://blog.csdn.net/RaymondCoder/article/details/105762743
https://blog.csdn.net/yibuchen/article/details/80456781

  • 33
    点赞
  • 338
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值