文章目录

  • 微服务及虚拟机技术
  • 微服务
  • 虚拟技术的弊端
  • 虚拟技术的优点
  • Docker原理浅析
  • Docker的优势
  • 容器特性
  • Linux Namespace
  • namespace常用操作
  • Cgroups
  • 把进程添加到cgroup进程配置组
  • cpu 子系统
  • cpuacct 子系统
  • memory子系统
  • 文件系统 Union FS
  • Docker常用命令
  • Dockerfile
  • 本地镜像管理
  • 镜像仓库
  • 容器操作


微服务及虚拟机技术

微服务

  最一开始开发的系统基本上都是单体应用,可能仅仅是一个 War 包就可以包含所有的业务逻辑及 UI 界面。但是随着业务的不断深入,这种紧耦合的开发模式必将加重系统的维护成本,并且一个问题的出现可能导致整个系统瘫痪,大大降低了系统的可用性。
  再后来,大家开始研究面向服务的架构 SOA ,将业务进行解绑,一个大的系统分成若干个不同的子模块,子模块之间通过 API 调用去相互交互。进而延申出一个新的模块[系统服务总线],再发展到后来我们熟知的微服务架构,微服务可以说是 SOA 的一种最佳实践。
  当我们要在一台物理机上部署微服务时,一般有三种方式:

  • 1、多进程:通过将不同的程序发布在不同的端口上,同时问弊端也很明显,比如 80 端口只能被一个程序使用
  • 2、虚拟技术:使用虚拟机,将程序发布在虚拟机上,每个虚拟机都相当于是一个独立的操作系统,拥有自己独立的 IP 那么每个虚拟机我们都可以使用 80 端口去发布程序。
  • 3、容器技术:每个应用是一个独立的进程,拥有独立的资源。

虚拟技术的弊端

1、占用更多的资源:
  因为虚拟机实质上是一个独立的操作系统,它除了需要能够支撑应用运行的环境、内存、以及各种依赖之外,他还要满足本身这个操作系统所需要的各种资源,而且我们所分配给虚拟机的资源往往是远大于它所需要的。比如我们预留给虚拟机的内存往往是大于它真正使用的内存。
2、排查问题更加困难:
  如果我们的应用出现了问题,我们不仅仅要考虑虚拟机中可能造成的原因,还要考虑物理机上可能出现的问题。
3、效率低下:
  虚拟机作为一个独立的操作系统,需要模拟物理机开机关机等各种行为,这些和我们的应用都是不相关的。同时因为虚拟机是建立在物理机的基础上的,所以我们所有需要请求到虚拟机上的数据包都需要先经过物理机,才能到达虚拟机,所以性能上会有一定的开销。

虚拟技术的优点

1、功能全面:
  应为他模拟的就是一个是完整的操作系统。
1、安全:
  与物理机操作系统相互隔离,虚拟机的崩溃不会影响物理机,所以可以用来做系统测试或检测木马等。

Docker原理浅析

Docker 基于 linux 内核的 CgroupsNamespaceUnion FS等技术实现,比虚拟机技术更加轻便。

Docker的优势

  • 资源利用率高
  • 启动更快速
  • 运行环境一致
  • 迁移更便利

容器特性

  • 隔离性
    提供网络端口以及应用运行所需要的环境(沙箱)等,这个环境与其他进程相互隔离。
  • 可配型
    对于容容器使用的内存、CPU等资源可以进行配置。
  • 安全性
  • 便携性
    因为容器的隔离性,容器内包含了支撑程序运行的所有条件,所以在程序转移的时候就很方便,我们只需要把整个容器转移到别的地方就可以,不存在环境不适用的问题。

Linux Namespace

Linux Namespace 是一种资源隔离方案:

  • 系统可以为进程分配不同的 Namespace
  • 保证不同的 Namespace 之间的资源独立分配,进程彼此分离,即不同 Namespace 之间的进程互不干扰
  • 在 Linux 系统中,每一个进程都是在 Namespace 的基础上运行的。

Namespace类型

隔离资源

IPC

System V IPC和 POSIX 消息队列

NetWork

网络设备、网络协议栈、网络端口等

PID

进程

Mount

挂载点、文件资源

UTS

主机名和域名

USR

用户和用户组

namespace常用操作

从当前进程fork一个子进程,并隔离指定namespace

unshare -f --pid --mount-proc /bin/bash 即子进程隔离了 pid namespace ,在父进程内看不到子进程内的进程信息
--mount-proc 自动挂载 proc文件系统,不需要手动执行 mount -t proc proc /proc 命令了

查看当前系统的 namespace

lsns -t [type] 指定 namespace 类型

查看指定进程的namespace

ls -la /proc/[pid]/ns/

进入到指定进程的namespace

nsenter -t [pid] -u, 即进入到指定容器进程主机名和域名的 namespace,可以查看容器内部的主机名和域名等信息

主要的几个参数

-t

要获取名字空间的目标进程

-m

进入 mount namespace

-u

进入 uts namespace

-i

进入 ipc namespace

加粗样式

-n

-p

进入 pid namespace

-U

进入 usr namespace

-S

设置已进入的namespace的uid

-G

设置已进入的namespace的gid

-r

设置root文件目录

-w

设置工作文件目录

-h

显示此帮助并退出

-V

输出版本信息并退出

Cgroups

Cgroups来实现资源管控,防止进程占用了整个操作性系统的资源。针对不同的资源例如CPU、内存、磁盘IO等,他都有相应的子系统(Subsystem)来实现。
比较重要的子系统诸如:

