3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AWS Copilotを使ってRailsアプリケーションのCI/CDパイプラインを爆速で構築する

Last updated at Posted at 2020-08-07

記事の概要

AWS Copilotを使って作成したECS上のRailsアプリケーションにおいて、CI/CDパイプラインを構築します。
また、その際にハマったポイントを共有します。

↓の記事の続きになります。
AWS Copilotを使ってRailsコンテナの本番環境を爆速で構築する

AWS Copilot

AWSでコンテナ化されたアプリケーションの開発、リリースを容易に行うためのコマンドラインツールです。
コマンドを叩くとCloudFormationが動き、必要なリソースの作成やデプロイを行うことができる。CI/CDパイプラインもコマンド一つで作成できます。

※Fargate起動タイプのみサポートしています

Pipeline

Githubへのpushをトリガにしてコンテナデプロイを実行するための仕組みです。
CopilotによってPipelineを作成すると、CloudFormationによってCodeBuildのリソースが作成されます。

Pipeline作成方法

手順概要

  • GitHubの個人アクセストークン準備
  • master.keyのAmazon SSMへの登録
  • Pipelineの定義
  • Pipelineの作成
  • ビルドプロジェクトのイメージ修正(Rubyのバージョン次第)

GitHubの個人アクセストークン準備

PipelineからGithubリポジトリを参照するために、GitHubの個人アクセストークンが必要なので事前に準備しておく必要があります。

アクセストークンはrepoadmin:repo_hookのスコープが必要です。
個人アクセストークンを使用する

master.keyのAmazon SSMへの登録

Railsのmaster.keyは普通はGit管理から外すためGithub上にありませんが、PipelineはGithubリポジトリを参照してDockerイメージを作るためmaster.keyを何かしらの方法でECSに渡す必要があります。
セキュアに管理するためにAmazon SSMのパラメータストアを利用します。

下記コマンドでmaster.keyの文字列をAmazon SSMのパラメータストアに登録します。
タグの値については適宜自身のものに変更してください。

  $ aws ssm put-parameter --name RAILS_MASTER_KEY --value master.keyの文字列 --type SecureString\
  --tags Key=copilot-environment,Value=production Key=copilot-application,Value=copilot-demo

登録されました。
スクリーンショット 2020-08-05 22.53.04.png

続いて、Serviceのmanifest.ymlを変更します。
secretsを宣言することでECSからSSMのパラメータストアを参照できます。
「ECSで参照できる環境変数: SSMに登録したパラメータのキー」のように指定します。

copilot/api/manifest.yml
  variables:
    RAILS_ENV: development

  secrets:
    RAILS_MASTER_KEY: RAILS_MASTER_KEY  # ECSで参照できる環境変数: SSMに登録したパラメータのキー

Pipelineの定義

続いてPipelineを定義します。
EnvironmentやServiceを作成した時と同じように対話型で進めていきます。
このタイミングでPipelineが参照するGithubリポジトリや個人アクセストークンを指定します。

$ copilot pipeline init

  Would you like to add an environment to your pipeline? [? for help] (y/N) 
  > y

  Which environment would you like to add to your pipeline?  [Use arrows to move, type to filter, ? for more help]
  > production

  Which GitHub repository would you like to use for your service?  [Use arrows to move, type to filter, ? for more help]
  > https://github.com/ssshun/rails_copilot

  Please enter your GitHub Personal Access Token for your repository rails_copilot: [? for help] 
  > XXXXXXXXXXXXXX

完了すると以下の2ファイルが作成されます。基本はデフォルトのままで問題ないです。

  • buildspec.yml
  • pipeline.yml

Pipelineの作成

以下のコマンドでPipelineを作成

  $ git add . && git commit -m "Adding Pipeline Buildspec" && git push
  $ copilot pipeline update

しばらく経ってからCodeBuildを確認すると、ビルドプロジェクトとパイプラインが作成されているのがわかります。
スクリーンショット 2020-08-07 18.09.01.png スクリーンショット 2020-08-07 18.09.06.png

ビルドプロジェクトのイメージ修正

アプリケーションのRubyのバージョン次第ではこの手順は不要です。
2020/08/08時点では、アプリケーションがRuby2.7を利用する場合、この作業が必要でした。

buildspec.ymlを修正し、ビルドプロジェクトのrubyランタイムのバージョンを2.7に変更します。

copilot/buildspec.yml
  version: 0.2
  phases:
    install:
      runtime-versions:
        docker: 18
        ruby: 2.7

続いて、AWSコンソールにて、ビルドプロジェクト > ビルド詳細 > 環境 からイメージを修正します。
CopilotでPipelineを作成した場合、イメージがaws/codebuild/amazonlinux2-aarch64-standard:1.0になるのですが、Ruby2.7のランタイムがaws/codebuild/amazonlinux2-aarch64-standard:1.0に対応していないためです。

Ruby2.7に対応しているaws/codebuild/amazonlinux2-x86_64-standard:3.0に変更します。
スクリーンショット 2020-08-07 18.26.25.png

buildspecを修正したので、Pipelineを更新します。

  $ git add . && git commit -m "Modifying Pipeline Buildspec" && git push
  $ copilot pipeline update

以下のようにPipelineが作成されました。
スクリーンショット 2020-08-06 0.35.24.png

