一. 从系统架构谈起
传统分层架构 vs 微服务
微服务改造
分离微服务的方法建议:
- 审视并发现可以分离的业务逻辑业务逻辑,在对业务领域不是特别熟悉的时候,按照部门职能进行划分,例如账号、财务等
- 寻找天生隔离的代码模块,可以借助于静态代码分析工具
- 如果可以闭环的解决一个用户场景,那么它应该是一个微服务
- 还可以根据访问频率进行区分划分,将用户高频访问的部分划分为一个服务,不同并发规模,不同内存需求的模块都可以分离出不同的微服务,此方法可提高资源利用率,节省成本
- 还可以根据读写进行划分
一些常用的可微服务化的组件:
- 用户和账户管理
- 授权和会话管理
- 系统配置
- 通知和通讯服务
- 照片,多媒体,元数据等
分解原则:基于 size, scope and capabilities
微服务间通讯
点对点:
- 多用于系统内部多组件之间通讯;
- 有大量的重复模块如认证授权;
- 缺少统一规范,如监控,审计等功能;
- 后期维护成本高,服务和服务的依赖关系错综复杂难以管理。
API 网关
- 基于一个轻量级的 message gateway
- 新 API 通过注册至 Gateway 实现
- 整合实现 Common function
为什么我们的服务不直接对外进行暴露?
- 前端(移动端、客户端、web)同学非常痛苦,需要对接多个服务,兼容性差,沟通效率低
- 后端同学也很痛苦,一年前的版本都有人使用,服务无法进行重构升级
为什么需要最外层的 api gateway?
- 基础库的同学非常痛苦,限流熔断安全等业务无关的功能需要进行升级的时候升不动
在内网主要看安全级别一般有三种:
- Full Trust:假定内网服务之间是安全的,在内网裸奔
- Half Trust:内网服务之间需要进行认证鉴权,但是不需要所有的都进行加密
- Zero Trust: 零信任,任务内部网络是不安全的,类似公网,所有的请求通过身份认证鉴权之后,都需要通过安全加密,防止被嗅探
https://www.microsoft.com/en-us/security/business/zero-trust
二. 理解 Docker
Docker是什么?
- 基于 Linux 内核的 Cgroup,Namespace,以及 Union FS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术,由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
- 最初实现是基于 LXC,从 0.7 以后开始去除 LXC,转而使用自行开发的 Libcontainer,从 1.11 开始,则进一步演进为使用 runC 和 Containerd。
- Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护,使得 Docker 技术比虚拟机技术更为轻便、快捷。
为什么要用 Docker?
- 更高效地利用系统资源
- 更快速的启动时间
- 一致的运行环境
- 持续交付和部署
- 更轻松地迁移
- 更轻松地维护和扩展
- ……
虚拟机和容器运行态的对比
性能对比
安装 Docker
ubuntu
上安装Docker运行时
,参考https://docs.docker.com/engine/install/ubuntu/
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
容器操作
启动
- docker run
- -it 交互
- -d 后台运行
- -p 端口映射
- -v 磁盘挂载
启动已终止的容器
- docker start
停止容器
- docker stop
查看容器进程
- docker ps
查看容器细节
- docker inspect
进入容器
- Docker attach:
- 通过 nsenter:
- PID=$(docker inspect --format “{ { .State.Pid }}” )
- nsenter --target $PID --mount --uts --ipc --net --pid
- 通过 nsenter:
拷贝文件至容器内
- docker cp file1 :/file-to-path
初识容器
cat Dockerfile
FROM ubuntu
ENV MY_SERVICE_PORT=80
ADD bin/amd64/httpserver /httpserver
ENTRYPOINT /httpserver
- 将
Dockerfile
打包成镜像
docker build -t cncamp/httpserver:${tag} .
docker push cncamp/httpserver:v1.0
- 运行容器
docker run -d cncamp/httpserver:v1.0
容器标准
- Open Container Initiative(OCI): 轻量级开放式管理组织(项目)
- OCI 主要定义两个规范
- Runtime Specification
- 文件系统包如何解压至硬盘,供运行时运行。
- Image Specification
- 如何通过构建系统打包,生成镜像清单(Manifest)、文件系统序列化文件、镜像配置。
- Runtime Specification
容器主要特性
Namespace
Linux Namespace
是一种Linux Kernel
提供的资源隔离方案:
- 系统可以为进程分配不同的
Namespace
; - 并保证不同的
Namespace
资源独立分配、进程彼此隔离,即不同的Namespace
下的进程互不干扰。
Linux 内核代码中 Namespace 的实现
# 进程数据结构
struct task_struct {
...
/* namespaces */
struct nsproxy *nsproxy;
...
}
# Namespace 数据结构
struct nsproxy {
atomic_t count;
struct uts_namespace *uts_ns;
struct ipc_namespace *ipc_ns;
struct mnt_namespace *mnt_ns;
struct pid_namespace
*pid_ns_for_children;
struct net *net_ns;
}
Linux 对 Namespace 操作方法
- clone
在创建新进程的系统调用时,可以通过 flags 参数指定需要新建的 Namespace 类型:
// CLONE_NEWCGROUP / CLONE_NEWIPC / CLONE_NEWNET / CLONE_NEWNS / CLONE_NEWPID /
CLONE_NEWUSER / CLONE_NEWUTS
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg)
- setns
该系统调用可以让调用进程加入某个已经存在的 Namespace 中:
Int setns(int fd, int nstype)
- unshare
该系统调用可以将调用进程移动到新的 Namespace 下:
int unshare(int flags)
# 这会创建一个新的网络命名空间,然后在这个隔离的环境中运行 sleep 60 命令。
unshare -fn sleep 60
隔离性 – Linux Namespace