okochangの馬鹿でありがとう

ふらふら適当に世間を生きる日々でございます

CodePipeline、Jenkins、Elastic Beanstalkの連携を試してみた(失敗からの大成功!)

こんにちは、前回のエントリーでJenkinsにCodePipelineのプラグインをインストールしました。 今回はCodePipelineと連携するJenkinsプロジェクトを作成し、Management ConsoleでPipelineを作成してみたいと思います。

最終的な構成イメージ

最終的な構成図は以下のようになります。Jenkinsと連携させ、この記事で作成したElastic Beanstalkにデプロイしたいと思います。

f:id:okochang:20150720205541p:plain

JenkinsがPipelineと連携するためのIAMユーザーを作成

最初にJenkinsがCodePipelineと連携するためのIAMユーザーを作成し、権限を割り当てます。この部分はIAMユーザーではなくIAMロールを使うという方法もあります。

IAMユーザーの作成と、認証情報の取得

IAMのコンソールホーム画面左メニューからUsers、Create New Usersをクリックします。

f:id:okochang:20150720233923p:plain

作成するIAMユーザーの名前を指定してCreateし、認証情報をメモしておきます。

f:id:okochang:20150720234033p:plain

作成したIAMユーザーにCodePipelineと連携する権限を追加

IAMコンソール画面の左メニューからUsersを選択し、先ほど作成したユーザーを選択します。

f:id:okochang:20150720234047p:plain

PermissionsのManaged PolicyからAttach Policyをクリックします。

f:id:okochang:20150720234058p:plain

リストされているポリシーからAWSCodePipelineCustomActionAccessを選択してAttach Policyをクリックします。

f:id:okochang:20150720234108p:plain

Jenkinsプロジェクトを作成

次はJenkinsプロジェクトの作成です。前回作成したJenkinsトップページにアクセスし、新規ジョブ作成をクリックします。

f:id:okochang:20150718232228p:plain

ジョブ名に任意のジョブ名(MimawarigumiProject)を入力し、フリースタイル・プロジェクトのビルドを選択してOKをクリックします。

f:id:okochang:20150718232423p:plain

ソースコードの管理でAWS CodePipelineを選択、AWS Access KeyとAWS Secret Keyにメモした認証情報を入力してProviderに任意の名前(MimawarigumiProvider)を入力します。

f:id:okochang:20150718233531p:plain

ビルド・トリガでSCMをポーリングを選択し、スケジュールに* * * * *を入力します。Jenkins側からCodeDeployにビルドするかどうかを定期的にチェックするようです。

f:id:okochang:20150718233720p:plain

ビルド環境の設定で、The Ruby versionを2.2.2にし、テスト実行に必要なスクリプトを入力します。

f:id:okochang:20150718234005p:plain

今回入力したスクリプトは以下のようなものです。

#!/bin/bash
bundle config build.nokogiri --use-system-libraries
bundle install --path vendor/bundle
bundle exec rake db:setup
bundle exec rake db:migrate RAILS_ENV=test
bundle exec rspec spec

ビルド後の処理で、AWS CodePipeline Publisherを選択し、追加します。Locationは空欄のままで構いません。最後に保存をクリックしてプロジェクトを作成します。

f:id:okochang:20150718234422p:plain

CodePipelineを作成

CodePipelineのホーム画面からGet Startedをクリックします。

f:id:okochang:20150720152708p:plain

作成するPipelineに割り当てる名前を指定してNext Stepをクリックします。

f:id:okochang:20150720152722p:plain

Source ProviderでGitHubを選択して、Connectをクリックします。

f:id:okochang:20150720152850p:plain

RepositoryとBranchにソースとしたいリポジトリ名とブランチを入力し、Next Stepをクリックします。

f:id:okochang:20150720154451p:plain

Build ProviderでAdd Jenkinsをクリックします。
Provider name、Server URL、Project nameにJenkinsの情報を入力して、Next Stepをクリックします。Provider name(MimawarigumiProvider)とProject name(MimawarigumiProject)は先ほどJenkinsのプロジェクトを作成したときと同じ名前にして下さい。

f:id:okochang:20150720154334p:plain

Deployment ProviderではAWS Elastic Beanstalkを選択します。今回は以前構築したElastic Beannstalkの環境を選択してNext Stepをクリックします。

f:id:okochang:20150720155610p:plain

次にCodePipelineが使用するIAMロールの設定をします。今回は新規作成するのでCreate roleをクリックします。

f:id:okochang:20150720161038p:plain

Role Nameが自動的に入力されますので、そのままAllowをクリックします。

f:id:okochang:20150720234741p:plain

先ほど作成したロールが選択されていることを確認してNext Stepをクリックします。

f:id:okochang:20150720161113p:plain

最後に作成した内容を確認して、Create Pipelineをクリックします。

f:id:okochang:20150720161440p:plain

そうすると、さっそくPipelineで定義されたプロセスが実行されます。

f:id:okochang:20150720210455p:plain f:id:okochang:20150720212124p:plain

CodePipelineのBuildが成功するとJenkis側でもビルドが成功しています。

f:id:okochang:20150720212224p:plain

と、ここまでは良かったのですが、最終的にElastic Beanstalkのデプロイで失敗してしまいました。

