JavaによるLambdaをCodepipelineで自動リリースする最小構成サンプル

TL;DR

以下の文書では、node.js でのLambda関数のリリースを自動化する例が出ています。
http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/automating-deployment.html

本文書では、これとほぼ同じようなアプリをJavaで書き、そのリリースを自動化します。それぞれの要素の意味や役割の説明は最低限に留めます。 (筆者もよくわかってません。えっへん。) 最小の動作サンプルの例示を行います。

本文書ではマネージメントコンソール上で色々手作業で設定を入れさせています。今後のUIの変更で、手順が変わっているかもしれません。ご容赦を。

前提

  • githubにコードが配置してあること。
  • 更新を検出するブランチが決めてあること。
  • Gradleでビルドを行います。
  • 中間ファイルを置くためのS3バケットがあること。例として、auto-release-sampleとします。

準備

ロールの作成

IAM マネージメントコンソールを開き、以下のようにロールを作成します。

項目 備考
名前 cloudformation-lambda-execution-role
ロールタイプ AWS CloudFormation 作成時は「AWS サービスロール」から選択する。作成後のロールの画面では、信頼関係 タブに表示される
アタッチされたポリシー AWSLambdaExecute ロールの画面では、アクセス許可 タブ=>管理ポリシー に表示される

一度ロールを作った後、作成したロールをマネージメントコンソールで開き、アクセス許可 タブ ->インラインポリシー にて、作成するには、ここをクリックしてください。をクリックする。  カスタムポリシー -> 選択 と進んだ後下記内容を記載する。ポリシー名は適宜設定する。

