K8S & EKS 简介与实践

Posted 踏破四方猪脚部

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了K8S & EKS 简介与实践相关的知识,希望对你有一定的参考价值。

本文面向有一定容器化基础知识的同学,介绍一些 K8S 的基础概念和 AWS EKS 的使用实践,使读者能快速了解一些使用细节并上手实践。权威文档:https://kubernetes.io/zh/docs/home/

EKS

K8S 相关基本信息不再赘述。EKS 是 AWS 提供的托管 K8S 集群,etcd 集群由 AWS 完全托管,保障高可用,进行升级等操作,避免了自建集群的一些弊端。
创建集群和添加工作节点等集群机器资源的相关操作由 AWS 提供的eksctl命令进行操作,整个过程全部单命令化,不需要考虑 K8S 相关集群操作细节。
在创建集群后,仍然使用标准的kubectl命令使用集群,与普通的 K8S 集群没有区别。
这里对于没有使用过 EKS 的同学来说有一个误区:以为eksctl是 AWS 封装后用来代替kubectl的命令。但其实并不是这样的,集群仍然是遵循 K8S 标准的使用方式进行。
因为 K8S 本身版本迭代的节奏就很快,所以 EKS 的迭代节奏也很快。一般大约每 3 个月提供一个新的版本,每个次要版本在发布后大约支持 12 个月。如果选择使用 EKS 则需要适应这个更新节奏。

Pod

Pod 是 K8S 管理的最小单位级,它是一个或多个容器的组合。这些容器共享存储、网络和命名空间。举个例子,在同一个 Pod 下的多个容器可以通过 localhost 进行互通,Pod 是它们的逻辑主机,Pod 包含业务相关的多个应用容器。
Pod 是不稳定的,Pod 的数据是易失的。在 Pod 中运行的程序需要遵循这样的设计标准,不要依赖 Pod 中的任何数据,将程序运行的状态设计到 Pod 外部,使其“无状态”化。这样即使 Pod 挂掉,也会由 K8S 服务启动新的 Pod 代替已经挂掉的 Pod,保障业务正常运转。

Deployment & ReplicaSets & Service

一个 Deployment 控制器为 Pods 和 ReplicaSets 提供声明式的更新能力。
Deployment 的概念类似于 swarm 的服务的概念,由它管理 ReplicaSets,而 ReplicaSets 用于保证 Pod 数量,当 Pod 挂掉时启动新的 Pod,当 Pod 数量过多时杀掉多余的 Pod。
对于常规用户来说没有必要直接使用 ReplicaSets 或者 Pods。由 Deployment 负责保证副本数和版本,由 Service 负责通过 label 筛选出指定 Pod 并对外提供服务。
一份典型的、完整的 Deployment yaml 文件如下(附描述):
  
    
    
  
apiVersion : apps/v1
kind : Deployment
metadata :
# 指定deployment的名称
name : nginx
labels :
servicename : nginx
namespace : default
spec :
# 期望创建的pod数
replicas : 3 # r5.large的单node最大pod数为29(包括系统pod)
selector :
# 选择label来创建实例
matchLabels :
servicename : nginx
strategy : # 策略
rollingUpdate : # 滚动更新
maxSurge : 1 # 最大额外可以存在的副本数,可以为百分比,也可以为整数
maxUnavailable : 1 # 示在更新过程中能够进入不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
type : RollingUpdate # 滚动更新策略
template :
metadata :
labels :
servicename : nginx
spec :
containers :
- name : nginx
image : nginx :1.19.2
ports :
- containerPort : 80
resources :
requests :
cpu : "0.1"
memory : 32Mi
limits :
cpu : "1"
memory : 2048Mi
# https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
# https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/#container-probes
# startupProbe目前是 v1.16 [alpha] 状态,暂不启用
livenessProbe :
httpGet :
path : / ?from=k8slivenessProbe
port : 80
initialDelaySeconds : 10 # 容器启动后要等待多少秒后存活和就绪探测器才被初始化,默认是 0 秒,最小值是 0。
periodSeconds : 10 # 执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。
timeoutSeconds : 5 # 探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。
successThreshold : 1 # 探测器在失败后,被视为成功的最小连续成功数。默认值是 1。存活探测的这个值必须是 1。最小值是 1。
failureThreshold : 3 # 当探测失败时,Kubernetes 的重试次数。存活探测情况下的放弃就意味着重新启动容器。就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1。
readinessProbe :
httpGet :
path : / ?from=k8sreadinessProbe
port : 80
initialDelaySeconds : 0 # 容器启动后要等待多少秒后存活和就绪探测器才被初始化,默认是 0 秒,最小值是 0。
periodSeconds : 10 # 执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。
timeoutSeconds : 5 # 探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。
successThreshold : 1 # 探测器在失败后,被视为成功的最小连续成功数。默认值是 1。存活探测的这个值必须是 1。最小值是 1。
failureThreshold : 3 # 当探测失败时,Kubernetes 的重试次数。存活探测情况下的放弃就意味着重新启动容器。就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1。
lifecycle :
preStop :
exec :
# 该命令会在业务容器中执行,如果容器中没有sleep命令,则会直接失败,不会等待30s
command :[ "sleep" , "30" ]
terminationGracePeriodSeconds : 60
# nodeSelector:
# alpha.eksctl.io/nodegroup-name: ng-workers-1
常规部署,只需要修改 yaml 文件的镜像的 tag,然后kubectl apply -f deployment.yaml即可。对于 yaml 文件,强烈建议通过 git 进行版本控制,这样可以追溯到每一次版本变更的细节,方便回滚或者排查问题。
Deployment 中并不是所有的字段都可以修改然后 apply。比如labels相关就不行,必须 kubectl replace,相关细节可以查询 K8S 官方文档。