f:id:okochang:20150720212512p:plain

CodePipelineとElastic BeanstalkのEventには以下のようなエラーメッセージが出ていました。
CodePipelineに割り当てているIAMロールの権限不足かなと思って確認してみたところ必要な権限は割り当ってるようでした。
ここに関してはまだ解決できていないので引き続き調査しないと。→解決方法を追記しました!

Service:AmazonElasticLoadBalancing, Message:User: arn:aws:sts::123456789012:assumed-role/AWS-CodePipeline-Service/1437394759838 is not authorized to perform: elasticloadbalancing:RegisterInstancesWithLoadBalancer on resource: arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/awseb-e-u-AWSEBLoa-Z20VI2NDPANA

ちなみに、CodeDeployを使ったパターンでは最後までしっかりと処理されました。

f:id:okochang:20150720222454p:plain

作成後は、GitHubに新しいバージョンをPushしたり、Release changeを実行するとPipelineが再実行されます。Pipelineを削除する場合は、編集画面のDeleteから消すことが出来ます。

7月25日追記

ブログを公開していて数日後、Twitterで以下のような情報を頂きました。

ツイートに記載されているリンクのForumで同じ問題が報告されておりまして、Pipeline作成ウィザードで作ったIAMロール(AWS-CodePipeline-Service)の権限を修正することで解決出来ます。@understeerさんからも解決方法を教えて頂きました、ありがとうございます! 具体的な修正手順は以下のようになります。

  1. IAMコンソール画面の左メニューからRolesを選択し、AWS-CodePipeline-Serviceをクリックします f:id:okochang:20150725011437p:plain
  2. InlinePoliciesにあるポリシーの編集画面に移ります f:id:okochang:20150725011548p:plain
  3. elasticloadbalancing:DescribeLoadBalancersの部分をelasticloadbalancing:*に変更してApply Policyをクリックします f:id:okochang:20150725011526p:plain

最終的には以下のようなポリシーになるはずです。

{
    "Statement": [
        {
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:GetBucketVersioning"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::codepipeline*",
                "arn:aws:s3:::elasticbeanstalk*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "codedeploy:CreateDeployment",
                "codedeploy:GetApplicationRevision",
                "codedeploy:GetDeployment",
                "codedeploy:GetDeploymentConfig",
                "codedeploy:RegisterApplicationRevision"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "elasticbeanstalk:CreateApplicationVersion",
                "elasticbeanstalk:DescribeApplicationVersions",
                "elasticbeanstalk:DescribeEnvironments",
                "elasticbeanstalk:DescribeEvents",
                "elasticbeanstalk:UpdateEnvironment",
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:DescribeLaunchConfigurations",
                "autoscaling:DescribeScalingActivities",
                "autoscaling:ResumeProcesses",
                "autoscaling:SuspendProcesses",
                "cloudformation:GetTemplate",
                "cloudformation:DescribeStackResource",
                "cloudformation:DescribeStackResources",
                "cloudformation:DescribeStackEvents",
                "cloudformation:DescribeStacks",
                "cloudformation:UpdateStack",
                "ec2:DescribeInstances",
                "ec2:DescribeImages",
                "ec2:DescribeAddresses",
                "ec2:DescribeSubnets",
                "ec2:DescribeVpcs",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeKeyPairs",
                "elasticloadbalancing:*",
                "rds:DescribeDBInstances",
                "rds:DescribeOrderableDBInstanceOptions",
                "sns:ListSubscriptionsByTopic"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "lambda:invokefunction",
                "lambda:listfunctions"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketPolicy",
                "s3:GetObjectAcl",
                "s3:PutObjectAcl",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::elasticbeanstalk*",
            "Effect": "Allow"
        }
    ],
    "Version": "2012-10-17"
}

編集後、改めてPipelineが実行されると以下のようにバッチリデプロイまで成功します!

f:id:okochang:20150725011934p:plain

感想

とてもシンプルではありますが、CodePipelineの作成までを追ってみました。とはいえ、このようなシンプルなものだとCodePipelineの強みが出づらいなというのが正直な感想です。 CIツールという意味では、JenkinsにもGitHubと連携するためのプラグインがあり、Jenkinsプロジェクトの設定でステージング環境やプロダクション環境へのデプロイまで自動化することが出来ます。また、JenkisではなくTravis CICircleCIといったSaaSを使うという手段もあります。
以下は作成したPipelineの編集画面なのですが、赤く囲まれたところに注目して下さい。

f:id:okochang:20150720223149p:plain

例えばBuildプロセスひとつでも、いくつかのものを順番に実行したり、同時に実行するといったことが出来るようになっています。Sourceについても複数のものを指定することが出来るようになっています。大きなプロジェクトを運用していたりすると、複数リポジトリを運用しつつビルドやデプロイの順番が決まっていたりしてリリースプロセスが複雑化する場合もあると思います。そういった複雑化した環境で継続的インテグレーションをする場合にCodeDeployは力を発揮してくれそうな気がしました(今回は紹介していませんが、負荷テストなどを組み込む事も可能です)。
Travis CI、CircleCI、 OpsWorksなどもっと色々なサービスにも対応して欲しいですね。

参考