LoginSignup
5
1

More than 1 year has passed since last update.

AWS CodeCommitへのプルリクエストでCodePipelineを起動させてみた

Posted at

はじめに

CodeCommitへのpushイベントはCodePipelineがいい感じにトリガー作ってくれるのですが、プルリクエストでも起動させてレビュー前に静的解析ツールなど実行できないかと思い調べてみました。

環境

■操作環境
EC2(Amazon Linux)

■使用サービス
・CodePipeline(CodeCommit,CodeBuild)
  CodeCommitからソースを取得して、コンテナを起動しLarastanを実行します。

・EventBridge
  プルリクエスト作成を検知してLambdaを実行させます。

・Lambda
  CodePipelineに設定されているブランチをプルリクエスト元ブランチに変更してCodePipelineを実行させます。

・ECR
  CodePipelineで使用するコンテナイメージを保存します。

本記事でやったこと

CodeCommitに保存したLaravelのソースへのプルリクエストをトリガーに、CodePipelineを起動してコンテナ立ち上げてプルリクエスト元のブランチのソースにLarastanを実行するまでを自動化します。一連の流れを通すのがメインになるので各サービスについての解説はしていません。

手順

1.実行環境用意

まず、EC2にコンテナイメージ作成とLaravelインストール用の環境を構築します。

GitとDockerをインストール

sudo yum install -y git docker

docker-composeインストール

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

サービス起動

sudo service docker start

dockerをec2-userで実行できるようにユーザーグループに加える

sudo usermod -a -G docker ec2-user

ec2-userでコマンド使用できるか確認する、permission deniedとか出る場合はSSH閉じて接続し直してください。

docker info

Dokerコンテナの実行環境構築

作業ディレクトリ作成

mkdir /home/ec2-user/docker

ここにDockerfileなどのコンテナ作成用のファイルを格納します。

mkdir /home/ec2-user/docker/web

Laravelのソース格納用、ここをCodeCommitに紐づけます

mkdir -p /home/ec2-user/docker/sample-laravel/src

Dockerfile作成

vi /home/ec2-user/docker/web/Dockerfile
FROM php:8.0-apache
WORKDIR /var/www
COPY 000-default.conf /etc/apache2/conf-enabled/000-default.conf

RUN apt-get update \
&& apt-get install -y \
git \
zip \
unzip \
vim \
libpng-dev \
libpq-dev

# Composerのインストール
RUN cd /usr/bin && curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer

# Laravelで必要になるmodRewriteを有効化する
RUN ln -s /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/rewrite.load \
&& a2enmod rewrite

000-default.conf作成

vi /home/ec2-user/docker/web/000-default.conf
<VirtualHost *:80>
       ServerAdmin webmaster@localhost
       DocumentRoot /var/www/sample-laravel/public
       ErrorLog ${APACHE_LOG_DIR}/error.log
       CustomLog ${APACHE_LOG_DIR}/access.log combined
       <Directory /var/www/sample-laravel/public>
         AllowOverride All
         Require all granted
       </Directory>
</VirtualHost>

docker-compose.yml作成

vi /home/ec2-user/docker/docker-compose.yml
services:
  web:
    container_name: web
    build:
      context: ./web
    ports:
        - '8080:80'
    volumes:
      - ./sample-laravel/src:/var/www/sample-laravel

コンテナ起動

cd /home/ec2-user/docker
docker-compose up -d

起動確認

docker ps

上手く起動していれば以下のようにwebって名前のコンテナが表示されます。

1.png

コンテナにログイン

 docker exec -it web bash

コンテナ内でLaravelをインストールします。

composer create-project laravel/laravel sample-laravel

ログディレクトリなどのパーミッション変更
本当はちゃんと適切に設定してあげないといけないのですが。。。今回は割愛します。

cd /var/www/sample-laravel/storage
chmod -R 777 app logs framework

ここでセキュリティグループで8080ポートをアクセスできる状態にすると
http://EC2のパプリックIP:8080
でLaravelの初期画面が表示されると思います。

image (2).png

Larastanインストール

cd /var/www/sample-laravel
composer require --dev nunomaduro/larastan

一番緩いレベル0で実行

./vendor/bin/phpstan analyse -l 0 app

エラーなしですね。
image (3).png

レベル7で実行

./vendor/bin/phpstan analyse -l 7 app

Laravel導入しただけの状態でも怒られるんですね。。。
image (4).png

2.LaravelのコードをCodeCommitリポジトリと紐づける

さてと、準備だけでかなり長くなりましたがここからが本題です。
まずCodeCommitでリポジトリを作成します。