{
    "Statement": [
        {
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:GetBucketVersioning"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::codepipeline*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "lambda:*"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:GetRole",
                "iam:CreateRole",
                "iam:DeleteRole"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:AttachRolePolicy",
                "iam:DetachRolePolicy"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:PassRole"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "cloudformation:CreateChangeSet"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        }
    ],
    "Version": "2012-10-17"
}

注:必要最低限の権限になってはいないかもです。今後の本記事の更新でなるべく削って行きたいです。

githubにファイルを配置する

アプリケーションのソースコードをgithubに保存します。

具体的なファイルの中身はサンプルリポジトリを参照してください。
https://github.com/kazurof/minimum-java-lambda-with-codepipeline
ファイルのディレクトリ構成を記載しておきます。

│  build.gradle
│  buildspec.yml
│  gradlew
│  gradlew.bat
│  minimum-lambda-java-model.yaml
│
│
├─gradle
│  └─wrapper
│          gradle-wrapper.jar
│          gradle-wrapper.properties
│
└─src
    └─main
        └─java
            └─codepipelinesample
                    Main.java

補足

buildspec.yml には、利用するS3リポジトリ名が記載されます。(先に、auto-release-sampleとしたもの。)実際に動かしてみる場合は適宜あなたが用意したリポジトリ名に変更してください。

CodePipeline の作成

AWS CodePipeline のマネージメントコンソールを開き、パイプラインを以下のように作成する。

パイプライン名

パイプライン名はわかればなんでも良い。

ソース

項目 備考
ソースプロバイダ GitHub GitHubを選択すると、GitHubリポジトリのURLとブランチを指定し、OAuth認証を行い、CodePipelineから指定したGitHubのリポジトリにアクセスできるようにする。
アクションカテゴリー ソース 作成時は入力を求められない。自動でつけられるものでOK
アクション名 Source 作成時は入力を求められない。自動でつけられる名前でOK
出力アーティファクト名 MyApp 作成時は入力を求められない。自動でつけられる名前でOK

ビルド

項目 備考
ビルドプロバイダ AWS CodeBuild
アクションカテゴリー ビルド 作成時は入力を求められない。
アクション名 CodeBuild 作成時は入力を求められない。

CodeBuildの新しいプロジェクトを作るを選択する。プロジェクト名はわかればなんでも良い。

ビルドプロジェクトの作成

項目
ビルド環境 Ubuntu Java8
ビルド仕様 ソースコードのルートディレクトリの buildspec.yml を使用

注:
– この時、AWS CodeBuild のサービスロールがユーザーに代わり自動的に作成されます。code-build-<ビルドプロジェクト名>-service-role という形になります。
– このビルドのアクションにおいて、以下項目が以下のように自動設定されます。

項目
入力アーティファクト MyApp
出力アーティファクト MyAppBuild

「ビルドプロジェクトの保存」を押下、「次のステップ」を押下してください。

デプロイ

項目 備考
デプロイプロバイダ AWS CloudFormation
アクションモード 変更セットの作成または置換
スタックの名前 MyBetaStack
変更セット名 MyChangeSet
テンプレートファイル packaged-minimum-lambda-java-model.yaml
Capabilities(特徴) CAPABILITY_IAM
ロール名 cloudformation-lambda-execution-role この作業手順の先頭で作ったロールを指定する。
アクションカテゴリー デプロイ 自動で設定される

AWS サービスロールの作成

ロールを新たに作ります。

当該画面の文言を転載:
「AWS CodePipeline がアカウントでリソースを使用するアクセス許可を付与するため、IAM にサービスロールを作成します。」

  • 「ロールの作成」を押下。
  • 「許可」を押下。
  • 「次のステップ」を押下。

ロール名は、「AWS-CodePipeline-Service」になるはずです。(すでにある場合はインラインポリシーに追加される挙動の様子。未確認です。)

パイプラインの確認

今まで入力した内容の確認画面が表示される。「パイプラインの作成」を押下します。

サービスロールを修正

Codebuild 向けに作成されたサービスロールが、用意したS3バケット(auto-release-sample)にアクセスできるように修正する。

今までの手順で、code-build-<ビルドプロジェクト名>-service-roleなるロールが生成されているのでそれを修正する。

  • IAM マネジメントコンソールから、ロール を選択する。
  • code-build-<ビルドプロジェクト名>-service-role を選択する。
  • アクセス許可=> インラインポリシー=> 「表示するインラインポリシーはありません。作成するには、ここをクリックしてください。」 をクリックする。
  • 「Policy Generator」 を選択して 「Select」 を選択する。
  • 「AWS Service」 で、「Amazon S3」 を選択する。
  • 「Actions」 で、「PutObject」 を選択する。
  • 「Amazon Resource Name (ARN)」 に arn:aws:s3:::auto-release-sample* と入力する。(末尾のアスタリスク必要!)
  • 「ステートメントを追加」 を選択して 「Next Step」 を選択する。
  • 「ポリシーの適用」 を選択する。

CodePipelineにLambdaを更新するステップを追加する

  • AWS CodePipeline マネジメントコンソールに移動 =>作成したpipelineを選択
  • 編集ボタンをクリック
  • Stagingの鉛筆アイコンをクリック
  • 既存のアクションの最後にある [+ Action] アイコンを選択する。
  • 以下のように入力
項目
アクションカテゴリー デプロイ
アクション名 execute_cs (わかればなんでも良い)
デプロイプロバイダ AWS CloudFormation
アクションモード 変更セットの実行
スタックの名前 MyBetaStack
変更セット名 MyChangeSet
  • 「更新」を押して保存
  • 「パイプラインの変更を保存」を押してパイプライン全体を保存

自動リリースとLambdaの実行

以上でCodepipeline 作成は終了です。gitリポジトリのmasterブランチに何か修正を入れてみてください。Codepipelineのマネジメントコンソールで、パイプラインが動作するところを確認できます。

正しく終了したら、Lambdaのマネージメントコンソールを開いてください。JavaによるLambda関数が作成されているはずです。テスト実行ができます。

感想

関係する要素技術多いせいか、手順長いですね。。。:sweat_smile:

続きを読む

[ChatOps]Opsidianとdroneを使って、SlackからAWSへデプロイしてみた

はじめに

 先日【drone.ioを使ってCI環境を構築したので、色々整理してみた___<基本編>】を書きました。タイトルは揃っていませんが、今回はそれの続編で、Slackからデプロイコマンドを打って、droneがおとなしく指示通りにやってくれる方法について書きます、。

SlackでのChatOps

 (AWS寄りになってしまいますが)Slackを使って、ChatOpsをする時に、下記API Gatewayを使うパータンがよくあるのではないかと思います。もちろん、SlackからHubotを呼ぶのもあります。
スクリーンショット 0029-08-01 20.56.17.png
 ちなみに、Slack → API Gateway → Lambdaにご興味がある方は、下記、昨年私が書いた記事を見て頂ければと思います。
【Slack de AWS CLI】SlackのChannelからAWS CLIを実行できるようにしてみました!

 元々、自分もAPI Gatewayを使うと考えていました…が、つい先日(夜眠れない日)に、「なんか面白いツールないかな」とSlackのインテグレーションを漁っていて、偶然に見つかったのはOpsidianというツールです。正確的にはOpsidian.aiという名で、aiが付いています…よ。Opsidian.aiにご興味がある方は、是非Opsidian.aiの公式ページを見てください。面白いことをいっぱい書いてあります。
※ 私はあまりにも感動しすぎて、めちゃくちゃの英語でこのツールの親であるewadwornikowskaさんにメッセージを送りました。

 話を戻りますと、最終的にAPI Gatewayを辞めて、こんな感じにしました。

スクリーンショット 0029-08-01 21.00.52.png
 一見、API GatewayのかわりにOpsidianを使っているだけじゃんというツッコミもありますが、個人的にはOpsidianのほうが結構楽だと思います。
 API Gatewayもそれなりの使い方がありますので、ChatOpsをやる時に、選択肢が1つ増えたという捉え方のほうがいいと思っています。

 API GatewayとOpsidianを簡単に比べてみますと、

 1. API Gatewayの設定より、Opsidianのほいうが楽
 2. API Gatewayを利用する場合、認証とか入れないと、エンドポイントがバレたら、だれでも叩けるようになる。一方、OpsidianはSlackに設定したアクセスキーでLambdaをinvokeするので、安全(?)かも
 3. だれがLambdaを呼べるかの処理は、Opsidian側で制御可能。
 4. Opsidianって、ただLambdaをinvokeするだけではなく、AWSリソースのモニタリングもできる。
 ※ 私個人的な意見にはなりますが、OpsidianってChatOpsの神ツールだと思っています。

SlackからAWS ECRにイメージプッシュまでやってみる

 流れ的には、こんな感じになります。
 Slack → Opsidian → Lambda → GitHub → drone → AWS ECR
 何をやっているかとざっくり説明しますと、
 1: Slackからデプロイの指示を出します
 2: Opsidianはその指示通りにLambdaをinvokeします。
 3: invokeされたLamndaはGitHubへdeploy APICallします。
 4: GitHubはdeployのWebhookをdroneに送信します。
 5: droneは受信したWebhookからソースを取得し、ビルドを実行し、AWS ECRへイメージをpushします。

 細かい設定とかは割愛します。今後時間がありましたら、書くかもしれません。…と言っても、簡単に何を設定しているかを書きます。

1: SlackからOpsidianを呼べるようにしました。
  - Opsidianのインストールはこちら
  - Opsidianの設定はこちら

2: OpsidianがinvokeするLambdaを作りました。
  - OpsidianのDashboardにて、Slackから呼べるLambdaのコマンドdeployを設定しました。
  WechatIMG27.jpeg

  - 下記、超雑なLambdaサンプルコード
   ※ Opsidianのコマンドから渡された引数を使って、GitHubへdeploy APICall
   ※ GithubのPersonal access tokenはlambdaの環境変数GIT_KEYに設定しています。

deploy
import boto3
import json
import os
import http.client

def lambda_handler(event, context):
    conn = http.client.HTTPSConnection("api.github.com")
    print(event)
    args = event["args"].split(" ")
    repo    = args[0]
    branch  = args[1]
    env     = args[2]
    payload = {
        "ref": branch,
        "auto_merge": False,
        "environment": env,
        "description": "Deploy to "+ env,
        "required_contexts": []
    }

    headers = {
        'authorization': "token " + os.environ['GIT_KEY'],
        'User-Agent': "Awesome-Octocat-App"
    }

    conn.request("POST", "/repos/"+ repo +"/deployments", json.dumps(payload).encode("utf-8"), headers)

    res = conn.getresponse()
    data = res.read()

    print(data.decode("utf-8"))
    return json.dumps({'message': 'Hello world!'})

3: Github
  - 下記2つのファイル(あくまでもサンプル)が対象のリポジトリの配下に格納しました。

.drone.yml

# masterブランチに対して、
# GitHubのevnetがdeploymentかつenvironmentがproductionと指定された場合
# ビルドを実行

pipeline:
  ecr:
    image: plugins/ecr
    region: ap-northeast-1
    repo: 284****1948.dkr.ecr.ap-northeast-1.amazonaws.com/ecr
    tags: [ latest,drone-test ]
    secrets: [ ECR_ACCESS_KEY,ECR_SECRET_KEY ]
    when:
      branch: master
      event: deployment
      environment: production
Dockerfile
FROM centos:6

RUN set -x && \
    yum install -y httpd

4: drone
  - AWS ECRへpushできるdroneのプラグインplugins/drone-ecrを利用しています
    ※ ソースコードはこちら
  - 対象ブランチを有効化しました。
  1.jpeg
  
  - droneにecrへpushできる権限のキーを設定しました。
   ※ plugins/drone-ecr利用時、設定する環境変数はECR_ACCESS_KEYECR_SECRET_KEYになります。
 2.jpeg

  - 今回はGitHubのdeploymentの場合ですので、「Settings」の「Deploy Hook」を有効にしました。
3.jpeg

5: ECR
  - droneがビルドしたdockerイメージのpush先を予め用意しました。
WechatIMG16.jpeg

Slackからやってみる

1: Slackから /ops run deploy [repository] [branch] [environment]を打ってみます。
W1.jpeg

2: Opsidianから返信が来ました. やっはり Hello worldにすべきじゃなかったかもしれません。微妙に違和感が感じますが、一旦よしとします。
W2.jpeg

3: droneが動いていますね。
W3.jpeg

W4.jpeg

W5.jpeg
ちゃんとpushまでできましたね!

4: ECRにpushされたことも確認できました。
W7.jpeg

5: 終了

最後

 Opsidianとdroneで、SlackからAWS ECRへイメージをpushするまでについて整理しました。繰り返しにはなってしまいますが、Opsidianが結構便利なツールなので、ChatOpsだけではなく、モニタリングとかにも活用したいと思っています。
 今日はとりあえずここまでにします。

続きを読む

サーバーレスアプリケーションを管理する(SERVER LESS)

前置き

だんだんと Lambda function が増えてきたので管理してみようと思いました。今回は Serverless を使ってみます。

インストール

ますはインストールします。

事前準備

以下をインストールします。

Serverless framework をインストール

この記事 を参考に、各プロジェクトごとにインストールをします。

package.json
{
  "name": "project-name",
  "devDependencies": {
    "serverless": "^1.16.0"
  },
  "scripts": {
    "sls": "serverless"
  }
}

エラーが出るとき

インストールしたときに怒られちゃいました・・・

Error: Cannot find module ‘/path/to/project/node_modules/serverless/node_modules/tabtab/src/cli.js’

issueを参考に、オプションをつけて再度インストールしたところ成功!
無事インストールが完了しました!

$ sls --version
1.16.0

サービスを作成する

Serverless framework では、サーバーレスアプリケーションを service という単位で切り分けるようです。
まずは Serverless framework が提供しているテンプレートを利用して作成してみまんす。

$ sls create --help
Plugin: Create
create ........................ Create new Serverless service
    --template / -t (required) ......... Template for the service. Available templates: "aws-nodejs", "aws-python", "aws-python3", "aws-groovy-gradle", "aws-java-maven", "aws-java-gradle", "aws-scala-sbt", "aws-csharp", "azure-nodejs", "openwhisk-nodejs", "openwhisk-python", "openwhisk-swift", "google-nodejs", "plugin" and "hello-world"
    --path / -p ........................ The path where the service should be created (e.g. --path my-service)
    --name / -n ........................ Name for the service. Overwrites the default name of the created service.

ふむふむ、テンプレートがたくさん良いされてますな。今回は AWS Lambda で python3 なので、 aws-python3 を選択します。

$ sls create -t aws-python3 -p service
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/path/to/project/service"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  ___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.16.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-python3"

でけた!ファイルが何個かできてますね。

ls -la srvice
total 24
drwxr-xr-x  5 user  staff   170  6 22 10:50 .
drwxr-xr-x  6 user  staff   204  6 22 10:47 ..
-rw-r--r--  1 user  staff   192  6 22 10:47 .gitignore
-rw-r--r--  1 user  staff   490  6 22 10:47 handler.py
-rw-r--r--  1 user  staff  2787  6 22 10:47 serverless.yml

何ができるのかな?

$ sls

Commands
* Serverless documentation: http://docs.serverless.com
* You can run commands with "serverless" or the shortcut "sls"
* Pass "--help" after any <command> for contextual help

config ........................ Configure Serverless
config credentials ............ Configures a new provider profile for the Serverless Framework
create ........................ Create new Serverless service
install ....................... Install a Serverless service from GitHub
package ....................... Packages a Serverless service
deploy ........................ Deploy a Serverless service
deploy function ............... Deploy a single function from the service
deploy list ................... List deployed version of your Serverless Service
deploy list functions ......... List all the deployed functions and their versions
invoke ........................ Invoke a deployed function
invoke local .................. Invoke function locally
info .......................... Display information about the service
logs .......................... Output the logs of a deployed function
login ......................... Login or sign up for the Serverless Platform
logout ........................ Logout from the Serverless Platform
metrics ....................... Show metrics for a specific function
remove ........................ Remove Serverless service and all resources
rollback ...................... Rollback the Serverless service to a specific deployment
rollback function ............. Rollback the function to a specific version
slstats ....................... Enable or disable stats

Plugins
AwsCommon, AwsCompileAlexaSkillEvents, AwsCompileApigEvents, AwsCompileCloudWatchEventEvents, AwsCompileCloudWatchLogEvents, AwsCompileCognitoUserPoolEvents, AwsCompileFunctions, AwsCompileIoTEvents, AwsCompileS3Events, AwsCompileSNSEvents, AwsCompileScheduledEvents, AwsCompileStreamEvents, AwsConfigCredentials, AwsDeploy, AwsDeployFunction, AwsDeployList, AwsInfo, AwsInvoke, AwsInvokeLocal, AwsLogs, AwsMetrics, AwsPackage, AwsProvider, AwsRemove, AwsRollback, AwsRollbackFunction, Config, Create, Deploy, Info, Install, Invoke, Login, Login, Logs, Metrics, Package, Platform, Remove, Rollback, SlStats

お、ローカルでのテスト用コマンドもあるみたいですね。試してみましょ。

テスト

まずはテンプレートで作成されたファンクションをテストしてみまんす。

$ cd service
$ sls invoke local -f hello

すると・・・

Error: spawn python3.6 ENOENT

まーた怒られちゃいました・・・どうやらローカル環境のpythonが3.6じゃないようですね。
pyenv と pyenv-virtualenv で解決しました!

デプロイ

では実際にAWSへデプロイしてみます!

その前に

デプロイの前にAWSのクレデンシャル設定をします。

$ aws configure

すでに複数のクレデンシャルを管理している場合は

$ export AWS_PROFILE="profileName" && export AWS_REGION=ap-northeast-1

いけます!

デプロイ!

これを実行するだけ!

$ sls deploy
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (1.35 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...
Service Information
service: service
stage: dev
region: ap-northeast-1
api keys:
  None
endpoints:
  None
functions:
  update: service

AWSコンソールでLambdaを確認すると・・・できてました!

Tips

環境でリソースを使い分ける

今回はテストコードでしたが、実際はステージングや本番で同じコードを利用した運用がしたいと思います。
例えば・・・

DB更新したいからVPCにLambdaをおきたいけど、ステージングと本番でVPCわけちゃってるやー

こんな時、デプロイの設定で配置するVPCがわけられたら素敵ですよね!そんな時はこうします!

18 # ステージによって使い分けたい設定を記述
19 custom:
26   vpc:
27     staging:
28       securityGroupIds:
29         - sg-sgsgsgsg
30       subnetIds:
31         - subnet-aaaaaaaa
32         - subnet-cccccccc
33 
34 provider:
35   # ステージの値をデプロイ時のパラメータで上書き(デフォルトはdev)
37   stage: ${opt:stage, self:custom.defaultStage}
38   # ステージの値を利用して値を使い分ける
42   vpc: ${self:custom.vpc.${self:provider.stage}}

こんな感じでserverless.ymlに設定します。

あとはデプロイコマンドにパラメータを追加すればOK!

$ sls deploy --stage staging
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (1.35 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...
Service Information
service: service
stage: staging
region: ap-northeast-1
api keys:
  None
endpoints:
  None
functions:
  update: update-pageviews-staging-update

stageが前回はdevでしたが、今回はstagingに変わってますね!この仕組みを利用すれば環境変数などもステージにより使い分けることができますので、より捗ります!

最後に

バージョン管理からデプロイまで管理できることにより、非常にサーバーレスヘの敷居が低くなりました。サーバレスアプリケーションは開発が簡単な分、運用への意識が低くなり、どうしても「今ってどのバージョンが動いてるんだっけ?」「これっていつ誰が作ったの?」など、逆にコストがかかることもありましたが、サーバーレスフレームワークを利用することにより、今までと変わらない開発、テスト、運用が適用できるようになりますね!

続きを読む

Rails + CircleCI 1.0 + AWS の設定手順 ビルド開始~デプロイ完了まで

はじめに

RailsでCircleCI環境を整えるまでの手順をまとめました。

CircleCIはバージョン2.0がありますが、
Dockerがないといけない?ようなので、バージョン1.0で準備しました。

circleCIとは

簡単に言うと、
githubのpushを検知して、自動でビルドからテスト、デプロイまで自動化してくれるツール。
(デフォルトだと全部ブランチ対象)

1コンテナは無料なので、時間が掛かってもよいのであれば無料枠で十分。

https://circleci.com/

設定ファイル

必要なファイルは以下3つ

① circle.yml
② config/database.yml.ci
③ script/deploy-staging.sh

① circle.yml

circleCIを動かくための設定ファイル。
Railsのアプリケーションディレクトリ直下にファイルを作ります。(gemfileとかと同じ場所)

② config/database.yml.ci

テストするためのDB設定ファイル。Rspecを実行するために必要。

③ script/deploy-staging.sh

テストが終わったらステージング環境へデプロイするためのスクリプトファイル。

設定ファイルの中身

circle.yml
machine:
  timezone:
    Asia/Tokyo
  ruby:
    version:
      2.3.0
dependencies:
  pre:
    - sudo pip install awscli
  override:
    - bundle install:
database:
  pre:
    - mv config/database.yml.ci config/database.yml
  override:
    - bundle exec rake db:create db:schema:load RAILS_ENV=test
    - bundle exec rake db:migrate RAILS_ENV=test
test:
  override:
    - bundle exec rspec spec/
deployment:
  staging:
    branch: master
    commands:
      - sh script/deploy-staging.sh:
          timeout: 1500

ポイント
AWSにデプロイするのにawscliを使用するために、
「sudo pip install awscli」を記述する。(デフォルトは古いらしい)
DB名は「test」じゃないと動かない。

config/database.yml.ci
test:
  adapter: postgresql
  encoding: unicode
  database: test
  pool: 5
script/deploy-staging.sh
#!/bin/sh

export AWS_DEFAULT_REGION="ap-northeast-1"

MYSECURITYGROUP="*"
MYIP=`curl -s ifconfig.me`

aws ec2 authorize-security-group-ingress --group-id $MYSECURITYGROUP --protocol tcp --port 22 --cidr $MYIP/32

bundle exec cap production deploy

aws ec2 revoke-security-group-ingress --group-id $MYSECURITYGROUP --protocol tcp --port 22 --cidr $MYIP/32

ポイント
MYSECURITYGROUPは、AWSのセキュリティーグループIDを指定する。
LFの改行コードで作成する。CRLFだと動かない。

その他設定

CircleCI側にAWSの秘密鍵を登録する。
AWS上で「cat ~/.ssh/id_rsa」で表示されるもの。

CircleCI側にAWSのアクセスキーとシークレットキーを設定

AWSの秘密鍵をAWSの認証キーとして登録。
AWS上で「cat id_rsa >> ~/.ssh/authorized_key」

Port 22をセキュリティグループで空けておく。

続きを読む

AWS LambdaのCI環境について ~表参道.rb #24~

自己紹介

@ebihara99999


ところで

私事ですが明日結婚します。
めでたいLTです

明後日結婚するので明日のLTは独身最後のLTになるのか。なんかめでたいLTだ笑

— ebi (@ebihara99999) July 5, 2017


発表すること

  • AWS Summit 2017でのt_wadaさんの講演がすごく参考になったので、AWS Lambdaで自動テストを行う仕組みを導入した
  • その際の知見やハマりどころを発表する

t_wadaさんの講演?

Testable Lambda: Working Effectively with Legacy Lambda

公式Lambdaチュートリアルを例として扱い、Lambda開発で自動テストを導入していくお話

スライド:
https://speakerdeck.com/twada/testable-lambda-working-effectively-with-legacy-lambda

動画: https://www.youtube.com/watch?v=C0zNc4bdWhY


t_wadaさんの講演?

拙記事もご覧ください(ご本人にはてぶして頂いて嬉しい)。

“t_wadaさんの講演を聞いたのは初めてでしたが、その分かりやすさにとても驚きました。概念の説明も実例の説明もすごく分かりやすく、一度聞いただけなのにすんなりと頭に入ってきました” ありがとうございます! / “AWS Sum…” https://t.co/mMLSWYoPwF

— Takuto Wada (@t_wada) June 22, 2017

“TLにオーラでテストを書かせてこそ本物と流れていましたが、たしかにt_wadaさん見てオーラを近くで感じるだけでテスト書けそうな気がしてきました” オーラ…… https://t.co/mUmzeZUETN

— Takuto Wada (@t_wada) June 22, 2017

http://biibiebisuke.hatenablog.com/entry/2017/06/03/132538


講演内容

AWS公式のLambdaチュートリアルのコードをリファクタリングしながらテストを書いていく

  • ローカル環境でのテスト
    localstack超便利
  • 本番環境相当のテスト
    AWS SAMを利用したCI環境の構築 ← 今日はこれについて
  • production環境でのサービス間のテスト

題材

構成としては、本家のLambdaチュートリアルと同様。

srcBucketにファイルが格納されたら何らかの処理を行い、結果をdestBucketに吐き出す。

lambda-flow.png

引用: http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-s3-example.html


SAM(Serverless Application Model)とは

  • サーバレスアーキテクチャ構築フレームワーク
  • CloudFormationの拡張
  • サーバーレスアプリケーションのリソースに最適化された専用のリソースタイプを定義できる
  • 本家にサンプル色々ある

AWS Summit 2017での吉田さんの講演がとても参考になります
動画: https://www.youtube.com/watch?v=ZDvcCY8QRWA

参考:
https://aws.amazon.com/jp/about-aws/whats-new/2016/11/introducing-the-aws-serverless-application-model/
http://dev.classmethod.jp/cloud/aws/aws-serverless-application-model/


実現したいCI環境

push後ブランチごとに実際のAWSサービスを利用した環境を立ち上げて、テストが終わったら使用した環境を削除したい(CircleCI使用)。

  • スタック名をブランチを含む形にしたい
  • テストで使用するリソース(今回はS3のバケット)も、ブランチ名を含む命名規則とし、想定可能な名称にしたい

リソースの名称を指定しないと下記のようにユニークな値を振ってくれるが、それではテストで利用できない(「hogeバケットにファイルが存在すること」など)。

例
arn:aws:iam:*******:role/lambda-tutorial-ProcessorFunctionRole-1GFMCGG1ORHNM

実現したいCI環境

例として、

  • CloudFormationスタック名

    ${プロジェクト名}-${ブランチ}
例: lambda-tutorial-develop
  • Sourceバケット名

    ${プロジェクト名}-\${ブランチ}-source
例: lambda-tutorial-develop-source

などなど


実現したいCI環境

後掃除もしっかり

  • S3のバケットはオブジェクト(ファイル)が存在している場合は消せないので、delete-stackを実行する前にs3バケット内のオブジェクトを削除しておく必要がある

具体的な設定(CircleCI編)

CircleCIの環境変数

  • PROJECT_NAME: lambda-tutorial
  • REGION
  • S3_BUCKET: CloudFormationのソース置き場
  • CIRCLE_BRANCH: CircleCIで保持している環境変数。ブランチ名を格納している

具体的な設定(CircleCI編)

circle.yml

machine:
  timezone: Asia/Tokyo
  node:
    version: 6.1.0
dependencies:
  override:
    - sudo pip install awscli
    - npm install
  post:
    - aws configure set region $REGION
test:
  pre:
    - aws cloudformation package --template-file app-spec.yml --output-template-file app-spec.deploy --s3-bucket $S3_BUCKET_NAME
    - aws cloudformation deploy --template-file app-spec.deploy --stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}" --capabilities CAPABILITY_NAMED_IAM 
  override: 
    - mocha test/large/index-test.js --timeout 10000
  post:
    - aws s3 rm --recursive s3://"${PROJECT_NAME}-${CIRCLE_BRANCH}"-source
    - aws s3 rm --recursive s3://"${PROJECT_NAME}-${CIRCLE_BRANCH}"-dest
    - aws cloudformation delete-stack --stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}"
deployment:
  production:
    branch: master
    commands:
      - aws cloudformation package --template-file app-spec.yml --output-template-file app-spec.deploy --s3-bucket $S3_BUCKET_NAME
      - aws cloudformation deploy --template-file app-spec.deploy --stack-name "${PROJECT_NAME}}" --capabilities CAPABILITY_NAMED_IAM

ポイント(CircleCI編)

  • --capabilities CAPABILITY_NAMED_IAMつけないとダメ
  • CloudFormationへデプロイ時に--stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}"のように、stack名にブランチ名を含めてしまうこと

SAM(CloudFormation)のテンプレートでブランチ名を取得するよりCircleCIで取得する方がはるかに楽。

test:
  pre:
    - aws cloudformation package --template-file app-spec.yml --output-template-file app-spec.deploy --s3-bucket $S3_BUCKET_NAME
    - aws cloudformation deploy --template-file app-spec.deploy --stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}" --capabilities CAPABILITY_NAMED_IAM

ポイント(CircleCI編)

  • S3バケット内にオブジェクトが残っているとdelete-stackできないので、先にオブジェクトを削除しておく
post:
    - aws s3 rm --recursive s3://"${PROJECT_NAME}-${CIRCLE_BRANCH}"-source
    - aws s3 rm --recursive s3://"${PROJECT_NAME}-${CIRCLE_BRANCH}"-dest
    - aws cloudformation delete-stack --stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}"

設定(SAM編)

app-spec.yml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: A function that is triggered off an upload to a bucket. It does something to the uploaded file and put the proccessed file to another bucket. 
Resources:
  ProcessorFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs6.10
      CodeUri: ./
      Timeout: 40
      Policies: AmazonS3FullAccess
      Environment:
        Variables:
          STACK_NAME: !Sub "${AWS::StackName}"
      Events:
        ImgUpload:
          Type: S3
          Properties:
            Bucket: !Ref SourceBucket
            Events: s3:ObjectCreated:*
  SourceBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-source"
  DestinationBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-dest"

ポイント(SAM編)

  • スタック名の取得
    CloudFormationの擬似パラメータで、!Sub "${AWS::StackName}"でスタック名を取得できるので、こちらを利用する。

デプロイ時にスタック名にブランチ名も含めて渡しているのでapp-spec.ymlではブランチ名について考慮する必要はない。


その他はまりどころ

  • ブランチ名はハイフンを使うこと

CloudFormationのスタック名はアンダーバーを使えない。
スタック名: lambda-tutorial-update_sam_configurationはinvalidになってしまう


触れられなかったお役立ち資料

SAMの概要から好ましいディレクトリ構成、CIパイプラインの構築まで幅広く非常に詳しく説明されています。 

私の設定ではディレクトリ構成やLambdaパッケージに含むファイルの選別が雑なところがあるので、こちらを参考にして直していきたいと思います。


最後に

ご清聴ありがとうございました

続きを読む

AWS 認定ソリューションアーキテクト – プロフェッショナル を受験した感想

先日、AWS 認定ソリューションアーキテクト – プロフェッショナル を受験してきました。

結果は残念ながらの不合格ですが、今後受験する人の参考になればと簡単に試験の内容と対策などをまとめられたらと思います。

試験概要

詳細な内容は 公式サイトにあるのですが、簡単にまとめると、AWS の各サービスを使って、高い可用性・耐障害性なアーキテクチャを与えられた要件に基づいて選択・設計できるかを確認する試験です。

