2021|sitateru tech blog

sitateru tech blog

シタテルの技術やエンジニアの取り組みを紹介するテックブログです。

2021年10月14日木曜日

Amazon EFSを使ってEKSに永続ボリュームを導入した

AWS EKSで動かしているアプリケーション用にEFSを使って永続ボリュームを用意してみたので、その方法をまとめてみようと思います。

とあるテスト用Kubernetes環境でMySQLのイメージを使ってデータベースを動かしているのですが、何かの拍子にpodが一旦削除などされてしまうとデータベースの中身のデータが全て無くなってしまいます。
そこで永続ボリュームを確保しておいて、MySQLデータ用のディレクトリをマウントしたボリュームにすればOKというわけです。

手順はほぼこのドキュメントどおりですが、一部変えないと動かなかった箇所があるのでその点も触れつつ書いてみようと思います。
Amazon EFS CSI ドライバー

ドキュメントに従っても動かないよ!という件のissueはこちら。
Missing permission in the example IAM policy file · Issue #489 · kubernetes-sigs/aws-efs-csi-driver · GitHub

また、今回やってみた環境は以下のようになっています。
Kubernetes v1.21
EKSプラットフォーム eks.2
EFS CSI ドライバー v1.3.4


  1. Amazon EFS CSI ドライバー

まずはIAMポリシーを作成します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "elasticfilesystem:DescribeAccessPoints",
                "elasticfilesystem:DescribeFileSystems",
                "elasticfilesystem:DescribeMountTargets",
                "ec2:DescribeAvailabilityZones"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticfilesystem:CreateAccessPoint"
            ],
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "aws:RequestTag/efs.csi.aws.com/cluster": "true"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": "elasticfilesystem:DeleteAccessPoint",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/efs.csi.aws.com/cluster": "true"
                }
            }
        }
    ]
}

AmazonEKS_EFS_CSI_Driver_Policy というポリシーを作成してこのjsonでアクセス権限を設定します。

AWSのドキュメントからリンクされているポリシーと比べると"elasticfilesystem:DescribeMountTargets", "ec2:DescribeAvailabilityZones"が増えているのですが、これを追加しないと権限不足のエラーが出てドライバーが動きませんでした。🤔

このポリシーでサービスアカウントを作成します。<cluster-name><Account ID>, <region>はお使いの環境に合わせて置き換えてください。

$ eksctl create iamserviceaccount \
    --name efs-csi-controller-sa \
    --namespace kube-system \
    --cluster <cluster-name> \
    --attach-policy-arn arn:aws:iam::<Account ID>:policy/AmazonEKS_EFS_CSI_Driver_Policy \
    --approve \
    --override-existing-serviceaccounts \
    --region <region>
$ eksctl create iamserviceaccount \
    --name efs-csi-node-sa \
    --namespace kube-system \
    --cluster <cluster-name> \
    --attach-policy-arn arn:aws:iam::<Account ID>:policy/AmazonEKS_EFS_CSI_Driver_Policy \
    --approve \
    --override-existing-serviceaccounts \
    --region <region>

Helmを使ってドライバーをクラスターにインストールします。
クラスターのリージョンによってimage.repositoryは変えないといけないようなので↓を参照してください。
Amazon EKS アドオンコンテナイメージのアドレス - Amazon EKS

$ helm repo add aws-efs-csi-driver https://kubernetes-sigs.github.io/aws-efs-csi-driver/
$ helm repo update
$ helm upgrade -i aws-efs-csi-driver aws-efs-csi-driver/aws-efs-csi-driver \
    --namespace kube-system \
    --set image.repository=602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/eks/aws-efs-csi-driver \
    --set controller.serviceAccount.create=false \
    --set controller.serviceAccount.name=efs-csi-controller-sa \
    --set node.serviceAccount.create=false \
    --set node.serviceAccount.name=efs-csi-node-sa

AWSのドキュメントでは efs-csi-node-sa は出てこないのですが、こちらも試した環境ではこのサービスアカウントを作成してhelmで指定しないと動きませんでした。🤔


  1. EFS ファイルシステム作成

ここはインフラ管理の都合上terraformで行いました。
セキュリティグループ、ファイルシステム、マウントターゲット(AWSコンソールでは「ネットワーク」という表示名になっています)を作成します。
VPCに複数のプライベートサブネットがある場合は aws_efs_mount_target も同様に複数作っておきましょう。

