Spinnaker第四节-对接k8s

前一篇我们介绍了Spinnaker是如何对接和管理实例云的,本篇我们将介绍Spinnaker如何对接k8s

Spinnaker在对接实例云时已经为我们做过很好的铺垫,让我们接触到Immutable的发布方式,并体验到随之而来的好处。K8s将Immutable发挥到极致,将版本的创建与销毁由分钟级提高到秒级。

 

Spinnaker管理K8S的前世今生

Spinnaker曾经按照管理实例的方式推出过一版对接k8s的管理机制,我们这里叫他V1,设计思路与上一篇中的pipeline一模一样,也是拆分为bake、deploy、scaledown、destroy等。

后来Spinnaker推出了V2版,也就是现在主推的版本,基于manifest的管理思路,以声明式的设计彻底颠覆了V1版的思想,使pipeline变得简单高效、便于管理。

以下所有内容都是基于V2版本展开介绍。

 

Spinnaker对接K8S的条件

必要条件:config+kubelet

Spinnaker管理云平台肯定需要配置认证信息来得到云平台的授权,K8S也不例外,对于K8S的授权配置只需要在.kube目录下存放容器云的config认证文件既可,跟aws有点类似,aws的认证是将key和secret存放在.aws目录下。

Spinnaker操作实例云平台是通过SDK,代码中直接调用云平台的各个接口;而Spinnkaer操作K8S是通过kubelet,代码转化成本地的kubelet命令的方式来实现的。所以一定要在spinnaker部署的机器上预先安装好kubelet。

推荐条件:交付仓库(Artifact)

Spinnaker支持S3、Http、Github、Gitlab等各种交付仓库,在对接K8S时交付仓库主要用来存放manifest文件的。虽然Spinnaker的Pipeline中可以直接读写manifest,如下图:

但是不适用于代码配置分离或者企业具有CMDB的场景,我们只让spinnaker运行manifest,而自身并不维护manifest时,将manifest的配置和管理交给Artifact,将采用这种方式:

Spinnaker如何干预K8S

了解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管理K8S初级pipeline

这里所谓初级,就是代码和配置在一起的独立镜像,spinnaker只负责deployment就好,不需要关心镜像内容。Pipeline如下

图中有2个service,test_service为测试环境提供服务,product_service为生产环境提供服务。

图中有4条pipeline,前两条为测试pipeline,第三条为灰度发布pipeline,第四条为生产发布pipeline。以下是详细介绍:

第一条:测试Pipeline

manifest挂在外存储中,spinnaker自身不关心资源文件,当外存储manifest发生变化时通过webhook自动触发测试环境更新操作。

Start:传入包含manifest文件的git配置,由git的webhook来自动触发

Deployment:

第二条:测试Pipeline(推荐)

manifest在spinnaker中维护,外系统传入镜像tag触发测试环境镜像更新操作。

Start:传入镜像的tag,可以由webhook来自动触发,也可以被Jenkins任务触发

Deployment:

第三条:灰度Pipeline

触发时传入镜像tag,新建副本数1的一个replicaSet挂载到生产service,观察结束后销毁灰度set,根据灰度观察结果选择是否触发生产Pipeline

Destroy环节:

根据灰度deployment时设置的标签,当灰度结束后可以删除这些pod

触发生产的Pipeline:

当灰度发布结果为yes时,触发下一级pipeline,并将镜像tag参数透传下去。

第四条:生产Pipeline

触发时传入镜像tag,按照生产现有副本数创建replicaSet,采用RollingUpdate的方式更新pod

这一步就很简单了,注意两点。

1 Deployment采用RollingUpdate的发布方式

2 strategy.spinnaker.io/use-source-capacity: 'true'这个annotation保证生产pod的容量。

 

Spinnaker对接K8S高阶pipeline

像我们这种有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:

配置详情:

secret的manifest:

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

configMap的manifest:

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

deployment的manifest:

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的不足

Spinnaker对于K8S的定位是持续部署工具,并不是核心的K8S管理工具,比起rancher这种专业的工具在管理上存在很大的差距。例如镜像授权、namespace管理、用户管理、性能监控、容器日志输出和控制台登陆等spinnaker都不支持。所以对于spinnaker的定位很重要,如果你们企业缺少一个自动发布的持续部署工具,请选择spinnaker;如果你们企业缺少一个专业的K8S管理工具,请选择Rancher。当然你可以两个都选(我们公司就是这么用的),因为spinnaker与rancher是可以兼容的,因为它们的数据来源都来自K8S本身。Spinnaker负责管理pod、service、ingress和发布流程,rancher负责管理namespace等其它spinnaker管理不了的资源。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Kubernetes (k8s) 是一种流行的容器编排平台,可以大大简化应用程序的部署和管理。CI/CD(持续集成/持续交付)管道是软件开发过程中的关键环节,可以将代码从开发到部署的流程自动化和加速。在 k8s 上部署 CI/CD 管道的步骤如下: 1. 创建代码仓库。您可以使用 Git 或其他版本控制工具。确保您的代码仓库可以与 CI/CD 工具集成。 2. 配置 CI 工具。这可以是 Jenkins、GitLab CI、CircleCI 等等。您需要将 CI 工具配置为从代码仓库拉取代码,并将其构建为容器镜像。确保您的 CI 工具可以与 Kubernetes 集群通信。 3. 配置 Docker Registry。您需要一个 Docker Registry 来存储构建的容器镜像,以便它们可以在 Kubernetes 集群中使用。您可以使用 Docker Hub、Google Container Registry、AWS ECR 等等。 4. 创建 Kubernetes 资源定义文件。这些文件告诉 Kubernetes 如何部署和管理您的应用程序。确保您的资源定义文件包含必要的配置和环境变量,以及指向您的 Docker Registry 的正确信息。 5. 部署应用程序。使用 kubectl 工具将 Kubernetes 资源定义文件应用于 Kubernetes 集群。 6. 配置 CD 工具。这可以是 Helm、Spinnaker、Argo CD 等等。您需要将 CD 工具配置为从 Docker Registry 拉取构建的容器镜像,并将其部署到 Kubernetes 集群。确保您的 CD 工具可以与 Kubernetes 集群通信。 7. 自动化部署。使用 CD 工具将新版本的应用程序自动部署到 Kubernetes 集群中。 总的来说,上述步骤是一个基本的 CI/CD 管道部署过程。当然,具体实现方式会因不同的应用程序和工具而异。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值