オンプレでGitLabとKubernetesの統合

オンプレで構築したGitLabとKubernetesを統合してCI/CDできる環境を構築してみます。
こちら の手順を進めます。
ドキュメントに書いてあるとおり
arm64はサポートされていないので ラズパイKubernetes は使えません。

Kubernetes integration isn’t supported for arm64 clusters. See the issue Helm Tiller fails to install on arm64 cluster for details.

残念。

GitLabのバージョンは13.11.2で確認しました。

gitlab_k8s_01.png

今回KubernetesはESXi上のUbuntu20.04にkubeadmを使って構築しました。
master1台のみの構成です。
最新のv1.21だとCoreDNSの名前解決がうまく動かなかったのでv1.20.2にしました。

ubuntu@k8s:~$ kubectl get nodes
NAME   STATUS   ROLES                  AGE   VERSION
k8s    Ready    control-plane,master   89m   v1.20.2

GitLabでクラスター統合

まずはローカルネットワーク間で通信するためにアウトバウンドリクエストの設定をします。
kubernetesを構築したUbuntuのIPを設定しておいてください。

gitlab_k8s_02.png

管理者エリアのKubernetesでクラスターを追加します。

gitlab_k8s_03.png

Connect existing clusterを選択します。

gitlab_k8s_04.png

この画面で入力する値は環境によって異なるので、 ドキュメント 通りに進めてください。
「Kubernetes クラスター名」は好きな名前にしてください。

gitlab_k8s_05.png

API URLを取得します。

ubuntu@k8s:~$ kubectl cluster-info | grep -E 'Kubernetes master|Kubernetes control plane' | awk '/http/ {print $NF}'
https://k8s:6443

CA 証明書を取得します。

ubuntu@k8s:~$ kubectl get secrets
NAME                  TYPE                                  DATA   AGE
default-token-dgj48   kubernetes.io/service-account-token   3      103m
ubuntu@k8s:~$ kubectl get secret default-token-dgj48 -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
-----BEGIN CERTIFICATE-----
MIIC5zCCAc+gAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
cm5ldGVzMB4XDTIxMDUxNTAxMTczNVoXDTMxMDUxMzAxMTczNVowFTETMBEGA1UE

(中略)

GYpcDmlrT8IcLIblr8OD8lNP3UMp02KiyhOvQbjzUmoLm5m1lO0zKq58jUY9dgCw
EtjztjfzfSTz4Y8MuYJTN0gGqge8Se0djUtj
-----END CERTIFICATE-----

サービスアカウントを作成します。

ubuntu@k8s:~$ cat gitlab-admin-service-account.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: gitlab-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: gitlab
    namespace: kube-system
ubuntu@k8s:~$ kubectl apply -f gitlab-admin-service-account.yaml
serviceaccount/gitlab created
clusterrolebinding.rbac.authorization.k8s.io/gitlab-admin created

サービストークンを取得します。
tokenの部分の長い文字列をコピーしてください。

ubuntu@k8s:~$ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab | awk '{print $1}')
Name:         gitlab-token-n6gp9
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: gitlab
              kubernetes.io/service-account.uid: fad206c3-7e93-4558-bc3e-260086211ab3

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1066 bytes
namespace:  11 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6Ilgzb1VHa21JMzRwM0dSWVVUaldFYUUzQUp5dXQwWkV6eS1VT1pUVEY0QncifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJnaXRsYWItdG9rZW4tbjZncDkiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZ2l0bGFiIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZmFkMjA2YzMtN2U5My00NTU4LWJjM2UtMjYwMDg2MjExYWIzIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmdpdGxhYiJ9.DdbHRbBSiALRxeKYMEa49OKBBA0st1mTXyxf70ZCQFed_HDPmZDG-wfu_h-wyqwsSrAPOHhDoa_jW-PTdqo9DlLLXYZKPRtlbjJOIPkUNWGaUdhh72dwLNuHA8tlqBb4ttqxBekx-fW7zO1Z8VkWm3u3TC8UcbEAr0rJZ8g5eyU2dCCNep7qvi9VM8sMjZr5rZcP7qrT-1y8xa99wwB46CRC9RrzATkMLwmnsvZFEawLmZkxOkoopRFu2wEv957GnQKapfmvYqrxWhqdxMtaIE0bzxKzOxfYFER_8VydtZGuNHBkGYdQJGPUXG7Unl6v7OXFSq_w_yRP6HTbDyqbzQ

取得した値を入力したらクラスターを追加します。
他はデフォルト設定にしました。

gitlab_k8s_06.png

Gitlab Runnerのインストール

統合できたらアプリケーションタブでGitlab Runnerをインストールします。

gitlab_k8s_07.png

無事runnerがRunningしてますね。

ubuntu@k8s:~$ kubectl get all --all-namespaces
NAMESPACE             NAME                                        READY   STATUS    RESTARTS   AGE
gitlab-managed-apps   pod/runner-gitlab-runner-7bf67d766b-9z6t9   1/1     Running   0          9m21s
kube-system           pod/coredns-74ff55c5b-7w7kq                 1/1     Running   0          125m
kube-system           pod/coredns-74ff55c5b-bmdnw                 1/1     Running   0          125m
kube-system           pod/etcd-k8s                                1/1     Running   0          125m
kube-system           pod/kube-apiserver-k8s                      1/1     Running   0          125m
kube-system           pod/kube-controller-manager-k8s             1/1     Running   0          125m
kube-system           pod/kube-flannel-ds-95hkq                   1/1     Running   0          124m
kube-system           pod/kube-proxy-tgdm2                        1/1     Running   0          125m
kube-system           pod/kube-scheduler-k8s                      1/1     Running   0          125m

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  125m
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   125m

