のべラボ.blog

Tech Blog | AWS や サーバーレスやコンテナ などなど

AWS SAM connectors を試してみた

前回と同じく、今回も AWS SAM ネタです。

下記の AWS ブログの記事を読んだので、 AWS SAM connectors を試してみたいと思います。

aws.amazon.com

AWS SAM connectors は、AWS SAM テンプレートで指定するリソースタイプの一種で、サーバーレスアプリケーションを構成するコンポーネント間のアクセス権限設定を容易に指定することができます。

今回は、次のドキュメントの記載内容を少しアレンジして、Node.js の AWS Lambda 関数から Amazon DynamoDB のテーブルにアイテムを Put するシンプルなアプリケーションの権限を AWS SAM connectors を使って設定していきます。

docs.aws.amazon.com

前提として、この記事の内容は、2022年 10月 16日時点のものです。

東京リージョンを使用し、AWS Cloud9 を使用して SAM CLI version 1.52.0 のコマンドを発行します。

また、AWS アカウント ID は12桁すべて 0 で表記します。

ではまず、sam init を実行します。今回は Node.js 16.x をランタイムに指定します。

sam init --runtime nodejs16.x

その後、対話形式で尋ねられる項目へは、次のように応答しました。今回は AWS X-Ray のトレースは有効化していません。

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Standalone function
        4 - Scheduled task
        5 - Data processing
        6 - Serverless API
Template: 1

Based on your selections, the only Package type available is Zip.
We will proceed to selecting the Package type as Zip.

Based on your selections, the only dependency manager available is npm.
We will proceed copying the template using npm.

Select your starter template
        1 - Hello World Example
        2 - Hello World Example TypeScript
Template: 1

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: 

Project name [sam-app]: sam-connectors-test   

これで、SAM のリソースを取得できました。

次に、AWS Lambda 関数のコードを書き替えます。

今回だと、sam-connectors-test/hello-world/app.js というファイルが作成されているので、それを開きます。

そして、既存のコードをすべて削除し、次のコードに置換えます。

const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event, context) => {
  await docClient.put({
    TableName: process.env.TABLE_NAME,
    Item: {
      id: context.awsRequestId,
      event: JSON.stringify(event) 
    }
  }).promise();
}

このコードでは、環境変数Amazon DynamoDB のテーブル名を取得して、リクエスト ID をキー属性に、イベントオブジェクトの内容をバリュー属性として Put を行っています。

では、次は SAM テンプレートを編集します。

今回だと、sam-connectors-test/template.yaml というファイルがあるので、それを開きます。

前述の AWS のドキュメントのサンプルの一部を流用、アレンジして、次のような内容にしました。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-connectors-test

  Sample SAM Template for sam-connectors-test
  
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  MyTable:
    Type: AWS::Serverless::SimpleTable
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello-world/
      Handler: app.handler
      Runtime: nodejs16.x
      Architectures:
        - x86_64
      Environment:
        Variables:
          TABLE_NAME: !Ref MyTable
  MyConnector:
    Type: AWS::Serverless::Connector
    Properties:
      Source:
        Id: HelloWorldFunction
      Destination:
        Id: MyTable
      Permissions:
        - Write
Outputs:
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

このテンプレート内の、MyConnectorAWS SAM connectors になります。

  MyConnector:
    Type: AWS::Serverless::Connector
    Properties:
      Source:
        Id: HelloWorldFunction
      Destination:
        Id: MyTable
      Permissions:
        - Write

今回だと、HelloWorldFunction 関数から MyTable テーブルへの Write 権限を許可するという指定になります。 IAMポリシーを直接作成するよりは、シンプルな書き方といえますね。

では、ビルドしてデプロイを実行します。

今回は、デプロイで --guided オプションをつけています。

cd sam-connectors-test
sam build
sam deploy --guided

--guided オプション を付けた場合にプロンプトで求められる入力の例を記載しておきます。

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: sam-connectors-test
        AWS Region [ap-northeast-1]: 
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: 
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: 
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: 
        Save arguments to configuration file [Y/n]: 
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

デプロイが正常に完了すると、次のようなメッセージが出力されます。

Successfully created/updated stack - sam-connectors-test in ap-northeast-1

また、今回の例だと次のような IAM ロールの ARN の Output があります。

これは、AWS Lambda 関数に付与された実行ロールの ARN になります。

Key                 HelloWorldFunctionIamRole                                                   
Description         Implicit IAM Role created for Hello World function                          
Value               arn:aws:iam::000000000000:role/sam-connectors-test-HelloWorldFunctionRole-  
WB0KUJXSC9YP                                                                                    

この IAM ロールの ARN うち、 arn:aws:iam::000000000000:role/より後のロールの名前の部分をメモします。

今回の例だと、sam-connectors-test-HelloWorldFunctionRole-WB0KUJXSC9YP になります。

そして、次のようにロール名を環境変数で指定して AWS CLI を実行し、ロールにアタッチされているポリシーの内容を表示してみましょう。

ROLE_NAME=sam-connectors-test-HelloWorldFunctionRole-WB0KUJXSC9YP  
aws iam list-attached-role-policies --role-name ${ROLE_NAME} --query "AttachedPolicies[].[PolicyArn]" --output text

出力例

arn:aws:iam::000000000000:policy/sam-connectors-test-MyConnectorPolicy-1LGRZ5UMK7FFY
arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

