kubernetes で GitLab および GitLab Runner を実行する設定サンプル
[履歴] [最終更新] (2019/11/11 21:53:18)
最近の投稿
注目の記事

概要

GitLab CI/CD 設定について、GitLab および GitLab Runner すべてを k8s 内で実行するサンプルを記載します。簡単のため minikube を利用します。

minikube config set memory 8192
minikube config set cpus 4
minikube start
minikube ip
192.168.99.103
minikube ssh
minikube addons enable ingress

curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
kubectl get nodes

NAME       STATUS   ROLES    AGE     VERSION
minikube   Ready    master   5m39s   v1.16.0

GitLab の k8s YAML 設定

設定はサンプルです。minikube ホストの /tmp/gitlab を GitLab の永続データ格納用のディレクトリとして設定しています。runner が hostname でアクセスするため hostname を設定する必要があることにも注意します。

kubectl apply -f gitlab.yaml

gitlab.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gitlab
  labels:
    app: gitlab
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gitlab
  template:
    metadata:
      labels:
        app: gitlab
    spec:
      volumes:
      - name: hostvolume
        hostPath:
          path: /tmp/gitlab
          type: DirectoryOrCreate
      hostname: gitlab
      containers:
      - name: gitlab
        image: gitlab/gitlab-ce:latest
        volumeMounts:
        - mountPath: /etc/gitlab
          subPath: config
          name: hostvolume
        - mountPath: /var/log/gitlab
          subPath: logs
          name: hostvolume
        - mountPath: /var/opt/gitlab
          subPath: data
          name: hostvolume

---

apiVersion: v1
kind: Service
metadata:
  name: gitlab
  labels:
    app: gitlab
spec:
  selector:
    app: gitlab
  ports:
  - name: http
    port: 80
    targetPort: 80
  - name: https
    port: 443
    targetPort: 443
  - name: ssh
    port: 22
    targetPort: 22

---

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: gitlab
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: gitlab.minikube
    http:
      paths:
      - path: /
        backend:
          serviceName: gitlab
          servicePort: 80

minikube の IP を名前解決できるようにしてアクセスしてみます。

$ tail -1 /etc/hosts
192.168.99.103 gitlab.minikube

Uploaded Image

GitLab Runner の k8s YAML 設定

Go バイナリ gitlab-runner を k8s Pod 内で実行します。

Job の実行方法として選択できる executor は複数ありますが、毎回クリーンな環境で実行するためには SSH executor や Shell executor は不適です。Docker executor で Pod 内に docker コンテナを起動することもできそうですが、ここでは Kubernetes executor で runner Pod 外に job 用の docker コンテナを起動します。

そのため、gitlab-runner を実行する Pod には必要な k8s 権限を付与しておきます

kubectl apply -f runner.yaml

runner.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: runner

