赞
踩
landscape 云原生全景图
1、云原生定义:其实是一条使用户能敏捷的、可复制、可扩展的最大化利用“云”的能力、发挥“云”的价值的最佳路径,官方定义:
- Cloud native technologies empower organizations to build and run scalable applications in modern, dynamic environments such as public, private, and hybrid clouds. Containers, service meshes, microservices, immutable infrastructure, and declarative APIs exemplify this approach.
- These techniques enable loosely coupled systems that are resilient, manageable, and observable. Combined with robust automation, they allow engineers to make high-impact changes frequently and predictably with minimal toil.
- The Cloud Native Computing Foundation seeks to drive adoption of this paradigm by fostering and sustaining an ecosystem of open source, vendor-neutral projects. We democratize state-of-the-art patterns to make these innovations accessible for everyone.
2、云原生的愿景:软件就生在云上、长在云上的,全新的软件开发,发布和运维模式、
3、云原生的技术范畴:
4、云原生思想的两个理论基础:
不可变基础设施:
云应用编排理论:
5、基础设施向云演进的过程:
6、基础设施向云演进的意义:
基础设施一致性和可靠性:
简单可预测的部署与运维:
7、云原生关键技术点
Kubernetes 源与希腊语,意为"舵手",或“飞行员”,k8s 是通过将8个字母“ubernete"替换为8而导出的缩写,container意为集装箱,k8s寓意成为运送集装箱的轮船。k8s为一个自动化的容器编排平台:负责应用的部署、弹性、管理
Kubernetes各个组件简介
pod 创建过程:
0、各组件启动时向apiserver 发起watch请求进行订阅,告诉apiserver自己需要订阅哪些类型的变化的数据。watch是一个典型的发布-订阅模式可以有条件的(比如kubelet只关心自己节点上的Pod列表)。list是watch失败后,数据过于陈旧后的弥补手段。k8s的watch功能是建立在etcd的watch之上的,etcd key-value发生变化,通知apiserver,apiserver对外提供watch api。
1、用户通过cli或者ui进行pod创建,请求被apiserver接收
2、apiserver收到请求后,不会直接创建pod,而是生成一个包含创建信息的yaml,并将yaml信息存储到etcd
3、scheduler查看k8s api,判断pod.spec.Node == null?决定是否需要创建,并根据一定的算法找到最合适的pod,并将信息存储到etcd(通过apiserver存储)
4、kubelet watch apiserver查询自己是否有新增pod需要创建,如果有,Kubelet调用contianer runtime去创建容器运行环境
pod : 是最小的调度以及资源单元、由一个或者多个容器组成、定义容器运行的方式(Command,环境变量等),提供给容器共享的运行环境(网络,进程空间等)
Volume:声明在pod中的容器可访问的文件目录,可以被挂载在Pod中一个或多个容器的指定路径下,支持多种后端多种存储的抽象(本地存储、分布式存储、云存储)
Deployment: 定义一组Pod的副本数目、版本等,通过Controller-manager维持Pod的数目;通过控制器指定的策略控制版本(滚动升级、重新生成、回滚等)
Service:提供访问一个或多个Pod实例的稳定访问地址,支持多种访问方式实现(ClusterIP,NodePort,LoadBalancer)
NameSpace:一个集群内部的逻辑隔离机制(鉴权、资源额度),每个资源都属于一个namespace,同一个Namespace中的资源命名唯一,不同Namespace中的资源可重命名
API:HTTP+JSON/YAML类型的api,kubectl/UI/curl命令 等发起请求
Label:一组key:value,可以被selector所查询,select color=red,资源集合的默认表达形式,例如Service 对应一组Pod
本地测试和实验使用
https://kubernetes/io/docs/tasks/tools/install-minikube
传统物理机上进程特点:APP可以相互“看见“,相互通信,使用同样的文件系统,同样的系统资源。意味着具有privileged权限的进程可以攻击其他进程。使用同一个文件系统,导致APP可以对已有的文件系统进行增删改查,进程间资源依赖会出现冲突,以及系统资源抢占问题。
为了解决上述问题,可以使用以下思路:
chroot: 视图级别进行隔离,把一个子目录编程根目录
namespace:资源试图隔离。进程在环境内使用独立的环境,但是资源还是使用操作系统的
cgroup: 限制APP的资源使用率
什么是容器:
什么是镜像:
DockerFile最佳实践: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
容器和镜像:
容器是一种具有隔离特性的进程集合,在使用doker run的时候可以使用image来提供独立的文件系统,以及指定相应的程序。所指定的这个程序称为init进程。容器的启停和init进程同步:
单进程模型:
数据持久化:
容器的生命周期和init进程是一致的
- # bindg host dir into container
- docker run -v /tmp:/tmp busybox:1.25 sh -c "date > /tmp/demo.log"
-
- # check result
- cat /tmp/demo.log
-
- # let it handled by docker container engine
- docker create volume demo
-
- #demo is volume name
- docker run -v demo:/tmp busybox:1.25 sh -c "date > /tmp/demo.log"
-
- #check result
- docker run -v demo:/tmp busybox:1.25 sh -c "cat /tmp/demo.log"
moby和docker-ce以及docker-ee说明:
shim的另外一个好处:对moby或者containerd升级,因为有了shim,所以可以做到不影响业务
容器的本质是?
kubernetes 是什么?
以kubernetes为一个操作系统来说明:(来看一个真是操作系统中的例子)
linux实现 线程为 轻量级的进程
注意:除非程序具有systemd的功能,否则他是没有管理多个进程的能力:
Pod为K8s提出的类似于一个进程组的概念:
四个进程共同组成的一个应用hello workld,实际上会被定义为拥有四个容器的pod。pod是一个逻辑概念,真实启动的是4个容器。pod是k8s分配资源的一个单位。pod是k8s分配资源的一个单位
Google的工程师么们发现,在Borg项目部署的应用,往往都粗壮乃着类似于”进程和进程组“的关系,更具体的说,就是这些应用之间有着密切的协作关系,使得他们必须部署在同一台机器上并且分享某些信息。
思考:为什么Pod必须是原子调度单位,为何不可以通过调度让容器实现调度在同一台机器上?
Pod解决了这两个问题:1、怎么去描述超亲密关系;2、怎么对超亲密关系的容器或者业务进行调度
Pod要解决的问题:如何让一个pod中的多个容器之间最高效的共享某些资源和数据?容器之间原本是被Linux Namespace和cgroups隔离开的
解决方法分为两个部分:共享网络和共享存储
容器A和B
通过infra container的方式共享network namespace
一个pod中的所有容器看到的网络试图是一样的,整个pod的生命周期一定是等于infra pod的生命周期,并且infra pod一定是第一个启动的
- apiVersion: "apps/v1"
- kind: "Pod"
- metadata:
- name: "name01"
- spec:
- restartPolicy: "Always"
- volumes:
- - name: shared-data
- hostPath:
- path: /data
- containers:
- - name: nginx-controller
- image: nginx
- volumeMounts:
- - name: shared-data
- mountPath: /usr/share/nginx/html
- - name: debian-container
- image: debian
- volumeMounts:
- - name: shared-data
- mountPath: /pod-data
- command: ["/bin/sh"]
- args: ["-c","echo Hello from the debian container ! > /pod-data/index.html"]

