ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

AWS CodeBuildでカスタムイメージを使ってRuby 3.0のCIができるようにする

Webエンジニアの本間です。 最近、急に寒くなりましたね、鍋が美味しい季節になりました。 今シーズン、みなさんは何鍋から始めますか?自分は安定のごま豆乳鍋でした。

さてRuby 3.0がリリースされてからそろそろ10ヶ月が経過しようとしており、弊社でもRuby 3.0ベースでアプリケーションを開発する機会が増えてきました。 しかし、1つ問題があります。なんと、いまだに CodeBuildのランタイム にRuby 3.0が追加されません。 そのためせっかくRuby 3.0で新しいアプリケーションを作っても、CodeBuildでCIをサクッと動かせない問題がありました。

Ruby 3.0のCIをCodeBuildでやろうとする場合、以下のいずれかの対応が必要になると思います。

  1. CodeBuild内でRuby 3.0をインストールする。
  2. Ruby 3.0を追加したCodeBuild用のDockerイメージを作成し、CodeBuildで使う。
  3. CodeBuild内で ruby:3.0 のイメージをpullして、Dockerを使って動かす。

1の方法は、時間がかかるため現実的ではありません。 2と3の方法が現実的ですが、今回は「2」の方法を使ってRuby 3.0をCodeBuildで使えるようにしてみたのでご紹介しようと思います。

詳細

システム構成

最終的にこんな感じのシステム構成になります。

f:id:ryu39:20211015180721p:plain
システム構成

事前準備

事前に下記コマンドを利用できるようにしておく必要があります。

docker --version
# => Docker version 20.10.8, build 3967b7d

aws --version
# => aws-cli/1.20.54 Python/3.9.7 Darwin/19.6.0 botocore/1.21.54

カスタムイメージの作成

今回は、CodeBuildで最初から利用できるマネージドイメージをベースに、Ruby 3.0を追加したカスタムイメージを作成してみます。 CodeBuildで利用できるマネージドイメージは、以下のGitHubのリポジトリで管理されています。

github.com

まず上記のリポジトリをローカルにcloneします。

git clone https://github.com/aws/aws-codebuild-docker-images.git

# 今回はGitHubのREADMEにもある standard:5.0 をベースに作成してみます
cd aws-codebuild-docker-images/ubuntu/standard/5.0/

この後、 docker build . を実行すればイメージを作成できますが、その前にRuby 3.0を使うための修正を入れます。 修正が必要なのは Dockerfileruntimes.yml です。 ビルド中にRuby 3.0をインストールし、CodeBuildでRuby 3.0を使うよう切り替えるための設定を入れています。

diff --git a/ubuntu/standard/5.0/Dockerfile b/ubuntu/standard/5.0/Dockerfile
index f31d3e2..ad62472 100644
--- a/ubuntu/standard/5.0/Dockerfile
+++ b/ubuntu/standard/5.0/Dockerfile
@@ -218,9 +218,11 @@ RUN     n $NODE_14_VERSION && npm install --save-dev -g -f grunt && npm install
 
 ENV RUBY_26_VERSION="2.6.6"
 ENV RUBY_27_VERSION="2.7.2"