resource "aws_security_group" "efs" {
  name   = "eks-${var.cluster_name}-efs"
  # ↓クラスターがあるVPCのid
  vpc_id = var.vpc_id
  ingress {
    from_port   = 2049
    to_port     = 2049
    protocol    = "tcp"
    # ↓VPCのCIDR
    cidr_blocks = [var.vpc_cidr]
  }
}
resource "aws_efs_file_system" "fs" {
  creation_token = "eks-${var.cluster_name}-fs"
  tags = {
    "Name" = "eks-${var.cluster_name}-fs"
  }
}
resource "aws_efs_mount_target" "az" {
  file_system_id  = aws_efs_file_system.fs.id
  # ↓プライベートサブネットのID
  subnet_id       = var.subnet_private.id
  security_groups = [aws_security_group.efs.id]
}

  1. クラスターでStorageClassを追加

まずはストレージクラスの宣言です。StorageClassはnamespaceに属していないので、一度applyしておけばOKです。
parametersについてはこちらを参考にしてください👇

aws-efs-csi-driver/examples/kubernetes/dynamic_provisioning at master · kubernetes-sigs/aws-efs-csi-driver · GitHub

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  # EFSで作成したファイルシステムのID
  fileSystemId: fs-00abcdef123456789
  directoryPerms: "700"

  1. アプリケーションで永続ボリュームを確保、マウント

これで準備ができたので、PersistentVolumeを使うアプリケーションでのyamlを書いていきます。

まずはPVC(PersistentVolumeClaim)です。
storageClassName は3.で宣言したStorageClassのnameですね。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 2Gi

このPVCで確保したボリュームをコンテナにマウントします。
以下のyamlはdeploymentでやる場合のvolumeに関するところを書き出したものです。 claimName がPVCリソースのnameですね。

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: mysql
          image: mysql:8.0.25
          volumeMounts:
            - name: persistent-storage
              mountPath: /var/lib/mysql
      volumes:
        - name: persistent-storage
          persistentVolumeClaim:
            claimName: efs-claim

と、このような作業で永続ボリュームを利用できました。

冒頭で触れたドキュメント不完全問題もあって少し手間取りましたが、振り返ってまとめてみるとそう難しいことはなさそうですね。

EKSで永続ボリュームが欲しくなったときはお試しください👐

, , ,

2021年8月27日金曜日

AWS App Mesh をEKSで試してみた(仮想ゲートウェイ)

前回に続き、EKS上でのAWS App Meshをやっていきます。

今回は、仮想ゲートウェイです。
ゲートウェイがあれば、メッシュ上のリソースにメッシュ外のpodやWebなどからアクセスできるようになります💁‍♂️

今回の内容もドキュメント等いまいち見つからなかったので正確さなどは怪しいところがありますがご了承ください🙇‍♂️

Virtual gateways - AWS App Mesh


  1. 仮想ゲートウェイ作成

まずは仮想ゲートウェイとそのルートを作成します。
リスナーのポートは後で作るゲートウェイの実体と番号を合わせれば何番でもよさそうです。ルートは、全てのリクエストを前回作った仮想サービス(svc-v)へ流すよう指定してみました。

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualGateway
metadata:
  namespace: mesh-test
  name: gateway-v
spec:
  namespaceSelector:
    matchLabels:
      mesh: mesh-1
  podSelector:
    matchLabels:
      for: gateway
  listeners:
    - portMapping:
        port: 8088
        protocol: http
      connectionPool:
        http:
          maxConnections: 1024
  logging:
    accessLog:
      file:
        path: /dev/stdout
---
apiVersion: appmesh.k8s.aws/v1beta2
kind: GatewayRoute
metadata:
  namespace: mesh-test
  name: gateway-v-route-v
spec:
  httpRoute:
    action:
      target:
        virtualService:
          virtualServiceRef:
            name: svc-v
    match:
      prefix: /
  1. ゲートウェイ作成

ゲートウェイの実体となる、envoyイメージのコンテナと type: LoadBalancer な サービスを作成します。
envoyのcontainerPortとサービスのtargetPortは仮想ゲートウェイのリスナにしているポートと等しくする必要があります。
また、envoyの環境変数としてリージョンと仮想ゲートウェイARNを与える必要があるようです。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gateway-v
  namespace: mesh-test
