[レポート] FUKUOKA Engineers Day 2018 で サーバーレスについて登壇してきました #edayfuk …

サンプルコード · AWS Serverless Application Model (AWS SAM) · AWS SAM Local と LocalStack を使って ローカルでAWS Lambdaのコードを動かす · AWS Cloud9からSAM Localをためしてみる #serverless #adventcalendar #reinvent · AWS SAM/CircleCI/LocalStackを利用した実践的なCI/CD – Classmethod … 続きを読む

~/.aws/(config|credentials) の設定から assume roleするラッパーをgolangで実装して、goreleaserでリリースしてみた

最近のgolangのCI周りを勉強する目的で、fujiwaraさんのaswrap – ~/.aws/(config|credentials) で定義した AssumeRole 定義から一時キーを取得してコマンドを起動してくれる wrapperをgolangで再実装してみた。

-> https://github.com/masahide/assumer

まだMFA対応のtodoが残ってたり本家より劣化しているところはありますが、一時キーのキャッシュ保存に対応させたり、rpm,deb,brewのパッケージを作成したので導入が簡単なところぐらいが少ない取り柄

今回やりたかったこと/やったこと

  • goreleaserを使ってrpm,deb,homebrewのパッケージのリリースを自動化
  • codecov.ioでカバレッジの可視化
  • gometalinterで行単位でのignore設定

goreleaser

golang製のソフトウェアのリリース処理を全部引き受けてくれてる便利なツールです。具体的には・・

  • goのクロスコンパイル
  • バイナリのtar.gzアーカイブやrpm,debパッケージ、dockerイメージの作成
  • github.comのGithub Releasesへの添付
  • dockerhubへの登録
  • homebrewのFormula作成
    などかなり幅広く対応しています。

使い方に関しては、 goreleaserを使ってGoで書いたツールのバイナリをGithub Releasesで配布する
を参考にしつつ、goreleaser自身の.travis.yml.goreleaser.ymlがとても参考になるのでこの辺りを真似ながらで基本的に問題ないかと。

codecov.ioでカバレッジの可視化

以前、 golangの静的解析,カバレッジ解析,バイナリリリースをCircleCIで簡単に整えるで使ったcoverallsより導入が簡単だった。
事前にcodecov.ioでトークンを取得して、travisのenvにCODECOV_TOKENとして設定しておいて、あとは、基本的にはこちらもgoreleaserの.travis.ymlを参考にしましたが

