LoginSignup
31
27

More than 5 years have passed since last update.

静的HTML公開フローをサーバレスでDevOps!(CodeCommit,Lambda,AWS S3)

Last updated at Posted at 2016-07-13
1 / 29

前回好評頂いた記事、静的HTML公開フローをサーバレスでDevOps!(Github,CircleCI,AWS S3)を、AWSクラウドネイティブへ再実装。

そのメリッット・デメリットを考察してみる。


「そもそも、可能なの?」

当時(2015/12)にはなかった、CodeCommit+Triggerが搭載された!

スクリーンショット 2016-07-12 17.42.52.png


ということは、
CodeCommit にpush -> trigger -> Lambda発火が可能。

trigger&Lambda実装次第で出来そう。


1 元構成のおさらい

スクリーンショット 2016-07-12 00.22.35.png

  1. GithubでHTMLコードを管理。
  2. CircleCIがブランチへのpushを検知。
  3. AWS S3の指定Bucketへ指定ブランチをデプロイ

2 フルAWS構成版

  • AWS S3 -> AWS S3 (そのまま)
  • Github -> AWS CodeCommit
  • CircleCI -> AWS Lambda

スクリーンショット 2016-07-13 15.12.03.png


3 Github -> CodeCommit


AWSコンソールにて

  • Git管理用IAMユーザ追加
  • CodeCommit用SSHKeyの登録
  • CodeCommitにて新規リポジトリ作成
  • git remote addでCodeCommit側のリポジトリを追加。
  • IAMユーザ+SSH通信にて作成したリポジトリのclone/pushを確認。

スクリーンショット 2016-07-13 14.40.13.png


次に肝となるトリガー追加

  • CodeCommitの対象リポジトリ「triggers」->「create trigger」
  • トリガー条件を[push]時のみにする。
  • 対象ブランチは[All branches]
  • Lambda関数を指定 (事前に空関数を作成しておく)

スクリーンショット 2016-07-12 18.03.54.png


  • trigger作成。

スクリーンショット 2016-07-13 12.33.16.png


  • テスト 
    Lambdaにてeventソースだけconsole.log出す簡単な関数を用意した上で、
    「test trigger」をポチるも、、エラー。
    Access権がないよ、と。

スクリーンショット 2016-07-12 18.25.59.png


CodeCommitの公式ドキュメント(英語)より、
Lambda関数側にCLIからJSON形式の許可設定を追加する必要あるとのこと。


AllowAccessfromMyDemoRepo.json
{
    "FunctionName": "push_s3_from_codecommit", 
    "StatementId": "1", 
    "Action": "lambda:InvokeFunction", 
    "Principal": "codecommit.amazonaws.com", 
    "SourceArn": "arn:aws:codecommit:us-east-1:[AWS ID]:devops-test-repo", 
    "SourceAccount": "[AWS ID]"
}
$ aws lambda add-permission --cli-input-json file://AllowAccessfromMyDemoRepo.json

今度はOK
スクリーンショット 2016-07-13 12.59.00.png


4 CircleCI -> Lambda


元々、CircleCiでやってたこと
- 指定ブランチへのpushを検知(webhook)
- 指定ブランチをclone
- html/以下を指定のS3 Bucketへsync

ほぼ数行の指示ファイルで可能。

circleci.yml

dependencies:
    override:
        - sudo pip install awscli

deployment:
  production:
    branch: master
    commands:
      - aws s3 sync html/ s3://[your s3 bucket]/ --delete
  staging:
    branch: staging
    commands:
      - aws s3 sync html/ s3://[your s3 bucket]/ --delete

Lambda for Pythonで実装

必要モジュール

SSH処理
- paramiko

git処理
- dulwich

aws cli処理
- awscli


- 上記関連モジュール

トータルでは諸々のモジュールが必要。
関連モジュールを含めるとzipして50MB近くなった。。(ただ、未精査なので、必要ないモジュールもあるかも。。)


Lambdaポイント

  • Gitログイン時のSSHキーやGit Cloneデータは/tmp/ 以下にファイル設置(500MB以内)
  • SSHキーは都度S3からDownloadさせる都合上、SSE-KMSにより暗号化
  • 実行時間はデフォルトの3sだとほぼ間違いなく時間切れとなるので、長めに確保しておく。(60s以上)

実装例

lambda_function.py
from __future__ import print_function  
import os  
import sys  
import subprocess  
import boto3  

from botocore.client import Config  

from dulwich.errors import (  
    SendPackError,  
    UpdateRefsError,  
    )  
from dulwich.objectspec import (  
    parse_object,  
    parse_reftuples,  
    )  
from contextlib import closing  
from dulwich import porcelain  
from dulwich.contrib.paramiko_vendor import ParamikoSSHVendor  