出力結果のうち、MyConnector という文字を含んでいる ポリシーがあります。

これが、AWS SAM connectors により作成された IAM ポリシーになります。

この IAM ポリシーの ARN をメモして、次のように環境変数で指定して AWS CLI コマンドを実行します。

POLICY_ARN=arn:aws:iam::000000000000:policy/sam-connectors-test-MyConnectorPolicy-1LGRZ5UMK7FFY
VERSION_ID=`aws iam get-policy --policy-arn ${POLICY_ARN} --query "Policy.DefaultVersionId"  --output text`
aws iam get-policy-version --policy-arn  ${POLICY_ARN} --version-id ${VERSION_ID}

出力例

{
    "PolicyVersion": {
        "CreateDate": "2022-10-16T01:29:31Z", 
        "VersionId": "v1", 
        "Document": {
            "Version": "2012-10-17", 
            "Statement": [
                {
                    "Action": [
                        "dynamodb:PutItem", 
                        "dynamodb:UpdateItem", 
                        "dynamodb:DeleteItem", 
                        "dynamodb:BatchWriteItem", 
                        "dynamodb:PartiQLDelete", 
                        "dynamodb:PartiQLInsert", 
                        "dynamodb:PartiQLUpdate"
                    ], 
                    "Resource": [
                        "arn:aws:dynamodb:ap-northeast-1:000000000000:table/sam-connectors-test-MyTable-1ONWBBRN2LWXQ", 
                        "arn:aws:dynamodb:ap-northeast-1:000000000000:table/sam-connectors-test-MyTable-1ONWBBRN2LWXQ/index/*"
                    ], 
                    "Effect": "Allow"
                }
            ]
        }, 
        "IsDefaultVersion": true
    }
}

AWS SAM connectors により作成された IAM ポリシーの内容が確認できました。PutItem や UpdateItem や DeleteItem など Action として許可されていますね。

今回は、AWS Lambda 関数から、Amazon DynamoDB へのアクセスを例にしましたが、他にも次のようなパターンがサポートされているので、今後は他のパターンも試していきたいです!

docs.aws.amazon.com

AWS SAM で 初期化時に AWS X-Ray のトレースの有効化を指定できるようになった

AWS SAM の CLI では、sam init というコマンドで SAM で使用するリソースを対話形式で指定して取得できますが、その対話の中に AWS Lambda と Amazon API Gateway に対して AWS X-Ray のトレース取得が指定できるようになったようです。

また sam init 時に --tracing のオプションを指定して AWS X-Ray の有効化を指定することもできます。

今回は、対話形式での指定について、Cloud9 の環境を使って試していきます。

なお、この記事の内容は 2022 年 10 月 10日 時点に確認したものです。

まずは Cloud9 のターミナルから AWS SAM のバージョンを確認してみます。

$ sam --version
SAM CLI, version 1.57.0

1.57.0 というバージョンが表示されました。

私が 少し前に使った Cloud9 の SAM CLI のバージョンは 1.33.0 だったので、なんか一気に新しくなった気がします。

次に 初期化します。なお今回は、Runtime に python3.7 を指定します。

$ sam init --runtime python3.7

この後、対話形式でいろいろと選択していきます。 まず、テンプレートについて選択します。今回は AWS のテンプレートを選択します。

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

次にアプリケーションのテンプレートを選択します。今回は Hello World レベルのシンプルなものを選択します。

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Infrastructure event management
        3 - Multi-step workflow
Template: 1

そして次に、AWS X-Ray の有効化をするか、否かを選択します。今回は、有効化するため y を入力します。

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: y
X-Ray will incur an additional cost. View https://aws.amazon.com/xray/pricing/ for more details

最後に SAM のプロジェクト名の入力を求められます。今回はデフォルトの sam-app でよいので、そのまま Enter キーを押下します。

Project name [sam-app]: 

これにより、プロジェクト名のフォルダ、つまり今回だと sam-app というフォルダに必要なリソースが保存されます。

このフォルダの直下にある、template.yaml というファイルを開いて内容を確認してみます。

これは、SAM でデプロイを行う時に使用する SAM テンプレートファイルです。

Globals:
  Function:
    Timeout: 3
    Tracing: Active
  Api:
    TracingEnabled: True

sam init 時に X-Ray の有効化を指定したので、SAM テンプレートの Globals セクションをみると、Lambda関数に対する設定である Function のプロパティで Tracing: Active が、Amazon API GatewayAPI に対する設定である Api のプロパティで、TracingEnabled: True が設定されているのがわかります。

では、SAM CLI のコマンドでビルドしてデプロイしてみましょう。

まず、プロジェクト名のフォルダに移動して sam build を実行します。

$ cd sam-app/
$ sam build

そしてデプロイですが、今回は sam deploy --guided でデプロイを行います。

$ sam deploy --guided

sam deploy --guided 実行によりデプロイに関する入力が求められます。

次は、その入力例です。

Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: 
        AWS Region [ap-northeast-1]: 
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: 
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: 
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: 
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
        Save arguments to configuration file [Y/n]: 
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

デプロイが終了すると、SAM テンプレートの Outputs セクションで指定した内容が表示されます。

その中の、API GatewayAPI のエンドポイントを見つけます。下記は例です。

Key                 HelloWorldApi                                                                            
Description         API Gateway endpoint URL for Prod stage for Hello World function                         
Value               https://qtm166m8r2.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/                 

