Spinnaker is a continuous delivery platform, originally developed by Netflix, for releasing software changes quickly and reliably. Spinnaker makes it easier for developers to focus on writing code without worrying about the underlying cloud infrastructure, and it integrates seamlessly with Jenkins It integrates seamlessly with Jenkins and other popular build tools. I’ve been wanting to try Spinnaker for a long time, but I’ve tried many times without success due to GFW, and this time I finally successfully deployed Spinnaker on a Kubernetes cluster after solving the proxy issue.

In this article, we will use helm3 to demonstrate the installation of Spinnaker on a Kubernetes cluster, and the corresponding environment version is shown below.

1
2
3
4
5
$ 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"}

The installation and configuration of Helm3 is really simple, just install the Helm3 client on top of the node where kubectl is located, and by default it will read the kubeconfig file to access the cluster. We use the helm chart repository provided by Microsoft here.

1
2
3
4
5
6
7
$  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!⎈ 

Since we are using Kubernetes version 1.16.x, which deprecated some old APIs for many resource objects, such as Deployment, we can only use the apps/v1 version, and the Spinnaker chart package we are using here is still using the previous API version. So we need to download it manually and make a change: apps/v1.

1
2
$ helm fetch stable/spinnaker
$ tar -xvf spinnaker-1.23.2.tgz

Then change the apiVersion of Deployment, StatefulSet and other resource objects in the spinnaker chart template to apps/v1, also remember that if it is Deployment you need to add the selector.matchLabels field, you can use it directly I changed the chart template https://github.com/cnych/spinnaker-helm.

In the values.yaml file of the chart template, I specified halyard.spinnakerVersion=1.17.6, which is still a problem because of the apiVersion version, which is compatible with Kubernetes v1.16.x clusters, and replaced the default gcr.io image with a Microsoft image. In addition, the default gcr.io image is replaced with the Microsoft image source gcr.azk8s.cn, and there is also a very important thing is the storage designation, here we create a StorageClass resource object to provide storage, I am creating a Ceph RBD type of storage rook-ceph-block, of course any available StorageClass resource object is fine: the

 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
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

It is necessary to specify the corresponding storage for halyard, redis, and mino, but of course it is possible to specify a suitable PVC directly, which can be decided here according to the actual situation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
halyard:
  ...
  persistence:
    storageClass: rook-ceph-block
...
redis:
  ...
  master:
    persistence:
      storageClass: rook-ceph-block
...
minio:
  ...
  persistence:
    storageClass: rook-ceph-block
...

The next most important step is to configure a proxy for halyard, so the prerequisite to continue is that you need to configure a proxy that can be accessed in the Kubernetes Pod, for example, if my proxy address is 10.151.30.11:8118, you need to configure the JAVA_OPTS environment variable as follows : `JAVA_OPTS

1
2
3
4
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\""'

Get the above modified Chart template of Spinnaker and replace the above configuration in the values.yaml file with your own configuration.

1
2
3
4
$ git clone https://github.com/cnych/spinnaker-helm spinnaker
$ kubectl create ns spinnaker
# 安装 spinnaker
$ helm install spinnaker --namespace spinnaker ./spinnaker

Since the installation process is very time consuming, there may be a timeout for the helm install process above, which can be ignored.

1
2
3
$ 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 

The installation will initially generate several Pods as shown below, with spinnaker-install-using-hal-th8qf being one of the Job tasks used to actually install Spinnaker: spinnaker-install-using-hal-th8qf.

1
2
3
4
5
$ 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

However, since the gcr.io image will be used during the installation of Spinnaker, you will see a lot of Pod image pulling failure errors, at this time we can manually edit the Deployment object to change the image address.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ 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

For example, change the mirror address of the Deployment resource object spin-deck to

1
2
$ kubectl edit deploy spin-deck -n spinnaker
# 然后在打开的编辑中将 gcr.io 替换成 gcr.azk8s.cn

Replace the other resource objects in the same way, and after a normal replacement, the Pod will start normally after some time. The final list of Pods is shown below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ 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

If we want to expose Spinnaker to external users, we can of course create a NodePort service or an Ingress resource object, which we can specify in the chart template above. In fact, in the chart template above, we can specify the parameters of the Ingress resource object through configuration. Since I am using Traefik version 2.1 here, I create a separate IngressRoute resource object to expose the service.

 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
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

Just create the resource object above, and then do a DNS resolution of the domain spinnaker.qikqiak.com to access Spinnaker in your browser.

Here the installation is successful, of course, this is only the first step of the long journey it, and then we will slowly go to understand Spinnaker in the end what features worth our attention.