TECHSTEP

ITインフラ関連の記事を公開してます。

GitLabからAmazon EKS上のリソースを更新する

今回はGitLabからAmazon EKS上のPodを更新する方法を紹介します。

docs.gitlab.com

背景

GitLabからAmazon EKSに接続し、リソースを更新するには、大きく3つの方法があります。

  • AWSアクセス情報を使ってkubectlで接続する
  • GitLab Agent for Kubernetesをインストールする
  • Flux CDなどを使ってGitOpsを利用する

今回はこのうち上2つを紹介します。

検証

準備

検証の前に事前に以下の準備をしておきます。

Amazon EKSの作成は以前使ったCloudFormationファイルを利用しました。

クラスター作成後はAWS CloudShellからクラスターにアクセスして状態を確認します。

[cloudshell-user@ip-10-134-10-124 ~]$ aws eks update-kubeconfig \
>    --name eks-cluster \
>    --region ap-northeast-1

[cloudshell-user@ip-10-134-10-124 ~]$ kubectl version
Client Version: v1.29.3-eks-ae9a62a
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.29.4-eks-036c24b

[cloudshell-user@ip-10-134-10-124 ~]$ kubectl get pods -A
NAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE
kube-system   aws-node-xfdkd             2/2     Running   0          5m19s
kube-system   aws-node-z5ll6             2/2     Running   0          5m2s
kube-system   coredns-676bf68468-pz8fl   1/1     Running   0          10m
kube-system   coredns-676bf68468-slrrh   1/1     Running   0          10m
kube-system   kube-proxy-2hppc           1/1     Running   0          5m2s
kube-system   kube-proxy-mhpkb           1/1     Running   0          5m19s

GitLab Project作成後は以下のマニフェストファイルを事前に配置しておきます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

AWSアクセス情報を使う場合

GitLabからkubectlを使ってアクセスするには、GitLabからAWS / Kubernetesそれぞれへのアクセス権限を付与する必要があります。

GitLabからAWSへのアクセスはOIDCを利用します。作成は以下のCloudFormationファイルを利用します。

AWSTemplateFormatVersion: '2010-09-09'
Description: IAM role for GitLab/EKS integration
Parameters:
  RepositoryPath:
    Type: String
    Default: "<GitLab Projectパス>"
  PJPrefix:
    Type: String
    Default: "gitlab-eks"
Resources:
 #OIDCを作成していない場合は以下のコメントを外してください
 #OIDCProviderForGitLab:
 #   Type: AWS::IAM::OIDCProvider
 #   Properties:
 #     Url: https://gitlab.com
 #     ClientIdList:
 #       - https://gitlab.com
 #     ThumbprintList:
 #       - ffffffffffffffffffffffffffffffffffffffff
  RoleForGitLabEKS:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${PJPrefix}-role"
      MaxSessionDuration: 3600
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRoleWithWebIdentity
            Principal:
              Federated: !Sub 'arn:aws:iam::${AWS::AccountId}:oidc-provider/gitlab.com'
            Effect: Allow
            Condition:
              ForAnyValue:StringLike:
                "gitlab.com:sub":
                  - !Sub "project_path:${RepositoryPath}:ref_type:branch:ref:*"
      Policies:
        - PolicyName: !Sub "${PJPrefix}-policy"
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - eks:*
                Resource:
                  - '*'

GitLabからEKSクラスターへのアクセスには、上記で作成したIAMロールがEKSクラスターにアクセスできるよう、EKSクラスター上の aws-auth ConfigMapを修正するか、Access Entryというリソースを作成します。今回はAccess Entryを利用しました。

※参考:

techblog.ap-com.co.jp

ここでは準備のときと同様、AWS CloudShellからコマンドを実行します。

#EKSの認証モードを変更する
[cloudshell-user@ip-10-134-10-124 ~]$ aws eks update-cluster-config \
>    --name eks-cluster \
>    --access-config authenticationMode=API_AND_CONFIG_MAP