.travis.yml
after_success:
  - bash <(curl -s https://codecov.io/bash)

これだけで良いみたいですね。

gometalinterで行単位でのignore設定

gometalinterで様々な静的解析が走るけどその解析ツール毎にignoreを設定するのは大変だなぁと思ってたんですが・・・

https://github.com/masahide/assumer/blob/master/cmd/assumer/main.go#L170

defer cf.Close() // nolint errcheck

のように行単位で// nolint <解析ツール名> でチェックを除外できるようです。
comment-directives に記載されてます。

続きを読む

AWS GreengrassにKerasのモデルをデプロイしてみた

AWS GreengrassにKerasのモデルをデプロイしてみました。

きっかけ

Re:Invent 2017で発表された新サービス「AWS Greengrass ML Inference」にプレビュー申請したところ、残念ながら結果はNot Approved。

GAまで待つのもちょっと悔しいので、普通のGreengrassにkerasのモデルをデプロイしてみることにしました。

必要なもの

  • AWSアカウント
  • Raspberry Pi

作業概要

  1. Kerasの環境準備(Mac)
  2. greengrassチュートリアル実施
  3. Raspberry PiにKeras等をインストール
  4. Kerasのモデル作成
  5. デプロイ用のLambda作成
  6. Greengrassへデプロイ
  7. 動作テスト

1. Kerasの環境準備(Mac)

MacにKerasの環境を準備します。

$ brew upgrade pyenv
$ pyenv install 2.7.14
$ pyenv virtualenv 2.7.14 keras
$ cd hoge/huga
$ pyenv local keras
$ pip install tensorflow jupyter keras h5py

2. Greengrassチュートリアル実施

Raspberry Piの環境構築を兼ねて、AWSドキュメントにあるGreengrassのチュートリアルを実施します。

「モジュール 3-I: AWS Greengrass での AWS Lambda」までの実施でOKです。

3. Raspberry PiにKeras等をインストール

こちらの記事を参考にさせて頂きました。
Raspberry Piにsshでログインしてインストールします。
熱暴走するかもとの事だったので、自分はUSB扇風機で風を当てながら一晩熟成させました。

$ sudo pip install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastStableBuild/artifact/output-artifacts/tensorflow-1.5.0rc1-cp27-none-any.whl
$ sudo pip install keras
$ sudo apt-get install python-h5py

4. Kerasのモデル作成

今回はkerasのexampleからMNISTの文字分類のソースコードを拝借して、Kerasのモデルを作成します。

1. 上記ソースコードをダウンロードする
2. 下記3行を追記して用意した環境で実行する

model.save('mnist_mlp.h5')
np.save('x_test.npy', x_test)
np.save('y_test.npy', y_test)

3. 実行後、下記3ファイルが生成される

  • mnist_mlp.h5 (Kerasのモデル)
  • x_test.npy (画像データ)
  • y_test.npy (画像データに対応する正解ラベル)

5. デプロイ用のLambda作成

GreengrassへデプロイするLambdaを作成します。

1. BlueprintsからLambdaを作成する
AWSマネジメントコンソールでLambdaを選択後、blueprintsから「greengrass-hello-world」を選択して、Lambdaを作成します。
ロールはチュートリアルで作成したものを指定してください。
2. ソースコードを置き換える
AWSマネジメントコンソール上で、Lambdaのコードを下記へ置き換えます。

from __future__ import print_function


import greengrasssdk
from threading import Timer
import time
import keras
from keras.models import load_model
import numpy as np
import random

client = greengrasssdk.client('iot-data')
x_test = np.load('x_test.npy')
y_test = np.load('y_test.npy')
x_test = x_test.reshape(10000, 784).astype('float32') / 255
model = load_model('mnist_mlp.h5')


def greengrass_keras_prediction_run():
    r = random.randrange(10000)
    prediction = model.predict(x_test[r].reshape(1, 784))
    predicted_value = np.argmax(prediction[0])
    answer = y_test[r]

    message = 'predicted value: {0}, answer:{1}'.format(predicted_value, answer)
    client.publish(topic='keras/prediction', payload=message)

    Timer(5, greengrass_keras_prediction_run).start()


greengrass_keras_prediction_run()


def function_handler(event, context):
    return

3. デプロイメントパッケージをダウンロードする
AWSマネジメントコンソールから、Lamdbaのデプロイメントパッケージをダウンロードします。
4. mnist_mlp.h5 / x_test.npy / y_test.npyの3ファイルをデプロイメントパッケージに含める
ダウンロードしたデプロイメントパッケージを展開後、3ファイルを含めて再度zip圧縮します。
zipファイルにはフォルダを含めないように注意してください。

$ zip -r ../keras_prediction.zip *

5. デプロイメントパッケージをアップロードして、Lambdaを更新する
6. 新しいバージョンを発行して、発行したバージョンに対しエイリアスを作成する
手順はGreengrassのチュートリアルと同じです。

6. Greengrassへデプロイ

手順はGreengrassのチュートリアルと同じです。Greengrassのコンソール画面から操作します。
1. Lamdbaを登録する
一覧から作成したLambdaを選択後、Lambdaのエイリアスを指定して登録します。
2. Lamdbaの設定を変更する

  • タイムアウト:25秒
  • ライフサイクル:Make this function long-lived and keep it running indefinitely

3. subscriptionを追加する

  • ソース:Lambda
  • ターゲット:IoT Cloud
  • トピック:keras/prediction

subscription.png

7. 動作テスト

1. Greengrassのコンソール画面の左側のTestをクリック
2. Subscription Topicにkeras/predictionを指定
3. Subscribe to topicをクリック
下記が表示されれば成功です。
test2.png

雑感

AWS Greengrass ML Inferenceでは、上記のように煩雑でなく簡単に学習モデルがデプロイできるようになるでしょうか。
似たようなサービスにAzure IoT Edge(こちらも未だプレビュー)がありますが、今度はこっちをさわってみたいと思います。

続きを読む

Docker導入するべき?するべきではない?

これは何?

Dockerを導入するにあたって、漠然としたイメージしかないという方も多そうなので、

  • どういうシステムに導入したらいいのか?
  • どういうシステムなら導入しないほうがいいのか?
  • 導入までにどんなことしないといけないのか?

をまとめてみました。
つっこみあればお願いします!


対象

下記のような方を対象として記載しています。

  • Docker自体はなんとなく分かったけど、自分の組織でやった方がいいのかよく分からない
  • 導入の検討しろって言われてるけど、具体的な内容まで落とせない

一般的なコンテナ(Docker)の特徴/メリット


  • パフォーマンス

    • 仮想マシンと比較すると、オーバーヘッドが少なく軽量
    • 起動が高速
  • 再現性、ポータビリティ

    • Dockerが動く環境であれば環境に依存しない
    • 1つのコマンドを実行した状態を再現
    • ホストと分離できる
  • コードで管理できるのでバージョン管理が可能

    • ロールバックが容易

メリットを活かすために必要なこと


  • アプリケーションのマイクロサービス化

    • 1サービス1コンテナ
    • 永続データの考慮
      • ステート情報
      • 共有データ
      • ログ
  • イミュータブルな環境の構築

    • CI/CDシステムの導入

      • バージョン管理システムとの連携
      • テストの自動化
      • デプロイ/ロールバック
  • オーケストレーションツールの導入

    • クラスタの管理
    • スケジューリング
    • スケーリング

他のAWSソリューションとの違い


CodeDeploy

  • OSの状態は再現できない
  • コードのみのロールバックなので、OSの変更には対応できない
    • コンテナはイメージごとロールバック

AMI運用

  • イメージの容量が大きい

    • 起動に時間がかかる
  • 変更作業の負担が大きい
    • インスタンス起動 → 変更 → イメージの保存 → インスタンスの削除
    • Dockerはコードの修正 → 再ビルド
      • CI/CDシステムがあればさらに容易

コンテナに対する誤解 (クラウドで使う場合)


  • オーバーヘッドが少ないのでパフォーマンスがいい

    • 仮想サーバとの比較であって、クラウド上で使う場合は コンテナ on 仮想サーバ になるのでオーバーヘッドは増える
  • どこでも同じ環境を再現できる

    • コンテナは環境に依存しないが、クラウドで利用する場合、LB等のクラウドサービスと組み合わせることが多いので、その違いの考慮は必要
  • 同一ホストにコンテナを相乗りさせることによに費用削減が可能

    • 1ホストを割り当てる必要がないレベルのコンテナがばかりであれば正しいが、ある程度のリソースが必要なコンテナであればトータルのリソース利用量はあまり変わらない

導入の問題点/課題


  • 構成が複雑になる

  • リソース管理/分離が難しい
  • 学習コスト
  • 組織の体制、線引
    • Dev と Ops

コンテナに向く/向かないシステム


向くシステム

  • システムの変更が活発に行われる
  • アップデート等の変更に対応していく必要がある
  • バッチ処理のために起動するシステム

向かないシステム

  • システムの変更がほとんどない
  • 長期の安定性が求められる
  • ライセンス管理、保守サポートが必要

導入のモチベーション


解決したい課題は何か?


共通インフラをつくりたい → X

  • すべてのアプリケーションがコンテナに向いているわけではない

そのまま移行したい → X

  • コンテナ化すること自体に意味はない

費用削減 → X

  • 使用するリソースは減らない

パフォーマンス向上 → ☓

  • クラウドサービス上で使う場合、コンテナ on 仮想マシンになる
  • マイクロサービス化した場合、コンテナ(サービス)間はネットワークを介するので、そのオーバーヘッドも発生する

運用負荷軽減 → △

  • 頻繁に変更が発生する場合で、CI/CD Pipelineの仕組みを適切につくれている場合は負荷の軽減は可能
  • CI/CD Pipelineの構築には試行錯誤が必要

変化への対応を容易にしたい → ◯

  • アプリケーションのアジリティを高める

導入に向けてやらないといけないこと


  • アプリケーション(再)設計

    • マイクロサービス化
    • 再実装
    • コードリポジトリの作成/導入
  • Dockerイメージの作成

    • Dockerfileの作成
    • コンテナリポジトリの作成/導入
  • インフラの設計/構築

    • オーケストレーションツールの導入
  • CI Pipelineの作成

  • 監視/運用フローの確立


AWSで利用できるDockerオーケストレーションサービス


Amazon ECS (Amazon EC2 Container Service)

  • AWS独自のオーケストレーションツール
  • 料金
    • ホスト(EC2)利用料金のみ発生
    • スポットフリート等のコスト削減に関するサービスが利用可能

AWS Fargate

  • クラスタ、ホストの管理をAWSが提供するサービス

    • ユーザー側でインフラ運用が不要
  • re:Invent2017でリリース
  • 東京リージョン未対応 (2018年1月現在)
  • AWS独自の概念
  • 料金
    • 同スペックのコンテナをスポットフリートで構成した場合に比べると高額

Amazon EKS (Amazon Elastic Container Service for Kubernetes)

  • AWSが提供するKubernetesのマネージドサービス
  • re:Invent2017で発表
  • プライベートベータが間もなく?(2018年1月現在)
  • 東京リージョンに来るのは・・・?

まとめ

  • メリットを理解し、導入するシステムの選定が必要
  • 導入に際しやらなければいけないことを整理し、自分の組織で対応できるかの見極めが必要
  • クラウドのマネージドサービスを理解し、うまく活用する

続きを読む

AWS S3でMavenリポジトリを構築する

Mavenリポジトリが必要な場合

社内などプライベートな環境でJavaライブラリを管理したい場合は多いと思います。
ある程度の規模になるとNexusを導入したりしますが、もう少し手軽に実現したい時もあります。
このエントリは、AWS S3を利用してMavenリポジトリを構築する方法です。

手順

以下の順でMavenリポジトリを作成、使用します。
1. S3にMavenリポジトリ用のBucketを作成
2. S3のMavenリポジトリにアクセスするためのユーザ作成
3. Gradleのpluginでライブラリの登録設定
4. ライブラリを利用するためのクライアント設定

1. Mavenリポジトリ用のBucketを作成

特筆すべきことはなく通常通り、S3のBucketを作成します。
ここではmy-mavenというBucketを作成したとします。

2. Mavenリポジトリにアクセスするためのユーザ作成

必須ではないですが、適切なアクセス制御のために、Mavenリポジトリ用のユーザを作成し、S3のアクセス権限を追加します。
また、このタイミングでAWSのAccess key IDSecret access keyを取得します。

アクセスポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::my-maven",
                "arn:aws:s3:::my-maven/*"
            ]
        }
    ]
}