spec:
  replicas: 1
  selector:
    matchLabels:
      for: gateway
  template:
    metadata:
      labels:
        for: gateway
    spec:
      serviceAccountName: appmesh-proxyauth
      containers:
        - name: gateway
          image: public.ecr.aws/appmesh/aws-apmesh-envoy:v1.19.0.0-prod
          env:
            - name: AWS_REGION
              value: ap-northeast-1
            - name: APPMESH_RESOURCE_ARN
              value: arn:aws:appmesh:ap-northeast-1:123456780000:mesh/mesh-1/virtualGateway/gateway-v_mesh-test
          ports:
            - containerPort: 8088
          resources:
            limits:
              cpu: 10m
              memory: 32Mi
---
apiVersion: v1
kind: Service
metadata:
  name: gateway-v
  namespace: mesh-test
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
  type: LoadBalancer
  ports:
    - name: http
      port: 80
      targetPort: 8088
  selector:
    for: gateway

以上をapplyすると、ロードバランサーが作られて仮想ゲートウェイとして動くようになります。

$ kubectl get service
NAME        TYPE           CLUSTER-IP       EXTERNAL-IP                                                                          PORT(S)
gateway-v   LoadBalancer   10.100.184.34    aae2598dca4e348b2a934f4cd88b7982-607b093417cc2f4d.elb.ap-northeast-1.amazonaws.com   80:31248/TCP

AWSコンソールでロードバランサーを見てみると、NLBができていました。


コンソールのApp Meshでもゲートウェイが表示されています。


ゲートウェイへのアクセスですが、クラスター内からは
$ curl gateway-v.mesh-test.svc.cluster.local
外からは
$ curl <NLBのドメイン名>
でリクエストを送って、仮想サービスsvc-vに送られることが確認できました。



ということで、App Mesh作ってみるシリーズでした。
今回はごく基本的な部分しか試していませんが、各リソースで設定できる機能はいろいろあるので公式ドキュメントやCustomResourceDefinitionを参照してみてください🙏

eks-charts/crds.yaml at master · aws/eks-charts

ちなみに、App Meshには(他のサービスと同様に)作れるリソース数の制限があります。
ほとんどはサポートセンターに頼めば引き上げ可能なようですが、メッシュ設計の際はちょっと気にしておいたほうがいいかもしれないですね。
AWS App Mesh エンドポイントとクォータ - AWS 全般のリファレンス

, , ,

2021年6月17日木曜日

AWS App Mesh をEKSで試してみた(仮想ルーター、仮想サービス)

前回に続き、EKS上でのAWS App Meshをやっていきます。
今回は、仮想ルーターと仮想サービスです。
前回作った仮想ノードにアクセスするには仮想ルーターか仮想ゲートウェイが必要になるので、いよいよメッシュができていきます💪

あまりしっかり説明されたドキュメントが見つからず経験ベースな部分が多いので、正しい説明になっているかどうか怪しい部分もありますがご了承ください🙇‍


  1. 仮想ルーター作成

仮想ノードへトラフィックを振り分ける仮想ルーターを作成します。
振り分け先は weightedTargetsvirtualNodeRef.name で仮想ノード名を指定します。
プロトコルはHTTPにしましたが、他にもGRPC, HTTP2, TCPが設定できるようです。

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualRouter
metadata:
  namespace: mesh-test
  name: vrouter-1
spec:
  listeners:
    - portMapping:
        port: 80
        protocol: http
  routes:
    - name: route-1
      httpRoute:
        match:
          prefix: /
        action:
          weightedTargets:
            - virtualNodeRef:
                name: vnode-1
              weight: 1
            - virtualNodeRef:
                name: vnode-2
              weight: 1

  1. 仮想サービス用サービス作成

仮想サービスの実体にするserviceを作成します。
selecter は、仮想サービスを介してアクセスする先のpodが全て含まれるように指定する必要があるみたいです。
今回の例だと、仮想サービス → 仮想ルーター(vrouter-1) → 仮想ノード(vnode-1, vnode-2) というトラフィックの流れになるので、vnode-1とvnode-2の実体になるpodに app: sample1 のラベルをつけてあります。

apiVersion: v1
kind: Service
metadata:
  name: svc-v
  namespace: mesh-test
  labels:
    app: sample1
