フロントエンド環境+CircleCI+AWS環境構築メモ

0.やること

  • WebpackベースでReact&Redux環境を構築する
  • GitHubにプッシュしたらCircleCIが自動テストを行い、S3に用意した検証環境にデプロイ
  • テスト結果をSlackに通知する

準備物

  • AWSのIAMユーザー情報
  • S3バケット
  • GitHubアカウント(BitBacketでもOK)

1.React&Redux&Webpack

ベースとなる環境はreact-redux-starter-kitを利用しました。公式が提供しているcreate-react-appと迷いましたが、Reduxとreact-routerが設定済みということもありreact-redux-starter-kitを選択しました。

react-redux-starter-kitはreact-routerのバージョンが3系なので、開発の様子を見てアップデートしていく必要がありそうです。

Node.jsは推奨版が6系でしたが、8系でも特に問題なく動作したのとNode.jsはあっという間ににバージョンアップされるのでNodeは最新版を選択しました。

$ node -v
v8.4.0
$ npm -v
5.4.2

react-redux-starter-kitでプロジェクト作成
$ git clone https://github.com/davezuko/react-redux-starter-kit.git <PROJECT_NAME>
$ cd <PROJECT_NAME>
$ npm start

http://localhost:3000/ にアクセスしてアヒルの画像が表示されたら環境構築成功です。

webpack-dev-serverが起動しているので、ソースの変更、保存を検知して自動でリロードしてくれます。ディレクトリの構成はAtomicDesignで構成したいので実際の開発ではかなり触ります。

[参考資料]

React + ReduxのプロジェクトにAtomic DesignとImmutable.jsを使ったらいい感じになった話

アメブロ2016 ~ React/ReduxでつくるIsomorphic web app ~

2.GitHubへのプッシュを検知してCircleCIが自動テストと検証環境へのデプロイを行う

CrcleCIとGitHubを接続

CircleCIとGitHubを連携します。CircleCIの公式から「Start Building Free」→「Start With GitHub」の順に進みます。GitHubのアカウントでログインした後「Project」ページの「Add Project」をクリックします。GitHubでログインしている場合はのリポジトリをが自動的に読み込んでくれるので、利用するリポジトリを選択します。Setup Projectの設定はそのままで「StartBuilding」をクリックして完了です。

CircleCIとAWSを接続

ソースコードをAWSのS3にデプロイするので、CircleCIとAWSを連携させます。「Project」→「Setting」→「AWS Permissions」に進んでAccessKeyIdとSecretAccessKeyを入力して完了です。

circle.ymlを作成

CircleCIで行いたいことはcircle.ymlに書きます。今回はESLintの構文チェック結果とKarmaのテスト結果をTestSummaryにレポートを表示させます。

circle.yml
machine:
  node:
    version: 8.4.0
  post:
    - npm install -g npm@5
  timezone: Asia/Tokyo

dependencies:
  pre:
    - sudo pip install awscli

test:
  override:
    - ./node_modules/.bin/eslint --format=junit -o $CIRCLE_TEST_REPORTS/eslint/report.xml .
    - cross-env NODE_ENV=test karma start build/karma.config --reporters junit

deployment:
  branch: master
  commands:
    - npm run build
    - cp -Rf dist/. ./
    - aws s3 cp dist s3://<S3_BACKET_NAME>/ --recursive --acl public-read

circle.ymlの記述方法

machine:

仮想マシンの設定を記述します。デフォルトでもNodeをインストールしてくれますが、バージョンが0系だったのでフロントの環境に合わせて8系をインストールするように設定しました。postは指定したコマンドの後に実行されます。この例ではNodeをインストールした後にnpmのバージョンを上げています。逆に指定したコマンドの前に行いたい処理はpreに記述します。

dependencies:

プロジェクト固有の依存関係をインストールします。今回はaws-cliを利用するのでここでインストールしました。

test:

ここで実際のテストが走ります。package.jsonのtestを自動的に実行してくれるのですが、今回はjunitのxmlを出力してCircleCI上でレポートが見たいのでoverrideを記述してpackage.jsonのtestを上書きました。

deployment:

Webサーバにコードを展開します。今回はシングルページアプリケーションで、ビルドされたソースは静的なので、AWSのS3を選択しました。ここでリポジトリ上のソースをそのまま展開できればいいのですが、webpackでReactをビルドする必要があるので、package.jsonにか書かれているnpm run buildを走らせます。その後生成されたdistフォルダをコンテナのルートに移動させてからaws-cliのコマンドでS3にアップロードしています。branch: masterはmasterブランチにプッシュされた場合のみ実行する記述です。

[参考資料]
Configuring CircleCI

AWS S3にデプロイ

作成したバケットにStatic website hostingを有効します。
※検証環境で利用するのにBasic認証が必要でした。S3にBasic認証をかけるのには一手間必要なので今後CodeDeployを利用してEC2にデプロイしたいと思っています。

Slackと接続

通知したいSlackのWorkspaceのURLを用意します。「Project」→「Setting」から「ChatNotification」に進み、SlackのURLを入力して「Save」します。

これで準備はOKです。

3.動作チェック

適当にソースを変更してmasterブランチにプッシュします。今はmaterに直接プッシュしていますが、開発ではタスクごとのブランチにプッシュしてテストが通ったらmasterやreleaseブランチにプルリクエストを飛ばしてmaterブランチにマージ、プッシュされたらS3に展開という運用を考えています。今回はテストが成功しようが失敗しようが問答無用にS3に展開されます。

circle.ymlに書かれたプロセスが順に実行されています

task1.png

4.結果

TestSummaryに出力

task3.png

Reactがビルドされてサーバに展開

