目录html
在k8s中全部的对象都叫作资源,例如:pod,service等前端
pod是在k8s中最小单元,前面有提到,k8s支持自愈,弹性扩容等高级特性,那么若是单纯的在k8s节点中跑业务docker是没有办法支持这些高级特性,必需要有定制化的容器,那么,pod就是这个官方已经定制化好的支持高级特性的容器,当启动一个pod时,至少会有两个容器,pod容器``和业务容器
,多个业务容器会共享一个pod容器(一组容器的集合),那么一个Pod中的容器共享网络命名空间,node
Pod容器分类nginx
Pod存在的意义:为亲密性应用而存在web
镜像拉取策略算法
imagePullPolicy 一、ifNotPresent:默认值,镜像在宿主机上不存在时才拉取 二、Always:每次建立Pod都会从新拉取一次镜像 三、Never:Pod永远不会主动拉取这个镜像
1.pod基本操做spring
// 指定yaml文件建立pod kubectl create -f [yaml文件路径] // 查看pod基本信息 kubectl get pods // 查看pod详细信息 kubectl describe pod [pod名] // 更新pod(修改了yaml内容) kubectl apply -f [yaml文件路径] // 删除指定pod kubectl delete pod [pod名] // 强制删除指定pod kubectl delete pod [pod名] --foce --grace-period=0
2.pod yaml配置文件docker
apiVersion: v1 kind: Pod metadata: name: nginx01 labels: app: web spec: containers: - name: nginx01 image: reg.betensh.com/docker_case/nginx:1.13 ports: - containerPort: 80
Pod与controllers的关系后端
label-selector
相关联Replication Controller 副本控制器,应用托管在Kubernetes以后,Kubernetes须要保证应用可以持续运行,这是RC的工做内容,它会确保任什么时候间Kubernetes中都有指定数量的Pod正在运行。在此基础上,RC还提供了一些高级的特性,好比滚动升级、升级回滚等。api
在新版本的 Kubernetes 中建议使用 ReplicaSet(简称为RS )来取代 ReplicationController
1.建立一个rc
apiVersion: v1 kind: ReplicationController metadata: name: myweb spec: replicas: 2 selector: app: myweb template: metadata: labels: app: myweb spec: containers: - name: nginx01 image: reg.betensh.com/docker_case/nginx:1.13 ports: - containerPort: 80
默认状况下pod名
会以rc名+随机值
组成,以下:
[root@k8s-master01 rc]# kubectl get pods NAME READY STATUS RESTARTS AGE myweb-0lp57 1/1 Running 0 45s myweb-zgfcf 1/1 Running 0 45s
RC经过标签选择器(labels)来控制pod,RC名称必需要和标签选择器名称一致
[root@k8s-master01 rc]# kubectl get rc -o wide NAME DESIRED CURRENT READY AGE CONTAINER(S) IMAGE(S) SELECTOR myweb 2 2 2 12m nginx01 reg.betensh.com/docker_case/nginx:1.13 app=myweb
2.RC滚动升级
前面咱们已经建立一个v1版本的http-server的pod在k8s环境中,若是咱们想要作一次版本升级该怎么办呢?难道把原来的pod停掉,再使用新的镜像拉起来一个新的pod吗,这样作明显是不合适的。
kubectl rolling-update myweb -f nginx_rc_v2.yaml --update-period=30s
3.RC滚动回退
假设如今myweb升级到myweb2,出现了bug,那么先强制中断升级
kubectl rolling-update myweb -f nginx_rc_v2.yaml --update-period=50s
而后将myweb2的版本回滚到myweb
kubectl rolling-update myweb myweb2 --rollback
deployment也是保证pod高可用的一种方式,明明有RC为什么还要引入deployment呢?
由于deployment解决了RC的一个痛点,当使用RC升级容器版本后,标签会发生变化,那么svc的标签仍是原来的,这样就须要手动修改svc配置文件。
Deployment 为Pod
和ReplicaSet
之上,提供了一个声明式定义(declarative)方法,用来替代之前的ReplicationController
来方便的管理应用。
你只须要在Deployment
中描述您想要的目标状态
是什么,Deployment controller
就会帮您将Pod
和ReplicaSet
的实际状态改变到您的目标状态
。您能够定义一个全新的Deployment
来,建立ReplicaSet
或者删除已有的 Deployment
并建立一个新的来替换。也就是说Deployment
是能够管理多个ReplicaSet
的,以下图:
虽然也 ReplicaSet 能够独立使用,但建议使用 Deployment 来自动管理 ReplicaSet,这样就无需担忧跟其余机制的不兼容问题
1.建立一个deployment
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.13 ports: - containerPort: 80 // 启动 [root@k8s-master01 deploy]# kubectl create -f nginx_deploy.yaml
查看deployment启动状态
deployment会先启动一个rs,然后在启动pod
[root@k8s-master01 deploy]# kubectl get all NAME READY STATUS RESTARTS AGE pod/nginx-deployment-fcfcc984f-t2bk4 1/1 Running 0 33s pod/nginx-deployment-fcfcc984f-vg7qt 1/1 Running 0 33s pod/nginx-deployment-fcfcc984f-zhwxg 1/1 Running 0 33s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx-deployment 3/3 3 3 33s NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-deployment-fcfcc984f 3 3 3 33s
2.关联service
kubectl expose deployment nginx-deployment --port=80 --type=NodePort
查看svc
[root@k8s-master01 deploy]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h nginx-deployment NodePort 10.96.171.141 <none> 80:31873/TCP 25s
访问svc地址以及端口
[root@k8s-master01 deploy]# curl -I 10.0.0.33:31873 HTTP/1.1 200 OK Server: nginx/1.13.12 Date: Thu, 14 Nov 2019 05:44:51 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Mon, 09 Apr 2018 16:01:09 GMT Connection: keep-alive ETag: "5acb8e45-264" Accept-Ranges: bytes
3.deployment升级
// 直接编辑对应deployment,并修改镜像版本 kubectl edit deployment nginx-deployment // 经过 set image 发布新的镜像 kubectl set image deploy nginx-deployment nginx-deployment=nginx:1.17
4.deployment回滚
// 回滚到上一级版本 kubectl rollout undo deployment nginx-deployment // 回滚到指定版本 kubectl rollout undo deployment nginx-deployment --to-revision=1 // 查看当前deploy历史版本 kubectl rollout history deployment nginx-deployment
5.命令行方式实现发布版本
# kubectl run nginx --image=nginx:1.13 --replicas=3 --record # kubectl rollout history deployment nginx deployment.extensions/nginx # kubectl set image deployment nginx nginx=nginx:1.15
在K8S里,咱们想要经过name来访问服务的方式就是在Deployment
上面添加一层Service
,这样咱们就能够经过Service name
来访问服务了,那其中的原理就是和CoreDNS
有关,它将Service name
解析成Cluster IP
,这样咱们访问Cluster IP
的时候就经过Cluster IP做负载均衡,把流量分布到各个POD
上面。我想的问题是CoreDNS
是否会直接解析POD的name,在Service的服务里,是不能够的,由于Service有Cluster IP,直接被CoreDNS解析了,那怎么才能让它解析POD呢,有大牛提出了可使用Headless Service
,因此咱们就来探究一下什么是Headless Service
。
Headless Service
也是一种Service
,但不一样的是会定义spec:clusterIP: None
,也就是不须要Cluster IP的Service
。
咱们首先想一想Service的Cluster IP
的工做原理:一个Service
可能对应多个EndPoint(Pod)
,client
访问的是Cluster IP
,经过iptables
规则转到Real Server
,从而达到负载均衡的效果。具体操做以下所示:
一、web-demo.yaml
#deploy apiVersion: apps/v1beta1 kind: StatefulSet metadata: name: web-demo namespace: dev spec: # 指定svc名称 serviceName: web-demo-svc replicas: 3 template: metadata: labels: app: web-demo spec: containers: - name: web-demo image: 10.0.0.33/base_images/web-demo:v1.0 ports: - containerPort: 8080 resources: requests: memory: 1024Mi cpu: 500m limits: memory: 2048Mi cpu: 2000m livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 20 periodSeconds: 10 failureThreshold: 3 successThreshold: 1 timeoutSeconds: 5 readinessProbe: httpGet: path: /hello port: 8080 scheme: HTTP initialDelaySeconds: 20 periodSeconds: 10 failureThreshold: 1 successThreshold: 1 timeoutSeconds: 5 --- #service apiVersion: v1 kind: Service metadata: name: web-demo-svc namespace: dev spec: ports: - port: 80 targetPort: 8080 protocol: TCP clusterIP: None selector: app: web-demo
查看svc,发现ClusterIP
为None
$ kubectl get svc -n dev | grep "web-demo-svc" web-demo-svc ClusterIP None <none> 80/TCP 12s
pod会按照顺序建立
$ kubectl get pod -n dev NAME READY STATUS RESTARTS AGE web-demo-0 1/1 Running 0 7m2s web-demo-1 1/1 Running 0 6m39s web-demo-2 1/1 Running 0 6m15s
登陆到Cluster的内部pod
$ kubectl exec -it web-demo-0 sh -n dev / # nslookup web-demo-svc Name: web-demo-svc Address 1: 10.244.2.67 web-demo-0.web-demo-svc.dev.svc.cluster.local Address 2: 10.244.3.12 web-demo-2.web-demo-svc.dev.svc.cluster.local Address 3: 10.244.1.214 web-demo-1.web-demo-svc.dev.svc.cluster.local
总结:经过dns访问,会返回后端pods的列表
首先Deployment
只是用于无状态服务,无差异而且没有顺序的Pod,而StatefulSet支持多个Pod之间的顺序性,用于 每一个Pod中有本身的编号,须要互相访问,以及持久存储区分
Pod顺序性
一、headless-service.yaml
apiVersion: v1 kind: Service metadata: name: springboot-web-svc spec: ports: - port: 80 targetPort: 8080 protocol: TCP clusterIP: None selector: app: springboot-web
二、statefulset.yaml
apiVersion: apps/v1 kind: StatefulSet metadata: name: springboot-web spec: # serviceName 该字段是告诉statefulSet用那个headless server去保证每一个的解析 serviceName: springboot-web-svc replicas: 2 selector: matchLabels: app: springboot-web template: metadata: labels: app: springboot-web spec: containers: - name: springboot-web image: 10.0.0.33/base_images/web-demo:v1.0 ports: - containerPort: 8080 livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 20 periodSeconds: 10 failureThreshold: 3 successThreshold: 1 timeoutSeconds: 5
查看pod
$ kubectl get pod NAME READY STATUS RESTARTS AGE springboot-web-0 1/1 Running 0 118s springboot-web-1 1/1 Running 0 116s
进入一个pod,而经过pod name访问另一个pod
$ kubectl exec -it springboot-web-0 sh / # ping springboot-web-1.springboot-web-svc PING springboot-web-1.springboot-web-svc (10.244.2.68): 56 data bytes 64 bytes from 10.244.2.68: seq=0 ttl=62 time=1.114 ms 64 bytes from 10.244.2.68: seq=1 ttl=62 time=0.698 ms
持久化存储
自动根据pod建立pvc
apiVersion: apps/v1 kind: StatefulSet metadata: name: nginx-demo spec: serviceName: springboot-web-svc replicas: 2 selector: matchLabels: app: nginx-demo template: metadata: labels: app: springboot-web spec: containers: - name: springboot-web image: 10.0.0.33/base_images/nginx:1.13 ports: - containerPort: 8080 volumeMounts: - name: data mountPath: / volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce storageClassName: glusterfs-storage-class resources: requests: storage: 1Gi
DaemonSet是在Kubernetes1.2 版本新增的一种资源对象
DaemonSet
可以让全部(或者一些特定)的Node
节点仅运行一份Pod
。当节点加入到kubernetes集群中,Pod会被(DaemonSet)调度到该节点上运行,当节点从kubernetes集群中被移除,被(DaemonSet)调度的Pod会被移除,若是删除DaemonSet,全部跟这个DaemonSet相关的pods都会被删除。
在使用kubernetes来运行应用时,不少时候咱们须要在一个区域(zone)
或者全部Node
上运行同一个守护进程(pod)
,例如以下场景:
DaemonSet的Pod调度策略与RC很相似,除了使用系统内置的调度算法在每一个Node上进行调度,也能够在Pod定义中使用NodeSelector或NodeAffinity来指定知足条件的Node范围进行调度
DaemonSet 资源文件格式
apiVersion: extensions/v1beta1 kind: DaemonSet metadata:
下面例子定义为在每一个Node上都启动一个filebeat
容器,其中挂载了宿主机目录"/var/log/messages"
$ vi k8s-log-filebeat.yaml apiVersion: v1 kind: ConfigMap # 定义一个config文件内容 metadata: name: k8s-logs-filebeat-config namespace: kube-system data: # 填写filebeat读取日志相关信息 filebeat.yml: |- filebeat.prospectors: - type: log paths: - /messages fields: app: k8s type: module fields_under_root: true output.logstash: # specified logstash port (by default 5044) hosts: ['10.0.0.100:5044'] --- apiVersion: apps/v1 kind: DaemonSet # DaemonSet 对象,保证在每一个node节点运行一个副本 metadata: name: k8s-logs namespace: kube-system spec: selector: matchLabels: project: k8s app: filebeat template: metadata: labels: project: k8s app: filebeat spec: containers: - name: filebeat image: docker.elastic.co/beats/filebeat:6.8.1 args: [ "-c", "/etc/filebeat.yml", "-e", ] resources: requests: cpu: 100m memory: 100Mi limits: cpu: 500m memory: 500Mi securityContext: runAsUser: 0 # 进行实际挂载操做 volumeMounts: # 将configmap里的配置挂载到 /etc/filebeat.yml 文件中 - name: filebeat-config mountPath: /etc/filebeat.yml subPath: filebeat.yml # 将宿主机 /var/log/messages 路径挂载到 /messages中 - name: k8s-logs mountPath: /messages # 定义卷 volumes: - name: k8s-logs hostPath: path: /var/log/messages type: File - name: filebeat-config configMap: name: k8s-logs-filebeat-config
使用kubectl create 命令建立该DeamonSet
$ kubectl create -f k8s-log-filebeat.yaml configmap/k8s-logs-filebeat-config created daemonset.apps/k8s-logs created
查看建立好的DeamonSet和Pod,能够看到在每一个Node上都建立了一个Pod
$ kubectl get ds -n kube-system | grep "k8s-logs" NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE k8s-logs 2 2 0 2 0 <none> 2m15s $ kubectl get pods -n kube-system -o wide | grep "k8s-logs" k8s-logs-gw4bs 0/1 Running 0 87s <none> k8s-node01 <none> <none> k8s-logs-p6r6t 0/1 Running 0 87s <none> k8s-node02 <none> <none>
在kubernetes 1.6之后的版本中,DaemonSet也能执行滚动升级了,即在更新一个DaemonSet模板的时候,旧的Pod副本会被自动删除,同时新的Pod副本会被自动建立,此时DaemonSet的更新策略(updateStrategy)为RollingUpdate,以下:
apiVersion: apps/v1 kind: DaemonSet metadata: name: k8s-logs namespace: kube-system spec: updateStrategy: type: RollingUpdate
updateStrategy 的另一个值是OnDelete,即只有当手工删除了DaemonSet建立的Pod副本,新的Pod副本才会被建立出来,若是不设置updateStrategy的值,则在kubernetes 1.6以后的版本中会被默认设置为RollingUpdate(滚动升级)。
咱们都知道在kubernetes中以Pod为最小调度单位,而且它的特性就是不肯定性,即随时会被销毁和从新建立、不肯定性会致使每一个Pod会经过调度器将其部署到不一样的N个Node节点,这样会致使Pod ip地址会发生变化;
举个例子,web场景,分为前端后端,前端须要去调用后端资源,若是后端的Pod天生的不肯定性致使IP地址不一样,那么前端确定是没法作到自动切换链接后端的IP地址,因此须要经过Service去发现Pod并获取其IP地址。
Pod与Service的关系
每一个Service关联一个应用
Service类型
1.Cluster IP详解:
Cluster IP,也叫VIP,主要实现不一样Pod之间互相访问
type: NodePort ports: - port: 80 targetPort: 80 protocol: TCP
开启proxy访问
kubectl proxy 让外部网络访问K8S service的ClusterIP
kubectl proxy --address='0.0.0.0' --accept-hosts='^*$' --port=8009 http://[k8s-master]:8009/api/v1/namespaces/[namespace-name]/services/[service-name]/proxy
详细:https://blog.csdn.net/zwqjoy/article/details/87865283
2.Node Port详解:
实现外部用户能够访问节点Node,节点Node会将其流量转发到内部Pod
访问流程:用户 -> 域名 -> 负载均衡器 -> NodeIP:Port ->PodIP:Port
还能够直接在Node前面部署一个LB负载均衡,如图:
type: NodePort ports: - port: 80 targetPort: 80 nodePort: 30008 protocol: TCP
参数解释
spec.ports.port:vip端口(cluster ip) spec.ports.nodePort:映射到宿主机的端口,即提供外部访问的端口 spec.ports.targetPort:pod 端口 spec.selector: 标签选择器
建立nodePort类型的时候也会分配一个Cluster IP,方便提供给Pod之间访问
三、LoadBalancer详解:
访问流程:用户 -> 域名 -> 负载均衡器 -> NodeIP:Port ->PodIP:Port
常规的docker映射场景:
访问 --> node IP:10.0.0.12 --> docker 容器: 172.16.48.2
若是当docker挂掉了后,在从新启动一个docker,容器IP地址就会发生变化,那么以前作的node和docker的映射就无效,就须要手动修改映射,这样就显得很麻烦
so,在k8s中新增了cluster IP,网段 10.254.0.0/16,series会自动建立这个cluster IP,也叫vip,当pod建立完成后会自动注册到service里,而且实现负载均衡(规则默认为rr),若是某个pod挂了后,会自动被剔除
访问 --> node IP:10.0.0.13 --> cluster IP:10.254.0.0/16 (service) --> pod IP:172.16.48.2
建立service
apiVersion: v1 kind: Service metadata: name: myweb spec: type: NodePort ports: - port: 80 nodePort: 30000 targetPort: 80 selector: app: myweb // 启动 kubectl create -f nginx-svc.yaml
查看Service是否正常接管pod网络服务:
[root@k8s-master01 svc]# kubectl get endpoints NAME ENDPOINTS AGE kubernetes 10.0.0.31:6443 2d myweb 172.16.12.2:80,172.16.15.4:80 2m
service底层流量转发与负载均衡实现:
一、一个service会建立不少的iptables规则(更新,非增量式)
二、iptables规则是从上到下逐条匹配(延时大)。
救世主:IPVS(内核态)
LVS基于IPVS内核调度模块实现的负载均衡,如:阿里云SLB,基于LVS实现四层负载均衡。
iptables:
IPVS: