CodePipeline、Jenkins、Elastic Beanstalkの連携を試してみた(失敗からの大成功!)
こんにちは、前回のエントリーでJenkinsにCodePipelineのプラグインをインストールしました。 今回はCodePipelineと連携するJenkinsプロジェクトを作成し、Management ConsoleでPipelineを作成してみたいと思います。
最終的な構成イメージ
最終的な構成図は以下のようになります。Jenkinsと連携させ、この記事で作成したElastic Beanstalkにデプロイしたいと思います。

JenkinsがPipelineと連携するためのIAMユーザーを作成
最初にJenkinsがCodePipelineと連携するためのIAMユーザーを作成し、権限を割り当てます。この部分はIAMユーザーではなくIAMロールを使うという方法もあります。
IAMユーザーの作成と、認証情報の取得
IAMのコンソールホーム画面左メニューからUsers、Create New Usersをクリックします。

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

作成したIAMユーザーにCodePipelineと連携する権限を追加
IAMコンソール画面の左メニューからUsersを選択し、先ほど作成したユーザーを選択します。

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

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

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

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

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

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

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

今回入力したスクリプトは以下のようなものです。
#!/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は空欄のままで構いません。最後に保存をクリックしてプロジェクトを作成します。

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

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

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

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

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

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

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

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

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

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

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

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

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

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を使ったパターンでは最後までしっかりと処理されました。

作成後は、GitHubに新しいバージョンをPushしたり、Release changeを実行するとPipelineが再実行されます。Pipelineを削除する場合は、編集画面のDeleteから消すことが出来ます。
7月25日追記
ブログを公開していて数日後、Twitterで以下のような情報を頂きました。
@oko_chang 申し訳ありません! NicholasW@AWSはその問題は解けました。https://t.co/fA6jUsYKYG
— David Killmon (@kohidave) 2015, 7月 23
ツイートに記載されているリンクのForumで同じ問題が報告されておりまして、Pipeline作成ウィザードで作ったIAMロール(AWS-CodePipeline-Service)の権限を修正することで解決出来ます。@understeerさんからも解決方法を教えて頂きました、ありがとうございます! 具体的な修正手順は以下のようになります。
- IAMコンソール画面の左メニューからRolesを選択し、AWS-CodePipeline-Serviceをクリックします

- InlinePoliciesにあるポリシーの編集画面に移ります

elasticloadbalancing:DescribeLoadBalancersの部分をelasticloadbalancing:*に変更してApply Policyをクリックします
最終的には以下のようなポリシーになるはずです。
{
"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が実行されると以下のようにバッチリデプロイまで成功します!

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

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