スクリーンショット 2017-09-29 22.15.29.png

Slackへの通知

スクリーンショット 2017-09-29 22.16.36.png

感想

  • CIツールそのものの環境構築を意識せず導入できるので取っ付き易い
  • 基本的な設定はpackage.jsonのscriptとcircle.ymlの記述だけで済むので設定が簡単
  • 黒画面でできる事は大体実現できる

CircleCIは出来ることが多いので、この環境をベースに試行錯誤しながらベストプラクティスを見つけたい思います:v_tone2:

続きを読む

【AWS】Elastic Beanstalkのデプロイ時に docker exec する

先に結論

Beanstalk のオートスケーリング設定が有効になっている状態で複数インスタンスにデプロイする際に、どれか一つのインスタンスだけで DB マイグレーションのコマンドを実行したいとします。
その場合、以下のような設定ファイルを追加してデプロイすると実現できます。

.ebextensions/post_migration.config
container_commands:
  01_migrate: # リーダー判定用の一時ファイルを作成
    command: "touch /tmp/leader_only"
    leader_only: true

files:
  "/opt/elasticbeanstalk/hooks/appdeploy/post/10_post_migrate.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash -eu
      if [ -f /tmp/leader_only ] # リーダーインスタンスでのみ実行
      then
        # リーダー判定用の一時ファイルを削除する
        rm /tmp/leader_only
        # 最後に起動したコンテナ上でマイグレーションコマンドを実行する (CakePHP3の場合)
        docker exec `docker ps -l -q` bin/cake migrations migrate
      fi

上記の説明

container_commands でマイグレーションせずに post hook スクリプトでマイグレーションするという回りくどい手順になっていますが、そこら辺の事情をデプロイ時の流れと共に説明します。

Beanstalk (Docker) のデプロイ時の流れ

1. pre hook スクリプトの実行:

  • 1-1. /opt/elasticbeanstalk/hooks/appdeploy/pre/00clean_dir.sh

    • デプロイの準備。/var/app/current の初期化などを行う。
  • 1-2. /opt/elasticbeanstalk/hooks/appdeploy/pre/01unzip.sh
    • アプリケーションを unzip して /var/app/current へ展開する。
  • 1-3. /opt/elasticbeanstalk/hooks/appdeploy/pre/02loopback-check.sh
  • 1-4. /opt/elasticbeanstalk/hooks/appdeploy/pre/03build.sh
    • /var/app/current にある Dockerfile OR Dockerrun.aws.json を元に Docker Image を作成 (docker build OR docker pull) する。

2. .ebextensions の container_commands の実行:

  • 2-1. .ebextensions/*.config に container_commands がある場合、順にそのコマンドが実行される。

    • 既に新バージョンのアプリは既に unzip 済みのため、それらに触れることができる。
    • このとき、新バージョン docker コンテナは まだ起動していない。

参考: .ebextensions の container_commands の挙動メモ – Qiita

3. enact hook スクリプトの実行:

  • 3-1. /opt/elasticbeanstalk/hooks/appdeploy/enact/00run.sh

    • 03build.sh で作成したイメージを docker run -d する。
  • 3-2. /opt/elasticbeanstalk/hooks/appdeploy/enact/01flip.sh
    • staging-appcurrent-app にする。

4. post hook スクリプトの実行:

  • 4-1. /opt/elasticbeanstalk/hooks/appdeploy/post/00_clean_imgs.sh

    • 未使用のイメージやコンテナを削除する。
  • 4-2. /opt/elasticbeanstalk/hooks/appdeploy/post/01_monitor_pids.sh

上記のような流れのため、デプロイ時に docker exec したい場合は 00run.sh の以降で行う必要があります。container_commands のタイミングでは駄目です。
その為 .ebextensions で post hook スクリプトを追加し、そこで docker exec するという方法をとっています。

また、オートスケールの設定をしている場合 post hook スクリプトはデプロイされる全てのコンテナ上で実行されるため、そのままだとマイグレーションが何度も実行されることになります。
その為、リーダーインスタンスの場合のみ事前に /tmp/leader_only のファイルを作成しておき、そのファイルがある場合にのみ post hook スクリプトを実行するようにしています。

container_commands の leader_only オプションについて:

Elastic Beanstalk によって選択された単一のインスタンスでコマンドを実行するのみです。リーダー専用コンテナコマンドは、他のコンテナコマンドより前に実行されます。コマンドはリーダー専用または test を持つことができますが、両方はできません

http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/customize-containers-ec2.html#linux-container-commands

参考

続きを読む

codedeploy-agentのキャッシュを削除したら

codedeployを使っている場合、ソースコードのキャッシュが

/opt/codedeploy-agent/deployment-root/[デプロイグループID]/

というディレクトリに溜まっていきます。
このディレクトリは5世代まで?保持されますが、インスタンスのディスク容量を圧迫するので、やむを得ず消さなければならない場合があります。
しかし、無闇に削除すると次回以降のデプロイが以下のようなエラーで失敗するようになります。

No such file or directory - /opt/codedeploy-agent/deployment-root/[デプロイグループID]/[デプロイID]/deployment-archive/appspec.yml

これは、codedeploy-agentが直前のリビジョン(デプロイID)を探すためですが、前回のデプロイ情報は

/opt/codedeploy-agent/deployment-root/deployment-instructions/

以下に格納されているので、このディレクトリ以下にあるファイル(デプロイグループIDがファイル名の頭についています)を全て削除してデプロイすれば、新規デプロイと同様の挙動になります。

続きを読む

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に変わってますね!この仕組みを利用すれば環境変数などもステージにより使い分けることができますので、より捗ります!

最後に

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

続きを読む