NAMESPACE     NAME                             DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/kube-flannel-ds   1         1         1       1            1           <none>                   124m
kube-system   daemonset.apps/kube-proxy        1         1         1       1            1           kubernetes.io/os=linux   125m

NAMESPACE             NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE
gitlab-managed-apps   deployment.apps/runner-gitlab-runner   1/1     1            1           9m21s
kube-system           deployment.apps/coredns                2/2     2            2           125m

NAMESPACE             NAME                                              DESIRED   CURRENT   READY   AGE
gitlab-managed-apps   replicaset.apps/runner-gitlab-runner-7bf67d766b   1         1         1       9m21s
kube-system           replicaset.apps/coredns-74ff55c5b                 2         2         2       125m

しかし、ログを見てみるとうまくGitLabと通信できていない様子。

ubuntu@k8s:~$ kubectl logs runner-gitlab-runner-7bf67d766b-9z6t9 -n gitlab-managed-apps
ERROR: Verifying runner... failed runner=pvqCNqRP
status=couldn't execute POST against https://example.tsuchinokometal.com:10080/gitlab/api/v4/runners/verify: Post https://example.tsuchinokometal.com:10080/gitlab/api/v4/runners/verify: 
http: server gave HTTP response to HTTPS client

http用の10080ポートにhttpsでアクセスしようとしているようですね。
ちなみにこのGitLabはnginxでリバースプロキシをしている構成です。
詳しくはこちら をご確認ください。

GitLabの設定を変更します。
このGitLabはsameersbn/gitlab を使っているので、
パラメーターのGITLAB_PORTを443に変更してみます。

    environment:
    - GITLAB_HTTPS=true
    - GITLAB_PORT=443

先程のGitLabの管理画面からGitLab Runnerを一旦アンインストールして、再インストールしてください。

再度ログを確認したところ、URLは正しくなったようですが違うエラーでまた失敗してますね。

ERROR: Verifying runner... failed runner=TYwjVr8Q
status=couldn't execute POST against https://example.tsuchinokometal.com/gitlab/api/v4/runners/verify: Post https://example.tsuchinokometal.com/gitlab/api/v4/runners/verify: 
x509: certificate signed by unknown authority

自己証明書で暗号化していることが原因のようです。
正しい対処方法はわかりませんが、 以前 と同じく
ホストの証明書と共有する方法で解決します。

まずKubernetesを構築したUbuntuに証明書をインストールします。
GitLabをhttps化した際の自己証明書をkubernetesを構築したUbuntuにコピーしてください。
以下の例で言うと「example.tsuchinokometal.com.crt」ですね。

ubuntu@k8s:~$ sudo mkdir -p /usr/local/share/ca-certificates/example
ubuntu@k8s:~$ sudo cp -p example.tsuchinokometal.com.crt /usr/local/share/ca-certificates/example/
ubuntu@k8s:~$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
ubuntu@k8s:~$ ls /etc/ssl/certs/ | grep example
example.tsuchinokometal.com.pem

deploymentを編集して/etc/ssl/certsをGitLab Runnerのコンテナにマウントします。

ubuntu@k8s:~$ kubectl edit deployment runner-gitlab-runner -n gitlab-managed-apps
deployment.apps/runner-gitlab-runner edited

volumesにhostPathを追記します。

      volumes:
      - hostPath:
          path: /etc/ssl/certs
          type: Directory
        name: certs

volumeMountsに追記します。

        volumeMounts:
        - mountPath: /etc/ssl/certs
          name: certs

自動的にpodが再作成されます。
ログを確認すると今度こそエラーは出なくなったようです。

ubuntu@k8s:~$ kubectl get po -n gitlab-managed-apps
NAME                                    READY   STATUS    RESTARTS   AGE
runner-gitlab-runner-785c8cbbc8-4xnrm   1/1     Running   0          6m8s
ubuntu@k8s:~$ kubectl logs runner-gitlab-runner-785c8cbbc8-4xnrm -n gitlab-managed-apps
Registration attempt 1 of 30
Runtime platform                                    arch=amd64 os=linux pid=14 revision=54944146 version=13.10.0
WARNING: Running in user-mode.                     
WARNING: The user-mode requires you to manually start builds processing: 
WARNING: $ gitlab-runner run                       
WARNING: Use sudo for system-mode:                 
WARNING: $ sudo gitlab-runner...                   
                                                   
Token specified trying to verify runner...         
WARNING: If you want to register use the '-r' instead of '-t'. 
Verifying runner... is alive                        runner=TYwjVr8Q
Merging configuration from template file "/configmaps/config.template.toml" 
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded! 
Runtime platform                                    arch=amd64 os=linux pid=1 revision=54944146 version=13.10.0
Starting multi-runner from /home/gitlab-runner/.gitlab-runner/config.toml...  builds=0
WARNING: Running in user-mode.                     
WARNING: Use sudo for system-mode:                 
WARNING: $ sudo gitlab-runner...                   
                                                   
Configuration loaded                                builds=0
Metrics server listening                            address=:9252 builds=0
[session_server].listen_address not defined, session endpoints disabled  builds=0

まだジョブは実行させていませんが、
GitLab側で確認したところ、オンラインと表示されているので大丈夫でしょう。

gitlab_k8s_08.png

Kubernetesだし複数ジョブが実行されたら自動でスケールアウトしてくれるのかな?
実際の開発で使えるかどうか、試してみたいですね。