All Articles

AWS App Runner が Ruby のソースコード連携に対応してなくて面倒?そんなときは Cloud Native Buildpacks

先日 AWS に App Runner という新サービスがリリースされました。

Fargate をさらに抽象化したようなサービスで、使い勝手は Heroku のような PaaS に近いです。

そんな App Runner ですが、

  • ECR と連携して、別途自作したコンテナイメージを使用
  • GitHub と連携して、自動でコンテナイメージを作成して使用

という 2 パターンの使い方があります。

後者の GitHub と連携して自動でコンテナイメージを作成してくれるパターンについては、現状では Node.js と Python しかサポートされていません。

Dockerfile を書かなくてもコンテナイメージが自動で作成されてデプロイされるというのはかなり楽なので、他の言語でも似たようなことをしてみたいです。

そこで、コンテナイメージの作成を自動でやってくれる Cloud Native Buildpacks と GitHub Actions を使って、Dockerfile を書かずに App Runner で Ruby のアプリケーションを起動してみようと思います。

※ サンプルとして Ruby を使いますが、他の言語でも同様のことができるはずです。

つまり…

やりたいことを簡単に整理すると、

  • GitHub Actions で Cloud Native Buildpacks を使ってイメージをビルドし、ECR に push
  • ECR と連携した App Runner に自動でデプロイされる

というイメージです。

セットアップ

では、セットアップしていきます。

手順は 6 ステップあるので多く見えますが、1 つ 1 つは簡単です。

1. サンプルアプリケーションの実装

Ruby のサンプルということで、今回は簡単に用意できる Sinatra を使うことにしました。

GitHub にリポジトリを作成し、

  • Gemfile
  • app.rb
  • config.ru

の 3 ファイルを以下のように作成します。

Gemfile

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "sinatra", "~> 2.1"

app.rb

require 'sinatra'

get '/' do
  'Hello world!'
end

config.ru

require './app'
run Sinatra::Application

コードは以下からも確認できます。

このコードが動くかローカルで動作確認したい場合は、Cloud Native Buildpacks の pack コマンドと Docker をインストールして、以下のようなコマンドを実行します。

$ pack build myapp --builder paketobuildpacks/builder:base
$ docker run --rm -e PORT=8000 -p 8000:8000 myapp

2. ECR リポジトリの作成

次に、AWS にログインし、ECR のリポジトリを作成します。

ECR のリポジトリ名は、GitHub のリポジトリ名と同じにしました。

3. IAM ユーザの作成

GitHub Actions から ECR に push するには、IAM ユーザのアクセスキー・シックレットアクセスキーを使う必要があります。

※ もしアクセスキー・シークレットアクセスキーを使いたくない場合は、GitHub Actions ではなく AWS CodeBuild を使いましょう。

専用の IAM ユーザを作成し、ECR にイメージを push するための権限を与えます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "GetAuthorizationToken",
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowPush",
            "Effect": "Allow",
            "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:PutImage",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:CompleteLayerUpload"
            ],
            "Resource": "arn:aws:ecr:ap-northeast-1:{AWSアカウントID}:repository/{リポジトリ名}"
        }
    ]
}

※ {AWSアカウントID} と {リポジトリ名} は読み替えが必要です。

4. IAM ユーザのアクセスキー・シークレットアクセスキーを GitHub に設定

上記の IAM ユーザのアクセスキー・シークレットアクセスキーを払い出したら、GitHub のリポジトリの設定画面から、「Settings」>「Secrets」と進み、

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

という名前でそれぞれ登録します。

5. GitHub Actions のワークフロー設定

以下の内容で、.github/workflows/main.yaml というファイルを作成します。

name: main

on:
  push:
    branches:
    - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-1

    - uses: aws-actions/amazon-ecr-login@v1
      id: login-ecr

    - uses: asdf-vm/actions/setup@v1

    - run: |
        asdf plugin-add buildpack
        asdf install
        pack build $ECR_REGISTRY/$ECR_REPOSITORY:latest --builder paketobuildpacks/builder:base
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        ECR_REPOSITORY: ${{ github.repository }}

ここでは pack コマンドのインストールに asdf を使っていますが、Cloud Native Buildpacks 側が提供しているアクション で pack コマンドをインストールしてもいいと思います。

この YAML ファイルを GitHub に push すれば、GitHub Actions が動き出し、ECR にイメージが push されます。

6. App Runner でサービスの作成

あとは App Runner でサービスを作成するだけです。

マネジメントコンソールから作成する場合は、雰囲気でぽちぽちすればいけます。

ちなみに、ポート番号はなんでも大丈夫です。 (App Runner はポート番号を PORT という環境変数でコンテナに渡してくれて、かつ、Ruby のコンテナ側は PORT という環境変数を使うようになっているため)

起動を待てば、問題なくアクセスできます。

$ curl https://<ドメイン>
Hello world!

まとめ

Cloud Native Buildpacks と GitHub Actions を使って、Dockerfile を書かずに App Runner で Ruby のアプリケーションを起動することができました。

App Runner のロードマップには Ruby のサポートや、Cloud Native Buildpacks のサポートも挙げられています。

ゆくゆくは、自前で GitHub Actions や Cloud Native Buildpacks を使う必要はなくなるかもしれません。