shared-data 对应在宿主机上的目录会被同时绑定挂载进了两个容器当中
所有设计模式的本质都是:解耦和重用
案例: WAR包 + Tomcat的容器化
InitContainer:
- apiVersion: "apps/v1"
- kind: "Pod"
- metadata:
- name: "javaweb-2"
- spec:
- initContainers:
- - image: resouer/sample:v2
- name: war
- command: ["cp","/sample.war","/app"]
- volumeMounts:
- - mountPath: /app
- name: app-volume
- containers:
- - name: tomcat
- image: tomcat7:latest
- command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
- volumeMounts:
- - name: app-volume
- mountPath: /root/apache-tomcat-7.0.42-v2/webapps
- ports:
- - containerPort: 8080
- hostPort: 8001
- volumes:
- - name: app-volume
- emptyDir: {}

这样的一种设计方式, 就是k8s中一个比较经典的设计模式:称为sidecar : 通过在pod内定义专门容器,来执行业务容器所需要的辅助工作
Sidecar的使用场景:
代理容器场景:一个container 需要访问外部系统或者服务,但是外部的服务或系统为集群状态,业务pod只需要访问一个ip地址,一种方法,改业务代码记录外部服务地址,还有一种方式就是解耦通过sidecar代理容器。单独写一个proxy专门用来对接外部的服务集群,但是对外只要暴漏一个ip地址就可以了。通过proxy代为连接集群。这里面该pod和proxy之间通信使用localhost无性能损耗。
kubernetes资源对象
资源 | 标签1 | 标签2 |
---|---|---|
R1 | Tie:front | Env:dev |
R2 | Tie:back | Env:prod |
R3 | Tie:front | Env:test |
R4 | Tie:back | Env:gray |
常见的selector:
- [root@master1 yaml]# kubectl run nginx1 --image=reg.mt.com:5000/nginx:latest -l env=dev,tie=front --dry-run=true -o yaml > pod1.yaml
- [root@master1 yaml]# kubectl run nginx2 --image=reg.mt.com:5000/nginx:latest -l env=dev,tie=front --dry-run=true -o yaml > pod2.yaml
- [root@master1 yaml]# cat pod1.yaml #pod2的只有pod的名称和label不一样
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- creationTimestamp: null
- labels:
- env: dev
- tie: front
- name: nginx1
- spec:
- replicas: 1
- selector:
- matchLabels:
- env: dev
- tie: front
- strategy: {}
- template:
- metadata:
- creationTimestamp: null
- labels:
- env: dev
- tie: front
- spec:
- containers:
- - image: reg.mt.com:5000/nginx:latest
- name: nginx1
- resources: {}
- status: {}
- [root@master1 yaml]# kubectl apply -f pod1.yaml -f pod2.yaml
- deployment.apps/nginx1 created
- deployment.apps/nginx2 created
-
- #1、获取pod的label
- [root@master1 yaml]# kubectl get pods --show-labels
- NAME READY STATUS RESTARTS AGE LABELS
- nginx1-fb5497587-gdj9k 1/1 Running 0 3m15s env=dev,pod-template-hash=fb5497587,tie=front
- nginx2-6d5c4f84fb-qzr9q 1/1 Running 0 3m15s env=dev,pod-template-hash=6d5c4f84fb,tie=front
-
- #2、为pod打标签/删除标签
- [root@master1 ~]# kubectl label pods nginx1-fb5497587-gdj9k env=test --overwrite
- pod/nginx1-fb5497587-gdj9k labeled
- [root@master1 ~]# kubectl get pods --show-labels #因为deployment,所以直接打pod会自动创建一个新的pod
- NAME READY STATUS RESTARTS AGE LABELS
- nginx1-fb5497587-54x29 1/1 Running 0 14s env=dev,pod-template-hash=fb5497587,tie=front
- nginx1-fb5497587-gdj9k 1/1 Running 0 3h9m env=test,pod-template-hash=fb5497587,tie=front
- nginx2-6d5c4f84fb-qzr9q 1/1 Running 0 3h9m env=dev,pod-template-hash=6d5c4f84fb,tie=front
- [root@master1 ~]# kubectl label pods nginx1-fb5497587-gdj9k env- #删除标签
-
- #3、label查找
- [root@master1 ~]# kubectl get pods --show-labels -l 'env in (dev,prod)'
- NAME READY STATUS RESTARTS AGE LABELS
- nginx1-fb5497587-54x29 1/1 Running 0 36m env=dev,pod-template-hash=fb5497587,tie=front
- nginx2-6d5c4f84fb-qzr9q 1/1 Running 0 3h45m env=dev,pod-template-hash=6d5c4f84fb,tie=front
- [root@master1 ~]# kubectl get pods --show-labels -l 'env notin (dev,prod)'
- NAME READY STATUS RESTARTS AGE LABELS
- nginx1-fb5497587-gdj9k 1/1 Running 0 3h45m pod-template-hash=fb5497587,tie=front
-
- #4、anotate
- [root@master1 ~]# kubectl annotate pods nginx1-fb5497587-dxl7k desc='author by MT'
- pod/nginx1-fb5497587-dxl7k annotated
- [root@master1 ~]# kubectl get pods nginx1-fb5497587-dxl7k -o yaml |grep annotations -A3
- annotations:
- desc: author by MT
- creationTimestamp: "2021-01-20T13:24:51Z"
- generateName: nginx1-fb5497587-
-
- #5、ownerReference
- [root@master1 ~]# kubectl get pods nginx1-fb5497587-dxl7k -o yaml |grep ownerReferences -A5
- ownerReferences:
- - apiVersion: apps/v1
- blockOwnerDeletion: true
- controller: true
- kind: ReplicaSet #被ReplicaSet控制的pod
- name: nginx1-fb5497587 #这个ReplicaSet的名称是 nginx1-fb5497587
- [root@master1 ~]# kubectl get ReplicaSet nginx1-fb5497587 -o yaml |grep ownerReferences -A5
- ownerReferences:
- - apiVersion: apps/v1
- blockOwnerDeletion: true
- controller: true
- kind: Deployment
- name: nginx1