勉強期間

1ヶ月ぐらいです。
だいたい仕事の前と終わり、土日は気が向いたら喫茶店とかで勉強するスタイルでした。

勉強法

この資格の一番辛いところは参考書がないとこです。
そのため、AWSが提供している、ホワイトペーパーだったり、BlackBelt、各サービスのドキュメントを中心に読み込みつつ、デザインパターン周りの本を読んで各サービスの仕様と使い所を覚えていきました。

その他にサンプル問題と模擬試験も合わせて受験し、実際にどういった問題や時間配分で問題を解いていけばいいかも確認。

試験当日

当日は早めに試験会場付近の喫茶店に到着して、軽く復習してからのレッドブルで頭をキレキレにして試験に臨みました。

試験結果

総合スコア: 53% 

トピックレベルのスコア: 

1.0 High Availability and Business Continuity: 58% 

2.0 Costing: 50% 

3.0 Deployment Management: 62% 

4.0 Network Design: 50% 

5.0 Data Storage: 58% 

6.0 Security: 43% 

7.0 Scalability & Elasticity: 53% 

8.0 Cloud Migration & Hybrid Architecture: 57% 

どの分野も平均的に 50% ですが、よく見るとデプロイ周りが他より少しできているのは、実際に業務でデプロイ関連のサービスを使ったことがあるのが要因の一つかもしれません。

ちなみに、合格ラインに関してはAWS側からは特別公表していないようなので正確な合格ラインはわからないのですが、いろんな人の受験したブログや記事を読むとどうやら 65% あたりが合格ラインのようです。

試験の振り返り

試験内容は模擬試験とほぼ変わらず(似た問題もチラホラ)、択一選択問題、複数選択問題、状況把握問題となっていて、内容も各AWSサービスの詳細な仕様を問うのではなく、その仕様を理解した上で、求められている課題をどうやって解決できるのかを問う問題ばかりでした。そこは、やはりアソシエイトの試験とは大きく違うところだと思います。

その他に試験全体の傾向として、オンプレとAWSの連携が絡む問題が多く (VPNやダイレクトコネクトなど)、ネットワークの知識が弱いと少し苦戦する印象でした。- 自分がそう(悲)

まとめ

なんでもそうですが、結果ではなくそこに到達する過程が大事だと思っています。(言い聞かせてます)
不合格になってしまったのは気持ち的にも金銭的にもかなり辛いですが、また機会があればリベンジして合格を勝ち取りたいと思います。

続きを読む