spec:
  type: ClusterIP
  selector:
    app: sample1
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

  1. 仮想サービス作成

先の svc-v を実体とする仮想サービスを作成します。
name は上で仮想サービス用に作ったサービス名と等しくする必要があるみたいです。
provider には仮想サービスを通してアクセスする先を指定を指定します。単一のvirtualNodeかvirtualRouterを選択できるので、トラフィックを複数ノードに分けたいならvirtualRouter、分けなくていいならvirtualNodeにするとよさそうです。

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualService
metadata:
  namespace: mesh-test
  name: svc-v
spec:
  provider:
    virtualRouter:
      virtualRouterRef:
        name: vrouter-1

  1. 仮想サービスをバックエンドに設定

作った仮想サービスにアクセスするには、「仮想ノードのバックエンド」にその仮想サービスを指定する必要があります。
仮想ノードのyamlで、backendsに仮想サービスを追加しておきます。

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualNode
metadata:
  name: vnode-x
  namespace: mesh-test
spec:
  # 主要部分は省略
  backends:
    - virtualService:
        virtualServiceRef:
          name: svc-v

仮想ノード化されたPodから仮想サービスへリクエストを送ると、
ルーティングに従ったレスポンスが返ってくるはずです。

$ kubectl exec -it somepod-524b1761b4-vg8kw -- bash
root@somepod-524b1761b4-vg8kw:/# curl svc-v.mesh-test.svc.cluster.local

いろいろ試してみたところ、「バックエンドにその仮想サービスを指定したpod」で「仮想サービス名.名前空間.svc.cluster.localへトラフィックを送る」場合に仮想サービスで設定したトラフィック振り分けが行われる仕様のようです。
それ以外の条件、例えばバックエンドを指定していないpodからのリクエストや仮想サービス名だけのホスト名にトラフィックを送る($ curl svc-v)場合は(仮想ではない)Serviceの svc-v に行くようです。
なかなかややこしいですね。

, , ,

2021年6月3日木曜日

AWS App Mesh をEKSで試してみた(準備~仮想ノードまで)

突然ですが、AWS App Meshは皆さんお使いでしょうか?
AWS製のサービスメッシュ構築サービスですね。

サービスメッシュといえばIstioが有名ですが、AWS App MeshはAWS製だけあってEKSはもちろんEC2やECSのインスタンス・コンテナもメッシュに組み込むことができるのが強みという印象です。

そんなApp MeshをEKS上でいろいろと実験してみたので、自分の理解の反芻のためにもまとめてみたいと思います。

試した環境は kubernetes 1.20, App Meshコントローラ 1.3.0 でした。


  1. 準備

ドキュメントに従ってコントローラをインストールします。

Getting started with AWS App Mesh and Kubernetes - AWS App Mesh

手順はドキュメントの通りなのでここでは書きませんが、完了するとappmesh-systemネームスペースでコントローラのポッドができていました。

$ kubectl get pod -n appmesh-system
NAME                                  READY   STATUS    RESTARTS   AGE
appmesh-controller-6c55b46558-8s363   1/1     Running   0          1d

  1. mesh作成

メッシュを作成します。
egressFilter はメッシュ内部から外部へのアクセスを許可するかどうかですね。許可しない場合はDROP_ALLにします。
namespaceSelecter も何でもいいので書いておきましょう。

apiVersion: appmesh.k8s.aws/v1beta2
kind: Mesh
metadata:
  name: mesh-1
spec:
  egressFilter:
    type: ALLOW_ALL
  namespaceSelector:
    matchLabels:
      mesh: sitateru-mesh

  1. namespace作成

メッシュのリソースを配置するネームスペースを宣言します。
上のMeshで指定した namespaceSelector とラベルを合わせておきましょう。
App Meshの機能を使うにはappmesh.k8s.aws/sidecarInjectorWebhook をenabledにしてEnvoyサイドカーが入れられるようにしておく必要があります。

apiVersion: v1
kind: Namespace
metadata:
  name: mesh-test
  labels:
    mesh: mesh-1
    appmesh.k8s.aws/sidecarInjectorWebhook: enabled

  1. サービスアカウント作成