3. Gradleのpluginでライブラリの登録設定

maven-publishプラグインを適用し、ライブラリを登録するための設定を行います。

build.gradle
apply plugin: 'maven-publish'

def tag = System.getenv('CIRCLE_TAG') // git tagのプッシュを検知 (CircleCIの場合の例)
def buildVersion = "1.0.0"
group = 'com.example'
version = tag ? "${tag}-RELEASE" : "${buildVersion}-SNAPSHOT" // tagプッシュの場合RELEASE、それ以外はSNAPSHOTとする (このあたりは実際の運用に合わせて指定)

// リポジトリ登録するライブラリにソースも含めるため
task sourceJar(type: Jar) {
    from sourceSets.main.allJava
}

publishing {
    repositories {
        maven {
            url "s3://my-maven"
            credentials(AwsCredentials) {
                accessKey System.getenv('AWS_ACCESS_KEY_ID')
                secretKey System.getenv('AWS_SECRET_ACCESS_KEY')
            }
        }
    }
    publications {
        mavenJava(MavenPublication) {
            from components.java
            artifact sourceJar {
                classifier "sources"
            }
        }
    }
}

以下のコマンドで、ソースのビルドと、リポジトリ登録を行います。
通常はCIなどを経由して利用することになると思います。

$ gradle publish