ハマったポイント

Pipeline名がCloudFormationの命名規則違反

プロジェクトディレクトリにアンダースコアを入れて、そのままPipelineを作成すると以下のようなエラーが発生します。

check if pipeline exists: describe stack pipeline-copilot-demo-ssshun-rails_copilot: ValidationError: 1 validation error detected: Value 'pipeline-copilot-demo-ssshun-rails_copilot' at 'stackName' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z][-a-zA-Z0-9]*|arn:[-a-zA-Z0-9:/._+]*

原因ですが、プロジェクトのディレクトリ名にアンダースコアが含まれると、デフォルトのPipeline名にもアンダースコアが入ります。
そのため、このままだとCloudFormationのスタック名の命名規則に違反してしまいます。

copilot/pipeline.yml
  # The name of the pipeline
  name: pipeline-copilot-demo-ssshun-rails_copilot # プロジェクトディレクトリがrails_copilotの場合のデフォルト

以下のようにアンダースコアが含まれないように名前を修正すれば解消されます。

copilot/pipeline.yml
  # The name of the pipeline
  name: pipeline-copilot-demo-ssshun-rails-copilot

ビルドプロジェクトのランタイムとイメージの不整合

CodeBuildにてビルドが成功しないのでログを確認したところ以下のエラーが発生していました。
アプリケーションのランタイム(Ruby2.7)とビルドプロジェクトのランタイム(Ruby2.6)の不整合が原因と思われます。

  rbenv: version `ruby-2.7.1' is not installed (set by /codebuild/output/src020247698/src/.ruby-version)

ビルドプロジェクトのランタイムをRuby2.7に変更したらいけるかと思い、buildspecを修正しましたが、

copilot/buildspec.yml
  version: 0.2
  phases:
    install:
      runtime-versions:
        docker: 18
        ruby: 2.7

再度、別のエラーが発生しました。
Ruby2.7のランタイムがCodeBuildのビルドプロジェクトのイメージaws/codebuild/amazonlinux2-aarch64-standard:1.0に対応していないためでした。

  Phase complete: DOWNLOAD_SOURCE State: FAILED
  Phase context status code: YAML_FILE_ERROR Message: Unknown runtime version named '2.7' of ruby. This 
  build image has the following versions: 2.6

上の手順で書いた通り、イメージをRuby2.7に対応しているaws/codebuild/amazonlinux2-x86_64-standard:3.0に変更して解決しました。

ECSからSSMのパラメータストアが参照不可

master.key参照のためにAmazon SSMのパラメータストアを登録する際に、タグは要らないだろうと思って以下のように登録していました。

  $ aws ssm put-parameter --name RAILS_MASTER_KEY --value master.keyの文字列 --type SecureString

その状態でPipelineでデプロイしたところ、ECSタスクで以下のエラーが発生しました。
パラメータストアのRAILS_MASTER_KEYの参照権限がないとのことでした。

  Fetching secret data from SSM Parameter Store in ap-northeast-1:AccessDeniedException:
  User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/copilot-demo-production-api-ExecutionRole-DYGK7EGS469J/0e93e07304b641d58e5fc147122d2f4c is not authorized to perform: ssm:GetParameters on resource: arn:aws:ssm:ap-northeast-1:XXXXXXXXXXXX:parameter/RAILS_MASTER_KEY
  status code: 400, request id: 8b6bac83-1d83-4abe-8d19-bbaa4a5e4a29

調べていくと、manifest.ymlでsecretsを設定するとECSのタスク実行ロールにSSM参照用のIAMポリシーが作成されることがわかりました。
ポリシーをよくよく見ると、パラメータストアのタグで条件指定して参照権限を付与していました。ここら辺のきめ細やかさはすごいですね。

copilot-demo-production-apiSecretsPolicy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Condition": {
                "StringEquals": {
                    "ssm:ResourceTag/copilot-environment": "production",
                    "ssm:ResourceTag/copilot-application": "copilot-demo"
                }
            },
            "Action": [
                "ssm:GetParameters"
            ],
            "Resource": [
                "arn:aws:ssm:ap-northeast-1:XXXXXXXXXXXX:parameter/*"
            ],
            "Effect": "Allow"
        },
        {
            "Condition": {
                "StringEquals": {
                    "secretsmanager:ResourceTag/copilot-application": "copilot-demo",
                    "secretsmanager:ResourceTag/copilot-environment": "production"
                }
            },
            "Action": [
                "secretsmanager:GetSecretValue"
            ],
            "Resource": [
                "arn:aws:secretsmanager:ap-northeast-1:XXXXXXXXXXXX:secret:*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": [
                "arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/*"
            ],
            "Effect": "Allow"
        }
    ]
}

パラメータストア登録時には以下のようにしっかりとタグ指定しましょう。

  $ aws ssm put-parameter --name RAILS_MASTER_KEY --value master.keyの文字列 --type SecureString\
  --tags Key=copilot-environment,Value=production Key=copilot-application,Value=copilot-demo

まとめ

今回作成したコードは以下です。
https://github.com/ssshun/rails-copilot

AWS Copilotを使って作成したECS上のRailsアプリケーションにおいて、CI/CDパイプラインを構築しました。
AWSコンソールでの操作は最小限で簡単にデプロイフローを作成できました。

3
3
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
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?