この Value で表示されているURLをコピーして Webブラウザでアクセスしてみると、次のようなメッセージが表示されます。

{"message": "hello world"}

これは、作成した Lambda 関数で リターンしているメッセージですので、API GatewayAPI から Lambda 関数を呼び出せたことを確認できます。

また、この呼び出しにより、AWS X-Ray のトレースも出力されているはずです。

AWS マネジメントコンソールで AWS X-Ray のコンソールを開き、左側のメニューから [トレース] を選択します。

次のように、 API Gateway と Lambda 関数のトレースが表示されることを確認します。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221010/20221010172317.png

sam init の対話形式やオプションで AWS X-Ray の有効化を指定できるようになったことで、後でプロパティを書き足す必要がなくなりました。

私は、X-Ray をよく使うのでありがたいです。

Amazon EKS にて Ingress で SSL を有効化してみる

Amazon EKS クラスターでは、AWS Load Balancer Controller を導入すると Ingress オブジェクトを作成時に、ELB のロードバランサーを作成できます。

今回は、IngressからSSL を有効化したELB ( Application Load Balancer ) を作成する手順をまとめてみます。

これは、2022年 10 月 1 日時点で試した内容です。


前提

Amazon EKS クラスターは構成済で、AWS Load Balancer Controller も導入済です。

このクラスターに接続できる クライアントも用意できています。

また、サーバー証明書を発行するのに必要なドメインの管理者であり、Amazon Route 53 でドメインレコードを設定できる前提です。


目標

次のような構成で、https://ingress.nobelabo.net で Pod にアクセスできるようにすることが目標です。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221001/20221001192515.png


AWS Certificate Manager ( ACM ) でサーバー証明書を発行

AWS マネジメントコンソールから、完全修飾ドメイン名を指定してパブリック証明書のリクエストを発行します。

Eメールまたは DNSによる検証を行うと証明書が発行されます。

検証は、ドメインの管理者である証明としてEメールを受信、または 対象のDNSに検証用のレコードを追加します。詳細は、次のドキュメントを参照しましょう。

docs.aws.amazon.com

発行された証明書の ARN をメモしておきます。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20221001/20221001192554.png


Deployment の作成

ingress からアクセスする Pod 用の Deployment を作成します。

次はあくまで例であり個人的に作ったコンテナイメージを指定してますが、もっとシンプルに nginx などを使っても良いと思います。

ここでは、deployment.yaml に保存した前提とします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-web-ec2-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: python-web-ec2
  template:
    metadata:
      labels:
        app: python-web-ec2
    spec:
      containers:
      - name: python-web-ec2
        image: tnobe/python-web-ec2
        ports:
        - containerPort: 8000

マニフェストが用意出来たら、作成して Pod が起動したことを確認します。

kubectl apply -f  deployment.yaml
kubectl get pods

Ingress と Service の作成

ではいよいよ Ingress と Service を作成します。

次のようなマニフェストを用意します。

ここでは、ingress.yaml に保存した前提とします。

apiVersion: v1
kind: Service
metadata:
  name: my-service-ingress-ssl
spec:
  ports:
    - port: 80
      targetPort: 8000
      protocol: TCP
  type: ClusterIP
  selector:
    app: python-web-ec2
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress-alb-ip-ssl
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:000000000000:certificate/6654fefe-7976-4ce7-8cad-44455fc79291
spec:
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-service-ingress-ssl
                port:
                  number: 80

annotationsalb.ingress.kubernetes.io/listen-ports を指定し、HTTPS: 443 も使用するように指定します。

また、alb.ingress.kubernetes.io/certificate-arn で発行した ACM の証明書の ARN を指定します。

マニフェストが用意出来たら、作成して ingress が起動したことを確認します。

kubectl apply -f  ingress.yaml
kubectl get ingress

次は、出力から抜粋した例です。

NAME                    CLASS    HOSTS   ADDRESS                                                                     
my-ingress-alb-ip-ssl   <none>   *       xxxxx.ap-northeast-1.elb.amazonaws.com   

ADDRESS 列に表示されているのが、Application Load Balancer (ALB) のDNS名になります。

この段階で、ブラウザから http://(ALBDNS名) で Pod にアクセスできることを確認しておきます。


DNS に 別名レコードを追加

今回は 個人的に管理している 別の AWS アカウントのRoute 53 のホストゾーンで DNS レコードを管理しているので、 AWS マネジメントコンソールから CNAME レコードを追加します。

レコード名: ingress.nobelabo.net

レコードタイプ: CNAME

値: ALBのDNS

ルーティングポリシー:シンプル

これで、https://ingress.nobelabo.net で Pod にアクセスできるようになりました!

