LambdaでSeleniumを使ってスクレイピングする
参考
写経
まずは流れを理解するためにざっと手動でやってみる。
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"
}
}
}
以下を使用させていただく。
$ 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...
終わったら全部消しておく。
GitHub Actionsで自動デプロイ
参考
上でも使わせていただいた以下のレポジトリをforkしてcloneする。
自分のはこれ。
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に登録した。
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
課題
- git/dockerのタグとかgithubのreleaseとかそのへんの整理は必要(あまりやったことない)
- IAM/ECR/LambdaとかはTerraformとかのIaCでやるほうがよい
デプロイ周りを先に進めてしまったけど、スクレイピング周りは後で
ECR介さないやり方もあるけど、Seleniumだとサイズとかの観点で厳しいかも。
最近はもうplaywrightでいいかなという気はしている。