4. ライブラリを利用するためのクライアント設定

作成したMavenリポジトリをクライアント側で追加すれば、他のリポジトリと同様に利用できるようになります。

build.gradle
repositories {
    mavenCentral()
    // 以下を追加
    maven {
        url "s3://my-maven"
        credentials(AwsCredentials) {
            accessKey System.getenv('AWS_ACCESS_KEY_ID')
            secretKey System.getenv('AWS_SECRET_ACCESS_KEY')
        }
    }
}

まとめ

構築も簡単なので、ライブラリ管理が必要になったときの手段の1つとして有効です。
また、今回の例はGradleでしたが、Mavenでも同様のことができます。

続きを読む

SpringBootアプリケーションをCodePipelineを用いてEC2インスタンスに自動デプロイ

SpringBootで構築したアプリケーションをAWS CodePipelineを用いてEC2インスタンスに自動デプロイするための手順をまとめます。

構成

Codepipeline.png

  • Gitリポジトリ

    • GitHub(なんでも良い)
  • CI
    • Jenkins
  • Test & Build
    • Maven(Gradleでもそんなに変わらない)
  • APサーバ
    • SpringBoot 1.4.x on EC2

大まかな流れ

基本的に以下で紹介していただいた内容をもとに実施した。
SpringBootで構築したアプリケーションがgitにpushされたらCodeDeployで自動デプロイされる仕組み

開発者
1. 任意の(ここでは例としてmaster) branchにpush

Jenkins
1. 5分毎にポーリングし、develop branchが更新されていればpull
2. Test & Build(Maven)
3. Test & Buildが成功したらS3にリビジョンをアップロード

CodePipeline
1. S3からアップロードされたファイルを取得
2. CodeDeployを起動

CodeDeploy
1. jarファイルに実行権限を付与
2. CodeDeployから各インスタンスにSpringBootアプリがdeployされ、新しいバージョンのアプリが起動する。

サンプルコード

CodeDeployを利用した自動デプロイを行ったサンプルコード(GitHub)

追加で実施した作業

以下は、更新した箇所のみ記載。

AWS EC2インスタンスのJavaバージョンを1.8にする。

AWS EC2インスタンスのJavaバージョンがOpenJDK1.7だった。
Oracle JDK1.8をインストールすることを前提としているため、JDKのアップデートを行う。
参照:Amazon Linuxにjdk1.7 or 1.8インストール

SpringBootアプリケーションのサービス化

以下のページを参考にSpringBootアプリケーションのサービス化を行う。
Spring Bootでwarファイル作成&jarのサービス化

  • デプロイするjarファイル名:demo.jar
  • 起動するサービス名:demo

CodeDeploy

  • アプリケーション名:springboot-demo
  • アプリケーショングループ名:springboot-demo-group

appspec.ymlは今回の構成は以下のようにした。

appspec.yml
version: 0.0
os: linux
files:
  - source: demo.jar
    destination: /var/myapp/
    overwrite: yes
hooks:
  ApplicationStop:
    - location: scripts/appstop.sh
      timeout: 300
      runas: root
  ApplicationStart:
    - location: scripts/appstart.sh
      timeout: 300
      runas: root

また、サービス停止・起動用スクリプトは以下のようにした。

サービス停止用スクリプト

scripts/appstop.sh
#!/bin/sh
service demo stop

サービス起動用スクリプト

scripts/appstart.sh
#!/bin/sh
chmod u+x /var/myapp/demo.jar # jarファイルに実行権限を付与
service demo start

AWS CodePipeline

CodePipelineの設定を行う。
1.パイプライン名の登録

  • パイプライン名:demo-pipeline

Codepipeline-setting1.png

2.ソース取得場所設定
Codepipeline-setting2.png

3.ビルド設定
Jenkinsでビルド済みなので、ビルド設定はなし。
Codepipeline-setting3.png

4.デプロイ設定
上記、CodeDeployで設定したアプリケーション名およびアプリケーショングループ名を選択
Codepipeline-setting4.png

