两类角色:master节点和worker节点。master用于调度和管理集群资源,worker节点是资源的提供者。worker节点提供的资源单位叫pod,可以理解为k8s云平台提供的虚拟机,pod中存放的是应用容器,比如docker容器。容器是cpu和内存的资源隔离单位,大部分情况下一个pod中只住一个应用容器,也有一个主容器多个辅助容器的情况,一个pod内的容器共享网络栈和存储资源。
k8s主要解决集群资源调度问题,当有应用发布请求,k8s根据集群资源空闲状况,将应用的pod分配到空闲的worker节点上,同时k8s时刻监控集群,有节点挂了需要重新协调及启动pod保证应用高可用。(自愈)
etcd:集中的状态存储,所有的集群状态数据包括节点、pods、发布配置等。是一个分布式的KV数据库,采用raft分布式一致性算法。
API server:其他组件操作etcd的代理,只有API server可以操作etc;事件总线,通知给订阅的外围组件。
Scheduler:调度决策的组件。
Controller manager:确保实际状态与预期状态最终一致的组件。
Kubelet:worker组件的资源管理者,监听Api Server事件,根据master节点的指示做相关的动作,将本节点的状态数据汇报给master节点。
Container Runtime:Kubelet不直接管理节点上的容器资源,委托给Container Runtime管理,如启动关闭容器,收集容器状态等。在启动容器时,如果本地没有镜像缓存就会拉取Docker Hub上的相应镜像缓存到本地。
Kube-proxy:管理k8s服务网络的组件。pod的ip是不固定的,Service屏蔽了po d的ip,并在调用时进行负载均衡。当需要将k8s中的服务暴露给外网时,也需要Kube-proxy进行代理转发。
假设使用kubectl创建ReplicaSet请求,API server将请求存储在etcd中,在监听中的Controller manager收到通知,比较当前状态与预期状态不一致则会创建pod,根据kubectl提供的pod模版创建预期的pod资源;监听中的Scheduler收到通知,会运行调度算法选择空闲的worker节点,通过Api server更新pod的定义,将pod指派到具体要发布到哪些worker节点上;Api server通知相应节点上的kubelet,指示Container Runtime去运行对应容器;Container Runtime去下载镜像启动容器,kubelet监控容器运行,到此则是一个完整的应用发布流程样例。
创建yaml文件:
apiVersion: v1
kind: Pod
metadata:
name: petclinic
spec:
containers: # 容器镜像名称
- name: petclinic
image: spring2go/spring-petclinic:1.0.0.RELEASE
根据yaml创建pod:kubectl apply -f petclinic-pod.yml
查看所有pod:kubectl get all
查看具体pod:kubectl get pod petclinic;kubectl describe pod petclinic
将服务端口指到pod端口(仅在本地或测试用):kubectl port-forward petclinic 8080:8080
删除pod:kubectl delete pod petclinic
添加反向代理service。petclinic-svc.yml:
apiVersion: v1
kind: Service
metadata:
name: petclinic
spec:
ports:
- name: http
port: 8080 # servic本身暴露的端口,集群内部的端口
targetPort: 8080 # 对接的pod的端口
nodePort: 31080 # 在本机的31080端口暴露service
selector:
app: petclinic # 找到对应标签的pod
type: NodePort
petclinic-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: petclinic
labels: # 为路由选择打标签
app: petclinic
spec:
containers: # 容器镜像名称
- name: petclinic
image: spring2go/spring-petclinic:1.0.0.RELEASE
蓝绿发布:
新版本和旧版本的pod,修改对应版本号即可。
apiVersion: v1
kind: Pod
metadata:
name: petclinic-v1.0.0
labels: # 为路由选择打标签
app: petclinic
version: v1.0.0
spec:
containers: # 容器镜像名称
- name: petclinic
image: spring2go/spring-petclinic:1.0.0.RELEASE
apiVersion: v1
kind: Pod
metadata:
name: petclinic-v1.0.1
labels:
app: petclinic
version: v1.0.1
spec:
containers:
- name: petclinic
image: spring2go/spring-petclinic:1.0.1.RELEASE
发布service,修改对应版本号实现新老版本切换
apiVersion: v1
kind: Service
metadata:
name: petclinic
spec:
ports:
- name: http
port: 8080
targetPort: 8080
nodePort: 31080
selector:
app: petclinic
version: v1.0.1
type: NodePort
应用集群抽象
应用集群抽象Replicates副本集,应用到了k8s的自愈能力。
petclinic-replicates.yml:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: petclinic
spec:
replicas: 3 # 发布3个实例
selector:
matchLabels:
app: petclinic # 给pod打的标签
template:
metadata:
labels:
app: petclinic
spec:
containers:
- name: petclinic
image: spring2go/spring-petclinic:1.0.0.RELEASE
replicas中发布了3个实例,当其中有实例挂掉,k8s会重启一个实例以维持集群中始终有3个实例。
滚动发布Rolling Update是一种发布策略,按批次依次替换老版本,逐步升级到新版本,发布过程中应用不中断。k8s中的Deployment是对Replicaset+滚动发布流程的一种包装。滚动发布适用于版本兼容,蓝绿发布适用于版本不兼容发布。
假设绿色版本已经发布,对应的Replicaset为v1.0.0,通过Deployment升级发布到v1.0.1,发布之后会创建新的Replicaset v1.0.1,之后Deployment会依次滚动,不断创建并拉入蓝色版本的pod,拉出并关闭绿色版本的pod,直到所有蓝色的pod都上线绿色版本的pod都下线。此过程中Deployment始终保持有可用pod,服务不会中断,而且前置的service会屏蔽掉内部ip的变化,实现无感发布。新版本有问题也可回退,方法同理。
petclinic-deployment.yml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: petclinic
spec:
selector:
matchLabels:
app: petclinic
minReadySeconds: 10 # 测试用,启动后10s状态才变为就绪
replicas: 3
template:
metadata:
labels:
app: petclinic # 与matchLabels下对应的app相同
spec:
containers:
- name: petclinic
image: spring2go/spring-petclinic:1.0.1.RELEASE
查看发布历史:kubectl rollout history deployment/petclinic
回退发布:kubectl rollout undo deployment/petclinic
指定回退版本:kubectl rollout undo deployment/petclinic --to-revision=2
动态查看发布进度:kubectl rollout status deployment/petclinic
k8s内部服务之间访问引入反向代理抽象,实现反向路由和负载均衡,内部使用ClusterIP 类型的service,k8s内部为避免pod的ip变化,使用解析app服务名的方式,找到对应服务集群。
假设将mysql通过k8s发布(一般来说mysql是一个单独服务,这里仅用于示例展示),有状态的服务一般只能部署一个pod实例。
mysql-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: petclinic
- name: MYSQL_DATABASE
value: petclinic
mysql-service.yml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
selector:
app: mysql
ports:
- name: tcp
port: 3306
targetPort: 3306
type: ClusterIP
petclinic-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: petclinic
spec:
selector:
matchLabels:
app: petclinic
replicas: 1
template:
metadata:
labels:
app: petclinic
spec:
containers:
- name: petclinic
image: spring2go/spring-petclinic:1.0.1.RELEASE
env:
- name: SPRING_PROFILES_ACTIVE
value: mysql
- name: DATASOURCE_URL
value: jdbc:mysql://mysql/petclinic
- name: DATASOURCE_USERNAME
value: root
- name: DATASOURCE_PASSWORD
value: petclinic
- name: DATASOURCE_INIT_MODE
value: always
petclinic-service.yml
apiVersion: v1
kind: Service
metadata:
name: petclinic
spec:
ports:
- name: http
port: 8080
targetPort: 8080
nodePort: 31080
selector:
app: petclinic
type: NodePort
查看pod启动日志:kubectl logs petclinic-cb946d644-5r7q9
k8s Service的三种类型:
ClusterIP:内部服务访问
NodePort:对外暴露服务
LoadBalancer:对外暴露服务(公有云)
Namespace是k8s中的逻辑隔离机制,一个k8s集群中可以配置多个Namespace,每个Namespace中住着独立的pod、service、replicasets等资源,不同Namespace之间的资源可以相互访问,可以使用kubectl get ns来看k8s内置的已经支持的名字空间,其中default是缺省名字空间,kube-system是系统名字空间其中是支持k8s运行的系统组件。也可以根据不同业务定制不同名字空间,比如按业务线划分,或者按功能分类如前、后端、监控等划分。
查看对应名字空间下的组件:kubectl get all -n kube-system
如kube-dns就是k8s内置的dns域名解析服务,coredns是它下的两个pod。
以终端交互的方式运行pod下的shell命令:kubectl exec -it petclinic-cb946d644-5r7q9 sh
我们进入pod查看发现,拼装成全域名以后查到对应的ip地址。所以单用mysql查不到,他的域名是10.101.75.79 mysql.default.svc.cluster.local。
需要根据环境的不同使用不同配置,这些配置有些是在启动时一次性配置好,如:数据库连接字符串,还有些配置可以在运行期动态调整的,如:缓存的过期时间TTL值,业务相关配置数据等。k8s平台内置支持微服务配置即ConfigMap。
开发人员将配置填写在ConfigMap中,发布后k8s将ConfigMap以环境变量的形式注入到pod中,这样pod中的应用可以用环境变量的形式访问这些配置,ConfigMap也支持以存储卷Volume方式挂载到pod中,实现配置热更新。
由于多个业务服务都需要连接数据库的配置,如果为每个服务增加配置会出现冗余和可维护问题,ConfigMap正好解决了这个问题。我们可以将配置统一放到公共的ConfigMap中,发布后k8s将ConfigMap中的配置注入到后台服务的pod中。
petclinic-config.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: petclinic-config-v2
data:
SPRING_PROFILES_ACTIVE: mysql
DATASOURCE_URL: jdbc:mysql://mysql/petclinic
DATASOURCE_USERNAME: root
DATASOURCE_PASSWORD: petclinic
DATASOURCE_INIT_MODE: always
TEST_CONFIG: test_config_v2
mysql-svc.yml
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: petclinic
- name: MYSQL_DATABASE
value: petclinic
---
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
selector:
app: mysql
ports:
- name: tcp
port: 3306
targetPort: 3306
type: ClusterIP
petclinic-svc.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: petclinic
spec:
selector:
matchLabels:
app: petclinic
replicas: 1
template:
metadata:
labels:
app: petclinic
spec:
containers:
- name: petclinic
image: spring2go/spring-petclinic:1.0.1.RELEASE
envFrom:
- configMapRef:
name: petclinic-config-v2
---
apiVersion: v1
kind: Service
metadata:
name: petclinic
spec:
ports:
- name: http
port: 8080
targetPort: 8080
nodePort: 31080
selector:
app: petclinic
type: NodePort
发布配置文件:kubectl apply -f petclinic-config.yml
查看configMap:kubectl get cm
查看petclinic-config详情:kubectl describe cm petclinic-config
发布mysql-svc.yml及petclinic-svc.yml:kubectl apply -f mysql-svc.yml;kubectl apply -f petclinic-svc.yml
打印出pod下全部环境变量:kubectl exec petclinic-f77f5c8f-bjvxl printenv
指定打印pod下某个环境变量:kubectl exec petclinic-f77f5c8f-bjvxl printenv | grep TEST_CONFIG
配置更新需要重启pod,建议更新ConfigMap的name及其引用。
微服务网关:微服务网关的主要作用是将前端和后端微服务进行解耦,使得两边不直接依赖,可以独立变化。网关本质上是一个七层反向代理,当前端向某个微服务发起调用,由网关根据配置的路由表做路由转发,由于网关是后端微服务的集中入口,它还可以实现安全认证、限流熔断、日志监控、解耦迁移和金丝雀测试等功能。
在公有云的k8s环境中要将微服务暴露到公网,我们需要申请负载均衡器(Load Balancer),由于LB需要购买,而且暴露一个服务就需要购买一个LB,当微服务数量多时,显然从成本角度考虑,这种做法是不可扩展的。为解决这个问题k8s中引入了ingress组件,和网关类似,ingress本质上也是一个七层反向代理。引入ingress我们可以只购买一个或者少量LB,就可以将多个微服务暴露出去,由ingress统一实现路由转发。每次要将服务暴露出去时,只需在ingress增加路由规则即可。ingress也是一个service服务,只不过它的功能时做路由转发,它也需要前置的LB才能将自己暴露出去。
ingress在k8s中主要是定义了规范,具体有很多种实现:
https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress-controllers/
代码来源:https://github.com/spring2go/k8s-msa-in-action 图片来源:https://github.com/spring2go/k8s-msa-in-action-ppt
我的个人公众号,“才浅coding攻略”,这里可以第一时间收到推送,期待你的关注和催更!