AWSコンソールを開いてデベロッパー用ツール > CodeCommit >リポジトリ から
リポジトリを作成します。

今回はリポジトリ名を「sample-laravel」として他デフォルトで作成します。

image (6).png

リポジトリが作成できたら以下のような画面が表示されますので
Git認証を作成していない場合は案内に従って認証を作成してください。

image (45).png

EC2に戻ってsample-laravel配下をCodeCommitに紐づけます。
※コンテナからは出てください。

cd /home/ec2-user/docker/sample-laravel

既存ソースをCodeCommitに紐づける手順はAWSのドキュメント参考にしました。
https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/how-to-migrate-repository-local.html#how-to-migrate-local-version

git init
git config --local init.defaultBranch master
git add .
git commit -m "Initial commit"
git push https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/sample-laravel --all

pushまで済むと先程作成したリポジトリが更新されます。
image (8).png

3.コンテナイメージをECRにアップロード

AWSコンソールを開きAmazon ECR > リポジトリからリポジトリを作成を押下。
リポジトリ名を「sample-laravel-image」とし他はデフォルトとしました。

image (9).png

リポジトリが作成できたらEC2のDockerfileから作成したイメージをアップします。
まず、実行環境のEC2にI AMロールでECRの権限を付与します。
EC2のコンソールでアクション > セキュリティ > IAMロールを変更から「新しい IAM ロールを作成」で
作成したロールに「AmazonEC2ContainerRegistryFullAccess」を割り当てました。

image (11).png

EC2に戻ってDockerflieのある階層に移動します。

cd /home/ec2-user/docker/web

ここからECRへのアップロードまではコンソールの「プッシュコマンドの表示」の手順そのままなので、そちらを見たほうがよいかもしれないです。

image (10).png

ECRへのログイン、ここで弾かれる場合はロールの割当がうまくいっていない可能性が高いです。

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com
docker build -t sample-laravel-image .
docker tag sample-laravel-image:latest アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/sample-laravel-image:latest
docker push アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/sample-laravel-image:latest

ECRへのpushまで終わるとECR側でもアップロードしたイメージが反映されます。
後ほど使用するので「URIのコピー」からURIをメモしておいてください。

image (12).png

CodeCommitとECRの準備はできたので、次はCodePipelineと連携させていきます。

4.CodePipeline構築

まず、EC2に戻ってCodePipelineで使うbuildspec.ymlとDockerfileを作成します。

mkdir /home/ec2-user/docker/sample-laravel/pipeline
vi /home/ec2-user/docker/sample-laravel/pipeline/buildspec.yml
version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --no-include-email --region ap-northeast-1)
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t web -f pipeline/Dockerfile .

  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker run web php vendor/bin/phpstan analyse -l 0 app
vi /home/ec2-user/docker/sample-laravel/pipeline/Dockerfile
FROM 先程メモしたイメージのURI

COPY ./src /var/www/src
WORKDIR /var/www/src
RUN cp -p .env.example .env
RUN composer install

追加したファイルはリポジトリにpushしておいてください。

AWSコンソールを開きデベロッパー用ツール > CodePipeline > パイプラインから「パイプラインを作成する」でパイプラインを新規作成します。

パイプライン名は「sample-laravel-pipeline」としました。

image (13).png

ソースプロバイダーをCodeCommitとしsample-laravelのmasterブランチを選択します。

image (14).png

ビルドステージのプロバイダーをCodeBuildに設定し「プロジェクトを作成する」を押下します。

image (15).png

buildプロジェクト名を入力します。
プロジェクト名は「sample-laravel-build」としました。
image (16).png

image (17).png

特権付与にチェック入れます

image (18).png

buildspec.ymlのパス「pipeline/buildspec.yml」を入力しバッチ設定、ログはデフォルトのままにします。
image (19).png

image (20).png

今回はデプロイは行いませんので「導入段階をスキップ」を選択します。
image (21).png

パイプラインを作成すると自動的に実行されますが、パイプラインに設定したロールにECRの権限設定をしていないため一度失敗します。
image (22).png

CodeBuild > ビルドプロジェクト > sample-laravel-buildからビルドの詳細タブで設定されたサービスロールをクリックします。
image (23).png

image (24).png

ロールの許可タブから「ポリシーをアタッチ」を選択し「AmazonEC2ContainerRegistryReadOnly」をアタッチします。
image (25).png

CodePiplineに戻り「変更をリリースする」から再実行すると、ロールに権限割り当てたので成功します。
image (26).png

Buildステージの詳細からログを確認すると、Larastanもちゃんと実行されています。
image (27).png

5.CodePipelineのブランチをプルリクエスト元のブランチに変更して、パイプラインを起動するLambda関数を作成する

