Google Chromeは動かない

はじめに WebアプリケーションのテストにHeadless Chromeを使いたいと思いました。 Lambdaで動かせると安いし起動も早いかなぁと思ってたのですがどうも動かないようです。 考えていた構成としてコンテナにChromeをインストールしてlambdaでコンテナを起動するというものでした。 結論 lambdaでは /tmp 以外が読み書きできないのでChromeが動かないようです。 具体的には /dev/fd とか /run に書き込めないって怒られます。 回避策 結局やりたかったことは手軽にheadlessをserverless環境で動かしたいということなのでECS Fargateの上で動かしました。 lambdaに比べると起動時間がだいぶ遅くなりましたが我慢しました。 EC2にECS clusterを構築すると多少早くはなりますが、ずっと起動しておくものでもないのでコスト的にFargateを利用しています。 参考 最新のGoogle Chromeとchromedriverを動かすDockerfile例 FROMdebian:latestWORKDIR/tmpRUN set -e \ && apt-get update \ && apt-get upgrade -y \ && sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ && apt-get install -y wget gnupg unzip \ && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ && apt-get update \ && apt-get install -y google-chrome-stable udev \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ && CHROME_VERSION=$(google-chrome --version | awk '{print $3}' ) \ && echo "Chrome version: ${CHROME_VERSION}" \ && wget -q -O /tmp/chromedriver....

10月 20, 2023

lambda function URLsのeventをプロキシしてhttp apiに流す

小規模なSlack BotはAWS lambda functions URLsに作ると楽だった の話の続きです. 先日lambda function URLsを利用してhttp apiのような実装を記述する方法を紹介しました. 今回は httpadapter と net/http/httputil を利用してlambda function URLsをリバースプロキシとして動かしてbackend apiに流す方法です. 概略図 実装 普通のリバースプロキシを実装するときはhttputil.ReverseProxyを定義してserverを作って待ち受けるわけですが、 今回の場合はhttputil.ReverseProxyを定義した後httpadapter.NewV2に食わせるだけですね. 次の例はlambdaのeventを受け取ったあとlocalで8080ポートで待ち受けるhttp serverにリクエストを流すproxyの例です. func main() { director := func(req *http.Request) { req.URL.Scheme = "http" req.URL.Host = ":8080" } rp := &httputil.ReverseProxy{Director: director} lambda.Start(httpadapter.NewV2(rp).ProxyWithContext) } すべてlambda関数上で完結させたい場合は func init() などでapiを予め立ち上げた後プロキシしてあげると良いと思います. github.com/ieee0824/le2hp ではそのような実装にしました.

2月 2, 2023

小規模なSlack BotはAWS lambda functions URLsに作ると楽だった

はじめに ここで言う小規模なSlack Botというのは個人で使うようなBotやチームレベルで使う書き捨てレベルのようなもののことです. このような想定のBotを実装するときそこまでちゃんとインフラコストをかけたくありません. 自前でサーバーを用意したとして処理内容と維持管理費用が割に合わないのです. 無料でhttp serverを立ち上げることができるけど定期的にリクエストを送っておかなければプロセスがkillされるようなサービスもあります. そのようなサービスを使う場合定期的にリクエストを送るか立ち上がるまで待った後Botのためのリクエストを送らないと機能しない問題があります. それらの問題を解消するのにlambda functions URLsは要件にあってそうだなぁと思いました. lambda function URLsはlambdaなので課金が発生する時間単位が短いのでたまにしか実行されないようなものでもサーバーを立てて実現するよりお金がかからないです. またlambda function URLsにリクエストを投げるとlambdaのeventが発火して即時にlambda関数が実行されるので待ち時間も発生しません. 一つ問題があるとしたらlambdaのeventとして作成したプログラムから見えるので普段Botをhttpのapiとして実装している場合はhttp requestとlambdaのeventとのギャップを埋める必要があるということです. とはいえそこまで大きな問題にはならないと思います. 特にGo言語の場合は github.com/awslabs/aws-lambda-go-api-proxy/httpadapter を利用するとほとんどhttp serverと同じような実装でアプリケーションを作ることができます. Goでlambda function URLsを使ってリクエスト受ける例 github.com/awslabs/aws-lambda-go-api-proxy/httpadapter を利用した実装例を上げておきます. frameworkを利用しない例 frameworkを利用しない例です. 生のGo言語でhttp serverを実装したことがある人なら雰囲気が解ると思います. package main import ( "io" "net/http" "github.com/aws/aws-lambda-go/lambda" "github.com/awslabs/aws-lambda-go-api-proxy/httpadapter" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "It Works!") }) // lambda function URLsはapi gateway v2と同じeventなのでv2にする必要がある lambda.Start(httpadapter.NewV2(http.DefaultServeMux).ProxyWithContext) } Ginを利用した例 frameworkを利用することもできます. 例えばGinを利用する場合は次のように記述ができます. package main import ( "context" "net/http" "github....