控制器模式,最核心的就是控制循环
外界通过修改资源的spec控制资源,控制器比较被控制资源的spec和status,计算一个diff。diff用来决定对系统执行什么样的操作。控制操作会使得系统产生新的输出。并被传感器以资源status的形式上报。控制器的各个组件都是独立自主的运行。
1、传感器sensor:
控制循环中逻辑的传感器主要有 Reflector,Informer,Indexer 三个组件构成。
2、控制器循环中的控制器组件
举例:ReplicaSet(name=rsA,namespace=nsA)资源的replicas(pod个数)使用kubectl edit由2改为3的场景
先更新replicaset.spec,后更新pod,最后更新replicaset.status
1、Reflector会watch Replicaset和Pod两种资源的变化,发现变化后在delta队列中新增记录
2、Informer从delta queue中pop记录,把新的replicaset更新到缓存中(交给indexer)并以namespace和rsa作为索引,另一方面调用update的回调函数
3、Replicaset控制器发现replicaset发生变化后,会把nsA/rsA字符串放入到工作队列中
4、工作队列中的一个worker获取 nsA/rsA 这个字符串的key,并且从缓存中获取最新的replicaset数据
5、worker通过比较replicaset中的status和spec中的replicas数据,发现需要对replicaset进行扩容。因此通知apiserver replicaset创建了一个pod,这个pod的ownereference取自 rsA,
6、Reflector watch到了新增事件,在delta中添加记录
7、informer从delta中获取新的记录,一方面通过indexer放入缓存中,另一方面调用repliset的控制器的add回调函数,add函数通过ownereference为rsA找到对应的replicaset,并把包括replicaset和namespace字符串放到 工作队列中
8、replicaset的worker从工作队列中获取数据,从缓存中获取最新的replicaset记录。并得到所有创建的pod
9、因为replicaset状态不是最新的,也就是所有创建的pod的数量已经不是最新的。因此更新rsA的status和spec一致。replicaset中的sepc和status达到了一致
API有两种声明方式:
kubernetes控制器模式:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。