Spinnaker 是一种持续交付平台,最初由 Netflix 开发,用于快速、可靠地发布软件变更。Spinnaker 使开发人员可以更轻松地专注于编写代码,而无需担心底层的云基础设施,它可以和 Jenkins 以及其他流行的构建工具无缝集成。很早就想要体验下 Spinnaker 了,但是由于 GFW 的原因尝试了很多次都无功而返,这次解决了代理的问题终于顺利的在 Kubernetes 集群上成功部署上了 Spinnaker。

本文将使用 helm3 来为大家演示在 Kubernetes 集群上安装 Spinnaker,对应的环境版本如下所示:

$ helm version

version.BuildInfo{Version:"v3.0.1", GitCommit:"7c22ef9ce89e0ebeb7125ba2ebf7d421f3e82ffa", GitTreeState:"clean", GoVersion:"go1.13.4"}

$ kubectl version

Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.2", GitCommit:"66049e3b21efe110454d67df4fa62b08ea79a19b", GitTreeState:"clean", BuildDate:"2019-05-16T18:55:03Z", GoVersion:"go1.12.5", Compiler:"gc", Platform:"darwin/amd64"}

Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:09:08Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}

对于 Helm3 的安装配置其实很简单,只需要在 kubectl 所在节点上面安装上 Helm3 客户端即可,默认就会读取 kubeconfig 文件来访问集群。我们这里使用微软提供的 helm chart 仓库源:

$  helm repo ls

NAME            URL

stable          http://mirror.azure.cn/kubernetes/charts/

$ helm repo update

Hang tight while we grab the latest from your chart repositories...

...Successfully got an update from the "stable" chart repository

Update Complete. ⎈ Happy Helming!⎈ 

由于我们这里使用的是 Kubernetes 1.16.x 版本,该版本之后将之前很多资源对象的一些旧的 API 废弃掉了,比如 Deployment 只能使用 apps/v1 这个版本了,而我们这里要使用的 Spinnaker 对应的 chart 包目前还是使用的以前的 API 版本,所以我们需要手动下载下来做一次更改:

$ helm fetch stable/spinnaker

$ tar -xvf spinnaker-1.23.2.tgz

然后将 spinnaker chart 模板中的 Deployment、StatefulSet 这些资源对象的 apiVersion 更改成 apps/v1,也需要记住如果是 Deployment 还需要添加上 selector.matchLabels 字段,大家可以直接使用我更改后的 chart 模板 https://github.com/cnych/spinnaker-helm。

在 chart 模板的 values.yaml 文件中指定了 halyard.spinnakerVersion=1.17.6,这还是因为 apiVersion 版本的问题,该版本以上就可以兼容 Kubernetes v1.16.x 的集群,另外将默认的 gcr.io 的镜像替换成了微软的镜像源 gcr.azk8s.cn,此外还有一个非常重要的就是存储的指定,这里我们创建了一个 StorageClass 的资源对象来提供存储,我这里是创建的一个 CephRBD 类型的存储 rook-ceph-block,当然任何可用的 StorageClass 资源对象都是可以的:

apiVersion: storage.k8s.io/v1

kind: StorageClass

metadata:

   name: rook-ceph-block

provisioner: rook-ceph.rbd.csi.ceph.com

reclaimPolicy: Retain

parameters:

    # clusterID 是 rook 集群运行的命名空间

    clusterID: rook-ceph


    # 指定存储池

    pool: k8s-test-pool


    # RBD image (实际的存储介质) 格式. 默认为 "2".

    imageFormat: "2"


    # RBD image 特性. CSI RBD 现在只支持 `layering` .

    imageFeatures: layering


    # Ceph 管理员认证信息,这些都是在 clusterID 命名空间下面自动生成的

    csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner

    csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph

    csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node

    csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph

    # 指定 volume 的文件系统格式,如果不指定, csi-provisioner 会默认设置为 `ext4`

    csi.storage.k8s.io/fstype: ext4

需要为 halyard、redis、mino 都指定对应的存储,当然直接指定一个合适的 PVC 也是可以的,这里可以根据实际情况决定:

halyard:

  ...

  persistence:

    storageClass: rook-ceph-block

...

redis:

  ...

  master:

    persistence:

      storageClass: rook-ceph-block

...

minio:

  ...

  persistence:

    storageClass: rook-ceph-block

...

接下来最重要的一步就是必须要为 halyard 配置代理,所以继续下去的前提是你需要配置一个在 Kubernetes 的 Pod 中可以访问的代理,比如我这里的代理地址为 10.151.30.11:8118,则需要配置如下所示的 JAVA_OPTS 这个环境变量:

halyard:

  env:

    - name: JAVA_OPTS

      value: '"-Djava.security.egd=file:/dev/./urandom" "-Dhttp.proxyHost=10.151.30.11" "-Dhttps.proxyHost=10.151.30.11" "-Dhttp.proxyPort=8118" "-Dhttps.proxyPort=8118" "-Dhttp.nonProxyHosts=\"localhost|*.spinnaker.com\""'

获取上面我修改过后的 Spinnaker 的 Chart 模板,将 values.yaml 文件中上面对应的配置替换成自己对应的配置即可。

