Skip to content

katainaka0503/ci-cd-hands-on-laravel

Repository files navigation

CI/CD 環境構築ハンズオン

アジェンダ

必要な事前準備

  • 自分の AWS アカウントのコンソールにログインする。(できれば EC2-Classic に対応していないアカウントが望ましいです)
  • 東京リージョンのコンソールが表示されるようにしておく
  • 自分の GitHub アカウントにログインする。
  • Git をインストール及びセットアップする。(自分の自分のリポジトリからのクローンおよびプッシュが行える状態にしておいてください。)
  • コンソールから起動しコードの編集が行えるエディタ(Vim, Emacs, VSCode 等)

ハンズオンの目的

CodePipeline を使用してデプロイの自動化が簡単に行えることを体感していただき、実際にデプロイの自動化に取り組むきっかけにしていただく。

このハンズオンでかかる AWS の費用

$1 未満

ハンズオンの流れ

  1. 構成の簡単な紹介
  2. サンプルアプリケーションのフォーク及びクローン
  3. ハンズオン用環境構築用の CloudFormation の実行
  4. 手動デプロイしてみる(講師が実演します)
  5. CodePipeline によるパイプラインの構築および自動デプロイの実行
  6. テストが失敗すると自動デプロイが止まるのを確認
  7. 再度正しいコードに戻して自動デプロイ

1. ハンズオンで構築する構成

構成図

今回は上記の図のような構成を構築します。

  • GitHub にコードがプッシュされると CodePipeline での処理が開始されます。
  • CodeBuild ではテスト、Docker イメージの作成および作成したイメージの ECR へのプッシュを行います。
  • CodeBuild での処理が成功したら ECS に新しいバージョンのイメージがデプロイされます。

2. サンプルアプリケーションのフォークおよびクローン

まずは、このリポジトリをフォークし、自分のアカウントにリポジトリを作成します。 サンプルアプリケーションは、Laravel のサンプルコードのタスク管理システムをほぼそのまま使用しました。

このリポジトリの右上の Fork というボタンからフォークを実行します。

自分の GitHub アカウント上に作成されたフォークしたリポジトリから、ローカルの PC にクローンします。 作業用のディレクトリで以下のコマンドを実行します。

$ git clone git@github.com:<ご自分のgithubのアカウント名>/ci-cd-hands-on-laravel.git

クローンされたリポジトリのディレクトリに移動して中身を確認し、クローンが正しく行われたことを確認します。

$ cd ci-cd-handson-laravel
$ ls
README.md               cloudformation          nginx
buildspec.pr.yml        codebuild_build.sh      src
buildspec.yml           laravel                 template

3. ハンズオン用環境構築用の CloudFormation の実行

今回 ECS でアプリケーションを動作させるにあたってサービスにリンクしたロールが作成されている必要があります。 そのため、IAM のコンソールを開き、AWSServiceRoleForECSというロールがあるかを確認してください。 ない場合はサービスにリンクしたロールがない状態ですので、タスクが失敗してしまいます。

その場合は、以下のコマンドを実行するか

aws iam create-service-linked-role --aws-service-name ecs.amazonaws.com

空の ECS のクラスタを作成し、すぐに削除するなどして ECS のサービスにリンクしたロールが作成された状態にします。

Launch Stack

上のリンクより、ハンズオン用の環境を構築するための CloudFormation を実行します。

この、CloudFormation によって、以下の図ような構成の環境が作成されます。

CloudFormationによってい構築される構成

アプリケーションの動作環境以外に後で CodeBuild で使用するための IAM Role を作成しています。

作成したスタックが CREATE_COMPLETE の状態になるまで待ちます。

動作確認

作成したスタックの出力にALBDNSNameというキーで出力された値が、今回のサンプルアプリケーションのアクセス先の URL です。アドレスバーにコピペして、サンプルアプリケーションの動作を確認します。

4. 手動デプロイしてみる(講師が実演します。読み飛ばし可)

ecs-deploy のようなデプロイに便利なツールもありますが、CodeBuild で行う処理との対比をわかりやすくするため、ここではそういったものは使わずにデプロイを実行します。

まずはデプロイされたことがわかりやすくするため、画面を修正します。

$ composer install
$ vim template/views/index.ejs
$ composer run test
$ git commit -am "manual deploy"

つぎに以下のコマンドを実行し、手動でデプロイを実行します。

まず、手元で Docker イメージを構築し、ECR にプッシュします。