5.サービスロール設定
「ロールの作成」からロール名を登録する。
Codepipeline-setting5-1.png
Codepipeline-setting5-2.png

作成したサービスロールを設定する。
Codepipeline-setting5.png

6.「パイプラインの作成」ボタンを押下して完了。

[Jenkins]S3にリビジョンをアップロードする

1.サンプルコードを利用する場合、S3にアップロードするファイル群をzip形式にまとめる。
JenkinsのJob設定画面でシェルの実行を選択し、以下を追加する。

cd target
cp demo-0.0.1-SNAPSHOT.jar ../deploy/demo.jar
cd ../deploy/
jar -cMf demo.zip *

2.JenkinsのS3アップロードプラグインを利用して、zip化したファイルをS3にアップロードにする。
以下、設定画面の例。
[Destination bucket]には、CodePipelineで設定したS3バケットを指定する。
S3-setting.PNG

3.[保存]ボタンを押下して完了。

続きを読む

AWS SAMとServerless Frameworkを比較してみた

この記事はServerless Advent Calendar 2017 23日目の記事です。

最近Serverless Frameworkを使っていたのですが、先輩に「今の時代はAWS SAMだぞ」と言われ、気になったので比べてみました。

Serveless Frameworkの特徴

デプロイしやすい・速い

まずこれが一番の特徴ですね。
下記の例みたいにたったコマンド2つですぐ動かせるサーバーレスアプリケーションが出来上がります。

$ serverless create --template hello-world
$ serverless deploy

もし↑と同じことSAMでやろうとした場合:

  • リリースステージ用のバケットの作成
  • Lambda関数のコーディング
  • 設定ファイルを書く
  • Lambda関数のzip化
  • Cloudformationによるパッケージング

これらの作業を全て自分でやらなければなりません。
Serverless Frameworkを使うとこういったデプロイ前の準備作業をよしなにやってくれますね。

まぁスクリプトやらCIでそこは解決できるとは思いますが、そもそもそこに時間や手間をかけずに自分のアプリケーションだけに集中したい人であれば、Serverless Frameworkの方が圧倒的に使い勝手が良いのではないでしょうか。

連携可能なサービスが豊富

Serverless FrameworkはAWSだけでなく、Azure FunctionsやGoogle Cloud Functionsなど他社のクラウドサービスでも利用できます。
もちろんそれぞれのサービスの仕様や特性をある程度把握した上で利用するべきですが、Serverless Frameworkから利用する部分に関してはほぼ変わりません。
特にデプロイはどのサービスも同じコマンドでできます。

$ serverless deploy

様々なプラグインが利用できる

Serverless Frameworkは使い勝手がとても良いのですが、もちろんまだ足りない部分や痒い所に手が届かないときもあったりします。そういう時はプラグインで補ったりすることができます。
例えば、デプロイしたファンクション毎にDead letter queueをserverless-plugin-lambda-dead-letterで設定できたり、Serverless Frameworkの定義ファイル内でStep Functionsの設定を可能にするserverless-step-functionsなどがあります。
Serverless Frameworkのコミュニティ自体が大きいので、様々なプラグインが多数みつかるのも良い点だと思います。

AWS Serverless Application Modelの特徴

AWS関連サービスとの親和性が高い

Cloud Formationを拡張したサービスなので当たり前かもしれませんが、AWSリソースとの連携がしやすい印象でした。
もしすでにCloud Formationを使ってきた方であればあまり不自由なくSAM利用できるでしょう。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  PutFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs6.10

このように通常のCloudFormationのテンプレートに Transform: AWS::Serverless-2016-10-31 と1行追加すれば、SAMのテンプレートフォーマットを利用することができます。

ローカル環境でのテストが可能

事前にDockerのインストールが必要になりますが、AWS SAM Localをインストールすればローカル環境でのファンクションのテストが可能になります。

$ npm install -g aws-sam-local

以下のように実行したいファンクション名と渡したいリクエストのボディをjsonで指定するとテストが可能になります。

$ sam local invoke "FunctionName" -e event.json

また、Lambdaを起動するイベントのペイロードもエミュレートできます、以下が対象サービスです:

  • S3
  • Kinesis
  • DynamoDB
  • Cloudwatch Scheduled Event
  • Cloudtrail
  • API Gateway

生成したイベントのペイロードをローカルで起動するファンクションに以下のようにパイプラインで渡すことができます。

$ sam local generate-event s3 --bucket bucket-name --key xxxxx | sam local invoke "FunctionName" 

※ Serveless Frameworkもserverless-dynamodb-localserverless-offlineというプラグインをインストールすればローカルでのテストも可能ですが、独自の設定が必要な上Node.js限定という欠点があります。

まとめ

すこしサクッとさわってみて比べた印象ですが、今後他のクラウドサービスに切り替えたいかもしれない時やとにかくスピード重視でアプリケーションを動かしたいのであればServerless Frameworkがいいと思います。
もしアプリケーションをAWSのサービス中心で構成し、それなりに長く運用していくのであればAWS SAMが適しているかもしれません。
ただ、「アプリケーションを素早く本番運用できる状態にし、またサーバーやそれに関連するサービスの運用にかける時間をアプリケーションのコーディングに割り当てることを可能とし、ユーザーにより価値のあるサービスを提供する」といったサーバレスの思想に一番近いのはServerless Frameworkではないでしょうか。