[cloudshell-user@ip-10-134-10-124 ~]$ aws eks describe-cluster \
>    --name eks-cluster \
>    --region ap-northeast-1 \
>    --query 'cluster.accessConfig'
{
    "authenticationMode": "API_AND_CONFIG_MAP"
}

#IAMロールのアクセスを許可する
[cloudshell-user@ip-10-134-10-124 ~]$ aws eks create-access-entry \
>    --cluster-name eks-cluster \
>    --principal-arn arn:aws:iam::<AWS Account ID>:role/gitlab-eks-role

[cloudshell-user@ip-10-134-10-124 ~]$ aws eks associate-access-policy \
>    --cluster-name eks-cluster \
>    --principal-arn arn:aws:iam::<AWS Account ID>:role/gitlab-eks-role \
>    --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy \
>    --access-scope type=cluster

#確認
[cloudshell-user@ip-10-134-10-124 ~]$ aws eks list-access-entries \
>    --cluster-name eks-cluster
{
    "accessEntries": [
        "arn:aws:iam::<AWS Account ID>:role/gitlab-eks-role",
        "arn:aws:iam::<AWS Account ID>:user/yamaji"
    ]
}
[cloudshell-user@ip-10-134-10-124 ~]$ 

GitLabからEKSにアクセスするためのAWS側の準備はできたので、GitLab側の設定を行います。

まずは以下のGitLab CI/CD変数を登録します。

  • AWS_ACCOUNT_ID: AWSアカウントID
  • AWS_DEFAULT_REGION: ap-northeast-1
  • AWS_IAM_ROLE: arn:aws:iam::<AWS Account ID>:role/gitlab-eks-role

CI/CD変数を設定後、以下のような .gitlab-ci.yml を作成します。

variables:
  AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION
  AWS_IAM_ROLE: $AWS_IAM_ROLE
  EKS_CLUSTER_NAME: "eks-cluster"
  DOCKER_TLS_CERTDIR: "/certs"
# 各CLIのインストール、AWSへの接続設定
default:
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.com
  before_script:
    - apk add --no-cache aws-cli
    - >
      apk --no-cache add curl &&
      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 &&
      mv ./kubectl /usr/local/bin/kubectl 
    - >
      export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s"
      $(aws sts assume-role-with-web-identity
      --role-arn ${AWS_IAM_ROLE}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token ${GITLAB_OIDC_TOKEN}
      --duration-seconds 3600
      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
      --output text))
# EKSへのデプロイを実行
deploy:
  stage: deploy
  script:
    - aws eks update-kubeconfig --name $EKS_CLUSTER_NAME --region $AWS_DEFAULT_REGION
    - kubectl version
    - kubectl get pods
    - kubectl apply -f deployment.yaml

.gitlab-ci.yml ファイルを作成するとCI/CDパイプラインが実行され、問題なければ成功します。

実行後AWS CloudShellから確認すると、以下のようにPodが作成されたことを確認できます。

[cloudshell-user@ip-10-134-10-124 ~]$ kubectl get pods 
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-7c79c4bf97-sszcp   1/1     Running   0          3m4s
[cloudshell-user@ip-10-134-10-124 ~]$ 

GitLab Agent for Kubernetesを使う場合

GitLab Agent for KubernetesKubernetesクラスターにインストールすると、前段で行ったようなAWSの接続設定をせずに、GitLabからKubernetesクラスターにアクセス可能となります。

GitLab Agent for Kubernetesをインストールするため、まずはGitLab UIから 操作Kubernetesクラスター を選択します。画面遷移後は クラスターに接続 を選択します。

ここでは新しく接続するAgentを用意するため、任意の名前を入力します。

入力後に 登録 を選択します。

次の画面でGitLabとAgentを接続するためのTokenが発行されます。またAgentをインストールするHelmコマンドも表示されるので、どこかにメモしておきます。

Token等の表示画面を閉じると、以下のようにAgentが追加されます。ここではまだインストールしていないので接続されていません。

