Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
k8s spec_k8s解决了什么问题,希望能够帮助你!!!。
前一篇我们介绍了Spinnaker是如何对接和管理实例云的,本篇我们将介绍Spinnaker如何对接k8s
Spinnaker在对接实例云时已经为我们做过很好的铺垫,让我们接触到Immutable的发布方式,并体验到随之而来的好处。K8s将Immutable发挥到极致,将版本的创建与销毁由分钟级提高到秒级。
Spinnaker曾经按照管理实例的方式推出过一版对接k8s的管理机制,我们这里叫他V1,设计思路与上一篇中的pipeline一模一样,也是拆分为bake、deploy、scaledown、destroy等。
后来Spinnaker推出了V2版,也就是现在主推的版本,基于manifest的管理思路,以声明式的设计彻底颠覆了V1版的思想,使pipeline变得简单高效、便于管理。
以下所有内容都是基于V2版本展开介绍。
Spinnaker管理云平台肯定需要配置认证信息来得到云平台的授权,K8S也不例外,对于K8S的授权配置只需要在.kube目录下存放容器云的config认证文件既可,跟aws有点类似,aws的认证是将key和secret存放在.aws目录下。
Spinnaker操作实例云平台是通过SDK,代码中直接调用云平台的各个接口;而Spinnkaer操作K8S是通过kubelet,代码转化成本地的kubelet命令的方式来实现的。所以一定要在spinnaker部署的机器上预先安装好kubelet。
Spinnaker支持S3、Http、Github、Gitlab等各种交付仓库,在对接K8S时交付仓库主要用来存放manifest文件的。虽然Spinnaker的Pipeline中可以直接读写manifest,如下图:
但是不适用于代码配置分离或者企业具有CMDB的场景,我们只让spinnaker运行manifest,而自身并不维护manifest时,将manifest的配置和管理交给Artifact,将采用这种方式:
了解K8S的同学都知道,manifest是声明式的,不管现状是怎样的,manifest文件中代表的是最终的目的和结果。对于manifest我计划下个月写一篇博文详细解读下,这里先看一个简单的例子:
apiVersion: apps/v1 kind: Deployment metadata: annotations: artifact.spinnaker.io/location: devops artifact.spinnaker.io/name: ci-gateway artifact.spinnaker.io/type: kubernetes/deployment moniker.spinnaker.io/application: ci moniker.spinnaker.io/cluster: ci-gateway strategy.spinnaker.io/max-version-history: '1' strategy.spinnaker.io/use-source-capacity: 'true' labels: app.kubernetes.io/managed-by: spinnaker app.kubernetes.io/name: ci-gateway name: ci-gateway namespace: devops spec: replicas: 1 selector: matchLabels: k8s-app: ci-gateway strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: annotations: artifact.spinnaker.io/location: devops artifact.spinnaker.io/name: ci-gateway artifact.spinnaker.io/type: kubernetes/deployment moniker.spinnaker.io/application: ci moniker.spinnaker.io/cluster: ci-gateway labels: app.kubernetes.io/managed-by: spinnaker app.kubernetes.io/name: ci-gateway configMap.version: '${ parameters.config_version}' k8s-app: ci-gateway task: monitoring spec: containers: - args: - '--spring.config.location=application.yml' image: 'hub.imgo.tv/spinnaker/gateway:${ parameters.image_version}' imagePullPolicy: IfNotPresent livenessProbe: httpGet: path: / port: 9000 scheme: HTTP initialDelaySeconds: 30 timeoutSeconds: 5 name: ci-gateway volumeMounts: - mountPath: /usr/lib/application.yml name: app-conf subPath: application.yml - mountPath: /usr/lib/iplist.txt name: app-conf subPath: iplist.txt volumes: - configMap: items: - key: application.yml path: application.yml - key: iplist.txt path: iplist.txt name: 'ci-gateway-configmap-${ parameters.config_version}' name: app-conf
这是一个deployment的manifest,采用滚筒发布,其中${}内是spinnaker的pipeline中定义的一些动态变量。
那么问题来了,Spinnaker最高理想是全自动,pipeline在初次配置后不需要再维护了,假如我生产某个replicaSet配有自动容缩的能力,一旦需要更换镜像岂不是被manifest强行恢复到pipeline中预设的副本数了么?Spinnaker的设计者早就想到了这个问题,解决思路是通过annotation。
strategy.spinnaker.io/use-source-capacity这个annotation就是为了专门解决上面的问题而设计的,默认为false,如果配置为true代表着直接使用replicaSet现有的容量,忽视manifest中配置的副本数!
类似的annotation还有很多,这一个个annotation解决了对接中的很多痛点。
moniker.spinnaker.io/application:资源属于哪个app
moniker.spinnaker.io/cluster:资源属于哪个cluster
strategy.spinnaker.io/max-version-history:replicaSet保留几个历史版本
strategy.spinnaker.io/recreate:deployment的时候是否每次都要重建pod
我猜想它的原理有点像Java开发Spring的AOP,有一个切面就是专门处理各种annotation的,有些annotation是前置加强,有些是后续加强,有些是循环加强。像strategy.spinnaker.io/use-source-capacity这个annotation应该就是前置加强了,spinnaker看到manifest中有这个annotation,先去k8s中获取到真实的容量,然后覆盖掉manifest中的副本数,才有了我们现在看到的这种“反声明式”的神奇效果。
这里所谓初级,就是代码和配置在一起的独立镜像,spinnaker只负责deployment就好,不需要关心镜像内容。Pipeline如下
图中有2个service,test_service为测试环境提供服务,product_service为生产环境提供服务。
图中有4条pipeline,前两条为测试pipeline,第三条为灰度发布pipeline,第四条为生产发布pipeline。以下是详细介绍:
manifest挂在外存储中,spinnaker自身不关心资源文件,当外存储manifest发生变化时通过webhook自动触发测试环境更新操作。
Start:传入包含manifest文件的git配置,由git的webhook来自动触发
Deployment:
manifest在spinnaker中维护,外系统传入镜像tag触发测试环境镜像更新操作。
Start:传入镜像的tag,可以由webhook来自动触发,也可以被Jenkins任务触发
Deployment:
触发时传入镜像tag,新建副本数1的一个replicaSet挂载到生产service,观察结束后销毁灰度set,根据灰度观察结果选择是否触发生产Pipeline
Destroy环节:
根据灰度deployment时设置的标签,当灰度结束后可以删除这些pod
触发生产的Pipeline:
当灰度发布结果为yes时,触发下一级pipeline,并将镜像tag参数透传下去。
触发时传入镜像tag,按照生产现有副本数创建replicaSet,采用RollingUpdate的方式更新pod
这一步就很简单了,注意两点。
1 Deployment采用RollingUpdate的发布方式
2 strategy.spinnaker.io/use-source-capacity: 'true'这个annotation保证生产pod的容量。
像我们这种有CMDB的企业,配置和代码都是分离的,研发只负责开发代码,敏感信息和软件配置信息是由业务运维来维护的。这种场景就需要用到K8S的configMap和Secret,Pipeline的设计和产品发布系统就需要重新设计,如下:
1 Harbor中镜像tag要显示的区分是内测版、公测版、发布版本
2 configMap和secret需要区分测试环境还是生产环境,其中configMap需要有版本的概念,secret无需版本的概念
其中ConfigMap和Secret的manifest直接通过http方式向cmdb获取,spinnaker本身来维护deployment的manifest。
Start:传入镜像tag和configMap版本动态参数,同时向cmdb去索取configMap和secret的manifest。可以由jenkins触发、harbor触发、webhook触发。
获取configMap:
获取secret:
动态参数:
Deploy ConfigMap:
Deploy Secret:
Deploy Pod:
apiVersion: v1 data: youdu_appId: my_youdu_app_id youdu_buin: my_youdu_buin youdu_encodingaesKey: my_youdu_encodingaes_key kind: Secret metadata: name: ci-youdu-secret namespace: devops type: Opaque
apiVersion: v1 kind: ConfigMap metadata: name: ci-youdu-configmap-v1 namespace: devops data: application.yml: | server: port: 8098 spring: application: name: ci-youdu eureka: instance: preferIpAddress: true instanceId: ${spring.cloud.client.ipAddress}:${server.port} hostname: ci-register client: serviceUrl: defaultZone: http://ci-register:8111/eureka/ youdu: address: im.imgo.tv:7080 swagger: enabled: true
apiVersion: apps/v1beta1 kind: Deployment metadata: annotations: artifact.spinnaker.io/location: devops artifact.spinnaker.io/name: ci-youdu artifact.spinnaker.io/type: kubernetes/deployment moniker.spinnaker.io/application: ci moniker.spinnaker.io/cluster: ci-youdu strategy.spinnaker.io/max-version-history: '1' strategy.spinnaker.io/use-source-capacity: 'true' labels: app.kubernetes.io/managed-by: spinnaker app.kubernetes.io/name: ci-youdu name: ci-youdu namespace: devops spec: replicas: 1 selector: matchLabels: k8s-app: ci-youdu strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: annotations: artifact.spinnaker.io/location: devops artifact.spinnaker.io/name: ci-youdu artifact.spinnaker.io/type: kubernetes/deployment moniker.spinnaker.io/application: ci moniker.spinnaker.io/cluster: ci-youdu labels: app.kubernetes.io/managed-by: spinnaker app.kubernetes.io/name: ci-youdu configMap.version: '${ parameters.config_version}' k8s-app: ci-youdu task: monitoring spec: containers: - args: - '--spring.config.location=application.yml' env: - name: youdu_appId valueFrom: secretKeyRef: key: youdu_appId name: ci-youdu-secret - name: youdu_buin valueFrom: secretKeyRef: key: youdu_buin name: ci-youdu-secret - name: youdu_encodingaesKey valueFrom: secretKeyRef: key: youdu_encodingaesKey name: ci-youdu-secret image: 'hub.imgo.tv/spinnaker/youdu:${ parameters.image_version}' imagePullPolicy: IfNotPresent livenessProbe: httpGet: path: / port: 8098 scheme: HTTP initialDelaySeconds: 30 timeoutSeconds: 5 name: ci-youdu volumeMounts: - mountPath: /usr/lib/application.yml name: app-conf subPath: application.yml volumes: - configMap: items: - key: application.yml path: application.yml name: 'ci-youdu-configmap-${ parameters.config_version}' name: app-conf
Spinnaker对于K8S的定位是持续部署工具,并不是核心的K8S管理工具,比起rancher这种专业的工具在管理上存在很大的差距。例如镜像授权、namespace管理、用户管理、性能监控、容器日志输出和控制台登陆等spinnaker都不支持。所以对于spinnaker的定位很重要,如果你们企业缺少一个自动发布的持续部署工具,请选择spinnaker;如果你们企业缺少一个专业的K8S管理工具,请选择Rancher。当然你可以两个都选(我们公司就是这么用的),因为spinnaker与rancher是可以兼容的,因为它们的数据来源都来自K8S本身。Spinnaker负责管理pod、service、ingress和发布流程,rancher负责管理namespace等其它spinnaker管理不了的资源。
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
上一篇
已是最后文章
下一篇
已是最新文章