続きを読む

AWS re:Invent 2017 DevOps関連セッションまとめ

まとめについて

re:Invent 2017 で行われたBreak Out Session から DevOps に関するオススメセッションを独断と偏見でピックアップしました。AWSだけに限った内容ではありませんので、DevOps開発プロセス、マネジメント、アーキテクチャ一般の勉強にもどうぞ。
なお、本投稿は個人の見解であり、所属企業とは関係がありません。

セッション動画(英語)のリンクをつけました。Slideshareもできるだけ拾いましたが資料が公開されていないものもあります。
できるだけYouTubeの動画を見ることをおすすめします。米国のカンファレンスは資料より話がメインです。多くは資料なんか見ないで話します。デモも多くあります。
英語が苦手な方はYouTubeの各種機能(英語字幕、自動翻訳による日本語字幕、文字起こし、スピード調整など)を使ってご覧になってください。英語字幕を見ながら聞くのはリスニングの勉強にもなります。

カテゴリは以下のとおり:

  • DevOps全般
  • Chaos Engineering
  • DevOpsを実現するためのアーキテクチャ
  • CI/CDパイプライン
  • CloudFormation
  • CLI
  • Management & Governance & Monitoring
  • DevOps ワークショップ

DevOps全般

Life of a Code Change to a Tier 1 Service (DEV206)

Launch Applications the Amazon Way (DEV203)

  • Amazonにおけるアプリケーション開発スタイルを紹介した後、Code Starのデモを中心にCode*サービス、プロビジョン、デプロイ系サービスの全体像を解説。
  • https://www.youtube.com/watch?v=ITNorHA9m6Q

Tools Won’t Fix Your Broken DevOps (DEV345) by DevOps Research and Assessment

Chaos Engineering

Performing Chaos at Netflix Scale (DEV334) by Netflix

DevOpsを実現するためのアーキテクチャ

Cisco’s Journey from Monolith to Microservices (DEV329)

  • 前半はAWSのSAがマイクロサービスにおける永続的データの管理方法について解説。これはいい内容。後半はCiscoが社内の既存データをマイクロサービスとして提供するためのアーキテクチャについて解説。
  • https://www.youtube.com/watch?v=Qv7iRDbxS6A

Embracing Change without Breaking the World (DEV319)

CI/CDパイプライン

Continuous Integration Best Practices for Software Development Teams (DEV322)

  • 効果的なCI実施のための3つ施策について解説。Nighty Check, Branch Check, PullRequest Check。ツールとしてCodeBuildの活用をベースに。登壇者はWarnerのKeynoteに出てきたClare。彼女はCodeBuildの開発チームの一員。
  • https://www.youtube.com/watch?v=GEPJ7Lo346A

Deep Dive on Advanced Continuous Delivery Techniques Using AWS DevOps Tools (DEV324)

  • 昨年もあったContinuous DeliveryのDeep Diveセッション。「CDパイプラインが本番環境を壊すことが怖いですか?」怖い人はこのセッションを。
  • https://www.youtube.com/watch?v=Lrrgd0Kemhw

Use Amazon EC2 Systems Manager to Perform Automated Resilience Testing in Your CI/CD Pipeline (DEV338) by Expedia

Manage Your Applications with AWS Elastic Beanstalk (DEV305)

CloudFormation

CFn関連セッションはこちらのブログにもまとめて紹介されています
https://aws.amazon.com/jp/blogs/mt/your-aws-cloudformation-guide-to-reinvent-2017/

Deep Dive on AWS CloudFormation (DEV317)

  • CFnのプロダクトマネージャAnilによるDeep Dive Session。中ほどにStackと実環境との違いを検知するDrift Detection (commin soon) について解説があります。
  • https://www.youtube.com/watch?v=01hy48R9Kr8

Learn How Intuit Built a Frictionless Infrastructure Management System Using AWS CloudFormation (DEV318)

Build Once, Deploy Many: Architecting and Building Automate (GPSTEC319)

CLI

Introduction to the AWS CLI (DEV323)

AWS CLI: 2017 and Beyond (DEV307)

Management & Governance & Monitoring

How Amazon.com Uses AWS Management Tools (DEV340)

Using AWS Management Tools to Enable Governance, Compliance, Operational, and Risk Auditing (DEV339)

NEW LAUNCH! Gain Operational Insights and Take Action on AWS Resources with AWS Systems Manager (DEV346)

Embrace DevOps and Learn How to Automate Operations (DEV306)

Using Amazon CloudWatch for Amazon ECS Resource Monitoring at Scale (DEV333)

DevOps ワークショップ

Advanced DevOps Practices for AWS(DEV401)

DevOps Essentials An Introductory Workshop on CICD Practices

続きを読む

JenkinsをEC2上にセットアップ

EC2の初期セットアップはこちら

https://qiita.com/kazupyong/items/8d05c8421db37dcf06c9

Jenkinsのセットアップ

Javaパッケージのインストール

$ java -version
java version "1.7.0_161"