IAMで以下のポリシーを作成します。
今回は動作検証なので mesh-1 メッシュの全ての仮想ノードと仮想ゲートウェイに対して StreamAggregatedResources を許可していますが、実使用の際には適宜リソース名を指定するほうが望ましいですね。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appmesh:StreamAggregatedResources",
            "Resource": [
                "arn:aws:appmesh:ap-northeast-1:111122223333:mesh/mesh-1/virtualNode/*",
                "arn:aws:appmesh:ap-northeast-1:111122223333:mesh/mesh-1/virtualGateway/*"
            ]
        }
    ]
}

続いてこのポリシーをアタッチしたサービスアカウントをEKSクラスターに作成します。

$ eksctl create iamserviceaccount \
    --cluster test-cluster \
    --namespace mesh-test \
    --name appmesh-proxyauth \
    --attach-policy-arn arn:aws:iam::111122223333:policy/appmesh-proxyauth \
    --override-existing-serviceaccounts \
    --approve

  1. 仮想ノード用サービス作成

仮想ノードの実体にするdeploymentとserviceを作成します。コンテナイメージは何でもいいのですが、今回はただのnginxにしています。
serviceAccountName には👆で作成したサービスアカウント名を指定します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-1
  namespace: mesh-test
  labels:
    app: sample0
spec:
  selector:
    matchLabels:
      app: sample0
  template:
    metadata:
      labels:
        app: sample0
        server: nginx
    spec:
      serviceAccountName: appmesh-proxyauth
      containers:
        - name: nginx
          image: nginx:1.19.0
          ports:
          - containerPort: 80
          resources:
            limits:
              cpu: 10m
              memory: 10Mi
---
apiVersion: v1
kind: Service
metadata:
  name: svc-1
  namespace: mesh-test
  labels:
    app: sample0
spec:
  selector:
    app: sample0
    server: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

  1. 仮想ノード作成

今作ったsvc-1 を実体とする仮想ノードを作成します。
serviceDiscovery で仮想ノードとする実体を指定するのですが、ここでは目的のサービスのDNSホスト名( サービス名.名前空間.svc.cluster.local )を指定します。

ServiceとPodに対するDNS | Kubernetes

ちなみにDNSではなくCloud Mapを使って指定することもできるみたいです。

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualNode
metadata:
  name: vnode-1
  namespace: mesh-test
spec:
  podSelector:
    matchLabels:
      app: sample0
  listeners:
    - portMapping:
        port: 80
        protocol: http
  serviceDiscovery:
    dns:
      hostname: svc-1.mesh-test.svc.cluster.local

うまくできていればAWSコンソールでもメッシュや仮想ノードが表示されているはずです。

できていない場合は appmesh-controller ポッドのログを見れば何かわかるかもしれないのでチェックしてみてください。


そこそこ長くなってきたのでここまでにしようと思います。
ここまで作ったものだけではぜんぜんサービスメッシュになっていないのですが、続きは近いうちにまた書きます!

ちなみに、メッシュのリソース作成はkubernetes的にはカスタムリソースの作成になっています。
そのカスタムリソースの定義は👇なので、yamlをどう書けばいいのかこちらを見つつやるのがいいのではないかと思います!

eks-charts/crds.yaml at master · aws/eks-charts


, , ,

2021年4月23日金曜日

シタテル開発陣に聞いてみた:便利なデスクトップアプリ

 今回はちょっと新企画として、シタテルの開発部にアンケートをとって記事を書いてみようかと思います。

第1回は、「日々の開発業務で便利なデスクトップアプリを聞いてみた」です😁

初めての試みということもあり、まずはジャンル問わずで募集してみました。
早速コメントとともにまとめてみたいと思います。

2021年2月26日金曜日

Node.jsのバージョン管理をVoltaに統一したわけ

Node.jsを使っていれば永遠のテーマである(?)バージョン管理ですが、皆さんはどのようにしているでしょうか。

今更ながら、ローカル環境で使用するバージョン管理を原則としてVoltaに統一する運びになったので、その背景などを書いてみたいと思います。



今までは特にバージョン管理ツールを標準で決めておらず、個人やチームでそれぞれ好きなものを使っているような状態でした。
それはそれで大きく困るようなことはなかったのですが、先日多くのリポジトリにざっといくつかの設定・アップデートをして回るようなタスクがあって話が変わりました。

それぞれのリポジトリで使っているNodeのバージョンをどこからか見つけてきて切り替えする作業を1日に何度もやるのはやはり効率が悪いしストレスですね。
バージョン管理ツールを決めて全社標準で設定してもらわないことには、私が 😇 してしまう・・・

