Open6

LambdaでSeleniumを使ってスクレイピングする

kun432kun432

写経

まずは流れを理解するためにざっと手動でやってみる。

ECRでレポジトリを作っておく。

$ aws ecr create-repository \
    --repository-name hello-world \
    --image-scanning-configuration scanOnPush=true \
    --region ap-northeast-1
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-1: XXXXXXXXXXXX:repository/hello-world",
        "registryId": "XXXXXXXXXXXX",
        "repositoryName": "hello-world",
        "repositoryUri": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world",
        "createdAt": "2023-05-02T11:07:50+09:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": true
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

以下を使用させていただく。
https://github.com/umihico/docker-selenium-lambda/

$ git clone https://github.com/umihico/docker-selenium-lambda
$ cd docker-selenium-lambda

Dockerイメージ作成

$ docker build -t hello_world .

ECRログイン

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world

ECRにpush

$ docker tag hello_world:latest XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest
$ docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest

Lambdaで関数作成

  • コンテナイメージから
  • URIは XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest にしてみた
  • その他はデフォルト

Lambdaの設定変更

  • メモリ: 256MB
  • タイムアウト: 10秒

Lambdaのテスト

  • hello-worldテンプレートが選択されていること

テストが成功して以下が出力されていればOK

Example Domain\nThis domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.\nMore information...

終わったら全部消しておく。

kun432kun432

GitHub Actionsで自動デプロイ

参考

https://dev.classmethod.jp/articles/deploying-to-aws-lambda-container-using-github-actions/

https://dev.classmethod.jp/articles/lambda-github-actions/

https://zenn.dev/ymiz/articles/2c7397c670b6a2

https://zenn.dev/kou_pg_0131/articles/gh-actions-oidc-aws


上でも使わせていただいた以下のレポジトリをforkしてcloneする。

https://github.com/umihico/docker-selenium-lambda/

自分のはこれ。

https://github.com/kun432/docker-selenium-lambda-github-actions

ECRのレポジトリを作成

$ aws ecr create-repository \
    --repository-name hello-world \
    --image-scanning-configuration scanOnPush=true \
    --region ap-northeast-1

とりあえずイメージをpush しておく

$ docker build -t hello_world .
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world
$ docker tag hello_world:test XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest
$ docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest

IAMロールとLambda関数を作成

$ aws iam create-role \
  --role-name lambda-exec-hello-world \
  --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}'

$ aws iam attach-role-policy \
  --role-name lambda-exec-hello-world \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

$ aws lambda create-function \
  --function-name hello-world \
  --package-type Image \
  --code ImageUri=XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest \
  --role arn:aws:iam::XXXXXXXXXXXX:role/lambda-exec-hello-world

$ aws lambda create-function \
  --function-name hello-world \
  --package-type Image \
  --code ImageUri=XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest \
  --role arn:aws:iam::XXXXXXXXXXXX:role/lambda-exec-hello-world

$ aws lambda update-function-configuration \
  --function-name hello-world \
  --memory-size 256 \
  --timeout 10

IAMアイデンティティプロバイダを設定。ここが参考になった。

$ ISSUER_URL=https://token.actions.githubusercontent.com

$ JWKS_FQDN=$(curl -sS $ISSUER_URL/.well-known/openid-configuration | jq -r '.jwks_uri' | perl -pe 's/^https:\/\/(.+?)\/.+$/${1}/')

$ CERTIFICATE_BODY=$(openssl s_client -servername $JWKS_FQDN -showcerts -connect $JWKS_FQDN:443 </dev/null 2>/dev/null | awk '/-----BEGIN CERTIFICATE-----/, /-----END CERTIFICATE-----/' | sed 's/^[ \t]*//;s/[ \t]*$//')

$ CERTIFICATE_FINGERPRINT=$(echo -n "$CERTIFICATE_BODY" | openssl x509 -fingerprint -noout | awk -F= '{print tolower($2)}' | sed 's/://g')

$ aws iam create-open-id-connect-provider \
  --url $ISSUER_URL \
  --thumbprint-list $CERTIFICATE_FINGERPRINT \
  --client-id-list sts.amazonaws.com 
{
    "OpenIDConnectProviderArn": "arn:aws:iam::XXXXXXXXXXXX:oidc-provider/token.actions.githubusercontent.com"
}

で、これを使って特定のレポジトリ・ブランチからのみ認証を許可するIAMロールを作成する。

$ aws iam create-role \
  --role-name github-deploy-lambda-hello-world \
  --assume-role-policy-document \
'{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::XXXXXXXXXXXX:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
                    "token.actions.githubusercontent.com:sub": "repo:kun432/docker-selenium-lambda-github-actions:ref:refs/heads/main"
                }
            }
        }
    ]
}'

Conditionで、OIDCプロバイダ経由特定のレポジトリ・ブランチからのみ認証を許可するようにしておく。

でロールにポリシーを追加して、ECRへのアップロードやLambda関数の更新を許可する。

$ aws iam create-policy \
  --policy-name github-deploy-ecr-lambda \
  --policy-document \
'{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "ecr:GetAuthorizationToken",
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:CompleteLayerUpload",
                "ecr:InitiateLayerUpload",
                "ecr:PutImage",
                "ecr:UploadLayerPart"
            ],
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "lambda:UpdateFunctionCode",
            "Resource": "*"
        }
    ]
}'

ポリシーのARNを控えておいて、

{
    "Policy": {
        "PolicyName": "github-deploy-ecr-lambda",
(snip)
        "Arn": "arn:aws:iam::XXXXXXXXXXXX:policy/github-deploy-ecr-lambda",
(snip)
    }
}

IAMロールと紐付ける。

$ aws iam attach-role-policy \
  --role-name github-deploy-lambda-hello-world \
  --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/github-deploy-ecr-lambda

これで準備完了。

ではGitHub Actionの設定を行う。ワークフローの設定。

$ mkdir -p .github/workflows
$ touch .github/workflows/deploy.yml

以下のファイルを作成。envは環境に合わせて書き換える。あと、元記事ではAWS_ACCOUNT_IDが埋め込まれていたけど、今回forkしたレポジトリでprivateに変更できないので、ここだけrepository secretに登録した。

github/workflows/deploy.yml
name: Deploy container image to AWS Lambda
on:
  push:
    branches:
     - main
env:
  AWS_ROLE_NAME: github-deploy-lambda-hello-world
  AWS_ROLE_SESSION_NAME: GitHubActions
  AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
  AWS_REGION: ap-northeast-1
  ECR_REPOSITORY: hello-world
  LAMBDA_FUNCTION_NAME: hello-world

permissions:
  id-token: write
  contents: read
jobs:
  aws-deploy:
    name: Push to ECR
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ env.AWS_ROLE_NAME }}
          role-session-name: ${{ env.AWS_ROLE_SESSION_NAME }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          aws lambda update-function-code --function-name $LAMBDA_FUNCTION_NAME --image-uri $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

あとはmainブランチにpushして反映されるのを確認すればOK

kun432kun432

課題

  • git/dockerのタグとかgithubのreleaseとかそのへんの整理は必要(あまりやったことない)
  • IAM/ECR/LambdaとかはTerraformとかのIaCでやるほうがよい
kun432kun432

デプロイ周りを先に進めてしまったけど、スクレイピング周りは後で