この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
「このExecutorの動き、どないなってるんや…」
現在支援している顧客環境では、CI/CD基盤として、GitLab RunnerをセルフホスティングのEKS上で動作させています。設定自体は、マニュアルを読みながら実施することでそれほど苦労するところはなかったんですが、さらに踏み込んでちょっとしたカスタマイズやインフラの最適化を実施しようとすると、内部構造を事前に理解しておく必要に迫られました。
GitLab Runnerのセルフホスティングと一口で言ってもその方式は複数種類あるのですが、このブログでは、その中のKubernetes Executorの動作原理を、公式マニュアルを紐解きながら解説していきます。
(祭) ∧ ∧ Y ( ゚Д゚) Φ[_ソ__y_l〉 GitLab Runnerマツリダワッショイ |_|_| し'´J
GitLab Runnerとは?
公式マニュアルのトップはこちら。
GitLab Runnerは、GitLab社が提供するCI/CD基盤。位置づけとしてはGitHubにおけるGitHub Actionsと同等です。SaaSとしてGitLab.comの中でも利用できますし、セルフホスティングして自分で管理するインフラ上で動作させることも可能です。
GitLab RunnerのExecutorとは?
GitLab Runnerをセルフホスティングする際に、Runnerを動作させる利用方式です。2022年5月現在、以下のExecutorが用意されています。
- SSH
- Shell
- Parallels
- VirtualBox
- Docker
- Docker Machine (auto-scaling)
- Kubernetes
- Custom
各Executorによる機能差はこちらに記載のとおり。
今回支援している顧客環境では、アプリケーションワークロードにEKSを利用していることも有り、機能が豊富でノウハウもあるKubernetes Executorを採用することになりました。
Kubernetes Executorの内部構造を理解する
The Kubernetes executor for GitLab Runner | GitLab
GitLabとGitLab RunnerのKubernetesの関連をシーケンス図で把握するとこうなります。画像は公式マニュアルからの引用です。
GitLab Runnerからは定期的にGitLab側のCIジョブを監視、CIジョブが登録されたら、ジョブが生成されたらその情報を取得、その情報を元にKUbernetes APIを叩き、ジョブ用のPodが起動します。起動したPodの中では、以下の処理が実行されます。
- Prepare:ジョブ用のPodが生成される
- Pre-build:全ステージのアーティファクトクローン、キャッシュ復元、ダウンロードを行う。これは、Podの一部である専用コンテナを利用
- Build:自身のジョブのビルドを実行
- Post-build:キャッシュ作成、アーティファクトのGitLabへのアップロード。これも、Podの一部である専用コンテナを利用
GitLab RunnerをKubernetesにインストールし、内部構造を調べてみる
ここまでで基本的なKubernetes Executorの内部構造のイメージができたかと思います。
GitLabからは、KubernetesへのGitLab Runnerインストール用途でHelm Chartが公開されています。ここからは、このHelmChartを利用して、もう少し細かくKubernetes Executorの中身を確認していきます。
GitLab Runner Helm Chart | GitLab
事前に最小構成の設定ファイルconfig-tmp.yaml
を用意しておきます。
config-tmp.yaml
gitlabUrl: https://gitlab.com/
runnerRegistrationToken: "XXXXXXXXXX1234567890"
rbac:
create: true
gitlabUrl
:GitLabサーバーのURL。SaaS版のGitLabからGitLab Runnerを利用する場合は、https://gitlab.com/
runnerRegistrationToken
:GitLabからこのGtiLab Runnerを利用するために必要なトークン。事前にGitLab側で取得しておく必要ありrbac
:Role Base Accecc Controleを有効にするために設定しておきます
helm installをdry-run
し、適用されるマニフェストファイルを確認します。
helm install hamada-gitlab-runner gitlab/gitlab-runner --dry-run -f config-tmp.yaml --namespace gitlab-runner
上記を実行すると適用予定のマニフェストファイル一式が出力されます。作成されるリソースは、以下の通り
- ServiceAccount
- Secret
- ConfigMap
- Role
- RoleBinding
- Deployment
以下に、作成されるリソースについて解説していきます。
ServiceAccount
GitLab Runnerで利用するService Accountの定義です。
# Source: gitlab-runner/templates/service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
name: hamada-gitlab-runner-gitlab-runner
labels:
app: hamada-gitlab-runner-gitlab-runner
chart: gitlab-runner-0.37.2
release: "hamada-gitlab-runner"
heritage: "Helm"
Secret
GitLabからGitLab Runnerを起動する際に利用するトークンを格納するためのSecretを作成します。
# Source: gitlab-runner/templates/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: "hamada-gitlab-runner-gitlab-runner"
labels:
app: hamada-gitlab-runner-gitlab-runner
chart: gitlab-runner-0.37.2
release: "hamada-gitlab-runner"
heritage: "Helm"
type: Opaque
data:
runner-registration-token: "R1IxMzQ4OTQxSGlMZnVFcmVGR2pHdno2WVhQOFM="
runner-token: ""
ConfigMap
GitLab RunnerのJobが実行されるとき専用のPodが起動しますが、そのPodで利用する設定情報が、このConfigMapで定義されます。data
以降に、PodのEntryポイントが記載されているので、環境編集や設定ファイルがどのように展開されているか、ここで確認できます。
data以降は長いのでここには全文は掲載していません。
# Source: gitlab-runner/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: hamada-gitlab-runner-gitlab-runner
labels:
app: hamada-gitlab-runner-gitlab-runner
chart: gitlab-runner-0.37.2
release: "hamada-gitlab-runner"
heritage: "Helm"
data:
entrypoint: |
#!/bin/bash
set -e
mkdir -p /home/gitlab-runner/.gitlab-runner/
cp /configmaps/config.toml /home/gitlab-runner/.gitlab-runner/
# Set up environment variables for cache
if [[ -f /secrets/accesskey && -f /secrets/secretkey ]]; then
export CACHE_S3_ACCESS_KEY=$(cat /secrets/accesskey)
export CACHE_S3_SECRET_KEY=$(cat /secrets/secretkey)
fi
〜〜後、省略〜〜
Role
ジョブ実行のPodで利用するServiceAccountで利用するRoleの設定です。権限は、rules:
配下に記載があるとおり、クラスター内の全リソースに対する全ての処理が許可されています。
# Source: gitlab-runner/templates/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: "Role"
metadata:
name: hamada-gitlab-runner-gitlab-runner
labels:
app: hamada-gitlab-runner-gitlab-runner
chart: gitlab-runner-0.37.2
release: "hamada-gitlab-runner"
heritage: "Helm"
namespace: "gitlab-runner"
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["*"]
RoleBinding
前述で作成したRoleを、このRoleBindingでServiceAccountに紐付けます。roleRef:
で紐付けるRoleを、subjects:
で紐付けるServiceAccountの名前を定義しています。
# Source: gitlab-runner/templates/role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: "RoleBinding"
metadata:
name: hamada-gitlab-runner-gitlab-runner
labels:
app: hamada-gitlab-runner-gitlab-runner
chart: gitlab-runner-0.37.2
release: "hamada-gitlab-runner"
heritage: "Helm"
namespace: "gitlab-runner"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: "Role"
name: hamada-gitlab-runner-gitlab-runner
subjects:
- kind: ServiceAccount
name: hamada-gitlab-runner-gitlab-runner
namespace: "gitlab-runner"
Deployment
ジョブ実行時に起動するPodの初期情報を設定するDeploymentです。ここで、Podに設定されるImage、Volume、紐づくConfigmap、利用するServiceAccount、環境変数などが全て指定されます。
実際にPodが起動される際に利用させる全ての設定情報がここに記載されているので、細かい情報はここで確認可能です。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hamada-gitlab-runner-gitlab-runner
labels:
app: hamada-gitlab-runner-gitlab-runner
chart: gitlab-runner-0.37.2
release: "hamada-gitlab-runner"
heritage: "Helm"
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: hamada-gitlab-runner-gitlab-runner
template:
metadata:
labels:
app: hamada-gitlab-runner-gitlab-runner
chart: gitlab-runner-0.37.2
release: "hamada-gitlab-runner"
heritage: "Helm"
annotations:
checksum/configmap: 9f5e01ff935a315851d42292060f67bc1387319f7ca2814f43546e9dd0daab7d
checksum/secrets: 6cb1d605cac5eac1bca1526e9761f649a33f0ca2d647bc7ba6b121c62b20850c
prometheus.io/scrape: 'true'
prometheus.io/port: "9252"
spec:
securityContext:
runAsUser: 100
fsGroup: 65533
terminationGracePeriodSeconds: 3600
initContainers:
- name: configure
command: ['sh', '/configmaps/configure']
image: gitlab/gitlab-runner:alpine-v14.7.0
imagePullPolicy: "IfNotPresent"
securityContext:
allowPrivilegeEscalation: false
env:
- name: CI_SERVER_URL
value: "https://gitlab.com/"
- name: CLONE_URL
value: ""
- name: RUNNER_EXECUTOR
value: "kubernetes"
- name: REGISTER_LOCKED
value: "true"
- name: RUNNER_TAG_LIST
value: ""
volumeMounts:
- name: runner-secrets
mountPath: /secrets
readOnly: false
- name: configmaps
mountPath: /configmaps
readOnly: true
- name: init-runner-secrets
mountPath: /init-secrets
readOnly: true
resources:
{}
serviceAccountName: hamada-gitlab-runner-gitlab-runner
containers:
- name: hamada-gitlab-runner-gitlab-runner
image: gitlab/gitlab-runner:alpine-v14.7.0
imagePullPolicy: "IfNotPresent"
securityContext:
allowPrivilegeEscalation: false
lifecycle:
preStop:
exec:
command: ["/entrypoint", "unregister", "--all-runners"]
command: ["/usr/bin/dumb-init", "--", "/bin/bash", "/configmaps/entrypoint"]
env:
- name: CI_SERVER_URL
value: "https://gitlab.com/"
- name: CLONE_URL
value: ""
- name: RUNNER_EXECUTOR
value: "kubernetes"
- name: REGISTER_LOCKED
value: "true"
- name: RUNNER_TAG_LIST
value: ""
livenessProbe:
exec:
command: ["/bin/bash", "/configmaps/check-live"]
initialDelaySeconds: 60
timeoutSeconds: 1
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
readinessProbe:
exec:
command: ["/usr/bin/pgrep","gitlab.*runner"]
initialDelaySeconds: 10
timeoutSeconds: 1
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
ports:
- name: "metrics"
containerPort: 9252
volumeMounts:
- name: runner-secrets
mountPath: /secrets
- name: etc-gitlab-runner
mountPath: /home/gitlab-runner/.gitlab-runner
- name: configmaps
mountPath: /configmaps
resources:
{}
volumes:
- name: runner-secrets
emptyDir:
medium: "Memory"
- name: etc-gitlab-runner
emptyDir:
medium: "Memory"
- name: init-runner-secrets
projected:
sources:
- secret:
name: "hamada-gitlab-runner-gitlab-runner"
items:
- key: runner-registration-token
path: runner-registration-token
- key: runner-token
path: runner-token
- name: configmaps
configMap:
name: hamada-gitlab-runner-gitlab-runner
GitLab Runnerのインストール
ここまでで、実際に作成されるリソースの一覧の概要を把握できたので、実際にhelm installすることで、Kubernetes環境上にGitLab Runnerをインストールします。
helm install hamada-gitlab-runner gitlab/gitlab-runner -f config-tmp.yaml --namespace gitlab-runner
無事インストールされ、GitLab.comからこのようにGitLab Runnerが認識されていれば、インストール成功です。お疲れさまでした!
[Settings] -> [CI/CD Settings] -> [Runners]
実際にデプロイされたPodを確認
Namespaceにgitlab-runner
を指定しているため、該当Namespaceのに以下のPodが常駐しています。
$ kubectl get pods -n gitlab-runner
NAME READY STATUS RESTARTS AGE
gitlab-runner-gitlab-runner-XXXXXXXXXX-YYYYYYYY 1/1 Running 0 3d17h
Describeすると、GitLab Runnerインストール時に設定された各種関連リソースを確認できます。
$ kubectl describe pod gitlab-runner-gitlab-runner-XXXXXXXXXX-YYYYYYYY -n gitlab-runne
Name: gitlab-runner-gitlab-runner-XXXXXXXXXX-YYYYYYYY
Namespace: gitlab-runner
Priority: 0
Node: ip-10-0-2-230.ec2.internal/10.0.2.230
Start Time: Mon, 02 May 2022 14:53:22 +0900
Labels: app=gitlab-runner-gitlab-runner
chart=gitlab-runner-0.28.0
heritage=Helm
pod-template-hash=5bf78645f6
release=gitlab-runner
Annotations: checksum/configmap: f38a8b6828475f9a23923abbc5cfefc71b8e77dd1711eb4a643ee33adc2f2035
checksum/secrets: b854aa3a7279d6415ddd6de04c79674630640ea1753a0dfee201d6c55d24003a
kubernetes.io/psp: eks.privileged
prometheus.io/port: 9252
prometheus.io/scrape: true
Status: Running
IP: 10.0.2.105
IPs:
IP: 10.0.2.105
Controlled By: ReplicaSet/gitlab-runner-gitlab-runner-5bf78645f6
Init Containers:
configure:
Container ID: docker://9b929e7b9b418a782e18c62b8c571339ce71b7fdb41a7557d1d21e7d6cbfcf6e
Image: gitlab/gitlab-runner:alpine-v13.11.0
Image ID: docker-pullable://gitlab/gitlab-runner@sha256:d01c7fdfe5b85d55b66bb0ba01d1e52ac31747811b522f05dac2d514219fbd9f
Port: <none>
Host Port: <none>
Command:
sh
/configmaps/configure
State: Terminated
Reason: Completed
Exit Code: 0
Started: Mon, 02 May 2022 14:53:23 +0900
Finished: Mon, 02 May 2022 14:53:23 +0900
Ready: True
Restart Count: 0
Environment:
CI_SERVER_URL: https://gitlab.com/
CLONE_URL:
RUNNER_REQUEST_CONCURRENCY: 1
RUNNER_EXECUTOR: kubernetes
REGISTER_LOCKED: false
RUNNER_TAG_LIST: hamada-common-eks-gitlab-runner
KUBERNETES_IMAGE:
KUBERNETES_NAMESPACE: gitlab-runner
KUBERNETES_CPU_LIMIT:
KUBERNETES_CPU_LIMIT_OVERWRITE_MAX_ALLOWED:
KUBERNETES_MEMORY_LIMIT:
KUBERNETES_MEMORY_LIMIT_OVERWRITE_MAX_ALLOWED:
KUBERNETES_CPU_REQUEST:
KUBERNETES_CPU_REQUEST_OVERWRITE_MAX_ALLOWED:
KUBERNETES_MEMORY_REQUEST:
KUBERNETES_MEMORY_REQUEST_OVERWRITE_MAX_ALLOWED:
KUBERNETES_SERVICE_ACCOUNT:
KUBERNETES_SERVICE_CPU_LIMIT:
KUBERNETES_SERVICE_MEMORY_LIMIT:
KUBERNETES_SERVICE_CPU_REQUEST:
KUBERNETES_SERVICE_MEMORY_REQUEST:
KUBERNETES_HELPER_CPU_LIMIT:
KUBERNETES_HELPER_MEMORY_LIMIT:
KUBERNETES_HELPER_CPU_REQUEST:
KUBERNETES_HELPER_MEMORY_REQUEST:
KUBERNETES_HELPER_IMAGE:
KUBERNETES_PULL_POLICY:
Mounts:
/configmaps from configmaps (ro)
/init-secrets from init-runner-secrets (ro)
/secrets from runner-secrets (rw)
/var/run/secrets/kubernetes.io/serviceaccount from gitlab-runner-gitlab-runner-token-6cqb4 (ro)
Containers:
gitlab-runner-gitlab-runner:
Container ID: docker://fcb071087e27e0a73fc33f095baa6c32cc60dc5644bd48b16b07f766ac09a01a
Image: gitlab/gitlab-runner:alpine-v13.11.0
Image ID: docker-pullable://gitlab/gitlab-runner@sha256:d01c7fdfe5b85d55b66bb0ba01d1e52ac31747811b522f05dac2d514219fbd9f
Port: 9252/TCP
Host Port: 0/TCP
Command:
/bin/bash
/configmaps/entrypoint
State: Running
Started: Mon, 02 May 2022 14:53:24 +0900
Ready: True
Restart Count: 0
Liveness: exec [/bin/bash /configmaps/check-live] delay=60s timeout=1s period=10s #success=1 #failure=3
Readiness: exec [/usr/bin/pgrep gitlab.*runner] delay=10s timeout=1s period=10s #success=1 #failure=3
Environment:
CI_SERVER_URL: https://gitlab.com/
CLONE_URL:
RUNNER_REQUEST_CONCURRENCY: 1
RUNNER_EXECUTOR: kubernetes
REGISTER_LOCKED: false
RUNNER_TAG_LIST: hamada-common-eks-gitlab-runner
KUBERNETES_IMAGE:
KUBERNETES_NAMESPACE: gitlab-runner
KUBERNETES_CPU_LIMIT:
KUBERNETES_CPU_LIMIT_OVERWRITE_MAX_ALLOWED:
KUBERNETES_MEMORY_LIMIT:
KUBERNETES_MEMORY_LIMIT_OVERWRITE_MAX_ALLOWED:
KUBERNETES_CPU_REQUEST:
KUBERNETES_CPU_REQUEST_OVERWRITE_MAX_ALLOWED:
KUBERNETES_MEMORY_REQUEST:
KUBERNETES_MEMORY_REQUEST_OVERWRITE_MAX_ALLOWED:
KUBERNETES_SERVICE_ACCOUNT:
KUBERNETES_SERVICE_CPU_LIMIT:
KUBERNETES_SERVICE_MEMORY_LIMIT:
KUBERNETES_SERVICE_CPU_REQUEST:
KUBERNETES_SERVICE_MEMORY_REQUEST:
KUBERNETES_HELPER_CPU_LIMIT:
KUBERNETES_HELPER_MEMORY_LIMIT:
KUBERNETES_HELPER_CPU_REQUEST:
KUBERNETES_HELPER_MEMORY_REQUEST:
KUBERNETES_HELPER_IMAGE:
KUBERNETES_PULL_POLICY:
Mounts:
/configmaps from configmaps (rw)
/home/gitlab-runner/.gitlab-runner from etc-gitlab-runner (rw)
/secrets from runner-secrets (rw)
/var/run/secrets/kubernetes.io/serviceaccount from gitlab-runner-gitlab-runner-token-6cqb4 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
runner-secrets:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium: Memory
SizeLimit: <unset>
etc-gitlab-runner:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium: Memory
SizeLimit: <unset>
init-runner-secrets:
Type: Projected (a volume that contains injected data from multiple sources)
SecretName: gitlab-runner-gitlab-runner
SecretOptionalName: <nil>
configmaps:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: gitlab-runner-gitlab-runner
Optional: false
gitlab-runner-gitlab-runner-token-6cqb4:
Type: Secret (a volume populated by a Secret)
SecretName: gitlab-runner-gitlab-runner-token-6cqb4
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events: <none>
参考:GitLab Runner構築時の公式マニュアルとそのあるき方
最後に、GitLab Runner関連の情報を得るときの公式マニュアルの参照方法を参考までにお届け。
こちらで、GitLab Runnerの構築手順が記載されています。GitLab Runnerは様々な環境でセルフホストする手段があるので、それぞれの環境で最適なものを選択し、利用してみてください。
Install GitLab Runner | GitLab
最初わかりにくかったのですが、公式マニュアルには、別の階層にGitLab Runnerの解説マニュアルがあります。
マニュアルの階層:[Use GitLab] -> [Build your application] -> [Runners]
1つ目に記した[Install GitLab Runner]配下にも、GitLab Runnerのカスタマイズに関する情報が含まれていますが、こちらでは、より詳細な設定方法や運用上のベストプラクティスも含まれているため、本格的にGitLab Runnerをセルフホスティングで運用するのであれば、こちらも一通り目を通しておくことをオススメします。
セルフホスティングのGitLab Runnerを細かくカスタマイズするためには、内部構造の理解は必須
インストールして動かすだけであれば、マニュアルに基づきそのままHelm installでEKS上にGitLab Runnerをインストールするだけで事足ります。が、その後急遽プロジェクトの要件で、GitLab Runnerの各ジョブに個別にIAMロールを紐付ける必要性がでてきました。
最初とりあえずインストールしただけでは、GitLab Runnerの設定ファイルであるvalues.yaml
の内容がイマイチ理解できていなかったのですが、今回、実際にGitLab Runnerインストール時に適用される各種Kubernetesリソースのマニフェストファイルを把握することで、起動されるジョブに紐づくServiceAccountや、関連するRole、各種設定ファイルの関連がわかり、より深くGitLab RunnerのKubernetes Executorの構造が理解できたのが収穫でした。
セルフホストのGitLab Runnerには膨大な設定項目があり、それらを利用することでよりプロジェクトの状況に合わせたCI/CD基盤が構築できます。カスタマイズを進めていくに当たり、基本的な構造を抑えておくことは必須なので、このブログを参考にしていただきながら、紹介した公式マニュアルと合わせて理解を深めてもらえれば幸いです。
それでは、今日はこのへんで。濱田(@hamako9999)でした。