【Rails / Flutter】Rails API をバックエンド、 Flutter をフロントエンドとする構成を作る Part1
今回は、 Rails をバックエンドに、 Flutter をフロントエンドにした構成を作ってみたいと思います。
インフラ構成に Terraform を使い、 API 通信には GraphQL を採用し、これまで単体でしか勉強したことがなかったものを組み合わせてみることにしました。
さっそく、始めましょう!
1. Docker で Rails API アプリを構築
Docker のインストール方法
まず最初に、Docker をインストールします。各プラットフォームに対応したインストールガイドに従ってください。
- Windows: Docker Desktop for Windows
- Mac: Docker Desktop for Mac
- Linux: Docker Engine for Linux
Dockerfile の作成
次に、プロジェクトディレクトリを作成し、 Dockerfile を作成します。
mkdir my_app
cd my_app
FROM ruby:3.3.3
RUN apt-get update -qq && apt-get install -y nodejs yarn default-mysql-client
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app
CMD ["rails", "server", "-b", "0.0.0.0"]
docker-compose を用いた開発環境の構築
次に、 docker-compose.yml ファイルを作成し、開発環境を構築します。
version: '3'
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: myapp_development
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
web:
build: .
command: bundle exec rails s -b '0.0.0.0'
volumes:
- ".:/myapp"
ports:
- "3000:3000"
depends_on:
- db
volumes:
db_data:
Rails プロジェクトの作成
そして、新しい Rails API プロジェクトを作成します。
ターミナルを開き、以下のコマンドを実行してください。
# Rails プロジェクトの作成
docker-compose run web rails new . --force --no-deps --database=mysql --api
これで、Docker を用いた Rails API アプリの環境構築が完了しました。
次に、 Rails のセットアップをおこないます。
2. Rails API アプリのセットアップ
必要な Gems のインストールと設定
まず、必要な Gem を追加します。
gem 'rails', '7.1.0'
gem 'mysql2', '>= 0.5.4'
次に、以下のコマンドを実行して Gems をインストールします。
docker-compose run web bundle install
データベースの設定
次に、config/database.yml ファイルを以下のように設定します。
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <your-username>
password: <your-password>
host: db
development:
<<: *default
database: myapp_development
test:
<<: *default
database: myapp_test
production:
<<: *default
database: myapp_production
username: <your-prod-username>
password: <your-prod-password>
データベースを作成するために、以下のコマンドを実行します。
docker-compose run web rails db:create
シンプルな API エンドポイントの作成
最後に、シンプルな API エンドポイントを作成しておきます。
class HomeController < ApplicationController
def index
render plain: "OK"
end
end
root 'home#index'
次に、Terraform を用いた AWS リソースの構成に進みます。
3. Terraform で AWS リソースを構成
Terraform のインストールと設定
まず、Terraform をインストールします。各プラットフォームに対応したインストールガイドに従ってください。
Terraform プロジェクトの作成
次に、新しいディレクトリを作成し、Terraform プロジェクトを初期化します。
mkdir terraform_project
cd terraform_project
terraform init
AWS クレデンシャルの設定
AWS CLI を使用して、クレデンシャルを設定します。
aws configure
Docker イメージのビルドと Amazon ECR へのプッシュ
まず、Docker イメージをビルドし、Amazon ECR にプッシュします。
# ECR リポジトリの作成
aws ecr create-repository --repository-name my_api
# Docker イメージのビルド
# M1 Mac なので buildx を使用していますが、ARMベースでなければ docker build -t my_app . で問題ないはずです
docker buildx build --platform linux/amd64 -t habit-coach --load .
# ECR ログイン
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin <aws_account_id>.dkr.ecr.us-west-2.amazonaws.com
# Docker イメージのタグ付け
docker tag my_api:latest <aws_account_id>.dkr.ecr.us-west-2.amazonaws.com/my_api:latest
# Docker イメージのプッシュ
docker push <aws_account_id>.dkr.ecr.us-west-2.amazonaws.com/my_api:latest
インフラストラクチャ(VPC、サブネット、セキュリティグループ、Fargate、RDS)の構築
次に、main.tf ファイルを作成し、AWS リソースを定義します。
# main.tf
provider "aws" {
region = "ap-northeast-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-northeast-1a"
}
resource "aws_security_group" "web_sg" {
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "db_sg" {
vpc_id = aws_vpc.main.id
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [aws_security_group.web_sg.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_ecs_cluster" "main" {
name = "main-cluster"
}
resource "aws_ecs_task_definition" "web" {
family = "web-task"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
container_definitions = jsonencode([
{
name = "web"
image = "<aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/my_api:latest"
essential = true
portMappings = [
{
containerPort = 3000
hostPort = 3000
}
]
}
])
}
resource "aws_ecs_service" "web" {
name = "web-service"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.web.arn
desired_count = 1
network_configuration {
subnets = [aws_subnet.public.id]
security_groups = [aws_security_group.web_sg.id]
assign_public_ip = true
}
}
resource "aws_db_instance" "default" {
allocated_storage = 10
engine = "mysql"
instance_class = "db.t2.micro"
name = "mydb"
username = "root"
password = "password"
parameter_group_name = "default.mysql8.0"
vpc_security_group_ids = [aws_security_group.db_sg.id]
skip_final_snapshot = true
db_subnet_group_name = aws_db_subnet_group.main.name
}
resource "aws_db_subnet_group" "main" {
name = "main-subnet-group"
subnet_ids = [aws_subnet.private.id]
}
※ 本来は以下のようにリソースごとの tf ファイルを作って管理した方がいいですが、この記事では省略しています
次に、以下のコマンドを実行して Terraform 設定を適用します。
terraform apply
これで、AWS リソースの構築が完了しました。
4. Rails API アプリのデプロイ
Fargate サービスが作成され、 Amazon ECR にプッシュした Docker イメージが使用されるので、作業は不要です。
タスクが正常に開始され、 Rails が Fargate で動作していることを確認してください。
動作確認
デプロイ後の動作確認を行うために、ブラウザで Fargate サービスのパブリックIPにアクセスします。
ECS → クラスター → サービス → タスク → パブリックIP にて確認ができます。
「シンプルな API エンドポイントの作成」にて OK
と表示されるように作ったのでそうなっていれば完了です。
まとめと次のステップ
この記事では、 Docker を用いて Rails API アプリを構築し、 Terraform を使って AWS 上にリソースを構成しデプロイする方法を紹介しました。
次の記事では Flutter アプリをフロントエンドとして GraphQL で繋ぐ方法を解説します!
Discussion
参考にさせてもらっています。ありがとうございます。
1.の際に、
を実行すると以下のようなエラーがでました。
記事には書かれていないのですが、Gemfileにrailsを追加したり、Gemfile.lockを作成したほうが良いでしょうか?