1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RailsアプリケーションをAWS Lambdaで動かす!Lambyを使った実践的なハンズオン

Last updated at Posted at 2025-06-08

RailsアプリケーションをAWS Lambdaで動かす!Lambyを使った実践的なハンズオン

はじめに

自分でwebアプリケーションを作成して公開したい!となると昔のようにherokuで無料ではできなくなってしまいましたよね。また、AWSで公開したい!と思った時もRDSなど何かと高くつきます。
「じゃあAWS Lambdaでできればリクエストに応じた課金しかしなくていいのに笑」とおもったら本当にあった。

調べてみるとLambyというのがあるんですね。しかし、Quick Start以上の情報が少なく、特に以下の点で苦労しましたのでまとめておきました。

  • AWS上のMySQL(RDS)との接続設定
  • System Managerのパラメーターストアからの環境変数の取得
  • VPC、サブネット、セキュリティグループの設定

AWSの基本知識がないことから起きる問題ですがその辺りも丁寧に触れられればと思います。

本記事では、これらの課題を解決しながら、実際のアプリケーションをデプロイするまでの手順を詳しく解説します。

説明したりない部分や誤っている解釈があったらご指摘ください :bow:

目次

  1. とりあえずQuick Start通りにローカル環境を立ち上げてみる
  2. AWSにデプロイしてみる
  3. AWSのRDSと接続してみる
    • VPCとサブネットの設定
    • セキュリティグループの設定
    • RDSの作成
  4. 環境変数の管理
    • System Managerパラメーターストアの設定
  5. マイグレーションをどうやるか?

1. Quick Start通りにローカル環境を立ち上げてみる

以下を参考にとりあえずローカル環境でYay! You’re on Rails!までやってみます
https://lamby.cloud/docs/quick-start

cd YOUR_OWN_DIRECTORY
docker run \
  --rm \
  --interactive \
  --volume "${PWD}:/var/task" \
  ghcr.io/rails-lambda/lamby-cookiecutter \
  "gh:rails-lambda/lamby-cookiecutter"

github上のlambyのクッキーカッタープロジェクトからRailsのテンプレートを参照してdockerコンテナ上で実行しているんですね。

Unable to find image 'ghcr.io/rails-lambda/lamby-cookiecutter:latest' locally
latest: Pulling from rails-lambda/lamby-cookiecutter
579b34f0a95b: Pull complete 
00152206209d: Pull complete 
981d19de32f1: Pull complete 
f32a7c3c67ff: Pull complete 
d2b34077d5c8: Pull complete 
5ab76f42a493: Pull complete 
fd387620f47a: Pull complete 
Digest: sha256:c583410d17557f119a0ddb905fa191d9ca4f88e997f3eaef696a5aaab460d70c
Status: Downloaded newer image for ghcr.io/rails-lambda/lamby-cookiecutter:latest

プロジェクト名を決める

project_name [my_awesome_lambda]: YOUR_ONW_APP_NAME

vscode(Cursor)からdev containerのワークスペースを開く。
スクリーンショット 2025-06-08 15.59.07.png

起動まで5分ほどかかる。

docker psでコンテナの起動を確認
APサーバーに加え、MySQLサーバーまで作ってくれるとは、、、。

docker ps

CONTAINER ID   IMAGE                   COMMAND                   CREATED         STATUS                   PORTS                 NAMES
357e95a57870   test_devcontainer-app   "/bin/sh -c 'echo Co…"   3 minutes ago   Up 2 minutes                                   test_devcontainer-app-1
933a7dee8d5e   mysql:8.0               "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes (healthy)   3306/tcp, 33060/tcp   test_devcontainer-mysql-1

Lambyが用意してくれている初期設定プログラムを実行

./bin/setup

中を見るとこのようになっており

  • 依存関係(gem)のインストール(bundle install)
  • データベースの準備(./bin/rails db:prepare)
  • 古いログや一時ファイルの削除(./bin/rails log:clear tmp:clear)
  • アプリケーションサーバーの再起動(./bin/rails restart)

をひとまとめにしてくれている。
なのでgemを追加した時、dbスキーマに更新があったときはとりあえずこのコマンドを実行すればいいわけですね。

#!/bin/sh
set -e

echo '== Installing dependencies =='
bundle install