$ cd laravel

$ $(aws ecr get-login --no-include-email --region ap-northeast-1)

$ IMAGE_REPOSITORY_NAME=`aws ssm get-parameter --name "IMAGE_REPOSITORY_NAME"| jq -r .Parameter.Value`
$ IMAGE_TAG=`git rev-parse HEAD`
$ docker build -t $IMAGE_REPOSITORY_NAME:$IMAGE_TAG .
$ docker push $IMAGE_REPOSITORY_NAME:$IMAGE_TAG

$ echo $IMAGE_REPOSITORY_NAME:$IMAGE_TAG

ECS の設定の修正で使用するため、イメージをプッシュしたリポジトリとタグの値を覚えておきます。

ここまでの操作の中でも、プッシュする対象とは異なるブランチで作業を行っていた場合や、リモートブランチとの同期を忘れるなどした場合には意図したものとは異なるソースコードをデプロイしてしまうリスクがあります。

つぎに、コンソールの操作に移り、実際に ECS へのデプロイを行っていきます。

マネジメントコンソールから ECS の画面に移動します。

まず、タスク定義の新しいリビジョンを作成します。

環境構築用スタックによって作成されたタスクの新しいリビジョンの作成画面を表示します。 コンテナ名 phpfpm の設定画面に移動し、イメージの指定を先程プッシュしたイメージのものに書き換え新しいリビジョンを作成します。

次に、環境構築用スタックによって作成されたサービスの編集画面に移動し、新しいタスク定義のリビジョンを指定するように編集をおこない、サービスの更新を実行します。

しばらくすると新しいタスク定義に基づくタスクが実行され、コードの修正が反映されます。

5. CodePipeline によるパイプラインの構築および自動デプロイの実行

手動でのデプロイが大変だと感じてもらったところで、CodePipeline/CodeBuild を使用したパイプラインを作成していきます。

今回作成するパイプラインは以下図の左側の部分です。

構成図

では、早速作成していきましょう。

マネジメントコンソールのトップ画面より「CodePipeline」をクリックします。

devops-hands-on-15

まだパイプラインを作成していない場合は以下のような画面が表示されるので「今すぐ始める」をクリックします。

devops-hands-on-16

パイプラインのセットアップが開始するのでパイプライン名としてhands-on-pipelineと入力して「次のステップ」をクリックします。

devops-hands-on-17

ソースプロバイダのセットアップが始まるので以下の表のように入力後、「次のステップ」をクリックします。

入力項目
ソースプロバイダ GitHub
リポジトリ フォークしておいたリポジトリ
ブランチ master

ビルドプロバイダのセットアップが始まるので以下の表のように入力後、「ビルドプロジェクトの保存」をクリックしてから「次のステップ」をクリックします。

入力項目
ビルドプロバイダ AWS CodeBuild
プロジェクトの設定 新しいビルドプロジェクトを作成
プロジェクト名 hands-on-project
環境イメージ カスタム Docker イメージの指定
環境タイプ Linux
Custom image type Other
カスタムイメージタイプ katainaka0503/codebuild-php:latest
ビルド仕様 ソースコードのルートディレクトリの buildspec.yml を使用
キャッシュ タイプ タイプ: AmazonS3, 場所: 環境構築用スタックのCodeBuildCachePlaceの値
CodeBuild サービスロール アカウントから既存のロールを選択しますを選択し環境構築用スタックの出力の値を入力
VPC No VPC
特権付与(アドバンスト内)
環境変数(アドバンスト内) 名前:IMAGE_REPOSITORY_NAME,
値:IMAGE_REPOSITORY_NAME,
Type: パラメータストア

デプロイプロバイダのセットアップが始まるのでプロバイダに「Amazon ECS」を入力後、「AWS CodeDeploy に新たにアプリケーションを作成します。」のリンクをクリックします。

入力項目
デプロイプロバイダ Amazon ECS
クラスター名 hands-on-environment-ECSCluster
サービス名 hands-on-environment-ECSService
イメージのファイル名 imagedefinitions.json

CodePipeline にアタッチする IAM Role の画面に変わるので、「ロールの作成」をクリック後、遷移する画面で「許可」をクリックします。

devops-hands-on-21

IAM Role の作成が完了したら「次のステップ」をクリックします。

devops-hands-on-22

最後に確認画面が表示されるので、内容を確認後、「パイプラインの作成」をクリックします。

すると、パイプラインが自動で開始されます。