(現在は、https://ingress.nobelabo.net はアクセスできないようにしています。)


最後に

Amazon EKS に AWS Load Balancer Controller を導入したとき IngressSSL でリスニングする時の方法について、これまで日本語で説明されたドキュメントを見つけることができなかったので、このブログを自分用のメモにしておきたいと思います。

AWS での分散負荷テスト ソリューションを試してみた

AWS ソリューションライブラリの一つである「AWS での分散負荷テスト」ソリューションを試してみました。

aws.amazon.com

このソリューションは、Amazon ECS の Fargateのタスクをクライアントとして任意のWebのエンドポイントに負荷テストを実施できるようで、 前からその存在は知っていたんですが、実際に試してみるのは初めてです。

なおこの記事に記述している内容は、2022年9月24日時点の内容に基づいていますのでご了承ください。

このソリューションを導入する事前準備としては、基本的に VPC と 2つ以上のサブネットが存在してればいけそうです。

詳細についてはソリューションガイドを参照しましょう。

https://d1.awsstatic.com/Solutions/ja_JP/distributed-load-testing-on-aws.pdf

では、このソリューションを導入していきます。

まず自分のAWSアカウントにサインインした状態にして、このソリューションのページにある [AWS コンソールで起動する] をクリックします。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924185908.png

そうすると CloudFormation でスタックを作成するページが表示されるので、必要なパラメータの入力を行います。

ここで入力する管理者の ID は、ソリューションが導入された後にテストを管理するコンソールにサインインするために必要になります。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924203340.png

なお、サブネットは Fargate のタスクの実行に使用するものを指定します。Public でも Private でも大丈夫ですが、Private の場合は Fargate がイメージを Pull するために NAT ゲートウェイを構成しておく必要があります。

必要なパラメータを入力後、CloudFormation でスタックを作成します。

無事にスタック作成が完了すると、パラメータで指定した管理者のメールアドレスに次のようなメールが届きます。

サブジェクト:

Welcome to Distributed Load Testing

本文:

Please use the credentials below to login to the Distributed Load Testing console. 
Username: admin1 
Password: B2ZXkPR0D.1d 
Console: https://xxxxxxxxxxxxxx.cloudfront.net/

このメールに記載されている [Console:] のURL で、テストを実行、管理するためのコンソールへのアクセスできます。

アクセスすると、次のようにサインインが求められます。( 少し前の AWS Amplify の 認証の UI ですね。)

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924185832.png

ここで、メールに記載されている [Username:] の値と [Password:] の値を入力してサインインを行います。

入力内容が正しければ、パスワード変更が求められますので新しいパスワードを入力します。

そうすると、テストを管理するコンソールが開き、テストシナリオ一覧が表示されます。まだテストは実行していないので何も表示されません。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924185836.png

これからテストシナリオを作成するので、[CREATE TEST] をクリックします。

そして、次の図のようにテストの設定を入力します。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924185841.png

今回は、シンプルに単一のエンドポイントにアクセスを行うだけの設定にすることにしました。

なお、上図ではチェックされていませんが、今回はテスト中も Liveデータをモニタリングしたいので [Include Live Data ] をチェックします。

すぐにテストを実行したかったので、[Run Now] を選択してページ右下にある [RUN NOW]ボタンをクリックします。

すると、テストの詳細ページに切り替わります。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924185847.png

この詳細ページを少し下にスクロールすると、Amazon ECS の Fargate のタスクの起動状況も表示されます。

[Running] の値が指定したタスク数になることを確認します。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924185851.png

ここには Amazon ECS のコンソールへのリンクも表示されています。タスクの状況はこのリンクをクリックして表示される Amazon ECS のコンソールからでも確認できます。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924185855.png

さらにページを下にスクロールすると、チャートでLive データが表示されます。これは、[Include Live Data ] をチェックした場合に表示されます。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924185859.png

もしページの内容が更新されない場合は、右上にある [REFRESH] ボタンを選択してみましょう。

テストが終了すると、結果が表示されます。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220924/20220924185903.png

今回はシンプルなシナリオでテストしてみましたが、JMeterを使用したテストや、複数のリージョンを使用したテストなどもできるようです。

多くの AWS サービスのリソースを使用して構築されているソリューションですが、CloudFormation を使用して比較的シンプルに導入できるのがいいですね!

Amazon EKS で Pod から AWS Secrets Manager のシークレットを取得する

今回は、AWS Secrets Manager で管理しているシークレットの情報を Amazon EKS の Pod から取得させてみます。

これを実現するために、AWS Secrets and Config Provider (ASCP) を使用します。

下図がそのイメージです。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220913/20220913083939.png

ASCP については、次の AWS ブログの記事や、AWS のドキュメントにも情報があるので、併せてご参照ください。

aws.amazon.com

docs.aws.amazon.com

ここに記述している内容は、2022 年 9 月13 日時点で動作を確認しています。

また、対象にしている Kubernetes のバージョンは 1.23 です。


前提と環境

今回は、大阪リージョンの「 ASCP-cluster 」という名前の EKS クラスター (バージョンは 1.23 ) を使う前提とします。

kubectl や eksctl 、AWS CLI 、Helm、git が使用でき、対象のクラスターに接続できる Amazon Linux2 の環境で実施していきます。


AWS Secrets and Config Provider (ASCP) のインストール

これは、AWS のドキュメントに基づいて行います。

まず Helm を使って Secrets Store CSI ドライバーをインストールします。

helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm install -n kube-system csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver

次に ASCP をインストールします。

kubectl apply -f https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml

環境変数の作成

このあとの手順でよく利用する情報を環境変数に格納しておきます。

REGION=ap-northeast-3
CLUSTERNAME=ASCP-cluster

AWS Secrets Manager のシークレットの作成

今回は、ユーザー名: admin とパスワード: admin1234 という値をシークレットとして作成します。

aws --region "$REGION" secretsmanager  create-secret --name ascp-demo-secret --secret-string '{"username":"admin", "password":"admin1234"}'

作成後に表示されるシークレットの ARN をメモしておきましょう。


Service Account の作成

Amazon EKS の Pod には、 AWS Secrets Manager のシークレットを取得するための権限を付与する必要があるので、Service Account を作成します。

まず 作成したシークレットの取得を許可する IAM ポリシーを作成します。次の例では、ポリシー名を ascp-demo-secret-policy にしています。

下記で、 <作成したシークレットのARN> の部分に、メモしておいた ARN を記載します。

POLICY_ARN=$(aws --region "$REGION" --query Policy.Arn --output text iam create-policy --policy-name ascp-demo-secret-policy --policy-document '{
    "Version": "2012-10-17",
    "Statement": [ {
        "Effect": "Allow",
        "Action": ["secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret"],
        "Resource": ["<作成したシークレットのARN>"]
    } ]
}')

次に EKS クラスターの OIDC プロバイダを AWS IAM に関連付けます。これはクラスター単位で 1回行うだけで OK です。

eksctl utils associate-iam-oidc-provider --region="$REGION" --cluster="$CLUSTERNAME" --approve 

そして、Service Account を作成します。次の例では、Service Account 名を ascp-demo-secret-sa にしています。

eksctl create iamserviceaccount --name ascp-demo-secret-sa --region="$REGION" --cluster "$CLUSTERNAME" --attach-policy-arn "$POLICY_ARN" --approve --override-existing-serviceaccounts

SecretProviderClass の作成

SecretProviderClass を作成するためのマニフェストを用意します。

次の例では、secret-provider-class.yaml というファイルで作成しています。

このマニフェストobjectName に作成したシークレットの名前を指定します。

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: ascp-demo-secrets-provider-class
spec:
  provider: aws
  parameters:
    objects: |
        - objectName: "ascp-demo-secret"
          objectType: "secretsmanager"

マニフェスト作成後、適用します。

kubectl apply -f secret-provider-class.yaml 

Deployment の作成

それでは、Pod から シークレットの情報を取得してみます。

まず Deployment のマニフェストを作成します。Pod の spec には、Service Account や SecretProviderClass を正しく指定しましょう。

次の例では、/mnt/secrets-store をマウントに指定し、シークレットを取得できるようにして example-deployment.yaml というファイルに保存しています。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      serviceAccountName: ascp-demo-secret-sa
      volumes:
      - name: secrets-store-inline
        csi:
          driver: secrets-store.csi.k8s.io
          readOnly: true
          volumeAttributes:
            secretProviderClass: "ascp-demo-secrets-provider-class"
      containers:
      - name: nginx-deployment
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: secrets-store-inline
          mountPath: "/mnt/secrets-store"
          readOnly: true

マニフェスト作成後、適用します。

kubectl apply -f example-deployment.yaml

無事に Deployment の Pod が作成されたことを確認します。

kubectl get deploy nginx-deployment

次の出力例ように、2つの Pod が READY になっていれば OK です。

出力例

NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           15s

もし Pod が作成されない場合は、kubectl describe で イベントに エラー情報が出力されているか確認しましょう。

kubectl get pods
kubectl describe pod   <Pod名>

Pod が作成されたら、シークレットの値を参照してみます。

まず、Pod 名を確認します。

kubectl get pods

次に Pod 名を指定して コンテナのシェルに接続します。

kubectl exec -it  <Pod名>  -- /bin/bash

シェルに接続したらシークレットの情報を参照してみます。

cat /mnt/secrets-store/ascp-demo-secret

次の例のように表示されれば OK です。

出力例

{"username":"admin", "password":"admin1234"}

最後に

Kubernetes には Secrets というリソースがありますが、Amazon EKS にて Pod から AWS Secrets Manager を使い、認証情報などのシークレットを取得したい場合は、この AWS Secrets and Config Provider (ASCP) が役立ちそうですね。

Amazon EKS で Amazon EFS CSI ドライバー を使ってみる

今回は、Amazon EKS で Amazon EFS CSI ドライバー を使って、Podから EFSボリュームにアクセスしてみます。

手順としては前回の「Amazon EKS で Amazon EBS CSI ドライバー を使ってみる 」の記事の内容と似ているところが多いので、今回の記事も内容や構成が似ていることはご容赦下さいww

ここに記述している内容は、2022 年 9 月11 日時点で動作を確認しています。

また、対象にしている Kubernetes のバージョンは 1.23 です。

今後の Update により、手順等が変更される可能性があることをご留意ください。

なお、下記のドキュメントを参考にしていますので、こちらも併せてご参照ください。

docs.aws.amazon.com

aws.amazon.com


前提と環境

今回は、東京リージョンの「 test123-cluster 」という名前の EKS クラスター (バージョンは 1.23 ) を使う前提とします。

kubectl や eksctl 、AWS CLI 、git が使用でき、対象のクラスターに接続できる Amazon Linux2 の環境で実施していきます。

記事の中で出てくる AWS アカウント ID は、12 桁すべてゼロで表記しています。


Amazon EFS CSI ドライバー用の Service Account の作成

Amazon EFS CSI ドライバーには、Amazon EFS のファイルシステムを操作する権限を付与する必要があります。

その権限を付与するため、AWS の IAM ロールと関連づいた Kubernetes の Service Account を作成します。

まず、クラスター用に IAM OpenID Connect (OIDC) プロバイダーを用意します。 (もし前に IAM ロールと関連付けた Service Account を作成したことがあるなら、すでに実施済のはずなので、その場合は不要です。)

eksctl utils associate-iam-oidc-provider --cluster test123-cluster --approve

次に、IAM ロール に付与する許可ポリシーを作成します。

ここでは、ポリシー名を AmazonEKS_EFS_CSI_Driver_Policy にしています。

curl -o iam-policy-example.json https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/docs/iam-policy-example.json

aws iam create-policy \
    --policy-name AmazonEKS_EFS_CSI_Driver_Policy \
    --policy-document file://iam-policy-example.json

ダウンロードした iam-policy-example.json にも目を通しておくと、どのようなポリシーが必要か確認できます。

そして、Service Account を作成します。

ここでは、Service Account 名を ebs-csi-controller-sa に、IAM ロール名を AmazonEKS_EBS_CSI_DriverRole にしています。

eksctl create iamserviceaccount \
    --cluster test123-cluster \
    --namespace kube-system \
    --name efs-csi-controller-sa \
    --attach-policy-arn arn:aws:iam::000000000000:policy/AmazonEKS_EFS_CSI_Driver_Policy \
    --approve \
    --region ap-northeast-1

Amazon EFS CSI ドライバー を Amazon EKS アドオンとしてインストールする

インストールではHelm も使用できますが、今回は kubectl でマニフェストを使って行います。

また、マニフェストで参照するイメージは、パブリック Amazon ECR レジストリに保存されているイメージを使う前提とします。

最初にマニフェストを取得します。

kubectl kustomize \
    "github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.4" > public-ecr-driver.yaml

public-ecr-driver.yaml ファイルを編集して、次の行を削除します。 これは、Service Account は前の手順ですでに作成しているためです。 この作業は注意して下さい。ファイル内に Service Account のマニフェストが複数存在している場合、削除する対象を間違えないようにしましょう。

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  name: efs-csi-controller-sa
  namespace: kube-system
---

これでマニフェストの準備が完了したので、適用します。

kubectl apply -f public-ecr-driver.yaml

インストールを確認します。

kubectl get deploy efs-csi-controller -n kube-system

次の出力例のように、efs-csi-controller の Deployment が起動できていることを確認します。

NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
efs-csi-controller   2/2     2            2           3m1s

 EFS ファイルシステムを作成する

EFS ファイルシステムを作成するために、まずは VPC の情報を環境変数に入れておきます。

EKSクラスターの VPC の ID の取得

vpc_id=$(aws eks describe-cluster \
    --name test123-cluster \
    --query "cluster.resourcesVpcConfig.vpcId" \
    --output text)

EKSクラスターの VPC の CIDR の取得

cidr_range=$(aws ec2 describe-vpcs \
    --vpc-ids $vpc_id \
    --query "Vpcs[].CidrBlock" \
    --output text)

次に EFS ファイルシステムのマウントポイントに適用するセキュリティグループを作成します。 今回は、セキュリティグループ名を MyEfsSecurityGroup にしています。

security_group_id=$(aws ec2 create-security-group \
    --group-name MyEfsSecurityGroup \
    --description "My EFS security group" \
    --vpc-id $vpc_id \
    --output text)

作成したセキュリティグループに イングレスルールを設定します。

今回は、アクセス元がクラスターの VPC の CIDR であれば NFS トラフィックを許可するルールにします。

aws ec2 authorize-security-group-ingress \
    --group-id $security_group_id \
    --protocol tcp \
    --port 2049 \
    --cidr $cidr_range

これで EFS ファイルシステムを作成する準備ができました。

リージョンを指定して EFS ファイルシステムを作成します。

file_system_id=$(aws efs create-file-system \
    --region ap-northeast-1 \
    --performance-mode generalPurpose \
    --query 'FileSystemId' \
    --output text)

EFS ファイルシステムのマウントターゲットを作成します。

そのために、まず EKS クラスターのVPCのサブネットの ID を取得します。

aws ec2 describe-subnets \
    --filters "Name=vpc-id,Values=$vpc_id" \
    --query 'Subnets[*].{SubnetId: SubnetId,AvailabilityZone: AvailabilityZone,CidrBlock: CidrBlock}' \
    --output table

出力された表形式の内容から、EKS で EFS ファイルシステムをマウントするノードのサブネットの ID をメモしておきます。

そのサブネット ID を指定して、EFS のマウントターゲットを作成します。 次の例では、サブネット ID を subnet-0b10aaaaaaaaaaaaa と指定しています。

aws efs create-mount-target \
    --file-system-id $file_system_id \
    --subnet-id subnet-0b10aaaaaaaaaaaaa \
    --security-groups $security_group_id

 サンプルアプリケーションで確認する

では、Pod から EFS ファイルシステムにアクセスできるかをサンプルアプリケーションを使って試していきます。

まず、作成した EFS ファイルシステムの ID をメモしておきます。 これまでの手順で、$file_system_id という環境変数で参照できます。

echo $file_system_id

もしくは、AWS CLI でも確認できます。

aws efs describe-file-systems --query "FileSystems[*].FileSystemId" --output text

次に、EFS の StorageClass を作成するためのマニフェストを入手します。

curl -o storageclass.yaml https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml

ダウンロードした storageclass.yaml を編集し、fileSystemId: 部分をメモしておいた ファイルシステム ID に変更します。 次の例では、ファイルシステム ID として fs-54321abc を指定してます。

fileSystemId: fs-54321abc

これで準備ができたので、StorageClassを作成します。

kubectl apply -f storageclass.yaml

Storage Class の情報を表示してみます。NAME に efs-sc 、PROVISONER に efs.csi.aws.com の Storage Class が表示されることを確認します。

kubectl get sc

次にサンプルアプリケーションを取得します。

curl -o pod.yaml https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/dynamic_provisioning/specs/pod.yaml

今回は、動的に EFS のボリュームをプロビジョニングするサンプルを動かしていきます。

ダウンロードしたマニフェスト pod.yaml を適用することで、Persistent Volume、Persistent Volume Claim、それを指定するサンプルの Pod が作成されます。

kubectl apply -f pod.yaml

Persistent Volume と Persistent Volume Claim の STATUS が Bound になっていることを確認します。

kubectl get pv
kubectl get pvc

efs-app というPod の STATUS が Running になっていることを確認します。

kubectl get pod efs-app

次のコマンドを実行し、このサンプルアプリケーションの Pod のマニフェストをみてみます。

cat  pod.yaml

次のように、Persistent Volume Claim を指定し、/data というパスにボリュームをマウントしています。

そして、echo コマンドを使用し、/data/out に日時を繰り返し書き込んでいます。 

apiVersion: v1
kind: Pod
metadata:
  name: efs-app
spec:
  containers:
    - name: app
      image: centos
      command: ["/bin/sh"]
      args: ["-c", "while true; do echo $(date -u) >> /data/out; sleep 5; done"]
      volumeMounts:
        - name: persistent-storage
          mountPath: /data
  volumes:
    - name: persistent-storage
      persistentVolumeClaim:

では、この Pod が EFS ボリュームに書き込み出来ているかを確認してみましょう。

kubectl exec efs-app -- bash -c "cat data/out"

次のような表示が確認できれば OK です。

出力例

Sun Sep 11 03:15:25 UTC 2022
Sun Sep 11 03:15:30 UTC 2022
Sun Sep 11 03:15:35 UTC 2022
Sun Sep 11 03:15:40 UTC 2022
Sun Sep 11 03:15:45 UTC 2022
Sun Sep 11 03:15:50 UTC 2022
Sun Sep 11 03:15:55 UTC 2022

ここで、もう1つ、同じ EFS のマウントターゲットを使用するPod を作成してみます。 次のマニフェストを作成して、nginx.yaml として保存します。

apiVersion: v1
kind: Pod
metadata:
  name: efs-app-nginx
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
        - name: persistent-storage
          mountPath: /data
  volumes:
    - name: persistent-storage
      persistentVolumeClaim:
        claimName: efs-claim

この Pod を作成します。

kubectl create -f  nginx.yaml

作成した Pod のシェルに接続してみます。

kubectl exec efs-app-nginx -it  -- /bin/bash

次のコマンドを実行し、efs-app の Pod が書き込んだファイルを参照できることを確認します。

cat /data/out

出力例

Sun Sep 11 03:15:25 UTC 2022
Sun Sep 11 03:15:30 UTC 2022
Sun Sep 11 03:15:35 UTC 2022
Sun Sep 11 03:15:40 UTC 2022
Sun Sep 11 03:15:45 UTC 2022
Sun Sep 11 03:15:50 UTC 2022
Sun Sep 11 03:15:55 UTC 2022

これで EFS なので、2つのコンピューティング環境から同時にマウントしてアクセスできることが確認できました!

確認出来たら、シェルを終了します。

exit

サンプルアプリケーションを停止する場合は、次を実行します。

これで、EFS ボリュームも削除されます。( EFS ファイルシステムは削除されません)

kubectl delete po efs-app-nginx
kubectl delete -f pod.yaml

最後に

前回と今回の記事で、Amazon EKS の CSI ドライバーを使用して Amazon EBS や Amazon EFS のボリュームをプロビジョニングして Pod から使用する手順を確認しました。 AWS の公式のドキュメント の内容をベースにしていますが、少し補足しつつ、よりシンプルに確認できる手順にしたつもりです。 これがどなたかのお役に立てば嬉しいです。

 

Amazon EKS で Amazon EBS CSI ドライバー を使ってみる

今回は、Amazon EKS で Amazon EBS CSI ドライバー を使って、Podから EBSボリュームにアクセスしてみます。

ここに記述している内容は、2022 年 9 月1 日時点で動作を確認しています。

また、対象にしている Kubernetes のバージョンは 1.23 です。

今後の Update により、手順等が変更される可能性があることをご留意ください。

なお、下記のドキュメントを参考にしていますので、こちらも併せてご参照ください。

docs.aws.amazon.com

aws.amazon.com


前提と環境

今回は、東京リージョンの「 test123-cluster 」という名前の EKS クラスター (バージョンは 1.23 ) を使う前提とします。

kubectl や eksctl 、AWS CLI 、git が使用でき、対象のクラスターに接続できる Amazon Linux2 の環境で実施していきます。

記事の中で出てくる AWS アカウント ID は、12 桁すべてゼロで表記しています。


Amazon EBS CSI ドライバー用の Service Account の作成

Amazon EBS CSI ドライバーには、Amazon EBS のボリュームを作成したり削除する権限を付与する必要があります。

その権限を付与するため、AWS の IAM ロールと関連づいた Kubernetes の Service Account を作成します。

まず、クラスター用に IAM OpenID Connect (OIDC) プロバイダーを用意します。 (もし前に IAM ロールと関連付けた Service Account を作成したことがあるなら、すでに実施済のはずなので、その場合は不要です。)

eksctl utils associate-iam-oidc-provider --cluster test123-cluster --approve

次に、IAM ロール に 付与する許可ポリシーを作成します。

ここでは、ポリシー名を AmazonEBSCSIDriverPolicy にしています。

curl -o example-iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/v0.9.0/docs/example-iam-policy.json

aws iam create-policy --policy-name AmazonEKS_EBS_CSI_Driver_Policy --policy-document file://example-iam-policy.json

ダウンロードした example-iam-policy.json にも目を通しておくと、どのようなポリシーが必要か確認できます。

そして、Service Account を作成します。

ここでは、Service Account 名を ebs-csi-controller-sa に、IAM ロール名を AmazonEKS_EBS_CSI_DriverRole にしています。

eksctl create iamserviceaccount \
  --name ebs-csi-controller-sa \
  --namespace kube-system \
  --cluster test123-cluster \
  --attach-policy-arn arn:aws:iam::000000000000:policy/AmazonEKS_EBS_CSI_Driver_Policy \
  --approve \
  --role-only \
  --role-name AmazonEKS_EBS_CSI_DriverRole

Amazon EBS CSI ドライバー を Amazon EKS アドオンとしてインストールする

インストールは、AWS マネジメントコンソール や AWS CLI も使用できますが、今回は eksctl を使用します。

eksctl create addon --name aws-ebs-csi-driver --cluster test123-cluster --service-account-role-arn arn:aws:iam::000000000000:role/AmazonEKS_EBS_CSI_DriverRole --force

インストールできたか確認してみます。

eksctl get addon --name aws-ebs-csi-driver --cluster test123-cluster

STATUS が ACTIVE と表示されることを確認します。

出力例 (UPDATE AVAILABLE 列は省略しています。)

NAME                    VERSION                 STATUS    ISSUES   IAMROLE                  
aws-ebs-csi-driver      v1.10.0-eksbuild.1      ACTIVE    0        (IAMロールのARN)

 サンプルアプリケーションで確認する

では、Pod から EBS ボリュームにアクセスできるかをサンプルアプリケーションを使って試していきます。

まず、サンプルアプリケーションを取得します。

git clone https://github.com/kubernetes-sigs/aws-ebs-csi-driver.git

今回は、動的に EBS ボリュームをプロビジョニングするサンプルを動かしていきます。

次を実行することで、Storage Class、Persistent Volume Claim、それを指定するサンプルの Pod が作成され、さらに Persistent Volume として EBS ボリュームも動的に作成されます。

cd aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/

kubectl  apply -f manifests/

Storage Class の情報を表示してみます。NAME に ebs-sc 、PROVISONER に ebs.csi.aws.com の Storage Class が表示されることを確認します。

kubectl get sc

Persistent Volume Claim、Persistent Volumeは、STATUS が Bound になっていることを確認します。

kubectl get pv
kubectl get pvc

次のコマンドを実行し、このサンプルアプリケーションの Pod のマニフェストをみてみます。

cat  manifests/pod.yaml

次のように、Persistent Volume Claim を指定し、/data というパスにボリュームをマウントしています。

そして、echo コマンドを使用し、/data/out.txt に日時を繰り返し書き込んでいます。 

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: centos
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim

では、この Pod が EBS ボリュームに書き込み出来ているかを確認してみましょう。

kubectl exec -it app -- cat /data/out.txt

次のような表示が確認できれば OK です。

出力例

Thu Sep 1 01:59:12 UTC 2022
Thu Sep 1 01:59:17 UTC 2022
Thu Sep 1 01:59:22 UTC 2022
Thu Sep 1 01:59:27 UTC 2022
Thu Sep 1 01:59:32 UTC 2022
Thu Sep 1 01:59:37 UTC 2022
Thu Sep 1 01:59:42 UTC 2022

ここで、このPod だけを削除してみます。

kubectl delete pod app

Pod を削除しても、Persistent Volume Claim が削除されない限り、EBS ボリュームは残っています。

その後、他の Pod を起動し、この EBSボリュームにマウントしてみます。

次のマニフェストを作成して、nginx.yaml として保存します。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim

この Pod を作成します。

kubectl create -f  nginx.yaml

作成した Pod のシェルに接続してみます。

kubectl exec -it nginx -- /bin/bash

次のコマンドを実行し、削除した 前の Pod が書き込んだファイルを参照できることを確認します。

cat /data/out.txt

出力例

Thu Sep 1 01:59:12 UTC 2022
Thu Sep 1 01:59:17 UTC 2022
Thu Sep 1 01:59:22 UTC 2022
Thu Sep 1 01:59:27 UTC 2022
Thu Sep 1 01:59:32 UTC 2022
Thu Sep 1 01:59:37 UTC 2022
Thu Sep 1 01:59:42 UTC 2022

確認出来たら、シェルを終了します。

exit

サンプルアプリケーションを停止する場合は、次を実行します。

これで、EBS ボリュームも削除されます。

app という Pod はすでに削除していますので、NotFoundのエラーが出ても無視して下さい。

kubectl delete po nginx
kubectl delete -f manifests/

最後に

Amazon EKS を触りだして間もないころは、Amazon EBS CSI ドライバーの構成方法はドキュメントをみてもよくわからなかたったり、上手くいかなかったりしたのですが、今回ようやくサンプルアプリケーションを動作させる手順をまとめることができました。 次は、Amazon EFS CSI ドライバーの構成方法の記事を書きたいと思います。

 

/* -----codeの行番号----- */