cpu : 为 cgroup 任务提供 CPU 访问
cpuacct : 产生cgroup 任务的 CPU 资源报告
cpuset : 如果是多核 CPU ,可以为 cgroup 任务指定核和内存
memory : 设置每个cgroup的内存限制以及内存资源报告
把进程添加到cgroup进程配置组
  • echo [pid] > cgroup.procs
    配置需要在当前cgroup下管控的进程id
cpu 子系统
  • cpu.shares
    当前 cgroup 中占用 cpu 资源的比重,默认是1024,如果有四个 cgroup ,那么他们的默认比重就是 1:1:1:1,但我们调整最后一个 cgroup 的cpu.shares值为 4096 ,那么他们的资源比重就会变为 1:1:1:4,最后一个cgroup 将会占到更多的cpu资源
  • cpu.cfs_period_us
    cpu 的时间片
  • cpu.cfs_quota_us
    配合 cpu.cfs_period_us 来控制一个 cgroup 能够使用的 cpu 的绝对值。指在 cpu.cfs_period_us 大小的时间片下面,可以使用多少 cpu。
    cpu.cfs_quota_us默认为 -1,没有资源限制,会消耗整个操作系统的 cpu 资源。
    假如 cpu.cfs_period_us 配置为 100000 ,cpu.cfs_quota_us 也配置为 100000,表示在100000个cpu分片中可以拿到100000个分片,即可以使用一个 cpu 的资源,如果cpu.cfs_quota_us 也配置为 10000,表示我们只能 1/10 个 cpu 的资源
cpuacct 子系统
  • cpuacct .usage
    包含cgroup 及其子cgroup下进程使用cpu的时间,单位是 ns
  • cpuacct .stat
    包含cgroup 及其子cgroup下进程使用cpu的时间,以及用户态和内核态的时间
memory子系统
  • memory.usage_in_bytes
    cgroup 及其子cgroup下进程使用的内存
  • memory.max_usage_in_bytes
    包含cgroup 及其子cgroup下进程使用内存的历史最大值
  • memory.limit_in_bytes
    包含cgroup 及其子cgroup下进程最多能使用的内存,设置为-1表示不做限制
  • memory.oom_control
    设置是否在cgroup中使用oom killer ,默认是使用的,即当cgroup中的进程出现内存溢出时,会立即被 oom killer 处理

文件系统 Union FS

用来控制容器能看到哪些文件。
Dokcerfile 作为一个docker源文件,当我们使用 docker build 打包的时候,会生成一个分层的容器镜像(即dockerfile中的每一行指令都是一个文件层),docker run 启动的是时候,就会回放这个镜像,通过Union FS按照层级加载,如果上层还有文件层,那么当前文件层设定为readonly并放入底层文件层。
LowerDir
  底层文件层:
UpperDir
  最上层文件层:
MergedDir
  合并文件层:
  能看到底层和上层的所有文件,但是对于上层和底层同名的文件,上层的文件会把下层的文件覆盖掉。
  写时复制,一个镜像会被多个容器使用,在需要修改底层文件的时候,因为底层文件是只读的,所以其实是复制了底层的文件,修改之后并保存在上层文件层中。
  用时分配,当文件被创建出来之后,才会分配空间。
WorkDir
  合并文件层时候的中转文件层

Docker常用命令

Dockerfile

Dockerfile 是我们构建 Docker 容器的源文件,使用语法参考官网

https://docs.docker.com/engine/reference/builder

其中要注意的一点是,因为上面已经提到过dockerfile在打包的时候,每一行命令就会生成一个文件层,所以对于 RUN 命令我们要尽量放在一行命令中,用换行符号 \ 分隔开,避免镜像臃肿。

本地镜像管理

查看本地所有镜像

docker images [OPTIONS] [REPOSITORY[:TAG]]
	-a :列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层);
	--digests :显示镜像的摘要信息;
	-f :显示满足条件的镜像;
	--format :指定返回值的模板文件;
	--no-trunc :显示完整的镜像信息;
	-q :只显示镜像ID。

打包

docker build [OPTIONS] Dockerfile_Path 打包时若不设置 Dockerfile_Path 默认是当前目录下的 Dockerfile
	-f :可以指定要使用的Dockerfile路径;
	-m :设置内存最大值;
	--cpu-shares :设置 cpu 使用权重;
	--cpu-period :限制 CPU CFS周期;
	--cpu-quota :限制 CPU CFS配额;
	--cpuset-cpus :指定使用的CPU id;
	--cpuset-mems :指定使用的内存 id;
	......

标记本地镜像,将其归入某一仓库

docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]image_name[:TAG]

删除

docker rmi [OPTIONS] IMAGE [IMAGE...]
	-f :强制删除;
	--no-prune :不移除该镜像的过程镜像;

镜像仓库

搜索镜像

docker search image_name

拉取

docker pull image_name
docker pull image_name[:tag]

推送

docker push image_name[:tag]

容器操作

创建容器但不启动

docker create [OPTIONS] IMAGE

创建容器并启动

docker run [OPTIONS] IMAGE
	-it 交互
	-d 后台运行
	-p 端口映射
	-v 磁盘挂载

启动已经终止的容器

docker start [OPTIONS] CONTAINER

停止容器

docker stop [OPTIONS] CONTAINER

杀掉正在运行中的容器

docker kill [OPTIONS] CONTAINER

重启容器

docker restart [OPTIONS] CONTAINER

删除容器

docker rm [OPTIONS] CONTAINER

暂停、恢复容器内的进程

docker pause CONTAINER
docker unpause CONTAINER

查看所有在运行的容器

docker ps

查看容器细节

docker inspect [containerid]

进入容器

docker attach [containerid]
docker exec [containerid]

Copy文件到容器内

docker cp [file] [containerid]:/file-to-path

退出容器

exit | Ctrl+D 退出后,容器也会关闭
Ctrl+P+Q 退出后,容器不会关闭