echo "== Preparing database =="
./bin/rails db:prepare

echo "== Removing old logs and tempfiles =="
./bin/rails log:clear tmp:clear

echo "== Restarting application server =="
./bin/rails restart

# ./bin/yarn

実際にrailsサーバーを起動

./bin/rails s

スクリーンショット 2025-06-08 16.15.04.png
ここまで約5分。すごい。

2.AWSにデプロイしてみる

では実際にawsにLambdaサーバーをデプロイしてみる

以下のコマンドを実行してawsのアカウントとこのプロジェクトを紐づけます。

aws configure

deployを実行する

./bin/deploy

内容を要約すると

  • 環境変数の設定
  • ECR(Elastic Container Registry)にイメージがなければ作成する
  • デプロイのためにbundle install
  • アセットプリコンパイル
  • 不要ファイルの削除
  • SAM(Serverless Application Model)関係の処理
    • アプリケーションのビルド
    • ビルドしたアプリケーションをパッケージング(コンテナイメージとしてECRリポジトリに保存するため)
    • パッケージングしたアプリケーションをデプロイ(AWSリソースなどを作成するため)

ECRを作成、./.aws-sam/build/template.yamlをもとに内容をECRに保存、ECR上のイメージを利用してAWSリソースを作成、あるいは更新という流れですね。

./bin/deployの内容はこちら
#!/bin/sh
set -e

RAILS_ENV=${RAILS_ENV-production}

AWS_REGION=${AWS_REGION-$(aws configure get region || echo 'ap-northeast-1')}
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
IMAGE_REPOSITORY="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/esoteric-word"

if [ "$CI" != "true" ]; then
  echo "== Cleaning dev dependencies for local deploy. Run ./bin/setup again afterward! =="
  rm -rf ./.bundle \
         ./vendor/bundle
fi

echo '== Create ECR Repo if needed. =='
aws ecr describe-repositories \
  --repository-names "esoteric-word" \
  --region "$AWS_REGION" > /dev/null || \
aws ecr create-repository \
  --repository-name "esoteric-word" \
  --image-tag-mutability "MUTABLE" \
  --image-scanning-configuration "scanOnPush=true" \
  --region "$AWS_REGION" > /dev/null || true

echo '== Bundle For Deployment =='
bundle config --global silence_root_warning true
bundle config --local deployment true
bundle config --local without 'development test'
bundle config --local path './vendor/bundle'
bundle install --quiet --jobs 4

echo "== Asset Hosts & Precompiling =="
NODE_ENV='production' ./bin/rails assets:precompile