Lambda > 関数 > 関数の作成で作成します。
関数名を「sample-laravel-pipline-trigger」としてランタイムは「Python3.9」を設定します。他はデフォルトにしました。

image (30).png

コードタブに以下のスクリプトを貼り付けてDeployします。

Lambda Function
import json
import boto3

# パイプライン名
PIPELINE_NAME = 'sample-laravel-pipeline'
codepipeline = boto3.client('codepipeline')

def lambda_handler(event, context):
    # 現在のcodepipelineの設定値を取得
    response = codepipeline.get_pipeline(
        name=PIPELINE_NAME
    )

    #EventBridgeから引き渡されるプルリク元のブランチ名を取得
    targetBranch = event['detail']['sourceReference'].replace('refs/heads/', '')
    #pipelineに設定するためプルリク元のブランチで更新パラメータを作成
    response['pipeline']['stages'][0]['actions'][0]['configuration']['BranchName'] = targetBranch
    #更新に不要な値削除
    del response['metadata'],response['ResponseMetadata']

    #pipelineの設定を更新
    updateResponse = codepipeline.update_pipeline(pipeline=response['pipeline'])

    #codepipelineを開始
    startResponse = codepipeline.start_pipeline_execution(
        name=PIPELINE_NAME
    )

    return

スクリプトにbotoによるCodePipelineの更新が入っているので、関数のロールにCodePipelineの編集権限を付与します。

設定タブからアクセス権限を選択してロールをクリックします。

image (31).png

ロールの編集画面でアクセス許可を追加から「AWSCodePipelineFullAccess」のポリシーをアタッチします。
image (32).png

6.プルリクエスト時に起動するようにEventBridgeのトリガーを変更する

まず、CodePipelineを作った最に自動で作成されたルールを削除してリポジトリへのpushではパイプラインを起動しないようにします。

※こちらはやらなくてもpushで余計にパイプラインが走るくらいで後の工程に支障はないので飛ばしても問題ないです。

Amazon EventBridge > ルール > codepipeline-sample-master-xxxxx-rule

ルール作成時の命名規則がいまいちよくわからないですがイベントパターンの
resourcesにsample-laravelが指定されているルールを削除します。

image (28).png

そのままルールの新規作成で、sample-laravelへのプルリクエストをトリガーに
Lambdaを起動させるルールを追加します。
ルール名は「sample-laravel-lambda-trigger」としました。

image (33).png

イベントをカスタムパターンにしてsample-laravelへのプルリクエスト作成のイベントで発火するよう定義する。
image (34).png

アカウントIDは利用しているAWSアカウントのIDに書き換えてください。

{
  "source": ["aws.codecommit"],
  "detail-type": ["CodeCommit Pull Request State Change"],
  "resources": ["arn:aws:codecommit:ap-northeast-1:アカウントID:sample-laravel"],
  "detail": {
    "event": ["pullRequestCreated"]
  }
}

ターゲットに先程作成したLambda関数の「sample-laravel-pipline-trigger」を選択してルールを作成
image (35).png

7.プルリクエストをしてみる

環境が整ったのでいよいよプルリクエストを作成してみます。

CodeCommitのブランチからブランチの作成。

image (36).png

ブランチ名はなんでもいいですが、「develop」にしました。
image (37).png

試しにbuildspec.ymlを編集してLarastanをレベル7に編集します。
Larastanインストール時にレベル7だと怒られていたのでビルドエラーを返すはず
image (38).png

image (40).png

プルリクエストの作成から[develop]->[master]にプルリクエストを作成します。
差分は先程編集したbuildspec.ymlです。
image (39).png

無事起動しました。
image (41).png

Sourceの「AWS CodeCommit」をクリックすると遷移する先がパイプライン構築時には存在していなかった「develop」になっています。
image (42).png

buildステージの詳細から遷移してログを確認するとやっぱりLarastanに怒られてBuild失敗のステータスとなっていました。
image (43).png

怒られて終わりはモヤモヤするので、Larastanの実行レベルを0に戻してプルリクエストを作り直しました。
無事成功ステータスで終了してますね。

image (44).png

今回は触れませんが実行結果をプルリクのコメントに書き込むなど、通知も自動化しておくとレビュアーは楽できそうですね。

おわりに

今回は簡単に導入できるLarastanで試しましたが、PHPUnitなんかも実行できますし
そもそも実行環境に自作コンテナイメージ使ってるので大抵のことはできるかと思います。

EventBridgeやCodeシリーズを使いこなせると自動化はかどりそうだなーと思いました。
精進せねば!

5
1
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
5
1