紹介する内容
- circleciにlocalstackをterraformで構築します
- terraformでlambdaを作ります
- ユーザーが指定したディレクトリにpython packageをインストールします
- インストールしたpackageをzipに固めます
- terraformでlambdaを作ります
- circleciをlocalで動かしてますが、本物のcircleciでも動きます
- circleciの
docker executor
を使います
結論
- localstackのdocker-entrypoint-initaws.dが使用できないから、
- docker-entrypoint-initaws.dの作業内容をPrimaryコンテナに書きます、
- localstack固有のもろもろ初期化が終わるタイミングを把握できません。愚直に初期化作業に掛かる時間を計測して、その時間分待つようにすることが最善です。
- circleciをlocal環境でデバックする方法はこちらで確認できます
- localstackコンテナの環境変数
HOSTNAME_EXTERNAL
をlocalhost
にして、Primaryコンテナからのlocalstackアクセスできるようにします。
circleciのdocker executorはvolumnsが使えない
- circleciのdocker executorはdocker composeのvolumesを使用できません。
- これがlocalstack固有のもろもろ初期化が終わるタイミングを把握不可能する原因です。volumesが使えないから、docker-entrypoint-initaws.dに介入が不可能です
- localstackのportが開くことを基準にするのは意味がありません。なぜなら、portを開けたままもろもろ初期化作業するからです
- https://circleci.com/docs/2.0/executor-types/#docker-benefits-and-limitations
- どうしてもdocker composeのvolumesを使う必要があったら、
machine executor
にしたら実装可能だと思います
- これがlocalstack固有のもろもろ初期化が終わるタイミングを把握不可能する原因です。volumesが使えないから、docker-entrypoint-initaws.dに介入が不可能です
circleciのdocker executorはネットワークのhost名がlocalhostになっています
- circleciのdocker executorは一つのネットワーク(
common network
)がありまして、host名はlocalhost
です。Primaryコンテナ含むすべてのコンテナが属してます- docker executorはコンテナ同士volumnsでやりとりできないから、コンテナ各々違うport番号を貼ってやりとりさせることが無難かと思います。
-
common network
の原文:https://circleci.com/docs/2.0/executor-types/#using-multiple-docker-images
(参考)Primaryコンテナ以外のコンテナはできることが限られている印象です
- docker executorが使えるオプション:https://circleci.com/docs/2.0/configuration-reference/#docker
紹介始めます
localstack紹介
実のAWSを使わずにいろいろ試せるものです。
バージョン0.11.0から大きな変化がありました。本記事は0.11.0バージョンのlocalstackを使います
https://github.com/localstack/localstack
terraform紹介
コードでインフラを管理できます。
https://www.terraform.io/
circleci紹介
コードの継続的な統合とテストを助けてくれるものです。
https://circleci.com/
構築実験環境
Linux
- CentOS Linux release 7.7.1908 (Core)
Docker Compose
- VERSION : 1.24.1
Docker
- VERSION : 19.03.5
local circleciをインストールします
ディレクトリ構成
全体ソースコードは https://github.com/cheekykorkind/circleci-localstack で確認できます
当記事のプロジェクトはdocker composeでlocalstackを作ってterraformでlambdaを作る
プロジェクトからcircleci設定を追加して調整したバージョンです。docker composeでlocalstackを作る詳しい内容はこちらの記事参考お願いします。
https://qiita.com/cheekykorkind/items/02c896465ddea5c5186f
circleciのconfig.ymlで構築します
jobの名前はtestです。my-testなどでも設定可能です
version: 2
jobs:
test:
docker:
- image: circleci/python:3.7-buster-node
environment:
AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_DEFAULT_REGION: us-east-1
LAMBDA_ZIP_PATH: /home/circleci/lambda.zip
HELLO_WORLD_PATH: /home/circleci/project/sam-lambda/hello_world
TERRAFORM_PATH: /home/circleci/project/terraform
COMMON_NETWORK: localhost
- image: localstack/localstack:0.11.0
environment:
AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_DEFAULT_REGION: us-east-1
SERVICES: lambda,logs
DEBUG: 1
HOSTNAME_EXTERNAL: localhost
steps:
- checkout
- run:
name: Wait for localstack
command: dockerize -wait tcp://localhost:4566 -timeout 2m
- run:
name: install pip packages at packages directory
command: |
pip -V
cd $HELLO_WORLD_PATH
pip install -t ./packages -r requirements.txt
zip -r9 $LAMBDA_ZIP_PATH .
- run:
name: install terraform 0.12.6
command: |
cd ~
sudo apt-get install unzip
wget https://releases.hashicorp.com/terraform/0.12.6/terraform_0.12.6_linux_amd64.zip
sudo unzip -o terraform_0.12.6_linux_amd64.zip
sudo mv terraform /usr/local/bin/
terraform --version
- run:
name: terraform apply
command: |
cd $TERRAFORM_PATH
terraform init
terraform apply -auto-approve -var="lambda_zip_path=$LAMBDA_ZIP_PATH" -var="endpoint_domain=$COMMON_NETWORK"
- run:
name: install aws cli
command: |
sudo apt install awscli
- run:
name: test lambda
command: |
aws lambda invoke --region us-east-1 \
--endpoint-url http://localhost:4566 \
--function-name hello_lambda \
--payload '{ "name": "Bob" }' \
response.json
コンテナの環境変数設定
-
circleci/python:3.7-buster-nodeコンテナ(Primaryコンテナ)
-
COMMON_NETWORK
はterraformにcircleciのdocker executorのデフォルトhost名localhost
を伝えるために作りました -
AWS_ACCESS_KEY_ID
、AWS_SECRET_ACCESS_KEY
、AWS_DEFAULT_REGION
はaws cliを便利に使うために設定しました -
LAMBDA_ZIP_PATH
はlambda生成に使うzipファイルの位置を書きました。コンテナ2つが連携して作業するから管理しやすくするために設定しました -
HELLO_WORLD_PATH
は便利にSAMプロジェクトのpythonコードのzip圧縮をするために設定しました-
TERRAFORM_PATH
はterraformファイルのパスです。terraformコマンド実行するためにterraformファイルがいるところに移動する必要があります。便利な移動のために事前に指定しておきました
-
-
-
localstack/localstack:0.11.0コンテナ
-
SERVICES
、DEBUG
、HOSTNAME_EXTERNAL
はlocalstack固有の環境変数です。localstackを調べると理解できると思います-
HOSTNAME_EXTERNAL
はcircleciのprimaryコンテナからlocalstackにアクセスできるようにcircleciのデフォルトhost名であるlocalhost
に合わせます。これでterraformがlocalstackに付けて実行可能になります
-
-
AWS_ACCESS_KEY_ID
、AWS_SECRET_ACCESS_KEY
、AWS_DEFAULT_REGION
はaws cliを便利に使うために設定しました
-
steps説明
-
name: Wait for localstack
- localstackコンテナが起動することを待ちます。一番前に置いた理由はterraform実行する前にlocalstackのもろもろ初期化作業する時間を稼ぐためです。当プロジェクトはlambdaとcloudwatch logs二つのサービスだけ使っていてこれで大丈夫ですが、localstackで使おうとするサービスが多い場合は大目に
sleep 300
などを入れることも考える必要があります
- localstackコンテナが起動することを待ちます。一番前に置いた理由はterraform実行する前にlocalstackのもろもろ初期化作業する時間を稼ぐためです。当プロジェクトはlambdaとcloudwatch logs二つのサービスだけ使っていてこれで大丈夫ですが、localstackで使おうとするサービスが多い場合は大目に
circleci local execute --job testによる作業の流れ
- circleci/python:3.7-buster-nodeコンテナ(Primaryコンテナ)が作られます
- localstackコンテナが作れます
- Primaryコンテナのstepが実行されます
-
name: Wait for localstack
stepで少なくともportが開けるまで待ちます - pythonのpackageをディレクトリ
/home/circleci/project/sam-lambda/hello_world/packages
に指定し、インストールします -
$LAMBDA_ZIP_PATH
に置きます - terraformをインストールしあます
- terraformファイルがいる
$TERRAFORM_PATH
に移動します - terraform initします
- terraform applyします。同時にterraformでlambdaのzipパス(
$LAMBDA_ZIP_PATH
)とcircleciのデフォルトhost名を入れたを$COMMON_NETWORK
を渡します - terraformによってlambdaが作られます
circleci local execute --job testを叩いた結果
circleciの最後のstepに書いたlambdaをinvokeする部分がちゃんと動いてresponseのstatusが200を返したことが確認できます