次にHelmコマンドを使ってAgentをインストールします。再びAWS CloudShellに移動し、以下のようにコマンドを実行します。

#Helmインストール
[cloudshell-user@ip-10-134-10-124 ~]$ wget https://get.helm.sh/helm-v3.15.2-linux-amd64.tar.gz
[cloudshell-user@ip-10-134-10-124 ~]$ tar -zxvf helm-v3.15.2-linux-amd64.tar.gz
[cloudshell-user@ip-10-134-10-124 ~]$ sudo cp -p linux-amd64/helm /usr/local/bin/
[cloudshell-user@ip-10-134-10-124 ~]$ helm version
version.BuildInfo{Version:"v3.15.2", GitCommit:"1a500d5625419a524fdae4b33de351cc4f58ec35", GitTreeState:"clean", GoVersion:"go1.22.4"}

#Agentインストール
[cloudshell-user@ip-10-134-10-124 ~]$ helm repo add gitlab https://charts.gitlab.io
"gitlab" has been added to your repositories

[cloudshell-user@ip-10-134-10-124 ~]$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "gitlab" chart repository
Update Complete. ⎈Happy Helming!⎈

[cloudshell-user@ip-10-134-10-124 ~]$ helm upgrade --install eks-cluster gitlab/gitlab-agent \
>     --namespace gitlab-agent-eks-cluster \
>     --create-namespace \
>     --set image.tag=v17.2.0-rc1 \
>     --set config.token=glagent-S7WtgzAsTr6uQgzM-v6UnoZ8H4szid4oEwGxCa4VYpZzzUMxgw \
>     --set config.kasAddress=wss://kas.gitlab.com
Release "eks-cluster" does not exist. Installing it now.
NAME: eks-cluster
LAST DEPLOYED: Tue Jul  9 23:38:08 2024
NAMESPACE: gitlab-agent-eks-cluster
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Thank you for installing gitlab-agent.

Your release is named eks-cluster.

## Changelog

### 1.17.0

- The default replica count has been increased from `1` to `2` to allow a zero-downtime upgrade experience.
  You may use `--set replicas=1` to restore the old default behavior.
[cloudshell-user@ip-10-134-10-124 ~]$ 


#インストール後の確認
[cloudshell-user@ip-10-134-10-124 ~]$ kubectl get ns
NAME                       STATUS   AGE
default                    Active   69m
gitlab-agent-eks-cluster   Active   31s
kube-node-lease            Active   69m
kube-public                Active   69m
kube-system                Active   69m

[cloudshell-user@ip-10-134-10-124 ~]$ kubectl get pods -n gitlab-agent-eks-cluster
NAME                                           READY   STATUS    RESTARTS   AGE
eks-cluster-gitlab-agent-v2-5c79b4c4d5-cj9rx   1/1     Running   0          48s
eks-cluster-gitlab-agent-v2-5c79b4c4d5-xh49j   1/1     Running   0          48s

Agentをインストール後にGitLab画面を見ると、Agentの接続ステータスが更新されていることを確認できます。

Agentをインストールしたので、GitLab CI/CDからデプロイしてみます。以下のように .gitlab-ci.yml を修正し、先ほど使ったIAMロール等を使わないよう変更します。先ほどと比べてかなり量が削減されたことが分かります。

deploy:
  stage: deploy
  variables:
    KUBERNETES_AGENT_NAME: "eks-cluster"
  image:
    name: bitnami/kubectl:latest
    entrypoint: ['']
  script:
    - kubectl config use-context $CI_PROJECT_PATH:$KUBERNETES_AGENT_NAME
    - kubectl apply -f deployment.yaml

.gitlab-ci.yml を変更するとCI/CDパイプラインが起動し、問題なければ成功します。

ログを見るとGitLabからEKSクラスターにアクセスする様子を確認できます。

検証後はEKSクラスターの削除と合わせてAgentの設定も削除します。