最新バージョン入れたいので1.8系のインストールする

$sudo yum install java-1.8.0-openjdk.x86_64

Jenkinsのレポジトリを追加してインストール

$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
$ sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
$ sudo yum install jenkins

Jenkinsの起動

$ sudo chkconfig jerkins on

$ sudo service jenkins start

Jenkinsアクセス

初期パスワードのコピーして

$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword

http://jenkins.xxxxx.com:8080/
へとアクセス

おまけnginxとLet’s Encryptを使ってジェンキンスをSSL化

nginxのインストール

$ sudo yum install nginx

nginxの起動

$ sudo chkconfig nginx on
$ sudo service nginx start

certbotのインストール

$ wget https://dl.eff.org/certbot-auto
$ chmod a+x certbot-auto
$ sudo mv certbot-auto /usr/local/bin/
$ sudo ./certbot-auto certonly --debug

メールアドレスやドメイン名を入れた後に発行される
これで/etc/letsencrypt/live/ドメイン 以下にSSLキーが発行される

/etc/nginx/nginx.conf の編集

httpのディレクティブに以下を追記

    upstream jenkins {
        server 127.0.0.1:8080 fail_timeout=0;
    }

    server {
        listen 80;
        server_name  XXXXXXXX;
        return 301 https://XXXXXXXX$request_uri;
    }