Stagingステージまで緑色になり、デプロイが完了したところで一度正常にページにアクセスできることを確認します。

6. テストが失敗すると自動デプロイが止まるのを確認

バグが混入した際に、テストで処理が失敗し、デプロイが途中で止まることを確認するため、フォークしたリポジトリのコードを修正します。

エディタで、laravel/app/Http/routes.phpを開きます。

意図的にバグを混入させるため、23 行目の

'tasks' => Task::orderBy('created_at', 'asc')->get()

と書かれた行を

## 'tasks' => [] #Task::orderBy('created_at', 'asc')->get()

のようにロジック部をコメントアウトし、代わりに空の配列を返すようにします。

修正が終わったらコミットし、GitHub 上にプッシュします。

$ git commit -am bug
$ git push origin master

GitHub にプッシュすると、CodePipeline での処理が開始されます。 しかし、CodeBuild でテストが失敗し、ECS へのデプロイは実行されません。

テストが自動で実行される環境が構築されていたため、バグの混入したバージョンがデプロイされるのを防ぐことができました!

7. 再度正しいコードに戻して自動デプロイ

先程の修正をもとに戻すため、vim laravel/app/Http/routes.php を開きます。

## 'tasks' => [] #Task::orderBy('created_at', 'asc')->get()

のように先程編集した行を

'tasks' => Task::orderBy('created_at', 'asc')->get()

のように修正し、GitHub にプッシュします。

$ git commit -am fixbug
$ git push origin master

同様に自動で CodePipeline 上での処理が開始されます。

今度はテストが成功するため、デプロイが行われました。

まとめ

CodePipeline を使用することでデプロイやテストが自動で実行されるようになりました。

煩雑な手作業が自動化されることで人為的ミスを削減し、デプロイにかかる時間を短縮できます。

参考資料

EC2 に CodeDeploy でデプロイするパターン

Pull Requestをビルドしたいパターン

サーバレスパターン

補足. 環境の削除

ハンズオンで作成した環境を削除したい場合は以下の手順を参考にしてください。 リソース間の依存関係がある関係で削除に失敗することがあるため、 CloudFormation スタックおよびクローンした GitHub のリポジトリは最後に削除を行ってください。

AWS

CodePipeline のパイプラインの削除

パイプラインの画面から編集ボタンをクリック、

表示された編集画面で削除ボタンをクリックし、表示された確認ダイアログにパイプライン名hands-on-pipelineを入力して削除します。

CodeBuild のプロジェクトの削除

CodeBuild の画面から、プロジェクトhands-on-projectを選択した状態で、アクションのドロップダウンリストから削除をクリックします。

IAM Role の削除  CodePipeline用 CodeBuild用

CodeBuild用のロールhands-on-environment-CodeBuild-ServiceRoleを削除します。

hands-on-environment-CodeBuild-ServiceRoleという名前のロールを選択し、ロールを削除します。

CodePipelineでの他のプロジェクトが存在しない場合はAWS-CodePipeline-Serviceという名前のロールも同様の手順で削除しましょう。

CodeBuildのキャッシュ用S3バケットの中身を削除

hands-on-environment-codebuildcachebucket-***という名前のバケットの画面に移動し、

中身のオブジェクトをすべて削除します。

CodePipeline のアーティファクト保存用 S3 バケット削除

codepipeline-ap-northeast-1-****バケットの中身を確認し、

もし、hands-on-xxx のフォルダだけしかなければ、バケット自体を削除します。

他のフォルダがあれば、フォルダ以下を削除します。

ECR リポジトリ内のイメージをすべて削除

ECSの画面の左側にある、リポジトリのリンクをクリックし、hands-***という名前のリポジトリの画面の移動します。

そして、すべてのイメージを選択し、削除を行います。リポジトリ自体は削除しなくても大丈夫です。

CloudFormation スタックの削除

CloudFormationのコンソールから、hands-on-environmentという名前のスタックを選択し、削除します

hands-on-task-definition の登録を解除

ECSの画面の左側にある、タスク定義のリンクをクリックし、hands-on-environment-****という名前のタスク定義の画面に移動します。

すべてのタスク定義を選択し、登録解除します。

GitHub

クローンしたリポジトリの削除

フォーク先リポジトリのSettingを開き、

一番下のDelete this Repositoryというボタンをクリック、確認ダイアログにリポジトリ名を入力して削除します。

About

CodePipelineのハンズオン用リポジトリです

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published