ようへいの日々精進XP

よかろうもん

いろいろとツッコミどころはあるばってん、Backlog Git と AWS CodePipeline の連携について考察してみたくさ

CodePipeline よ Github や CodeCommit と連携出来るのはわかった

では、Backlog Git と連携はどげんすればよかとかね。

その答えにヒントを与えてくれたのは以下の記事。

Integrating Git with AWS CodePipeline | AWS DevOps Blog

なるほど…とにかく、何らかの方法で Codepipeline までソースコードをお届け出来れば…ということで、Backlog Git の Webhook と API Gateway + Lambda を組み合わせればいけそうな気がする!

ということで

ざっくり構成

以下のような構成を作ってみた。

f:id:inokara:20170611103801p:plain

Backlog Git の Webhook は…

以下のような JSON データを送信する。

{
  "before": push前のコミット,
  "after": push後のコミット,
  "ref": 参照
  "repository": {
    "url": リポジトリのURL,
    "name": リポジトリ名,
    "description": リポジトリの説明,
  },
  "revisions": [{
    "id": コミットのID,
    "url": コミットのURL,
    "author": {
      "email": コミットした人のメールアドレス,
      "name": コミットした人の名前
    },
    "message": コミットメッセージ,
    "timestamp": タイムスタンプ,
    "added": [ 追加されたファイル ],
    "removed": [ 削除されたファイル ],
    "modified": [ 修正されたファイル ],
  }]
}

詳細は以下のページに記載されている。

www.backlog.jp

Lambda ファンクションは…

Python で書いてみた。

# -*- coding: utf-8 -*-

import os
import os.path
import sys
import urllib
import urlparse
import shutil
import json

sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'vendor'))

import boto3
import dulwich.client
from dulwich.repo import Repo
from dulwich import porcelain

target = os.environ['TARGET_DIR']
username = os.environ['USER_NAME']
password = os.environ['PASSWORD']
source_bucket = os.environ['BUCKET_NAME']

def git_clone(repo_url):
    print repo_url + ' からソースコードを取得します.'

    parsed_url = urlparse.urlparse(repo_url)
    src = parsed_url.scheme + '://' + username + ':' + password + '@' + parsed_url.netloc + parsed_url.path + '.git'

    if not os.path.isdir(target):
        os.mkdir(target)
    else:
        shutil.rmtree(target)

    try:
        porcelain.clone(src, target)
    except Exception as e:
        print(e)

    print(os.listdir(target))

def zip_files():
    print 'ソースコードを zip で圧縮します.'

    try:
        shutil.make_archive(target, 'zip', target)
    except Exception as e:
        print(e)

def upload_to_s3():
    print '圧縮したソースコードを s3 にアップロードします.'

    zip_file_name = target.split('/')[-1]

    s3 = boto3.client('s3')
    try:
        s3.upload_file(target + '.zip', source_bucket, zip_file_name + '.zip')
    except Exception as e:
        print(e)

def git(event, context):

    payload = json.loads(event['body']['payload'])
    repo_url = payload['repository']['url']

    git_clone(repo_url)
    zip_files()
    upload_to_s3()

    response = {
        'statusCode': 200
    }

    return response

以下の点を直したいけど取り急ぎ。

  • エラー処理
  • 環境変数で指定している各種値を KMS で暗号化

API Gateway と Lambda ファンクションのセットアップは…

Serverless Framework を使えば一瞬だった… serverless.yml は以下の通り。

service: slstest
provider:
  name: aws
  runtime: python2.7
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "s3:PutObject"
      Resource: "arn:aws:s3:::demodemo-codepipeline/*"
functions:
  hello:
    handler: handler.git
    memorySize: 128
    timeout: 60
    events:
      - http:
          path: git/push
          method: post
          integration: lambda
          request:
            parameters:
              querystrings:
                payload: true
    environment:
        USER_NAME: kappa
        PASSWORD: xxxxxxxxxxxxxx
        TARGET_DIR: /tmp/oreno-repo
        BUCKET_NAME: demodemo-codepipeline

今まで何で Serverless Framework を使っていなかったんだろうと後悔。

CodePipeline と S3 バケットの連携は…

以前に書いた記事を参考にした。

inokara.hateblo.jp

これはマネジメントコンソールから。

S3 バケットを作って、バージョニングを有効にして CodePipeline からソースプロバイダとして指定するだけ。

Codebuild では Ruby のテストを走らせてみる

以下のドキュメントを参考にして Codebuild で Ruby のテストを走らせてみた。

docs.aws.amazon.com

ファイル構成は以下の通り。

$ tree oreno-repo/
oreno-repo/
├── HelloWorld.rb
├── HelloWorld_spec.rb
└── buildspec.yml

0 directories, 3 files

buildspec.yml は以下の通り。

version: 0.1

phases:
  install:
    commands:
      - echo Installing RSpec...
      - gem install rspec
  build:
    commands:
      - echo Build started on `date`
      - echo Compiling the Ruby code...
      - rspec HelloWorld_spec.rb
  post_build:
    commands:
      - echo Build completed on `date`
artifacts:
  files:
    - HelloWorld.rb

実際にビルドを走らせた図。

f:id:inokara:20170611110705p:plain

あえて Failed させている。

まとめ

課題

本構成には以下のような課題が残っている。

  • Webhook 用 URL のアクセス制限(API キーによる認証又は IP アドレス制限
  • Lambda ファンクションで利用する環境変数の暗号化(KMS と連携させる)
  • ブランチ毎に処理を変えられるようにする(master ブランチ以外のブランチだけでビルドが走るようにするとか)

Serverless Framework

API Gateway と Lambda のセットを丸っとサクッと作ってくれるのが気持ち良すぎた。