+ENV RUBY_30_VERSION="3.0.2"
 
 RUN rbenv install $RUBY_26_VERSION; rm -rf /tmp/*
 RUN rbenv install $RUBY_27_VERSION; rm -rf /tmp/*; rbenv global $RUBY_27_VERSION;ruby -v
+RUN rbenv install $RUBY_30_VERSION; rm -rf /tmp/*; rbenv global $RUBY_30_VERSION;ruby -v
 
 #**************** END RUBY *****************************************************
 
diff --git a/ubuntu/standard/5.0/runtimes.yml b/ubuntu/standard/5.0/runtimes.yml
index 96c5065..8713c4a 100644
--- a/ubuntu/standard/5.0/runtimes.yml
+++ b/ubuntu/standard/5.0/runtimes.yml
@@ -89,6 +89,10 @@ runtimes:
         commands:
           - echo "Installing Ruby version 2.7 ..."
           - rbenv global $RUBY_27_VERSION
+      3.0:
+        commands:
+          - echo "Installing Ruby version 3.0 ..."
+          - rbenv global $RUBY_30_VERSION
   nodejs:
     versions:
       12:

上記の修正後、ビルドします。自分の環境では、ビルド完了まで1時間ほどかかりました。 ビルド後、作成されたイメージにRuby 3.0が含まれているかも確認します。

docker build -t aws/codebuild/standard:5.0 .

docker run -it --rm --entrypoint sh aws/codebuild/standard:5.0 -c bash 

rbenv versions # => 2.6.6, 2.7.2, 3.0.2
rbenv global $RUBY_30_VERSION
ruby -v # => ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux]

これで、CodeBuildで使うカスタムイメージが作成できました。

作成したイメージをECRにpush

CodeBuildから参照できるよう、ビルドしたカスタムイメージをECRにアップロードします。 Docker hubも利用可能ですが、pull回数の制限もあるため、特別な理由がない限りは同じAWS内のECRを使った方が良いと思います。

まず、コンソールからアップロードするrepositoryを作成しています。 Elastic Container Registry > Repositories > Create repository から作成します。 リポジトリ名は aws/codebuild/standard 、CodeBuildからしか参照しないので可視性は「Private」で作成しています。

f:id:ryu39:20211015181756p:plain

また、アップロードしたイメージをCodeBuildから参照できるようPermissionを設定します。JSONで以下のようなpolicyをセットすればOKです。

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "CodeBuildAccess",
      "Effect": "Allow",
      "Principal": {
        "Service": "codebuild.amazonaws.com"
      },
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer"
      ]
    }
  ]
}

これでDockerイメージを入れる箱はできたので、ここにビルドしたカスタムイメージをアップロードします。

# AWS_ACCESS_KEY_IDやAWS_SECRET_ACCESS_KEY, AWS_PROFILEなど
# 対象のAWSアカウントにアクセスするための環境変数をセットしておく

aws ecr get-login-password | docker login --username AWS --password-stdin ${AWSのアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com

docker tag aws/codebuild/standard:5.0 ${AWSのアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/aws/codebuild/standard:5.0
docker push ${AWSのアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/aws/codebuild/standard:5.0

ビルドしたイメージをECRにアップロードできました。

CodeBuildで作成したイメージを利用

アップロードしたカスタムイメージを使ってCodeBuildのプロジェクトを作ります。 途中割愛しますが、「Environment」の項目で以下のように選択します。

  • 「Environment image」を「Custom image」に変更。
  • 「Environment type」は「Linux」を選択。
  • 「Image registry」は「Amazon ECR」を選択。
  • 「ECR Account」は「My ECR Account」を選択。
  • 前の節でアップロードしたイメージを選択。

f:id:ryu39:20211015192739p:plain

これでCodeBuildの設定は完了です。

それでは、本当にCodeBuildでRuby 3.0が使えるようになったかテストしてみます。 以下のような buildspec.yml を用意し、リポジトリに変更をpushしてCodeBuildを動かしてみます。

version: 0.2

phases:
  install:
    runtime-versions:
      ruby: 3.0
  build:
    commands:
      - ruby -v
      - 'ruby -e "puts Ractor"'

結果はこうなりました。

f:id:ryu39:20211015200934p:plain

無事、Ruby 3.0が使えるようになりました!Ruby 3.0で追加された Ractor も問題なく参照できてますね。

まとめ

今回、カスタムイメージとECRを使い、CodeBuildでRuby 3.0を使えるようにしてみました。 Ruby 3.1以上でも同じ方法で対応できますので、これで最新のRubyを使ったアプリケーション開発が捗りそうです。

一つ注意点として、CodeBuildのマネージドイメージは頻繁に更新されています。 最低でも年1回ほどはイメージを作り直して、ECRにアップロードし直した方がよいと思います。 願わくは、公式のマネージドイメージにRuby 3.0、そして12月にリリースされると思われるRuby 3.1が早く追加されると嬉しいですね。

以上です。最後までご覧いただきありがとうございました。

ユニファでは、最新のRubyを使ってアプリケーション開発したい人を募集しています。 気になる方は下記リンクから採用ページをご覧いただければと思います。

unifa-e.com