ということで何のツールをツールを使うか検討を始めました。
今回の悩みを解消するためには、要件はこんなところです。

  • 設定しておけばカレントディレクトリに応じて自動でNodeのバージョンが切り替わる
  • 設定したバージョンをVCSに記録できる
  • npmのバージョンも記録して自動切換えできる

ちなみに最後の条件はnpmのバージョン7がもう一般リリースされているので出てきたものです。
npm 7 is now generally available! - The GitHub Blog
それまでのバージョン6とは機能面の破壊的変更とlockファイルの変更などがあるので、これも併せてバージョン管理しておきたくなったわけですね。



さて結論ですが、Voltaを使うことにしました。
Volta - The Hassle-Free JavaScript Tool Manager
ある程度メジャーなツールで上の要件を満たすものとなるとVoltaしかなかったためです。

使うのも簡単でいい感じですね。
Voltaの使い方については詳しい記事が各地にあるのでここではあまり書きませんが、例えばNode 14, npm 6を使うなら

$ volta install node@14 npm@6
$ volta pin node@14 npm@6

とすると package.json にバージョンが書き込まれます。

{
  ...
  "volta": {
    "node": "14.15.5",
    "npm": "6.14.11"
  }
}

これをgitにコミットしておけば、自動でこのバージョンのnodeとnpmが実行されるようになります。
全リポジトリで設定されればもうバージョンを気にしなくてよくなるわけですね🤗

Nodeはもちろん、npmやその他nodeツール類のバージョン管理をしっかりやりたいという方はVoltaを一度試してみてはいかがでしょうか💁‍♂️

,

2021年1月15日金曜日

GitHub dependabot でDockerタグをバージョン指定する

寒い日が続きますね。

ところで皆さんはGitHubのdependabotは使っていますでしょうか?
リポジトリをスキャンして、使っているライブラリやパッケージの脆弱性をお知らせしてくれるサービスですね。

依存関係を自動的に更新する - GitHub Docs

そのdependabotでちょっとした問題を調べて解決したので記録しておこうと思います。
題して「特定のDockerタグを無視する設定の書き方」です。
dependabotの概要や初期設定などはこの記事ではちょっと飛ばしますのでご了承ください🙇‍


dependabotはDockerタグにも対応していて、脆弱性対応された新しいバージョンタグがある場合はそれを出すようになっています。
例えばリポジトリの docker/Dockerfile をスキャン対象にする場合、コミットしておく設定ファイル .github/dependabot.yml はこのようになります。

version: 2
updates:
  - package-ecosystem: "docker"
    directory: "/docker"

さて、基本的にはdependabotはメジャーバージョンアップも含めて最新バージョンにアップデートさせるように動作するようです。
そのため、Dokerfileで node:14.x.x イメージを使っている場合

このように node:15 系にアップデートしなよ!というPRが作成されるのです。

でもNode.jsはバージョン14はLTSで15はLTSじゃない・・・更新するなら14系の最新にしてほしい!
というわけで、「Dockerタグの特定バージョンを無視する設定」を調べて入れてみました。


依存関係の更新の設定オプション - GitHub Docs

こちらのドキュメントによると、あるバージョンへの更新を無視するためにはdependabot.ymlにそのバージョンを明記すればいいのですが、

範囲を定義する場合は、パッケージマネージャーの標準パターンを使用します

Dockerタグの標準パターンって何だ・・・?🤔

結局わからなかったのでソースを見てみたところ、判定しているのはおそらくこのあたり。

dependabot-core/update_checker.rb at main · dependabot/dependabot-core · GitHub

バージョンの取り扱いに使っているのは Gem::Versionクラス のようです。

class Gem::Version (Ruby 3.0.0 リファレンスマニュアル)

ということはGemfileでバージョンを指定するのと同じ記法で良さそうですね。
dependabot.ymlはこうなりました。

version: 2
updates:
  - package-ecosystem: "docker"
    directory: "/docker"
    ignore:
      - dependency-name: "node"
        versions: ["~>15.0"]
        # nodeイメージの 15.x 系は無視

これでnodeイメージは 15.x を対象外にして更新するようになりました。
新しく作られるPRは14系の範囲でバージョンアップするものになっていますね。


dependabotでDocker更新、なかなか便利なのでお試しください🙏
, ,