---

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: runner
rules:
- apiGroups: [""]
  resources: ["pods", "pods/exec"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: default
  name: runner
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: runner
subjects:
- kind: ServiceAccount
  name: runner

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: runner
  labels:
    app: runner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: runner
  template:
    metadata:
      labels:
        app: runner
    spec:
      containers:
      - name: runner
        image: gitlab/gitlab-runner:latest
      serviceAccountName: runner

GitLab Runner を GitLab に登録

GitLab から事前に取得しておいた registration token を用いて、gitlab-runner の register サブコマンドで GitLab Runner を GitLab に登録します。

kubectl exec runner-9696bb9d4-hznr7 -- gitlab-runner register \
  --non-interactive \
  --description my-runner \
  --url http://gitlab/ \
  --registration-token HuTcoef5pErhtTwuYjjU \
  --executor kubernetes

登録に成功すると gitlab-runner 内に config.toml が生成されます。config.toml 内の token は、gitlab-runner を register する際の registration token とは別物であることに注意します。

$ kubectl exec runner-9696bb9d4-hznr7 -- cat /etc/gitlab-runner/config.toml
concurrent = 1
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "my-runner"
  url = "http://gitlab/"
  token = "-mzLiiPmH153ANSiVz_Z"
  executor = "kubernetes"
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
  [runners.kubernetes]
    host = ""
    bearer_token_overwrite_allowed = false
    image = ""
    namespace = ""
    namespace_overwrite_allowed = ""
    privileged = false
    service_account_overwrite_allowed = ""
    pod_annotations_overwrite_allowed = ""
    [runners.kubernetes.pod_security_context]
    [runners.kubernetes.volumes]

生成された config.toml を Pod から取り出して、k8s ConfigMap として runner にマウントされるように runner.yaml を編集すれば、register する必要のない runner deployment 設定を作成できます。

runner.yaml

       labels:
         app: runner
     spec:
+      volumes:
+      - name: config
+        configMap:
+          name: runner
       containers:
       - name: runner
         image: gitlab/gitlab-runner:latest
+        volumeMounts:
+        - name: config
+          subPath: config.toml
+          mountPath: /etc/gitlab-runner/config.toml
       serviceAccountName: runner
+
+---
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: runner
+data:
+  config.toml: |
+    concurrent = 1
+    check_interval = 0
+    
+    [session_server]
+      session_timeout = 1800
+    
+    [[runners]]
+      name = "my-runner"
+      url = "http://gitlab/"
+      token = "-fseJu4_VcJwGu_-wPPg"
+      executor = "kubernetes"
+      [runners.custom_build_dir]
+      [runners.cache]
+        [runners.cache.s3]
+        [runners.cache.gcs]
+      [runners.kubernetes]
+        host = ""
+        bearer_token_overwrite_allowed = false
+        image = ""
+        namespace = ""
+        namespace_overwrite_allowed = ""
+        privileged = false
+        service_account_overwrite_allowed = ""
+        pod_annotations_overwrite_allowed = ""
+        [runners.kubernetes.pod_security_context]
+        [runners.kubernetes.volumes]

.gitlab-ci.yml 設定例

.gitlab-ci.yml には Job を実行するために必要な環境が含まれる docker image を指定します。GitLab への push をトリガーとして、commit された Python のコードを flake8 でチェックする設定は以下のようになります。

kubectl port-forward gitlab-6577c9fff5-wlw75 2222:22
git clone ssh://git@localhost:2222/mygroup/myproject.git

.gitlab-ci.yml

run-test:
  image: alpine/flake8:latest
  script:
    - echo ok
    - which flake8
    - ls

git push すると、指定した docker image を用いて Pod が新規に作成され、ソースコードが git clone されます。flake8 を利用する script を設定すれば、簡単な構文チェックが行えます。

Uploaded Image

GitLab Runner Deployment 更新について

k8s deployment を更新する際に 現在実行中の Pod には SIGTERM が送信されます。GitLab Runner は SIGTERM を受け取ると、現在実行中の Job を強制的に終了します。k8s の preStop を設定して SIGQUIT を送信することで、これを回避できます。GitLab Runner の docker image に killall などをインストールしておくと簡単です。

Dockerfile

FROM gitlab/gitlab-runner:latest
RUN apt update && apt install -y psmisc
COPY config /etc/gitlab-runner
...

preStop は以下のように設定します。preStop が完了すると SIGTERM が送信されてしまうため sleep しています。3時間以内に終了しなければ SIGTERM が送信された後、すぐに SIGKILL が送信されます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: runner
  labels:
    app: runner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: runner
  template:
    metadata:
      labels:
        app: runner
    spec:
      containers:
      - name: runner
        image: my/gitlab-runner:latest
        imagePullPolicy: "Always"
        lifecycle:
          preStop:
            exec:
              command: ["bash", "-c", "killall -SIGQUIT gitlab-runner && sleep 10800"]
      terminationGracePeriodSeconds: 10800
      serviceAccountName: runner
関連ページ
    概要 GitLab CI/CD について使い方を把握してみます。 検証用 GitLab の準備 簡単のため docker イメージを利用します。マウントしたディレクトリは、Docker エントリーポイントから実行される Chef によってプロビジョニングされます。 docker run \ --hostname localhost \ --publish 10443:443 --publis