网络

每个 Pod 会被分配一个唯一的 IP 地址,如果我们选择 K8S 默认的网络策略,使用集群内部的网络负载均衡机制,那么这个 IP 是集群内部的 IP,在集群外部无法通过这个 IP 访问 Pod。
AWS 提供了 EKS 网络插件,它可以给每个 Pod 分配一个 VPC 下的 IP,可以认为是将 Pod 直接暴露到 EC2 所在的内网。Pod 是 VPC 下的一等公民,Pod 和 EC2 可以通过 IP 相互访问,这样简化了网络拓扑,不管是从性能上还是从排查问题的角度上都更加方便。
基于这样的机制,我们的负载均衡并不是走 K8S 内部,而是通过 Service 的标签筛选出所有的 Pod,获取到这些 Pod 的 VPC 下 IP,然后注册到 AWS 的 Load Balancer 中,流量直接从负载均衡器打到 Pod 上。
这样将 Pod 直接开放到 VPC 下有一个需要注意的问题,因为 Pod 数量和内网 IP 一一对应,所以内网 IP 消耗量特别大,保守估计需要为一个 K8S 集群预留 8k 个 IP。

日志收集

这里采用 K8S 推荐的日志收集方案,具体是将 fluentd 的容器以 DaemonSet 的形式部署到每个节点上,以 tail 日志文件的形式收集日志并投递到统一的日志收集中心。收集日志的组件可以有多种选择,我们现在采用的是通过 GELF 协议将日志通过 logstash 直接落地到磁盘,然后通过日志轮转脚本备份到 S3。

金丝雀发布

https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/#canary-deployment
对于同一个服务,存在两个 deployment,分别命名为 canary 和 stable,这两个概念不存在于 K8S 中,而是人为定义的。
初始状态 canary 的 Pod 数为0,stable 的 Pod 数为正常数量,新老版本 Pod 都可以通过相同的 label 被同一个 Service 选中,并导流。
在进行一次金丝雀发布时,首先将 canary 的 Pod 的版本修改为新版,并扩充一定 Pod 数量,使新老版本并存,新版 Pod 可以分到一部分流量并其观察行为。如果无异常,则逐渐扩充 canary 的 Pod 数,直到认为无异常后,将 stable 的 Pod 版本修改为新版本并部署,canary 的副本数重新置为 0,则完成一次金丝雀发布。
有更方便的工具可以做到金丝雀发布自动化,但是我们现阶段希望控制引入的新工具的数量,当前状态下,这部分流程手动控制不会对发布效率造成很大影响。

有状态服务

如果只是常规使用 K8S 的用户,一般不建议将 Redis、mysql 等有状态服务放入 K8S 集群中运行。将他们放在集群外部,单独进行精心维护,或者直接使用云服务商提供的托管服务更好。

以上是关于K8S & EKS 简介与实践的主要内容,如果未能解决你的问题,请参考以下文章

Amazon EKS 与 JFrog Artifactory容器化CI/CD发布的最佳实践

Day920.结构化日志&业务审计日志 -SpringBoot与K8s云原生微服务实践

AWS EKS 详细升级流程

k8s实践liveness与readiness 2种探针使用

基于K8s的DevOps平台实践

基于K8s的DevOps平台实践