k8s入门篇-资源管理
作者:@skyflask
转载本文请注明出处:https://www.cnblogs.com/skyflask/p/16787704.html
目录
Kubernetes入门
一、为什么需要Kubernetes
1.1 传统的容器编排痛点
1.2 Kubernetes 能解决的问题
1.3 什么时候使用 Kubernetes?
1.4 什么时候不适合使用 Kubernetes
二、Kubernetes的发展
三、kubernetes组成
3.1 Master节点
3.2 Node工作节点
3.3 其他组件
四、Pod
4.1 Pod是什么
4.2 Pod定义
4.3 零宕机必备之Pod探针
4.4 pod的退出流程
4.5 pod实践
五、RC和RS
5.1 Replication Controller
5.2 ReplicaSet
六、Deployment
6.1 创建一个Deployment
6.2 Deployment的更新
6.3 Deployment的回滚
6.4 Deployment的暂停
6.5 Deployment的恢复
6.6 Deployment的扩缩容
6.7 Deployment的配置项
七、StatefulSet
7.1 StatefulSet的基本概念
7.2 StatefulSet注意事项
7.3 创建一个StatefulSet
7.4 statefulset特征
7.5 statfulset更新
7.6 statfulset灰度发布
7.7 statfulset删除和级联删除
7.8 statfulset更新和回滚
九、DaemoSet
9.1 DaemonSet是什么?
9.2 定义一个DaemonSet
9.3 DaemonSet更新和回滚
9.4 DaemonSet更新策略
十、HPA(水平pod扩缩容)
10.1 HPA实践
10.2 HPA注意事项
十一、服务发布
11.1 label和selector
11.2 label操作
11.3 service
11.4 Ingress
Kubernetes入门
一、为什么需要Kubernetes
1.1 传统的容器编排痛点
容器技术虽然解决了应用和基础设施异构的问题,让应用可以做到一次构建,多次部署,但在复杂的微服务场景,单靠 Docker 技术还不够,它仍然有以下问题没有解决:
- 集成和编排微服务模块
- 提供按需自动扩容,缩容能力
- 故障自愈
- 集群内的通信
1.2 Kubernetes 能解决的问题
- 按需的垂直扩容,新的服务器(node)能够轻易的增加或删除
- 按需的水平扩容,容器实例能够轻松扩容,缩容
- 副本控制器,你不用担心副本的状态
- 服务发现和路由
- 自动部署和回滚,如果应用状态错误,可以实现自动回滚
1.3 什么时候使用 Kubernetes?
- 应用是微服务架构
- 开发者需要快速部署自己的新功能到测试环境进行验证
- 降低硬件资源成本,提高使用率
1.4 什么时候不适合使用 Kubernetes
- 应用是轻量级的单体应用,没有高并发的需求
- 团队文化不适应变革
二、Kubernetes的发展
- 2014年6月 谷歌云计算专家Eric Brewer在旧金山的发布会为这款新的开源工具揭牌。
- 2015年7月22日K8S迭代到 v 1.0并在OSCON大会上正式对外公布。为了建立容器编排领域的标准和规范,Google、RedHat 等开源基础设施领域玩家们,在 2015 年共同牵头发起了名为 CNCF(Cloud Native Computing Foundation)的基金会。Kubernetes 成为 CNCF 最核心的项目。
发起成员:AT&T, Box, Cisco, Cloud Foundry Foundation, CoreOS, Cycle Computing, Docker, eBay, Goldman Sachs, Google, Huawei, IBM, Intel, Joyent, Kismatic, Mesosphere, Red Hat, Switch SUPERNAP, Twitter, Univa, VMware and Weaveworks。
- 2018年,超过 1700 开发者成为 Kubernetes 项目社区贡献者,全球有 500 多场沙龙。国内出现大量基于 Kubernetes 的创业公司。
- 2020 年,Kubernetes 项目已经成为贡献者仅次于 Linux 项目的第二大开源项目。成为了业界容器编排的事实标准,各大厂商纷纷宣布支持 Kubernetes 作为容器编排的方案。
三、kubernetes组成
3.1 Master节点
- Kube-APIServer:集群的控制中枢,各个模块之间信息交互都需要经过Kube-APIServer,同时它也是集群管理、资源配额、整个集群安全机制的入口。【信息交互,大脑】
- Controller-Manager:集群的状态管理器,保证Pod或其他资源达到期望值,也是需要和APIServer进行通信,在需要的时候创建、更新或删除它所管理的资源。【资源管理,控制】
- Scheduler:集群的调度中心,它会根据指定的一系列条件,选择一个或一批最佳的节点,然后部署我们的Pod。【资源分配,调度】
- Etcd:键值数据库,保存一些集群的信息,一般生产环境中建议部署三个以上节点(奇数个)。【数据存储,存储】
3.2 Node工作节点
Worker、node节点、minion节点
- Kubelet:负责监听节点上Pod的状态,同时负责上报节点和节点上面Pod的状态,负责与Master节点通信,并管理节点上面的Pod。
- Kube-proxy:负责Pod之间的通信和负载均衡,将指定的流量分发到后端正确的机器上。
查看Kube-proxy工作模式:curl 127.0.0.1:10249/proxyMode
Ipvs:监听Master节点增加和删除service以及endpoint的消息,调用Netlink接口创建相应的IPVS规则。通过IPVS规则,将流量转发至相应的Pod上。
Iptables:监听Master节点增加和删除service以及endpoint的消息,对于每一个Service,他都会创建一个iptables规则,将service的clusterIP代理到后端对应的Pod。
3.3 其他组件
- Calico:符合CNI标准的网络插件,给每个Pod生成一个唯一的IP地址,并且把每个节点当做一个路由器。最新Cilium插件,可关注
- CoreDNS:用于Kubernetes集群内部Service的解析,可以让Pod把Service名称解析成IP地址,然后通过Service的IP地址进行连接到对应的应用上。
- Docker:容器引擎,负责对容器的管理。
四、Pod
4.1 Pod是什么
Pod是Kubernetes中最小的单元,它由一组、一个或多个容器组成,每个Pod还包含了一个Pause容器,Pause容器是Pod的父容器,主要负责僵尸进程的回收管理,通过Pause容器可以使同一个Pod里面的多个容器共享存储、网络、PID、IPC等。
4.2 Pod定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | apiVersion: v1 # 必选,API的版本号 kind: Pod # 必选,类型Pod metadata: # 必选,元数据 name: nginx # 必选,符合RFC 1035规范的Pod名称 namespace: default # 可选,Pod所在的命名空间,不指定默认为default,可以使用-n 指定namespace labels: # 可选,标签选择器,一般用于过滤和区分Pod app: nginx role: frontend # 可以写多个 annotations: # 可选,注释列表,可以写多个 app: nginx #格式要求不是很严格 spec: # 必选,用于定义容器的详细信息 initContainers: # 初始化容器,在容器启动之前执行的一些初始化操作 - command : - sh - -c - echo "I am InitContainer for init some configuration" image: busybox imagePullPolicy: IfNotPresent name: init-container containers: # 必选,容器列表 - name: nginx # 必选,符合RFC 1035规范的容器名称 image: nginx:latest # 必选,容器所用的镜像的地址 imagePullPolicy: Always # 可选,镜像拉取策略 command : # 可选,容器启动执行的命令 - nginx - -g - "daemon off;" workingDir: /usr/share/nginx/html # 可选,容器的工作目录 volumeMounts: # 可选,存储卷配置,可以配置多个 - name: webroot # 存储卷名称 mountPath: /usr/share/nginx/html # 挂载目录 readOnly: true # 只读 ports: # 可选,容器需要暴露的端口号列表 - name: http # 端口名称 containerPort: 80 # 端口号 protocol: TCP # 端口协议,默认TCP env : # 可选,环境变量配置列表 - name: TZ # 变量名 value: Asia /Shanghai # 变量的值 - name: LANG value: en_US.utf8 resources: # 可选,资源限制和资源请求限制 limits: # 最大限制设置 cpu: 1000m memory: 1024Mi requests: # 启动所需的资源 cpu: 100m memory: 512Mi # startupProbe: # 可选,检测容器内进程是否完成启动。注意三种检查方式同时只能使用一种。 # httpGet: # httpGet检测方式,生产环境建议使用httpGet实现接口级健康检查,健康检查由应用程序提供。 # path: /api/successStart # 检查路径 # port: 80 readinessProbe: # 可选,健康检查。注意三种检查方式同时只能使用一种。 httpGet: # httpGet检测方式,生产环境建议使用httpGet实现接口级健康检查,健康检查由应用程序提供。 path: / # 检查路径 port: 80 # 监控端口 livenessProbe: # 可选,健康检查 #exec: # 执行容器命令检测方式 #command: #- cat #- /health #httpGet: # httpGet检测方式 # path: /_health # 检查路径 # port: 8080 # httpHeaders: # 检查的请求头 # - name: end-user # value: Jason tcpSocket: # 端口检测方式 port: 80 initialDelaySeconds: 60 # 初始化时间 timeoutSeconds: 2 # 超时时间 periodSeconds: 5 # 检测间隔 successThreshold: 1 # 检查成功为2次表示就绪 failureThreshold: 2 # 检测失败1次表示未就绪 lifecycle: postStart: # 容器创建完成后执行的指令, 可以是exec httpGet TCPSocket exec : command : - sh - -c - 'mkdir /data/ ' preStop: httpGet: path: / port: 80 # exec: # command: # - sh # - -c # - sleep 9 restartPolicy: Always # 可选,默认为Always #nodeSelector: # 可选,指定Node节点 # region: subnet7 imagePullSecrets: # 可选,拉取镜像使用的secret,可以配置多个 - name: default-dockercfg-86258 hostNetwork: false # 可选,是否为主机模式,如是,会占用主机端口 volumes: # 共享存储卷列表 - name: webroot # 名称,与上述对应 emptyDir: {} # 挂载目录 #hostPath: # 挂载本机目录 # path: /etc/hosts |
4.3 零宕机必备之Pod探针
- StartupProbe:k8s1.16版本后新加的探测方式,用于判断容器内应用程序是否已经启动。如果配置了startupProbe,就会先禁止其他的探测,直到它成功为止,成功后将不在进行探测。【判断容器内的程序是否正常提供服务】
- LivenessProbe:用于探测容器是否运行,如果探测失败,kubelet会根据配置的重启策略进行相应的处理。若没有配置该探针,默认就是success。【判断容器是否运行或者判断容器是否需要重启】
- ReadinessProbe:一般用于探测容器内的程序是否健康,它的返回值如果为success,那么久代表这个容器已经完成启动,并且程序已经是可以接受流量的状态。【判断容器内的程序是否健康】
4.3.1 Pod探针的检测方式
- ExecAction:在容器内执行一个命令,如果返回值为0,则认为容器健康。
- TCPSocketAction:通过TCP连接检查容器内的端口是否是通的,如果是通的就认为容器健康。
- HTTPGetAction:通过应用程序暴露的API地址来检查程序是否是正常的,如果状态码为200~400之间,则认为容器健康。
4.3.2 探针使用场景
- LivenessProbe探针
如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活态探针; kubelet
将根据 Pod 的 restartPolicy
自动执行修复操作。
如果你希望容器在探测失败时被杀死并重新启动,那么请指定一个存活态探针, 并指定 restartPolicy
为 "Always
" 或 "OnFailure
"。
- ReadinessProbe探针
如果要仅在探测成功时才开始向 Pod 发送请求流量,请指定就绪态探针。 在这种情况下,就绪态探针可能与存活态探针相同,但是规约中的就绪态探针的存在意味着 Pod 将在启动阶段不接收任何数据,并且只有在探针探测成功后才开始接收数据。
如果你希望容器能够自行进入维护状态,也可以指定一个就绪态探针, 检查某个特定于就绪态的因此不同于存活态探测的端点。
如果你的应用程序对后端服务有严格的依赖性,你可以同时实现存活态和就绪态探针。 当应用程序本身是健康的,存活态探针检测通过后,就绪态探针会额外检查每个所需的后端服务是否可用。 这可以帮助你避免将流量导向只能返回错误信息的 Pod。
如果你的容器需要在启动期间加载大型数据、配置文件或执行迁移, 你可以使用启动探针。 然而,如果你想区分已经失败的应用和仍在处理其启动数据的应用,你可能更倾向于使用就绪探针。
- StartupProbe探针
对于所包含的容器需要较长时间才能启动就绪的 Pod 而言,启动探针是有用的。 你不再需要配置一个较长的存活态探测时间间隔,只需要设置另一个独立的配置选定, 对启动期间的容器执行探测,从而允许使用远远超出存活态时间间隔所允许的时长。
如果你的容器启动时间通常超出 initialDelaySeconds + failureThreshold × periodSeconds
总值,你应该设置一个启动探测,对存活态探针所使用的同一端点执行检查。 periodSeconds
的默认值是 10 秒。你应该将其 failureThreshold
设置得足够高, 以
便容器有充足的时间完成启动,并且避免更改存活态探针所使用的默认值。 这一设置有助于减少死锁状况的发生。
4.3.3 探针参数
# initialDelaySeconds: 60 # 初始化时间,容器初始化的时间
# timeoutSeconds: 2 # 超时时间
# periodSeconds: 5 # 检测间隔
# successThreshold: 1 # 检查成功为1次表示就绪
# failureThreshold: 2 # 检测失败2次表示未就绪
探针整体设计思路:
由于有些程序可能启动时间比较长,所以新增了StartupProbe探针。一旦启用了StartupProbe探针,其他2个就禁用了,等StartupProbe探针检测完成后,再进行容器存活和容器ready检测。
4.4 pod的退出流程
pod退出的流程,当用户执行删除pod操作时:
1、pod的状态变为terminating
2、endpoint中删除该pod的ip
3、执行prestop命令,进行pod退出前的一些清理操作
优雅退出默认时间:30s
terminationGracePeriodSeconds: 30
如果我们希望更长,可以进行配置;或者命令行 kubectl delete pod nginx --grace-period=40
4.5 pod实践
定义一个pod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | apiVersion: v1 # 必选,API的版本号 kind: Pod # 必选,类型Pod metadata: # 必选,元数据 name: nginx # 必选,符合RFC 1035规范的Pod名称 namespace: default # 可选,Pod所在的命名空间,不指定默认为default,可以使用-n 指定namespace labels: # 可选,标签选择器,一般用于过滤和区分Pod app: nginx role: frontend # 可以写多个 annotations: # 可选,注释列表,可以写多个 app: nginx spec: # 必选,用于定义容器的详细信息 containers: # 必选,容器列表 - name: nginx # 必选,符合RFC 1035规范的容器名称 image: nginx:1.15.2 # 必选,容器所用的镜像的地址 imagePullPolicy: IfNotPresent # 可选,镜像拉取策略, IfNotPresent: 如果宿主机有这个镜像,那就不需要拉取了. Always: 总是拉取, Never: 不管是否存储都不拉去 command : # 可选,容器启动执行的命令 ENTRYPOINT, arg --> cmd - nginx - -g - "daemon off;" workingDir: /usr/share/nginx/html # 可选,容器的工作目录 ports: # 可选,容器需要暴露的端口号列表 - name: http # 端口名称 containerPort: 80 # 端口号 protocol: TCP # 端口协议,默认TCP env : # 可选,环境变量配置列表 - name: TZ # 变量名 value: Asia /Shanghai # 变量的值 - name: LANG value: en_US.utf8 #exec: # 执行容器命令检测方式 #command: #- cat #- /health startupProbe: tcpSocket: port: 80 |
创建pod
1 2 | [root@k8s-master01 ~] # kubectl apply -f nginx-pod.yaml pod /nginx created |
查看pod
1 2 3 | [root@k8s-master01 ~] # kubectl get pod NAME READY STATUS RESTARTS AGE nginx 1 /1 Running 0 32s |
查看pod实时动态
1 | kubectl get pod -w<br>kubectl |
五、RC和RS
Replication Controller(复制控制器,RC)和ReplicaSet(复制集,RS)是两种简单部署Pod的方式。因为在生产环境中,主要使用更高级的Deployment等方式进行Pod的管理和部署,所以本节只对Replication Controller和Replica Set的部署方式进行简单介绍。
5.1 Replication Controller
Replication Controller(简称RC)可确保Pod副本数达到期望值,也就是RC定义的数量。换句话说,Replication Controller可确保一个Pod或一组同类Pod总是可用。
如果存在的Pod大于设定的值,则Replication Controller将终止额外的Pod。如果太小,Replication Controller将启动更多的Pod用于保证达到期望值。与手动创建Pod不同的是,用Replication Controller维护的Pod在失败、删除或终止时会自动替换。因此即使应用程序只需要一个Pod,也应该使用Replication Controller或其他方式管理。Replication Controller类似于进程管理程序,但是Replication Controller不是监视单个节点上的各个进程,而是监视多个节点上的多个Pod。
定义一个Replication Controller的示例如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | apiVersion: v1 kind: ReplicationController metadata: name: nginx spec: replicas: 3 selector: app: nginx template: metadata: name: nginx labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 |
5.2 ReplicaSet
ReplicaSet是支持基于集合的标签选择器的下一代Replication Controller,它主要用作Deployment协调创建、删除和更新Pod,和Replication Controller唯一的区别是,ReplicaSet支持标签选择器。在实际应用中,虽然ReplicaSet可以单独使用,但是一般建议使用Deployment来自动管理ReplicaSet,除非自定义的Pod不需要更新或有其他编排等。
定义一个ReplicaSet的示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | apiVersion: apps /v1 kind: ReplicaSet metadata: name: frontend labels: app: guestbook tier: frontend spec: # modify replicas according to your case replicas: 3 selector: matchLabels: tier: frontend matchExpressions: - {key: tier, operator: In, values: [frontend]} template: metadata: labels: app: guestbook tier: frontend spec: containers: - name: php-redis image: gcr.io /google_samples/gb-frontend :v3 resources: requests: cpu: 100m memory: 100Mi env : - name: GET_HOSTS_FROM value: dns # If your cluster config does not include a dns service, then to # instead access environment variables to find service host # info, comment out the 'value: dns' line above, and uncomment the # line below. # value: env ports: - containerPort: 80 |
Replication Controller和ReplicaSet的创建删除和Pod并无太大区别,Replication Controller目前几乎已经不在生产环境中使用,ReplicaSet也很少单独被使用,都是使用更高级的资源Deployment、DaemonSet、StatefulSet进行管理Pod。
六、Deployment
用于部署无状态的服务,这个最常用的控制器。一般用于管理维护企业内部无状态的微服务,比如configserver、zuul、springboot。他可以管理多个副本的Pod实现无缝迁移、自动扩容缩容、自动灾难恢复、一键回滚等功能。
6.1 创建一个Deployment
手动创建:
1 | kubectl create deployment nginx --image=nginx:1.15.2 |
从文件创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # cat nginx-deploy.yaml apiVersion: apps /v1 kind: Deployment metadata: annotations: deployment.kubernetes.io /revision : "1" creationTimestamp: "2020-09-19T02:41:11Z" generation: 1 labels: app: nginx name: nginx namespace: default spec: progressDeadlineSeconds: 600 replicas: 2 #副本数 revisionHistoryLimit: 10 # 历史记录保留的个数 selector: matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type : RollingUpdate template: metadata: creationTimestamp: null labels: app: nginx spec: containers: - image: nginx:1.15.2 imagePullPolicy: IfNotPresent name: nginx resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 |
从文件创建:
1 | kubelet apply -f nginx-deploy.yaml |
查看deployment
1 2 3 | [root@k8s-master01 ~ /k8s ] # kubectl get deploy -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR nginx 2 /2 2 2 3m42s nginx nginx:1.15.2 app=nginx |
- NAME: Deployment名称
- READY:Pod的状态,已经Ready的个数
- UP-TO-DATE:已经达到期望状态的被更新的副本数
- AVAILABLE:已经可以用的副本数
- AGE:显示应用程序运行的时间
- CONTAINERS:容器名称
- IMAGES:容器的镜像
- SELECTOR:管理的Pod的标签
可以直接通过修改replicas数量来动态调整pod的数量,pod创建后,不可动态修改labels,需要删掉pod后,重建pod才行。
6.2 Deployment的更新
更改deployment的镜像并记录:
1 | kubectl set image deploy nginx nginx=nginx:1.15.3 –record |
查看更新过程:
1 2 3 4 5 6 7 8 9 | # kubectl rollout status deploy nginx deployment "nginx" successfully rolled out [root@k8s-master01 ~] # kubectl rollout status deploy nginx Waiting for deployment "nginx" rollout to finish: 1 out of 2 new replicas have been updated... Waiting for deployment "nginx" rollout to finish: 1 out of 2 new replicas have been updated... Waiting for deployment "nginx" rollout to finish: 1 out of 2 new replicas have been updated... Waiting for deployment "nginx" rollout to finish: 1 old replicas are pending termination... Waiting for deployment "nginx" rollout to finish: 1 old replicas are pending termination... deployment "nginx" successfully rolled out |
或者使用describe查看:
1 2 3 4 5 6 7 8 9 10 11 | # kubectl describe deploy nginx Normal ScalingReplicaSet 25m deployment-controller Scaled up replica set nginx-66bbc9fdc5 to 1 Normal ScalingReplicaSet 18m (x2 over 23m) deployment-controller Scaled up replica set nginx-66bbc9fdc5 to 2 Normal ScalingReplicaSet 7m7s deployment-controller Scaled up replica set nginx-5dfc8689c6 to 1 Normal ScalingReplicaSet 6m28s (x2 over 23m) deployment-controller Scaled down replica set nginx-66bbc9fdc5 to 1 Normal ScalingReplicaSet 6m27s deployment-controller Scaled up replica set nginx-5dfc8689c6 to 2 Normal ScalingReplicaSet 5m58s deployment-controller Scaled down replica set nginx-66bbc9fdc5 to 0 Normal ScalingReplicaSet 4m19s deployment-controller Scaled up replica set nginx-6cdd5dd489 to 1 Normal ScalingReplicaSet 3m44s deployment-controller Scaled down replica set nginx-5dfc8689c6 to 1 Normal ScalingReplicaSet 3m44s deployment-controller Scaled up replica set nginx-6cdd5dd489 to 2 Normal ScalingReplicaSet 3m6s deployment-controller Scaled down replica set nginx-5dfc8689c6 to 0 |
6.3 Deployment的回滚
# 执行更新操作
模拟操作一个不存在或者错误的镜像:
1 2 3 4 5 6 7 | [root@k8s-master01 ~] # kubectl set image deploy nginx nginx=nginx:787977da --record deployment.apps /nginx image updated [root@k8s-master01 ~] # kubectl get po NAME READY STATUS RESTARTS AGE nginx-6cdd5dd489-lv28z 1 /1 Running 0 7m12s nginx-6cdd5dd489-nqqz7 1 /1 Running 0 6m37s nginx-7d79b96f68-x7t67 0 /1 ContainerCreating 0 19s |
查看历史版本
1 2 3 4 5 6 7 | [root@k8s-master01 ~] # kubectl rollout history deploy nginx deployment.apps /nginx REVISION CHANGE-CAUSE 1 <none> 2 kubectl set image deploy nginx nginx=nginx:1.15.3 --record= true 3 kubectl set image deploy nginx nginx=nginx:1.15.4 --record= true 4 kubectl set image deploy nginx nginx=nginx:787977da --record= true |
回滚到上一个版本
1 2 | [root@k8s-master01 ~] # kubectl rollout undo deploy nginx deployment.apps /nginx rolled back |
查看回滚结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [root@k8s-master01 ~] # kubectl get po NAME READY STATUS RESTARTS AGE nginx-6cdd5dd489-lv28z 1 /1 Running 0 9m8s nginx-6cdd5dd489-nqqz7 1 /1 Running 0 8m33s [root@k8s-master01 ~] # kubectl get deploy nginx -oyaml | grep nginx kubernetes.io /change-cause : kubectl set image deploy nginx nginx=nginx:1.15.4 app: nginx k:{ "name" : "nginx" }: k:{ "name" : "nginx" }: name: nginx selfLink: /apis/apps/v1/namespaces/default/deployments/nginx app: nginx app: nginx - image: nginx:1.15.4 name: nginx message: ReplicaSet "nginx-6cdd5dd489" has successfully progressed. |
进行多次更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@k8s-master01 ~] # kubectl set image deploy nginx nginx=nginx:787977da --record deployment.apps /nginx image updated [root@k8s-master01 ~] # kubectl set image deploy nginx nginx=nginx:787977dadaa --record deployment.apps /nginx image updated [root@k8s-master01 ~] # kubectl set image deploy nginx nginx=nginx:787977xxxxxdadaa --record deployment.apps /nginx image updated [root@k8s-master01 ~] # kubectl set image deploy nginx nginx=nginx:787977dadxxxxxdadaa --record deployment.apps /nginx image updated [root@k8s-master01 ~] # # 查看历史记录 [root@k8s-master01 ~] # kubectl rollout history deploy nginx deployment.apps /nginx REVISION CHANGE-CAUSE 1 <none> 2 kubectl set image deploy nginx nginx=nginx:1.15.3 --record= true 5 kubectl set image deploy nginx nginx=nginx:1.15.4 --record= true 6 kubectl set image deploy nginx nginx=nginx:787977da --record= true 7 kubectl set image deploy nginx nginx=nginx:787977dadaa --record= true 8 kubectl set image deploy nginx nginx=nginx:787977xxxxxdadaa --record= true 9 kubectl set image deploy nginx nginx=nginx:787977dadxxxxxdadaa --record= true |
查看指定版本的详细信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | [root@k8s-master01 ~] # kubectl rollout history deploy nginx --revision=5 deployment.apps /nginx with revision #5 Pod Template: Labels: app=nginx pod-template- hash =6cdd5dd489 Annotations: kubernetes.io /change-cause : kubectl set image deploy nginx nginx=nginx:1.15.4 --record= true Containers: nginx: Image: nginx:1.15.4 Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none> |
回滚到任意指定版本
1 2 | [root@k8s-master01 ~] # kubectl rollout undo deploy nginx --to-revision=5 deployment.apps /nginx rolled back |
查看deploy状态
1 | [root@k8s-master01 ~] # kubectl get deploy -oyaml |
6.4 Deployment的暂停
Deployment 暂停功能
1 2 | [root@k8s-master01 ~] # kubectl rollout pause deployment nginx deployment.apps /nginx paused |
暂停后多次配置
第一次配置
修改deploy镜像
1 2 | [root@k8s-master01 ~] # kubectl set image deploy nginx nginx=nginx:1.15.3 --record deployment.apps /nginx image updated |
第二次配置
暂停后添加内存CPU配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | [root@k8s-master01 ~] # kubectl set resources deploy nginx -c nginx --limits=cpu=200m,memory=128Mi --requests=cpu=10m,memory=16Mi deployment.apps /nginx resource requirements updated [root@k8s-master01 ~] # kubectl get deploy nginx -oyaml apiVersion: apps /v1 kind: Deployment metadata: annotations: deployment.kubernetes.io /revision : "11" kubernetes.io /change-cause : kubectl set image deploy nginx nginx=nginx:1.15.3 --record= true creationTimestamp: "2020-09-19T02:41:11Z" generation: 18 labels: app: nginx name: nginx namespace: default resourceVersion: "2660534" selfLink: /apis/apps/v1/namespaces/default/deployments/nginx uid: 1d9253a5-a36c-48cc-aefe-56f95967db66 spec: paused: true progressDeadlineSeconds: 600 replicas: 2 revisionHistoryLimit: 10 selector: matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type : RollingUpdate template: metadata: creationTimestamp: null labels: app: nginx spec: containers: - image: nginx:1.15.3 imagePullPolicy: IfNotPresent name: nginx resources: limits: cpu: 200m memory: 128Mi requests: cpu: 10m memory: 16Mi terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 status: availableReplicas: 2 conditions: - lastTransitionTime: "2020-09-19T03:26:50Z" lastUpdateTime: "2020-09-19T03:26:50Z" message: Deployment has minimum availability. reason: MinimumReplicasAvailable status: "True" type : Available - lastTransitionTime: "2020-09-19T03:30:15Z" lastUpdateTime: "2020-09-19T03:30:15Z" message: Deployment is paused reason: DeploymentPaused status: Unknown type : Progressing observedGeneration: 18 readyReplicas: 2 replicas: 2 |
查看pod是否被更新
1 2 3 4 | [root@k8s-master01 ~] # kubectl get po NAME READY STATUS RESTARTS AGE nginx-6cdd5dd489-lv28z 1 /1 Running 0 30m nginx-6cdd5dd489-nqqz7 1 /1 Running 0 30m |
6.5 Deployment的恢复
1 2 3 4 5 6 7 8 9 10 11 12 | [root@k8s-master01 ~] # kubectl rollout resume deploy nginx deployment.apps /nginx resumed [root@k8s-master01 ~] # kubectl get rs NAME DESIRED CURRENT READY AGE nginx-5475c49ffb 0 0 0 21m nginx-5dfc8689c6 0 0 0 33m nginx-66bbc9fdc5 0 0 0 52m nginx-68db656dd8 1 1 0 15s nginx-6cdd5dd489 2 2 2 31m nginx-799b8478d4 0 0 0 21m nginx-7d79b96f68 0 0 0 24m nginx-f974656f7 0 0 0 21m |
6.6 Deployment的扩缩容
1 | kubectl scale --replicas=1 deploy nginx |
扩缩容不会增加rs,因为他只是增加或减少某个rs下的pod数量。
6.7 Deployment的配置项
- .spec.revisionHistoryLimit:设置保留RS旧的revision的个数,设置为0的话,不保留历史数据
- .spec.minReadySeconds:可选参数,指定新创建的Pod在没有任何容器崩溃的情况下视为Ready最小的秒数,默认为0,即一旦被创建就视为可用。
滚动更新的策略:
.spec.strategy.type:更新deployment的方式,默认是RollingUpdate
- RollingUpdate:滚动更新,可以指定maxSurge和maxUnavailable
maxUnavailable:指定在回滚或更新时最大不可用的Pod的数量,可选字段,默认25%,可以设置成数字或百分比,如果该值为0,那么maxSurge就不能0。
maxSurge:可以超过期望值的最大Pod数,可选字段,默认为25%,可以设置成数字或百分比,如果该值为0,那么maxUnavailable不能为0
假如副本4个,如果最大不可用设置成0,最大期望也是0,那就没法滚动了。最大不可用至少为1,最大期望值可以是0或者以上的值,才能进行滚动;
同理,最大期望如果设置成0,则最大不可用至少必须设置1,才能进行滚动。
- Recreate:重建,先删除旧的Pod,再创建新的Pod
七、StatefulSet
StatefulSet(有状态集,缩写为sts)常用于部署有状态的且需要有序启动的应用程序,比如在进行SpringCloud项目容器化时,Eureka的部署是比较适合用StatefulSet部署方式的,可以给每个Eureka实例创建一个唯一且固定的标识符,并且每个Eureka实例无需配置多余的Service,其余Spring Boot应用可以直接通过Eureka的Headless Service即可进行注册。
1 2 3 4 5 6 7 | Eureka的statefulset的资源名称是eureka,eureka-0 eureka-1 eureka-2 Service:headless service,没有ClusterIP eureka-svc Eureka-0.eureka-svc.NAMESPACE_NAME eureka-1.eureka-svc.NAMESPACE_NAME eureka-N-1.eureka-svc...... |
7.1 StatefulSet的基本概念
StatefulSet主要用于管理有状态应用程序的工作负载API对象。比如在生产环境中,可以部署ElasticSearch集群、MongoDB集群或者需要持久化的RabbitMQ集群、Redis集群、Kafka集群和ZooKeeper集群等。
和Deployment类似,一个StatefulSet也同样管理着基于相同容器规范的Pod。不同的是,StatefulSet为每个Pod维护了一个粘性标识。这些Pod是根据相同的规范创建的,但是不可互换,每个Pod都有一个持久的标识符,在重新调度时也会保留,一般格式为StatefulSetName-Number。比如定义一个名字是Redis-Sentinel的StatefulSet,指定创建三个Pod,那么创建出来的Pod名字就为Redis-Sentinel-0、Redis-Sentinel-1、Redis-Sentinel-2。而StatefulSet创建的Pod一般使用Headless Service(无头服务)进行通信,和普通的Service的区别在于Headless Service没有ClusterIP,它使用的是Endpoint进行互相通信,Headless一般的格式为:
statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local。
说明:
- serviceName为Headless Service的名字,创建StatefulSet时,必须指定Headless Service名称;
- 0..N-1为Pod所在的序号,从0开始到N-1;
- statefulSetName为StatefulSet的名字;
- namespace为服务所在的命名空间;
- .cluster.local为Cluster Domain(集群域)。
假如公司某个项目需要在Kubernetes中部署一个主从模式的Redis,此时使用StatefulSet部署就极为合适,因为StatefulSet启动时,只有当前一个容器完全启动时,后一个容器才会被调度,并且每个容器的标识符是固定的,那么就可以通过标识符来断定当前Pod的角色。
比如用一个名为redis-ms的StatefulSet部署主从架构的Redis,第一个容器启动时,它的标识符为redis-ms-0,并且Pod内主机名也为redis-ms-0,此时就可以根据主机名来判断,当主机名为redis-ms-0的容器作为Redis的主节点,其余从节点,那么Slave连接Master主机配置就可以使用不会更改的Master的Headless Service,此时Redis从节点(Slave)配置文件如下:
1 2 3 4 5 6 7 8 9 10 11 | port 6379 slaveof redis-ms-0.redis-ms.public-service.svc.cluster. local 6379 tcp-backlog 511 timeout 0 tcp-keepalive 0 …… |
其中redis-ms-0.redis-ms.public-service.svc.cluster.local是Redis Master的Headless Service,在同一命名空间下只需要写redis-ms-0.redis-ms即可,后面的public-service.svc.cluster.local可以省略。
7.2 StatefulSet注意事项
一般StatefulSet用于有以下一个或者多个需求的应用程序:
- 需要稳定的独一无二的网络标识符。
- 需要持久化数据。
- 需要有序的、优雅的部署和扩展。
- 需要有序的自动滚动更新。
StatefulSet注意事项
- 如果应用程序不需要任何稳定的标识符或者有序的部署、删除或者扩展,应该使用无状态的控制器部署应用程序,比如Deployment或者ReplicaSet。
- StatefulSet是Kubernetes 1.9版本之前的beta资源,在1.5版本之前的任何Kubernetes版本都没有。
- Pod所用的存储必须由PersistentVolume Provisioner(持久化卷配置器)根据请求配置StorageClass,或者由管理员预先配置,当然也可以不配置存储。
- 为了确保数据安全,删除和缩放StatefulSet不会删除与StatefulSet关联的卷,可以手动选择性地删除PVC和PV(关于PV和PVC请参考2.2.12节)。
- StatefulSet目前使用Headless Service(无头服务)负责Pod的网络身份和通信,需要提前创建此服务。
- 删除一个StatefulSet时,不保证对Pod的终止,要在StatefulSet中实现Pod的有序和正常终止,可以在删除之前将StatefulSet的副本缩减为0。
7.3 创建一个StatefulSet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | [root@k8s-master01 ~ /k8s ] # cat nginx-sts.yaml apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps /v1 kind: StatefulSet metadata: name: web spec: serviceName: "nginx" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.15.2 ports: - containerPort: 80 name: web |
创建statefulset
1 2 3 | [root@k8s-master01 ~ /k8s ] # kubectl apply -f nginx-sts.yaml service /nginx created statefulset.apps /web created |
查看statefulset的svc
1 2 3 4 5 | web-1 1 /1 Running 0 10s [root@k8s-master01 ~ /k8s ] # kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 192.168.0.1 <none> 443 /TCP 21d nginx ClusterIP None <none> 80 /TCP 18s |
新创建的statefulset的svc是一个无头服务,也就是他没有ep,直接可以通过svc进行访问服务,这样就少了一层代理。
我们直接通过服务访问后端pod,启动一个busybox:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: busybox namespace: default spec: containers: - name: busybox image: busybox:1.28 command: - sleep - "3600" imagePullPolicy: IfNotPresent restartPolicy: Always EOF |
对服务进程访问
1 2 3 4 5 6 7 8 9 10 11 12 | [root@k8s-master01 ~ /k8s ] # kubectl get pods -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES busybox 1 /1 Running 0 38s 172.17.125.14 k8s-node01 <none> <none> nginx 1 /1 Running 0 120m 172.25.244.200 k8s-master01 <none> <none> nginx-5dfc8689c6-bdxk7 1 /1 Running 0 65m 172.27.14.195 k8s-node02 <none> <none> web-0 1 /1 Running 0 3m53s 172.25.92.71 k8s-master02 <none> <none> web-1 1 /1 Running 0 3m52s 172.17.125.13 k8s-node01 <none> <none> [root@k8s-master01 ~ /k8s ] # kubectl exec -it busybox sh kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. / # ping web-0.nginx.default PING web-0.nginx.default (172.25.92.71): 56 data bytes 64 bytes from 172.25.92.71: seq =0 ttl=62 time =0.244 ms |
可以看到,我们通过statefulset-name-0.svc-name.namespace.svc.cluster.local进行服务访问。
7.4 statefulset特征
1、启动的时候,一定是web-0启动成功后,才会启动web-1;同样,删除的时候,是从最后一个开始删,删除最后一个后,再删除倒数第二个。
7.5 statfulset更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | apiVersion: apps /v1 kind: StatefulSet metadata: annotations: name: web namespace: default spec: replicas: 2 revisionHistoryLimit: 10 selector: matchLabels: app: nginx serviceName: nginx template: metadata: labels: app: nginx spec: containers: - image: nginx:1.15.2 imagePullPolicy: IfNotPresent name: nginx ports: - containerPort: 80 name: web protocol: TCP resources: limits: cpu: 1000m memory: 100Mi requests: cpu: 10m memory: 10Mi dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 updateStrategy: rollingUpdate: partition: 0 type : RollingUpdate |
更新策略:滚动更新
7.6 statfulset灰度发布
1 | partition参数设置 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | apiVersion: apps /v1 kind: StatefulSet metadata: annotations: name: web namespace: default spec: replicas: 5 revisionHistoryLimit: 10 selector: matchLabels: app: nginx serviceName: nginx template: metadata: labels: app: nginx type : statefulset spec: containers: - image: nginx:1.15.2 imagePullPolicy: IfNotPresent name: nginx ports: - containerPort: 80 name: web protocol: TCP resources: limits: cpu: 1000m memory: 100Mi requests: cpu: 10m memory: 10Mi dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 updateStrategy: rollingUpdate: partition: 3 # 从第三个pod开始更新 type : RollingUpdate |
7.7 statfulset删除和级联删除
级联删除:删除statefulset的同时删除pod(默认)
1 | kubectl delete sts web |
非级联删除:删除statefulset的同时不删除pod
1 | kubectl delete sts web --cascade= false |
这样删除会出现孤儿pod,即pod无法管理了,删除pod后就没了。
7.8 statfulset更新和回滚
statefulset更新:
1 | kubectl set image sts web nginx=nginx:1.15.1 --record= true |
statefulset回滚:
1 2 3 4 | #查看历史版本 kubectl rollout history sts web #回滚到上一个版本 kubectl rollout undo sts web |
statefulset回滚到任意指定版本:
1 2 3 4 5 6 7 8 9 10 11 | #查看历史版本 kubectl rollout history sts web #查看当前镜像 kubectl get pods -l type =statefulset -o yaml| grep image #回滚到指定版本 kubectl rollout undo sts web --to-revision=14 #查看当前镜像 kubectl get pods -l type =statefulset -o yaml| grep image |
九、DaemoSet
9.1 DaemonSet是什么?
DaemonSet:守护进程集,缩写为ds,在所有节点或者是匹配的节点上都部署一个Pod。
使用DaemonSet的场景
- 运行集群存储的daemon,比如ceph或者glusterd
- 节点的CNI网络插件,calico
- 节点日志的收集:fluentd或者是filebeat
- 节点的监控:node exporter
- 服务暴露:部署一个ingress nginx
9.2 定义一个DaemonSet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | apiVersion: apps /v1 kind: DaemonSet metadata: annotations: name: web namespace: default spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeSelector: ds: "true" containers: - image: nginx:1.15.2 imagePullPolicy: IfNotPresent name: nginx ports: - containerPort: 80 name: web protocol: TCP resources: limits: cpu: 1000m memory: 100Mi requests: cpu: 10m memory: 10Mi dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 |
其中:nodeSelector用于节点选择。
1 | kubectl label node k8s-node01 ds= true |
节点打上标签后就会在上面创建对应的pod。
9.3 DaemonSet更新和回滚
Daemonset更新
Daemonset回滚
9.4 DaemonSet更新策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #滚动更新 updateStrategy: rollingUpdate: maxSurge: 0 maxUnavailable: 1 type : RollingUpdate #即使删除 updateStrategy: rollingUpdate: maxSurge: 0 maxUnavailable: 1 type : OnDelete |
建议使用OnDelete方式,删除某个pod后,进行更新,查看没问题后,全部更新。【灰度更新方式】
十、HPA(水平pod扩缩容)
10.1 HPA实践
DaemonSet无法自动扩缩容,他的初衷就是每个node部署一个。
1、创建deloyment
1 | kubectl create deployment nginx-server-hpa --image=nginx:1.15.2 --port=80 --dry-run=client -o yaml>hpa-deloy.yaml |
2、增加reources
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | apiVersion: apps /v1 kind: Deployment metadata: creationTimestamp: null labels: app: nginx-server-hpa name: nginx-server-hpa spec: replicas: 1 selector: matchLabels: app: nginx-server-hpa strategy: {} template: metadata: creationTimestamp: null labels: app: nginx-server-hpa spec: containers: - image: nginx:1.15.2 name: nginx ports: - containerPort: 80 resources: requests: cpu: 10m status: {} |
3、暴露服务
1 2 | [root@k8s-master01 ~ /k8s ] # kubectl expose deployment nginx-server-hpa --port=80 service /nginx-server-hpa exposed |
4、查看服务并访问
1 2 3 4 5 | [root@k8s-master01 ~ /k8s ] # kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 192.168.0.1 <none> 443 /TCP 24d nginx ClusterIP None <none> 80 /TCP 2d13h nginx-server-hpa ClusterIP 192.168.166.198 <none> 80 /TCP 5s |
5、创建hpa
1 2 | [root@k8s-master01 ~ /k8s ] # kubectl autoscale deployment nginx-server-hpa --cpu-percent=10 --min=1 --max=10 horizontalpodautoscaler.autoscaling /nginx-server-hpa autoscaled |
查看hpa
1 2 3 | [root@k8s-master01 ~ /k8s ] # kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-server-hpa Deployment /nginx-server-hpa <unknown> /10 % 1 10 0 6s |
再次查看
1 2 3 | [root@k8s-master01 ~ /k8s ] # kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-server-hpa Deployment /nginx-server-hpa 0% /10 % 1 10 1 78s |
10.2 HPA注意事项
1 2 3 4 5 6 | 注意事项: 1、必须安装metrics-server或其他自定义metrics-server 2、必须配置requests参数 3、不能扩容无法缩放的对象,比如DaemonSet 4、要考虑压力的根本原因,假如是后端的瓶颈,我们扩容front,是没有作用的。 此时,需要后端提供压力接口才能进行扩缩容。 |
十一、服务发布
11.1 label和selector
Label:对k8s中各种资源进行分类、分组,添加一个具有特别属性的一个标签。
Selector:通过一个过滤的语法进行查找到对应标签的资源
11.2 label操作
1 2 3 4 5 6 7 8 9 10 11 12 13 | #创建标签 kubectl label pods nginx unhealthy= true #修改标签 kubectl label --overwrite pods nginx status=unhealthy #删除标签 kubectl label pods nginx app- #过滤资源 kubectl get pods -l 'app in (nginx,nginx-server-hpa)' -owide --show-labels kubectl get pods -l 'app in (nginx,nginx-server-hpa)' ,controller-revision- hash !=web-cdd4c789b -owide --show-labels |
11.3 service
在k8s中,service用于东西流量的实现,而南北流量则是通过ingress实现。
11.3.1 service定义
Service可以简单的理解为逻辑上的一组Pod。一种可以访问Pod的策略,而且其他Pod可以通过这个Service访问到这个Service代理的Pod。相对于Pod而言,它会有一个固定的名称,一旦创建就固定不变。
service创建后,同时会创建一个同名的EP(endpoint),也就是podIP:port的记录,记录了service调度到后端的信息。
11.3.2 创建一个service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # cat nginx-svc.yaml apiVersion: v1 kind: Service metadata: labels: app: nginx-svc name: nginx-svc spec: ports: - name: http # Service端口的名称 port: 80 # Service自己的端口, servicea --> serviceb http://serviceb, http://serviceb:8080 protocol: TCP # UDP TCP SCTP default: TCP targetPort: 80 # 后端应用的端口 - name: https port: 443 protocol: TCP targetPort: 443 selector: app: nginx sessionAffinity: None type : ClusterIP |
11.3.3 为什么要有service?
访问服务时,我们可以通过svc直接访问后端的pod,因为pod经常创建和删除,为了保证服务一直连接,而不关心后端pod,所以引进了svc。
service ==> endpoint ==> pod
11.3.4 使用Service代理k8s外部应用
使用场景:
- 希望在生产环境中使用某个固定的名称而非IP地址进行访问外部的中间件服务
- 希望Service指向另一个Namespace中或其他集群中的服务
- 某个项目正在迁移至k8s集群,但是一部分服务仍然在集群外部,此时可以使用service代理至k8s集群外部的服务
通过service反代外部服务,我们可以统一配置文件,即使从外部迁移到容器内部,也不需要修改配置文件,只需要修改EP的地址!非常方便。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # cat nginx-svc-external.yaml apiVersion: v1 kind: Service metadata: labels: app: nginx-svc-external name: nginx-svc-external spec: ports: - name: http # Service端口的名称 port: 80 # Service自己的端口, servicea --> serviceb http://serviceb, http://serviceb:8080 protocol: TCP # UDP TCP SCTP default: TCP targetPort: 8081 # 后端应用的端口 sessionAffinity: None type : ClusterIP #创建好了svc后,ep不会自动创建,需要我们手动创建一个ep,指向后端代理的服务。我们这里使用baidu的地址来测试。 # cat nginx-ep-external.yaml apiVersion: v1 kind: Endpoints metadata: labels: app: nginx-svc-external name: nginx-svc-external namespace: default subsets: - addresses: - ip: 140.205.94.189 ports: - name: http port: 8081 protocol: TCP |
测试:
11.3.5 使用Service代理域名
1 2 3 4 5 6 7 8 9 | apiVersion: v1 kind: Service metadata: labels: app: nginx-externalname name: nginx-externalname spec: type : ExternalName externalName: www.baidu.com |
注意:说明: ExternalName 服务接受 IPv4 地址字符串,但作为包含数字的 DNS 名称,而不是 IP 地址。实测下来,这里使用IP地址不行
11.3.6 service的常见类型
- ClusterIP:在集群内部使用,也是默认值。
- ExternalName:通过返回定义的CNAME别名。一定要使用域名!
- NodePort:在所有安装了kube-proxy的节点上打开一个端口,此端口可以代理至后端Pod,然后集群外部可以使用节点的IP地址和NodePort的端口号访问到集群Pod的服务。NodePort端口范围默认是30000-32767。
- LoadBalancer:使用云提供商的负载均衡器公开服务。
11.4 Ingress
11.4.1 Ingress安装
通俗来讲,ingress和之前提到的Service、Deployment,也是一个k8s的资源类型,ingress用于实现用域名的方式访问k8s内部应用。
首先安装helm管理工具:https://helm.sh/docs/intro/install/
使用helm安装ingress:https://kubernetes.github.io/ingress-nginx/deploy/#using-helm
添加ingress的helm仓库(课程讲解的版本已经上传至百度网盘)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
下载ingress的helm包至本地
helm pull ingress-nginx/ingress-nginx
1 2 3 4 5 | tar xf ingress-nginx-3.6.0.tgz cd ingress-nginx vim values.yaml |
更改对应的配置
- a) Controller和admissionWebhook的镜像地址,需要将公网镜像同步至公司内网镜像仓库(和课程不一致的版本,需要自行同步gcr镜像的,可以百度查一下使用阿里云同步gcr的镜像,也可以参考这个连接https://blog.csdn.net/weixin_39961559/article/details/80739352,或者参考这个连接: https://blog.csdn.net/sinat_35543900/article/details/103290782)
- b) hostNetwork设置为true
- c) dnsPolicy设置为 ClusterFirstWithHostNet
- d) NodeSelector添加ingress: "true"部署至指定节点
- e) 类型更改为kind: DaemonSet
部署ingress
给需要部署ingress的节点上打标签
1 2 3 4 5 | kubectl label node k8s-master03 ingress= true kubectl create ns ingress-nginx helm install ingress-nginx -n ingress-nginx . |
- 将ingress controller部署至Node节点(ingress controller不能部署在master节点,需要安装视频中的步骤将ingress controller部署至Node节点,生产环境最少三个ingress controller,并且最好是独立的节点)
kubectl label node k8s-node01 ingress=true
kubectl label node k8s-master03 ingress-
11.4.2 Ingress入门使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | apiVersion: networking.k8s.io /v1beta1 # networking.k8s.io/v1 / extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io /ingress .class: "nginx" name: example spec: rules: # 一个Ingress可以配置多个rules - host: foo.bar.com # 域名配置,可以不写,匹配*, *.bar.com http: paths: # 相当于nginx的location配合,同一个host可以配置多个path / /abc - backend: serviceName: nginx-svc servicePort: 80 path: / - host: foo2.bar.com # 域名配置,可以不写,匹配*, *.bar.com http: paths: # 相当于nginx的location配合,同一个host可以配置多个path / /abc - backend: serviceName: nginx-externalname servicePort: 80 path: /test |
说明:
- 配置了2个主机,一个后端服务是nginx-svc,另一个后端服务是nginx-externalname
- 确保后端服务都是可用的
- 本地测试,在本机上写hosts,hosts为ingress的主机ip
1 2 | #ingress-nginx所在机器的ip<br>10.10.2.129 foo.bar.com 10.10.2.129 foo2.bar.com |
验证:
集群级别的资源,没有命名空间隔离。
classrole
classrolebinding
storageclass
ingressclass
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步