VPC内のGitlabで管理しているGitbookのドキュメントをCodePipelineとCodeBuildでS3にデプロイする話

こんにちは(ほ)です。

私の所属している社内コミュニティでは、IoT についてのドキュメントをGitbookで作成し、EC2上のJenkinsでビルドとデプロイを行っておりました。

ただ、この環境では下記の点から、コスト的にもったいないと感じていたり、重要なタイミングでサーバの再起動が必要になることがあったため、CodePipeline, CodeBuildを使用したサーバーレス環境に移行することにしました。

  • t2.microだと1GBのメモリしかないため、ビルド時にJenkinsがお亡くなりになることがある。
  • t2.microだと1GBのメモリしかないため、GitbookのプラグインのインストールでJenkinsがお亡くなりになることがある。
  • かといって、大きなインスタンスを起動させておくほどは更新頻度が高くない時期がある。

構成

CodePipeline, CodeBuildはソースコードの取得先がGithubやS3には対応しているのですが、Gitlabには対応していないため、コンソール上の設定だけではすみません。

そこで、Integrating Git with AWS CodePipelineを参考に、下記のような構成で作ることにしました。

1. Lambda : Webhookでの処理

まず、GitlabへPushした際のWebhookを受けるエンドポイントを API Gateway で作成し、下記のLambda function(Python3) と連携させます。

ここでは下記のような処理をしています。

  1. GitlabからソースコードをZIP形式で取得。
  2. ZIPを解凍し、ルートにあるディレクトリを除去。
  3. 再度ZIPで圧縮して、CodePipelineで監視しているBucketに置く。

このようなことをしているのは、Gitlabから取得できるソースコードは下記のような形式なのですが、

source.zip
┗ project-branch-hash/
  ┣ buildspec.yml
  ┣ README.md
  ┗ SUMMARY.md

CodeBuildに渡すファイルは下記のように、ZIPの直下にbuildspec.ymlが必要なためです。

source.zip
┣ buildspec.yml
┣ README.md
┗ SUMMARY.md

ちなみに、GitlabにPush時にWebhookで渡されるJSONはこちらを参照してください。

2. VPC endpoints

前述のLambdaでは、Gitlabから取得したソースコードをS3に保存しているのですが、実はこのLambdaはVPCで起動しているため、S3を直接触ることができません。

http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/vpc.html

Lambda 関数に VPC 設定を追加した場合、関数でアクセスできるのは、その VPC 内のリソースのみになります。Lambda 関数から VPC リソースとパブリックインターネットの両方にアクセスする必要がある場合は、VPC 内に NAT > (Network Address Translation) インスタンスが必要になります。

そのため、S3にアクセスできるようにVPCのエンドポイントを作成する必要があります。

http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpc-endpoints.html

重要
現在、Amazon S3 のみとの接続のエンドポイントがサポートされています。エンドポイントは IPv4 トラフィックでのみサポートされています。

VPC内のLambdaがS3にファイルを置けるように、endpointのポリシーは下記のように設定しました。

3. CodeBuild

CodeBuildでは、Gitbookをビルドするために、下記のように設定します。

  • プロジェクト名 : Gitbook-build(任意)
  • ソースプロバイダ : Amazon S3
  • バケット : 適当なbucket名
  • S3 オブジェクトキー : source.zip
  • 環境イメージ : AWS CodeBuild によって管理されたイメージの使用
  • オペレーティングシステム : Ubuntu
  • ランタイム : Node.js
  • バージョン : aws/codebuild/nodejs:7.0.0
  • ビルド仕様 : ソースコードのルートディレクトリのbuildspec.ymlを使用
  • アーティファクトタイプ : Amazon S3(任意で、No artifactsでも構いません)

buildspec.yml

CodeBuildでのビルドの設定のために、Gitlabのプロジェクトに下記の buildspec.yml を追加してください。

このyamlで使用している$branch変数は、前述のLambdaの処理内にてPush時のBranch名を設定するようにしています。

これは、Branchごとに異なるS3のディレクトリに公開するためです。

4. Lambda : artifactのS3への公開

下記のLambdaでCodeBuildのArtifactをCodePipelineから受け取り、S3に公開します。

CodePipeLineを使用した場合のCodeBuildのArtifactのパスは、CodeBuildに設定したものではなく、CodePipelineから渡されるJSONをパースする必要があります。

HTMLをS3に置く際に、ContentTypeを設定しないと、”binary/octet-stream”が設定され、ブラウザで開くとダウンロードされるために、content_type()にてファイル形式の判断を行っています。

5. CodePipeline

まず、下記の設定値を入力してパイプラインを作成します。

  • パイプライン名 : GitbookBuild(任意)
  • ソースプロバイダ : Amazon S3
  • Amazon S3 の場所 : s3://適当なbucket名/source.zip
  • ビルドプロバイダ : AWS CodeBuild
  • プロジェクトの設定 : 既存のビルドプロジェクトを選択
  • プロジェクト名 : Gitbook-build(3. CodeBuild で設定したプロジェクト)
  • デプロイプロバイダ : デプロイなし

次に作成したパイプラインを選択して下記のように編集します。

Source

  • 出力アーティファクト#1 : prebuild

Build

  • 入力アーティファクト#1 : prebuild
  • 出力アーティファクト#1 : release

Deploy

Buildステージの下をクリックし、Deployステージを作成してアクションを追加します。

  • アクションカテゴリー : 呼び出し
  • アクション名 : publish-gitbook(任意)
  • プロバイダ : AWS Lambda
  • 関数名 : 4. Lambdaで作成した関数名
  • ユーザパラメーター : 入力なし
  • 入力アーティファクト#1 : release

この状態で「変更のリリース」ボタンを押したり、GitlabにPushすることでパイプラインが動き始めるはずです。

6. S3(公開用)

最後に、サイトの公開範囲を社内に限定するために、バケットポリシーを下記のように設定しています。

まとめ

実際はもっと簡単にできると考えていたのですが、buildspec.ymlの場所や環境変数の設定、VPCからS3を触れないなど、色々とつまずくポイントはありましたが何とか出来ました。

今回はGitlabとCodePipelineを連携させてみましたが、Github以外と連携させる需要は意外と多いのではないでしょうか。
また、buildspec.ymlのコマンドを変えれば、当然ですがGitbook以外のプロジェクトもビルドできます。

お手軽にCI環境が欲しい方は試してみてください。

  • このエントリーをはてなブックマークに追加