GitLabとGitLab Runnerを同一EKSクラスター上で稼働させつつワーカーノードを分離してみた

GitLabとGitLab Runnerを同一EKSクラスター上で稼働させつつワーカーノードを分離してみた

Clock Icon2025.03.23

Amazon EKSでGitLabをセルフホストしています。

GitLab Runnerを利用するにあたり、同一EKSクラスター上で稼働させつつGitLabとは別のマシン上で動作させたいことがありました。

今回はこの方法についてブログにします。

前提

本記事では、以下を前提とします。

  • GitLab・GitLab Runner をEKSにインストール済み

インストール方法については、以下の記事をご参照ください。

https://dev.classmethod.jp/articles/gitlab-eks-helm-tutorial/
https://dev.classmethod.jp/articles/gitlab-runner-eks-helm/

なぜGitLabとGitLab Runnerを別ノードで動作させたいのか?

公式ドキュメントには以下の記載があり、別のマシン上で動作させることが推奨されています。

For security and performance reasons, install GitLab Runner on a machine separate from the machine that hosts your GitLab instance.
セキュリティとパフォーマンス上の理由から、GitLab インスタンスをホストするマシンとは別のマシンに GitLab Runner をインストールします。

Install GitLab Runner | GitLab Docsから引用

GitLab Runnerでは、CI/CDのジョブ毎にRunnerノード上にPodが起動します。

同一マシン上で稼働させている場合、GitLab Runnerのジョブ数増加によるリソース逼迫でGitLab自体のパフォーマンスが落ちる可能性があります。

どのレベルでGitLabとGitLab Runnerを分離するか

今回GitLabはEKS上に構築していることを前提としています。

GitLab RunnerもEKS上で構築する場合、分離の選択肢は以下があると思います。

  1. EKSクラスター単位
  2. EKSノードグループ単位

ざっくり以下のようなメリット・デメリットがあると思います。

- EKSクラスター EKSノードグループ
メリット 分離の複雑性: Kubenetes側のノード分離設定が不要
コスト: 単一EKSクラスター料金のみ(72USD/月)
管理: EKSバージョンアップが1回で済む
デメリット コスト: EKSクラスター料金が2倍((72USD/月 * 2))
管理: EKSバージョンアップが2回必要
分離の複雑性: Kubenetes側のノード分離設定が必要(Node Afinity/Taints等)

今回はコストとEKSクラスター管理を重視して、ノードグループ単位の分離としました。

このブログでは、ノードグループ単位の分離を前提として、ノード分離設定について紹介します。

やってみた

GitLab Runner用のマネージドノードグループを作成

任意の方法でGitLab Runner用のマネージドノードグループを作成します。

今回はawscliを利用する方法を紹介します。

以下のファイルを用意します。

クラスター名サブネットIDノードIAMロールARNは各自の環境に合わせて置き換えてください。

動作させるだけであれば、Node Role ARNは既存マネージドノードグループにアタッチされているノードIAMロールでも問題ありません。

gitlab-runner-nodegroup.json
{
    "clusterName": "<クラスター名>",
    "nodegroupName": "gitlab-runner",
    "subnets": [
      "<サブネットID A>",
      "<サブネットID B>",
      "<サブネットID C>"
    ],
    "nodeRole": "<ノードIAMロールARN>",
    "scalingConfig": {
      "minSize": 1,
      "maxSize": 1,
      "desiredSize": 1
    },
    "instanceTypes": [
      "t3.medium"
    ],
    "diskSize": 30,
    "labels": {
      "workload": "gitlab-runner"
    },
    "taints": [
      {
        "key": "workload",
        "value": "gitlab-runner",
        "effect": "NO_SCHEDULE"
      }
    ]
}

GitLab Runner専用のノードとするために、taintslabelsを設定しておきます。

GitLab Runnerについては、必要スペックがCI/CDジョブによって異なります。

明示的な推奨スペックは無いため、各自の環境に合わせてインスタンスタイプを選定してください。

https://docs.gitlab.com/runner/install/#system-requirements