if [ "$CI" = "true" ]; then
  echo "== Cleanup Unused Files & Directories =="
  rm -rf \
    log \
    node_modules \
    test \
    tmp \
    vendor/bundle/ruby/*/cache
fi

echo "== SAM build =="
sam build \
  --parameter-overrides \
    RailsEnv="${RAILS_ENV}"

echo "== SAM package =="
sam package \
  --region "$AWS_REGION" \
  --template-file ./.aws-sam/build/template.yaml \
  --output-template-file ./.aws-sam/build/packaged.yaml \
  --image-repository "$IMAGE_REPOSITORY"

echo "== SAM deploy =="
sam deploy \
  --region "$AWS_REGION" \
  --template-file ./.aws-sam/build/packaged.yaml \
  --stack-name "esoteric-word-${RAILS_ENV}" \
  --image-repository "$IMAGE_REPOSITORY" \
  --capabilities "CAPABILITY_IAM" \
  --parameter-overrides \
    RailsEnv="${RAILS_ENV}"

if [ "$CI" != "true" ]; then
  echo "== Cleaning prod deploy dependencies from local. =="
  rm -rf ./.bundle \
         ./vendor/bundle \
         ./node_modules \
         ./public/assets
fi

デプロイ完了。簡単すぎる、、、。

CloudFormation outputs from deployed stack
-------------------------------------------------------------------------------------------
Outputs
-------------------------------------------------------------------------------------------
Key                 RailsLambdaUrl
Description         Lambda Function URL
Value               https://b4hsncwngvxg6rv67b64r545ly0jrwnk.lambda-url.us-east-1.on.aws/
-------------------------------------------------------------------------------------------

Successfully created/updated stack - new-service-production in us-east-1

ここまではすんなりできたのですがいくつかハマった点があるので順に見ていきます。

  • AWSのRDSは使えるのか(環境変数の設定をSystem Managerでできるのか)

3. AWSのRDSと接続してみる

VPCとサブネットの設定

Lambda関数からRDSにアクセスするために、VPCとサブネットの設定が必要なのでVPCとサブネット(2つ)を作成します。
VPCとサブネットを作成し、VPCの中に2つのサブネットが属している状態にします。
スクリーンショット 2025-05-17 10.09.33.png

セキュリティグループの設定

LambdaのSG

LambdaがRDSにアクセスできるようにするため
スクリーンショット 2025-05-17 10.16.06.png
スクリーンショット 2025-05-17 10.15.57.png

RDSのSG

Lambdaからのアクセスのみを受け入れられるようにするため
インバウンドルールに上記で作成したSG(lambda-rds-1)を設定します。
スクリーンショット 2025-05-17 10.16.36.png
スクリーンショット 2025-05-17 10.16.49.png

awsコンソールからRDSの接続をクリックして手動で作成したが、本当は自動でできるかも?

Lambdaのプロジェクトに対してVPCを設定するには.aws-sam/build/template.yamlを以下のように変更します。

VpcConfig:
  SubnetIds:
    - subnet-xxxxxxxxxxxxxxxxx
    - subnet-xxxxxxxxxxxxxxxxx
  SecurityGroupIds:
    - sg-xxxxxxxxxxxxxxxxx # lambda-rds-1

RDSの作成

RDSのサブネットグループに先ほど作成したサブネット二つを設定する
スクリーンショット 2025-06-08 18.11.44.png
このように設定できていればOK
スクリーンショット 2025-05-17 10.06.42.png

config/database.ymlを変更

# config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: <%= ENV["MYSQL_ROOT_PASSWORD"] %>
  host: <%= ENV.fetch("MYSQL_HOST") { "localhost" } %>

development:
  <<: *default
  database: esoteric_word_development

test:
  <<: *default
  database: esoteric_word_test

production:
  <<: *default
  database: esoteric_word_production
  url: <%= ENV["DATABASE_URL"] %>
  username: <%= ENV["MYSQL_ADMIN_USER"] %>
  password: <%= ENV["MYSQL_ADMIN_PASSWORD"] %>

4. 環境変数の管理

System Managerパラメーターストアの設定

機密情報はSystem Managerパラメーターストアで管理します
スクリーンショット 2025-05-17 10.19.48.png

System Managerの設定を.aws-sam/build/template.yamlが参照できるように書き換えます。

Environment:
  Variables:
    MYSQL_HOST: !Sub '{{resolve:ssm:/esoteric/MYSQL_HOST}}'
    MYSQL_ADMIN_USER: !Sub '{{resolve:ssm:/esoteric/MYSQL_ADMIN_USER}}'
    MYSQL_ADMIN_PASSWORD: !Sub '{{resolve:ssm:/esoteric/MYSQL_ADMIN_PASSWORD}}'

ドキュメントの書き方だとなぜか参照できなかったので書き方を変更しました。

これでRDSと接続まではできるようになりました。

5.マイグレーションをどうやるか?

まず真っ先に思い浮かぶ方法が./bin/deployを実行するスクリプトに含めること(bundle installやアセットプリコンパイルをしているから)ですが、これはうまくいきませんでした。
ほんとかどうかわかりませんがAI曰く「デプロイスクリプトの実行はインターネット環境からのアクセスであり、RDSはインターネット環境からのパブリックアクセスが許可されていないから」とのこと。

ここで公式ドキュメントをちゃんと読みます。
lambda-console-cliを使えとありますね。
自分の場合はlambda-console-cliを実行したら必要なパッケージが足りていないとメッセージが出ましたが、順番にインストールしたら実行できました。
以下の通り、rubyやrailsのバージョンも答えてくれましたのでマイグレーションを実行できました。
自分はridgepoleを使っていますがridgepoleができるのだからmigrateもできると思います。
スクリーンショット 2025-04-27 17.49.16.png

これでLamby + RDSという環境を作成することができました!

課題の課題

  • もっと節約するためにDynamoDBを利用する方式に変更したい(次回また記事書くかも)
  • github actionのワークフローが失敗してしまう

参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?