$ git clone https://github.com/cnych/spinnaker-helm spinnaker

$ kubectl create ns spinnaker

# 安装 spinnaker

$ helm install spinnaker --namespace spinnaker ./spinnaker

由于安装过程非常耗时,可能上面的 helm install 的过程可能会有超时提示,这个可以忽略:

$ helm ls -n spinnaker

NAME            NAMESPACE       REVISION        UPDATED                                 STATUS  CHART            APP VERSION

spinnaker       spinnaker       1               2020-02-17 19:28:02.644552 +0800 CST    failed  spinnaker-1.23.2 1.16.2 

安装完成后最开始会生成如下所示的几个 Pod,其中 spinnaker-install-using-hal-th8qf 就是用来去真正安装 Spinnaker 的一个 Job 任务:

$ kubectl get pods -n spinnaker

spinnaker-install-using-hal-th8qf   0/1     Completed   0          17h

spinnaker-minio-86f5b8785-bkjfq     1/1     Running     0          17h

spinnaker-redis-master-0            1/1     Running     0          17h

spinnaker-spinnaker-halyard-0       1/1     Running     0          17h

不过由于在安装 Spinnaker 的过程中会使用 gcr.io 的镜像,所以会看到很多 Pod 镜像拉取失败的错误,这个时候我们可以手动编辑 Deployment 对象更改镜像地址:

$ kubectl get deploy -n spinnaker

NAME               READY   UP-TO-DATE   AVAILABLE   AGE

spin-clouddriver   0/1     1            0           17h

spin-deck          0/1     1            0           17h

spin-echo          0/1     1            0           17h

spin-front50       0/1     1            0           17h

spin-gate          0/1     1            0           17h

spin-igor          0/1     1            0           17h

spin-orca          0/1     1            0           17h

spin-rosco         0/1     1            0           17h

spinnaker-minio    1/1     1            1           17h

比如修改 spin-deck 这个 Deployment 资源对象的镜像地址:

$ kubectl edit deploy spin-deck -n spinnaker

# 然后在打开的编辑中将 gcr.io 替换成 gcr.azk8s.cn

用同样的方法替换其他资源对象,正常替换过后隔一段时间就可以正常启动 Pod 了,最终的 Pod 列表如下所示:

$ kubectl get pods -n spinnaker

NAME                                READY   STATUS      RESTARTS   AGE

spin-clouddriver-76b8989b4f-cjw8r   1/1     Running     0          17h

spin-deck-5fd7b64b77-fnl5r          1/1     Running     0          17h

spin-echo-644c4cb6b6-gh98w          1/1     Running     0          17h

spin-front50-9d99cd697-cqbxb        1/1     Running     0          17h

spin-gate-6c49bccb6f-nhbzx          1/1     Running     0          17h

spin-igor-7c84d9bcb-rltw7           1/1     Running     0          17h

spin-orca-b5944685-wbm5p            1/1     Running     0          17h

spin-rosco-6d5f9c8f55-g89hq         1/1     Running     0          17h

spinnaker-install-using-hal-th8qf   0/1     Completed   0          17h

spinnaker-minio-86f5b8785-bkjfq     1/1     Running     0          17h

spinnaker-redis-master-0            1/1     Running     0          17h

spinnaker-spinnaker-halyard-0       1/1     Running     0          17h

到这里就证明我们的 Spinnaker 已经安装成功了,这个时候如果我们想要把 Spinnaker 暴露给外部用户访问,当然可以创建一个 NodePort 类型的 Service,或者创建一个 Ingress 资源对象即可,其实上面的 chart 模板中我们就可以通过配置指定 Ingress 资源对象的参数。由于我这里使用的是 Traefik2.1 版本,所以单独创建一个 IngressRoute 资源对象来暴露服务:

apiVersion: traefik.containo.us/v1alpha1

kind: IngressRoute

metadata:

  name: spin-deck-https

  namespace: spinnaker

spec:

  entryPoints:

  - websecure

  routes:

  - match: Host(`spinnaker.qikqiak.com`)

    kind: Rule

    services:

    - name: spin-deck

      port: 9000

  tls:

    certResolver: ali

    domains:

    - main: "*.qikqiak.com"

---

apiVersion: traefik.containo.us/v1alpha1

kind: Middleware

metadata:

  name: redirect-https

  namespace: spinnaker

spec:

  redirectScheme:

    scheme: https

---

apiVersion: traefik.containo.us/v1alpha1

kind: IngressRoute

metadata:

  name: spin-deck-http

  namespace: spinnaker

spec:

  entryPoints:

  - web

  routes:

  - match: Host(`spinnaker.qikqiak.com`)

    kind: Rule

    services:

    - name: spin-deck

      port: 9000

    middlewares: 

    - name: redirect-https

直接创建上面的资源对象即可,对 Traefik2 使用不是很熟悉的,可以查看前面的文章 一文搞懂 Traefik2.1 的使用 了解更多,然后直接对域名 spinnaker.qikqiak.com 做好 DNS 解析即可在浏览器中访问 Spinnaker 了:

到这里就安装成功了,当然这只是万里长征的第一步呢,后面我们再慢慢的去了解 Spinnaker 到底有哪些值得我们关注的功能。