SSLと先程発行された鍵の設定を行う

    server {
        listen       443 ssl http2 default_server;
        listen       [::]:443 ssl http2 default_server;
        server_name  XXXXXXXX;
        root         /usr/share/nginx/html;

        ssl_certificate "/etc/letsencrypt/live/XXXXXXXX/fullchain.pem";
        ssl_certificate_key "/etc/letsencrypt/live/XXXXXXXX/privkey.pem";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;
        ssl_prefer_server_ciphers on;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
            proxy_redirect          http:// https://;
            proxy_pass              http://jenkins;
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

nginxの再起動

$ sudo service nginx start

これでHTTPS化DONE!

certbotを自動更新

crontabに以下を追記
10日おきの午前1:00に更新するようにする

 # crontab -e
0 1 */10 * * /usr/local/bin/certbot-auto --post-hook"service restart nginx"  > /dev/null

以下参考にした記事
https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+on+Red+Hat+distributions
https://issues.jenkins-ci.org/browse/JENKINS-22448
https://inaba-serverdesign.jp/blog/20160630/lets-encrypt_update_sslcert.html

続きを読む

Terraformの構成 ver.2017冬

https://qiita.com/uraura/items/f20b21baf7f28101a9d9 の続編です.

おおざっぱな説明だけで具体的な構成の話がなくてよくわからん :thinking: って感じなので,続きを書きます.

ディレクトリ構成

.
├── 10_network
│   ├── main.tf
│   ├── output.tf
│   └── variable.tf
├── 10_network.tf
├── 20_backend
│   ├── main.tf
│   ├── output.tf
│   └── variable.tf
├── 20_backend.tf
├── 25_app_backend
│   ├── main.tf
│   ├── output.tf
│   └── variable.tf
├── 25_app_backend.tf
├── 25_app_datastore
│   ├── main.tf
│   ├── output.tf
│   └── variable.tf
├── 25_app_datastore.tf
├── README.md
├── terraform.tf
└── variables.tf

ディレクトリ名のプレフィックスの数値自体に意味はありません.ディレクトリと同じ名前のファイルがあり,それにmoduleが定義されています.
数値の大小で依存関係を表していて,数値の大きいmoduleは数値の小さいmoduleに依存しています.言いかえると,数値の小さいmoduleのoutputを数値の大きいmoduleは利用できる,ということです.

各moduleにどういうリソースが入ってるかは下図の通りです.
image.png

各層に何を入れるか,は厳密にわけるのは難しいのでフィーリングな部分もあります👻が,大きな方針は

  • アプリケーションによらない,AWSでシステム運用するのに必要なリソースをnetwork層に
  • アプリケーションで共通で使用するようなリソースをbackend層に
  • アプリケーション固有のリソースをapp_backend層に
  • アプリケーションがデータストアを必要とするのであればapp_datastore層に

です.backendとかapp_xxxとか名称は試行錯誤してたらこんな感じになってたので深い意味はあまりない...😔
app_backendapp_datastoreが分かれているのは,特にマイクロサービス的な構成をとると,データストアを必要としないサーバーもあったりするためです.

module

20_backendを見てみます.

20_backend.tf

20_backend.tf
module "backend" {
  source = "./20_backend"
}

output "backend_aws_iam_role_lambda" {
  value = "${module.backend.aws_iam_role_lambda}"
}

output "backend_aws_key_pair_ec2_key" {
  value = "${module.backend.aws_key_pair_ec2_key}"
}

output "backend_aws_s3_bucket_config" {
  value = "${module.backend.aws_s3_bucket_config}"
}

トップレベルにあるtfファイルには,moduleの定義と,そのmoduleからのoutputを定義します.
ポイントは

  • このmoduleは外部にどういう値をエクスポートしているのかが明確になる

    • terraform outputで見れるので,実際はわざわざソースを見る必要はない
  • outputする必要ないリソースのことは完全に無視できる(当該moduleをいじるときだけ気にすればいい)

20_backend/variable.tf

20_backend/variable.tf
data "terraform_remote_state" "aws_main" {
  backend     = "s3"
  environment = "${terraform.workspace}"

  config {
    bucket = "tfstate"
    key    = "aws/main/terraform.tfstate"
    region = "ap-northeast-1"
  }
}

Terraform Providerを利用するための設定です.
Terraformのworkspaceを利用して,環境(dev/stg/prd)を表現しています.environmentに渡すことにより,1つのtfstateで環境を考慮していい感じにやってくれます.

20_backend/main.tf

20_backend/main.tf
locals {
  network_aws_subnet_jump                 = "${data.terraform_remote_state.aws_main.network_aws_subnet_jump}"
  network_aws_route53_zone_main           = "${data.terraform_remote_state.aws_main.network_aws_route53_zone_main}"
  network_aws_security_group_localnet     = "${data.terraform_remote_state.aws_main.network_aws_security_group_localnet}"
}

data "aws_route53_zone" "main" {
  zone_id = "${local.network_aws_route53_zone_main}"
}

data "aws_security_group" "localnet" {
  id = "${local.network_aws_security_group_localnet}"
}

ここは実際のリソースが定義されています.
locals内にある,${data.terraform_remote_state.aws_main.network_aws_route53_zone_main}が,Terraform Providerを利用して値を取ってきてるところです.
ここは20_backendなので,それより下位の10_networkoutputだけを利用しています.

とりあえずファイルは1つにして全部おしこんでいますが,リソース数によっては

  • ファイルを分ける
  • サブモジュールとする
  • そもそも階層を増やす

などを考える必要がありそうです.
ファイルを分けるとリソースをどのファイルへ書く?問題が起きますし,サブモジュールにすると見通しが...?階層増えるとそれはそれでメンドいか...?など,まだ自分の中でもベストアンサーはありません🙇

local

余談ですが,localは便利なので積極的に使うと良いと思います.

internal_flagがtrueの場合に何かリソースを生成する,みたいな定義がある場合に,わざわざフラグで判定しなくてもよくなります.

module "foo" {
  internal_flag = true
  # internal_flagがONの場合に作られるリソースの設定値
  config = {
    name = "xxx"
  }
}

# internal_flagによってリソースを作ったり作らなかったりする
resource "aws_lb" "bar" {
  count = "${internal_flag ? 1 : 0}"
  :
}

↓↓↓

sample.tf
module "foo" {
  config = {
    name = "xxx"
  }
}

# moduleにconfigがあるかどうかでフラグを計算
# デフォルト値は{}にしておく必要がある
locals {
  internal_flag = "${length(keys(var.config)) != 0}"
}

# configがあるかによってリソースを作ったり作らなかったりする
resource "aws_lb" "bar" {
  count = "${internal_flag ? 1 : 0}"
  :
}

のようになり,moduleの外で設定しなければならない値が減って良い感じになります.

20_backend/output.tf

output "aws_s3_bucket_config" {
  value = "${aws_s3_bucket.config.id}"
}

外部で使用したいリソースのID等をひたすらoutputするだけです.
20_backend.tfにも書いてるじゃないか!と思うかもしれませんが,Terraform Providerを使うにはrootレベルでoutputされている必要があるため,moduleのoutputをそのままrootでoutputする,という感じになってしまっています.ちょっと面倒ですがまぁ仕方ないかな...と.

outputする値は,dataが使える場合は識別子(ARNやresource id等)のみ,使えない場合は↓な感じでmapにしています.

output "aws_iam_access_key_ci" {
  value = {
    id = "${aws_iam_access_key.ci.id}"
  }
}

他のmodule

25_app_backend25_app_datastoreも,上記と同様の方針でファイルを構成しています.
違うのは,25層は下位の10,20層のどちらのoutputも使用できる点ぐらい.

plan/applyする

現時点での構成では,moduleわけはしたもののリポジトリ単位でわかれているわけではないので,そのままplanなどとすると全モジュール読みこまれてしまい時間がかかる問題は解決されません.

ですが,module分割を行ったことにより,module単位で実行することは可能になります.

terraform plan -target=module.backend

などと引数を付けて実行することで,指定したモジュールだけ(今回の構成でいけば指定した層だけ)を対象にして実行できるので,下位層に変更がないことが分かってる場合は大幅に実行速度が上がります.

注意しなければならない点

  • 下位層のoutput追加と,上位層での利用を同時に追加したら死ぬ

    • 依存関係があるので,先に下位層のoutput追加をapplyまでしてからでないと上位層でいきなり参照してはいけません
  • output追加だけだとplanしてもno changesになってしまうのでapplyを忘れがちになってしまう

今までハマったのはこれぐらい....?もっとあったかも...

あとは,今は単一リポジトリでやっていますが,複数のリポジトリに完全に分離してしまった場合,下位層の変更を上位層はどうやって検知すればいいのか?という問題があるような気がしています.

そのへんは試行錯誤中なのでまたそのうち😶

続きを読む