文章目录
- 微服务及虚拟机技术
- 微服务
- 虚拟技术的弊端
- 虚拟技术的优点
- 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 内核的 Cgroups、Namespace、Union 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 容器的源文件,使用语法参考官网
其中要注意的一点是,因为上面已经提到过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 退出后,容器不会关闭