以下のコマンドを実行してマネージドノードグループを作成します。

aws eks create-nodegroup \
  --region <リージョン> # us-east-2 \
  --cli-input-json file://gitlab-runner-nodegroup.json

GitLab Runner用マネージドノードとGitLab用マネージドノード間では通信が必要です。

マネージドノードグループに以下のTerraformコードで作成したSecurityGroupをアタッチします。

network/main.tf
resource "aws_security_group" "gitlab_internal_networking" {
  name_prefix = "${var.prefix}-internal-networking"
  vpc_id      = module.vpc.vpc_id

  description = "${var.prefix} - Internal Networking Security Group"

  tags = {
    Name = "${var.prefix}-internal-networking"
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_vpc_security_group_ingress_rule" "gitlab_internal_networking" {
  security_group_id = aws_security_group.gitlab_internal_networking.id

  description = "Open internal networking for VMs and Node Groups"
  ip_protocol = "-1"

  referenced_security_group_id = aws_security_group.gitlab_internal_networking.id

  tags = {
    Name = "${var.prefix}-internal-networking"
  }
}

resource "aws_vpc_security_group_egress_rule" "gitlab_internal_networking_internet" {
  security_group_id = aws_security_group.gitlab_internal_networking.id

  description = "Open internet access for VMs"
  ip_protocol = "-1"

  cidr_ipv4 = "0.0.0.0/0"

  tags = {
    Name = "${var.prefix}-internal-networking-internet"
  }
}

GitLab RunnerマネージドノードグループEC2インスタンス及び、GitLabマネージドノードグループEC2に上記のセキュリティグループをアタッチします。

aws ec2 modify-instance-attribute \
  --instance-id <インスタンスID> \
  --groups <セキュリティグループID>

今回は手順の簡略化のために、マネージドノードグループ内のEC2インスタンスに直接セキュリティグループをアタッチしています。

この方法はノードのスケールに対応できないため、実環境ではEC2起動テンプレート側でセキュリティグループを設定することを推奨します。(スケールアップ等で新規に作成されたノードに上記のセキュリティグループがアタッチされない)

values.yamlの更新

values.yamlを更新します。GitLab URLトークンは置き換えてください。

values.yaml
gitlabUrl: <GitLab URL> # example: https://gitlab.exmaple.com/
runnerRegistrationToken: "<トークン>"
rbac:
  create: true
serviceAccount:
  create: true
  name: "gitlab-runner"

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: workload
          operator: In
          values:
          - gitlab-runner

tolerations:
  - key: "workload"
    operator: "Equal"
    value: "gitlab-runner"
    effect: "NoSchedule"

runners:
  # tpl: https://helm.sh/docs/howto/charts_tips_and_tricks/#using-the-tpl-function
  # runner configuration: https://docs.gitlab.com/runner/configuration/advanced-configuration.html
  # kubernetes executor: https://docs.gitlab.com/runner/executors/kubernetes/
  config: |
    [[runners]]
      [runners.kubernetes]
        [runners.kubernetes.affinity]
          [runners.kubernetes.affinity.node_affinity]
            [runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution]
              [[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms]]
                [[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms.match_expressions]]
                  key = "workload"
                  operator = "In"
                  values = ["gitlab-runner"]
        [runners.kubernetes.node_tolerations]
          "workload=gitlab-runner" = "NoSchedule"

追加したのはNode AffinityTolerations関係の設定です。

これはGitLab Runner用マネージドノードグループを、GitLab Runnerの専用ノードにするための設定です。

  • Node Affinity: GitLab Runner用のPodを、workload=gitlab-runnerラベルを持つノードにのみスケジュールする設定
  • Tolerations: GitLab Runner用のPodが、workload=gitlab-runner:NoScheduleのTaintを持つノードにスケジュールできるようにする設定

runners配下でも同様の設定をしています。

これはジョブPodの設定です。GitLab Runnerでは、CI/CDジョブ毎にPodが起動します。(ジョブPod)

ジョブPodはGitLab Runner管理用Podの設定を引き継ぐことはなく、TolerationsNode Affinityを別途設定する必要があります。

上記のように設定することで、ジョブPodもGitLab Runner専用ノードで起動するように設定しています。

Helmリリースの更新

準備ができたら以下のコマンドで、Helmリリースを更新します。

# Dry-run
helm upgrade gitlab-runner gitlab/gitlab-runner \
  -f values.yaml \
  --dry-run \
  -n gitlab-runner
# Run
helm upgrade gitlab-runner gitlab/gitlab-runner \
  -f values.yaml \
  -n gitlab-runner

動作確認

ノードを管理しているマネージドノードグループを確認します。

kubectl get nodes --label-columns=eks.amazonaws.com/nodegroup
出力例
NAME                                        STATUS   ROLES    AGE     VERSION               NODEGROUP
ip-10-0-100-67.us-east-2.compute.internal   Ready    <none>   105m    v1.30.9-eks-5d632ec   default-20250321091112021200000024
ip-10-0-11-239.us-east-2.compute.internal   Ready    <none>   105m    v1.30.9-eks-5d632ec   default-20250321091112021200000024
ip-10-0-19-178.us-east-2.compute.internal   Ready    <none>   7m50s   v1.30.9-eks-5d632ec   gitlab-runner

上記から、ip-10-0-19-178.us-east-2.compute.internalがGitLab Runner用のノードであることが分かりました。

このノードでGitLab Runner用のPodが稼働することを確認します。

kubectl get pods -o wide -n gitlab-runner
出力例
NAME                             READY   STATUS    RESTARTS   AGE   IP            NODE                                        NOMINATED NODE   READINESS GATES
gitlab-runner-5b6cc88b68-gd5nt   1/1     Running   0          73s   10.0.45.240   ip-10-0-19-178.us-east-2.compute.internal   <none>           <none>

Podgitlab-runner-5b6cc88b68-gd5ntNODEip-10-0-19-178.us-east-2.compute.internalになっているため、GitLab Runner用のノードで起動していることが確認できます。

他のリソースがGitLab Runner用のノードで稼働していないことも確認できました。

kubectl get pods -o wide -n gitlab
出力例
NAME                                             READY   STATUS      RESTARTS      AGE   IP             NODE                                        NOMINATED NODE   READINESS GATES
gitlab-certmanager-7c6f6b775f-gszfh              1/1     Running     0             18m   10.0.118.119   ip-10-0-100-67.us-east-2.compute.internal   <none>           <none>
gitlab-certmanager-cainjector-75c88bbb77-spcx9   1/1     Running     0             18m   10.0.118.118   ip-10-0-100-67.us-east-2.compute.internal   <none>           <none>
gitlab-certmanager-webhook-86f7d45d4f-8hss6      1/1     Running     0             18m   10.0.40.169    ip-10-0-11-239.us-east-2.compute.internal   <none>           <none>
gitlab-gitaly-0                                  1/1     Running     0             18m   10.0.118.121   ip-10-0-100-67.us-east-2.compute.internal   <none>           <none>
gitlab-gitlab-exporter-8fd649d5c-cvbk4           1/1     Running     0             18m   10.0.40.167    ip-10-0-11-239.us-east-2.compute.internal   <none>           <none>
gitlab-kas-65d6c4dc77-5n62r                      1/1     Running     2 (17m ago)   18m   10.0.40.170    ip-10-0-11-239.us-east-2.compute.internal   <none>           <none>
gitlab-kas-65d6c4dc77-s9dx2                      1/1     Running     0             17m   10.0.118.123   ip-10-0-100-67.us-east-2.compute.internal   <none>           <none>
gitlab-migrations-6ff953e-cqw5c                  0/1     Completed   0             18m   10.0.103.48    ip-10-0-100-67.us-east-2.compute.internal   <none>           <none>
gitlab-postgresql-0                              2/2     Running     0             18m   10.0.40.171    ip-10-0-11-239.us-east-2.compute.internal   <none>           <none>
gitlab-prometheus-server-c7f9d89dc-nnzzw         2/2     Running     0             18m   10.0.40.172    ip-10-0-11-239.us-east-2.compute.internal   <none>           <none>
gitlab-redis-master-0                            2/2     Running     0             18m   10.0.118.116   ip-10-0-100-67.us-east-2.compute.internal   <none>           <none>
gitlab-registry-5499795975-7wx8b                 1/1     Running     0             17m   10.0.118.117   ip-10-0-100-67.us-east-2.compute.internal   <none>           <none>
gitlab-registry-5499795975-dwkfg                 1/1     Running     0             18m   10.0.40.166    ip-10-0-11-239.us-east-2.compute.internal   <none>           <none>
gitlab-sidekiq-all-in-1-v2-6fdb8b7656-xmjmw      1/1     Running     1 (15m ago)   18m   10.0.118.120   ip-10-0-100-67.us-east-2.compute.internal   <none>           <none>
gitlab-toolbox-d76bf6d7-678f2                    1/1     Running     0             18m   10.0.40.168    ip-10-0-11-239.us-east-2.compute.internal   <none>           <none>
gitlab-webservice-default-5bf789cbf5-9hghz       2/2     Running     1 (15m ago)   17m   10.0.118.122   ip-10-0-100-67.us-east-2.compute.internal   <none>           <none>
gitlab-webservice-default-5bf789cbf5-c2pbq       2/2     Running     1 (15m ago)   18m   10.0.40.165    ip-10-0-11-239.us-east-2.compute.internal   <none>           <none>

ip-10-0-19-178.us-east-2.compute.internalで稼働しているPodは無いため、問題なさそうです。

最後に、GitLabで適当なパイプラインを実行して、ジョブ用のPod(Pod名runner-から始まるもの)がGitLab Runner用のノードで起動するか確認します。

kubectl get pods -o wide -n gitlab-runner
出力例
NAME                                              READY   STATUS        RESTARTS   AGE     IP          NODE                                        NOMINATED NODE   READINESS GATES
gitlab-runner-5fcb7987c4-chwtj                    1/1     Running       0          5m32s   10.0.42.1   ip-10-0-19-178.us-east-2.compute.internal   <none>           <none>
runner-t1htgj4s-project-1-concurrent-0-areczxil   2/2     Running       0          19s     10.0.42.3   ip-10-0-19-178.us-east-2.compute.internal   <none>           <none>
runner-t1htgj4s-project-1-concurrent-0-hstmi422   2/2     Terminating   0          36s     10.0.42.2   ip-10-0-19-178.us-east-2.compute.internal   <none>           <none>

すべてのPodがGitLab Runner用ノード(ip-10-0-19-178.us-east-2.compute.internal)で稼働していることが確認できました。

おまけ: Node Affinity・Tolerationsの確認

Helmチャート側で設定したNode Affinity・Tolerationsの確認方法です。

ジョブPod・GitLab Runner管理用Podでそれぞれ設定されていることが確認できます。

POD_NAME="<Pod名>"
Node Affinity
kubectl get pod $POD_NAME -o yaml | grep -A 10 affinity
Node Affinity出力例
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: workload
            operator: In
            values:
            - gitlab-runner
Tolerations
kubectl get pod -n gitlab-runner $POD_NAME -o yaml | grep -A 5 tolerations
Tolerations出力例
  tolerations:
  - effect: NoSchedule
    key: workload
    operator: Equal
    value: gitlab-runner

おわりに

GitLab RunnerとGitLabを同一EKSクラスターで稼働させつつ、ノードを分ける方法についてでした。

この方法を使うことでEKSクラスターを分けることなく、GitLabとGitLab Runnerを別マシンで稼働させることが可能です。

GitLab Runner管理PodとジョブPod、それぞれにNode Affinity・Tolerations設定が必要なことにご注意ください。

特にジョブPodの設定を忘れると、他のノードでジョブPodが動いてノードのリソースを逼迫することがあります。

以上、AWS事業本部の佐藤(@chari7311)でした。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.