1月 31, 2023

Amazon ECS FargateでS3から環境変数読み込むときの注意点

S3に保存するときのファイルの拡張子は .env であること .env 以外でやろうとするとTaskDefinitionの作成時に An invalid environment file extension was used. Specify a valid .env file and try again. というエラーを見ることになる プラットフォームバージョンは 1.4.0 以上であること AWSのECS FargateでプラットフォームバージョンをLATESTにしたときの挙動がLATESTぽくない気がする S3から環境変数を読み込む機能を利用できるのが1.4.0からなんだけどLATESTだと使えなくて明示的に1.4.0にすると使えたからLATESTにしたときに古いバージョンが利用されているのではないか? — 煩悩 (@ast839) November 5, 2020 これは注意点と言うよりもおかしな挙動をしてるんじゃないかってことなんだけど. 公式のマニュアルには When specifying a platform version, you can use either a specific version number, for example 1.4.0, or LATEST (which uses the 1.4.0 platform version). と書いてあるので LATEST でも大丈夫なはずなんだけど実際にやってみたら One or more of the requested capabilities are not supported....

11月 6, 2020

雑メモ

fagateハマったとこ lbのセキュリティグループ コンテナ側のセキュリティグループ |外の世界| -(1)-> |alb| -(2)-> |コンテナ🐳| (1), (2) に別々にセキュリティグループを設定する必要がある. EC2インスタンスがないから忘れてた.

9月 6, 2020

ECSでSQSのAPIを叩くときハマった

golangでSQSのqueueの一覧を取得しようとしたときこんなふうに書くことができる. package main import ( "fmt" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/sqs" ) func main() { c := &aws.Config{ Region: aws.String("ap-northeast-1"), } svc := sqs.New(session.Must(session.NewSession(c))) list, err := svc.ListQueues(&sqs.ListQueuesInput{}) if err != nil { panic(err) } fmt.Println(list.String()) } このように書いた場合 github.com/aws/aws-sdk-go/aws/credentials とか github.com/aws/aws-sdk-go/aws/stscredes とかを利用していない. つまり利用されるawsのアクセス権限の元になる情報は ~/.aws 以下に設定された情報だったり ECSの場合はtaskRoleARNに設定された情報となる. 私が上記の実装をした上でdocker containerをビルドして実行したときハマったことを書こうと思う. ECSは標準出力の内容をcloud watch logsに出力することができる. 上記の実装を実行したと気次のようなエラーが出力された. For verbose messaging see aws.Config.CredentialsChainVerboseErrors panic: NoCredentialProviders: no valid providers in chain. Deprecated. はじめはtask roleにsqsのアクセス権限を忘れたことによって発生していた問題かと思ったが違った. ECS上でコンテナを動かしたとき特に何もしない場合はtask roleで設定した情報を元に権限が設定される. 実際のところ裏側ではAWS SDK側で 169.254.170.2 にアクセスしてメタ情報からクレデンシャル情報を引っ張ってくる....

10月 25, 2018