import dulwich  
import dulwich.repo  
import paramiko  
import paramiko.client  

import commands
import json
import os
from cStringIO import StringIO
import re

print('Loading function')

def _(cmd):
    return commands.getoutput(cmd) 

s3 =boto3.client('s3', config=Config(signature_version='s3v4'))  

class KeyParamikoSSHVendor(object):  

    def __init__(self):  
        self.ssh_kwargs = {'key_filename': '/tmp/id_rsa'}  

    def run_command(self, host, command, username=None, port=None,  
                    progress_stderr=None):  
        if not isinstance(command, bytes):  
            raise TypeError(command)  
        if port is None:  
            port = 22  

        client = paramiko.SSHClient()  

        policy = paramiko.client.MissingHostKeyPolicy()  
        client.set_missing_host_key_policy(policy)  
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())  
        client.connect(host, username=username, port=port,  
                       **self.ssh_kwargs)  

        # Open SSH session  
        channel = client.get_transport().open_session()  

        # Run commands  
        channel.exec_command(command)  

        from dulwich.contrib.paramiko_vendor import (  
                    _ParamikoWrapper as ParamikoWrapper)  
        return ParamikoWrapper(  
            client, channel, progress_stderr=progress_stderr)  


def lambda_handler(event, context):
    print(sys.stderr)
    print(getattr(sys.stderr, 'encoding', 'utf-8'))
    s3.download_file('pd-test-data', 'test_id_rsa', '/tmp/id_rsa')
    cmd = "chmod 600 /tmp/id_rsa"
    output = subprocess.check_output(cmd.split(" "))
    print(output)

    dulwich.client.get_ssh_vendor = KeyParamikoSSHVendor
    github_repo = '[Your CodeCommit Account]@git-codecommit.us-east-1.amazonaws.com:/v1/repos/[Your Repository]'

    repo = dulwich.porcelain.clone(github_repo, '/tmp/temp')

    print (_("./aws s3 sync /tmp/temp/html s3://[Your S3 Bucket] --delete"))

    cmd = "rm -rf /tmp/temp"
    output = subprocess.check_output(cmd.split(" "))
    print(output)

コード参考サイト
@mag4j さん
http://www.magtranetwork.com/aws/aws_lambda_python_aws_cli.html

@ijin さん
http://ijin.github.io/blog/2016/02/18/ssh-and-git-on-aws-lambda/


あと、必要に応じて、

  • triggerの対象ブランチを特定したり、
  • ブランチ名をevent情報から取得し、ブランチ毎の処理を実装。

作成した関数群をZIPで固め、LambdaにUP。
これで準備完了。

実際に対象ブランチにpushし、S3にファイルアップロードされることを確認。


実行ログ
S3へのputやGetObjectなどの各権限などが問題なければ、CloudWatchのLogに以下のようにSyncデータログが流れる。

スクリーンショット 2016-07-13 13.45.13.png


ちなみに、それぞれの実行時間の比較。
(約4MBのHTMLファイル群アップロード時間)

CircleCI(1コンテナ=無料) = 60s〜80s
Lambda = 13〜14s


5 まとめ

フルAWS構成化は実装できた。
ただ、万事OKかと言われると、一長一短があることも分かった。


Github->CodeCommit

メリット

  • 無料枠内なら無制限にプライベートリポジトリが作成可能
  • ユーザをIAMにて統合管理可能

デメリット

  • Githubの優良機能が使えない(pull req/レビュー/margeの連携など)

CircleCi->Lambda

メリット

  • ほぼ無料枠内で利用可能(100万リクエストまで)。
  • 実行完了が短い。(ファイル数、サイズによる)
  • 並列処理が可能。
  • 同じ要領で、ほぼすべてのAWSリソースと連携可能。

デメリット

  • 権限、コード実装が大変。複雑。
  • Slack通知、hubot連携など必要なら自前て実装する必要あり。
  • 上限時間以上の処理ができない。

総評

単に、AWSクラウドネイティブにこだわるなら、この実装はありですが、世界的にデファクトスタンダードなGithubを利用する意義、CIに特化したCircleCIを利用する意義、
は必ずあります。
ここの挙げた以上のメリット・デメリットを把握し、状況に応じて選択出来ればと思います。


追記。

CI(test/deploy)にLambda利用する事に特化したLambCIというOSSが最近発表されたらしい。
LmabdaでCi、これからのスタンダードになるのかも?

スクリーンショット 2016-07-13 14.36.35.png

LambCI
https://github.com/lambci/lambci
https://medium.com/@hichaelmart/lambci-4c3e29d6599b#.ys4gcjmug

31
27
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
31
27