19 分前

https://dev.classmethod.jp/cloud/aws/devsumi2018-multicloud/ 「ほんまに運用できるの?」毎秒6000イベントをミリsec対応するウェブサービスを、マルチクラウドで構築した話を聞いてきた #devsumi | Developers.IO. 「ほんまに運用できるの?」毎秒6000イベントをミリsec対応するウェブサービスを、マルチクラウドで構築 … 続きを読む

AWS Lambdaでkintoneアプリの簡易自動バックアップを作ってみた その1(フォーム設計情報とレコードの取得)

kintone自体はアプリケーションを非常に簡単に作成できるのですが、そのバックアップ、となると有償の製品を購入するか、あるいは手動で実施する、というのが現状です。

そこで、有償のバックアップとまでは行かなくても、簡易的なバックアップの仕組みを作れないか、試してみました。

ゴール

とりあえず以下の条件をゴールとします。

  1. バックアップ対象は「フォームの設計」と「データ一式」
  2. バックアップは自動で定期的に実施される
  3. 必要であればリストアの仕組みも作る

バックアップのための仕組み

・フォームの設計情報をバックアップ
 →フォーム設計情報取得
・データ一式のバックアップ
 →第10回 kintone REST APIを利用したレコード取得

これらをAWS Lambda(Python 3)上から呼び出せるように実装します。リストアもjson形式で対応できそうなので、上記のページの通りの結果が得られればバックアップとしては問題なさそうです。

処理対象

こんな感じの備品在庫管理(既成品)を利用します。

スクリーンショット 2018-01-28 16.28.42.png

実装

前処理

色々と準備が必要なので、最初に実施します。

KINTONE_BASE_URL = os.environ['KINTONE_URL']
KINTONE_FORM_BASE_URL = os.environ['KINTONE_FORM_BASE_URL']
URL = KINTONE_BASE_URL.format(
    kintone_domain=os.environ['KINTONE_DOMAIN'],
    kintone_app=os.environ['KINTONE_APP']
)
FORM_URL = KINTONE_FORM_BASE_URL.format(
    kintone_domain=os.environ['KINTONE_DOMAIN'],
    kintone_app=os.environ['KINTONE_APP']
)
HEADERS_KEY = os.environ['KINTONE_HEADERS_KEY']
API_KEY = os.environ['KINTONE_API_KEY']

S3_BUCKET = os.environ['S3_BUCKET']
S3_OBJECT_PREFIX = os.environ['S3_OBJECT_PREFIX']

s3_client = boto3.client('s3')

全レコードの取得

こんな感じでQueryに何も指定しない全件取得を行います。

def get_all_records(headers):
    query = u''

    response_record = requests.get(URL + query , headers=headers)
    return json.loads(response_record.text)

フォーム設計情報取得

フォームは前述のページを参考にこのような実装になります。

def get_form_info(headers):

    response_record = requests.get(FORM_URL, headers=headers)
    return json.loads(response_record.text)

取得したデータをS3にバックアップとして保持

botoライブラリを利用して、tmpフォルダに一時的に作成したファイルをS3にアップロードします。

def put_data_to_s3(contents):
    date = datetime.now()
    date_str = date.strftime("%Y%m%d%H%M%S")
    tmp_dir = "/tmp/"
    tmp_file = S3_OBJECT_PREFIX + "_" + date_str + ".json"

    with open(tmp_dir + tmp_file, 'w') as file:
        file.write(json.dumps(contents, ensure_ascii=False, indent=4, sort_keys=True, separators=(',', ': ')))

    s3_client.upload_file(tmp_dir + tmp_file, S3_BUCKET, tmp_file)

    return True

上記を呼び出し側メソッド

今まで作成したきた部品をつなぎ合わせます。それぞれレコード一覧とフォーム設計情報を一つのJSONファイルにまとめる様に実装しています。

def run(event, context):

    headers = {HEADERS_KEY: API_KEY}
    record_data = get_all_records(headers)
    records = record_data['records']

    form_data =get_form_info(headers)
    forms = form_data['properties']

    result = {
        "records": records,
        "properties": forms
    }

    return put_data_to_s3(result)

(おまけ)環境変数はステージごとに切り替えるように実装

クラメソさんの記事を参考に、ステージごとに環境変数を切り替えられるようにしています。

serverless.yml
service: aws-kintone-backup

provider:
  name: aws
  runtime: python3.6
  region: us-east-1
  stage: ${opt:stage, self:custom.defaultStage}
  environment:
    KINTONE_URL: https://{kintone_domain}/k/v1/records.json?app={kintone_app}
    KINTONE_FORM_BASE_URL: https://{kintone_domain}/k/v1/form.json?app={kintone_app}
    KINTONE_HEADERS_KEY: X-Cybozu-API-Token
custom:
  defaultStage: dev
  otherfile:
    environment:
      dev: ${file(./conf/dev.yml)}
      prd: ${file(./conf/prd.yml)}

functions:
  run:
    handler: handler.run
    environment:
      KINTONE_DOMAIN: ${self:custom.otherfile.environment.${self:provider.stage}.KINTONE_DOMAIN}
      KINTONE_API_KEY: ${self:custom.otherfile.environment.${self:provider.stage}.KINTONE_API_KEY}
      KINTONE_APP: ${self:custom.otherfile.environment.${self:provider.stage}.KINTONE_APP}
      S3_BUCKET: ${self:custom.otherfile.environment.${self:provider.stage}.S3_BUCKET}
      S3_OBJECT_PREFIX: ${self:custom.otherfile.environment.${self:provider.stage}.S3_OBJECT_PREFIX}
dev.yml
KINTONE_DOMAIN: xxxxxx.cybozu.com
KINTONE_API_KEY: XXXXXXXXX
KINTONE_APP: XXX
S3_BUCKET: XXXXXX
S3_OBJECT_PREFIX: XXXXXX

slsコマンドでアップロードをする際に--stageオプションを指定する必要があります。(デフォルトはdev

実行してみる

さて、それぞれ環境変数を指定して実行してみます。無事S3にファイルが出力されました。中身も無事出力されています。(コンテンツが長いからここには載せないけど)

スクリーンショット 2018-02-05 22.08.06.png

AWS Lambdaで開発しているので、あとはスケジューリングでもすれば自動起動は簡単ですね。

現状の課題

一応できましたが、いくつかすでにわかっている課題があります。

  1. レコードの一括取得は一度に500件までしかできない。(kintoneの仕様)
  2. レコードの一括登録は一度に100件までしかできない。(kintoneの仕様)
  3. S3へアップロードしたファイルはずっと残ってしまう。(手動で削除しに行かないと後々ゴミになる)
  4. リストアの仕組みがない

この辺を解消するような実装はまた後ほど。

成果物

ここまでの成果物は以下になります。

https://github.com/kojiisd/aws-kintone-backup/tree/v1.0

まとめ

よくあるkintoneアプリケーションのバックアップの一部を自動化することができました。とはいえAPIとしてはプロセス管理やアプリケーションの一般的な設定まで取得するものがあるので、この辺を盛り込むと、どんどんとリッチなバックアップ処理になりそうです。その辺りはまた次にでも。

続きを読む

ローカルでLambdaのテストをする環境を作ったメモ

何?

Lambdaをテストする際、いちいちUPしてCloudWatchを確認して・・・とテストするのは辛いのでローカルでテストする環境を作る。
作ったメモ

検証環境

Mac: macOS Sierra
awscli: aws-cli/1.14.32 Python/2.7.13 Darwin/16.7.0 botocore/1.8.36
nodejs: v9.4.0
npm: 5.6.0
docker: Version 17.06.2-ce-mac27

ディレクトリ構成

.
├── docker-compose.yml
├── event.json
├── index.js
├── package.json
└── template.yml

aws-sam-localのインストール

npm i aws-sam-local -g

私はこいつはグローバルインストールしている

手順

作業ディレクトリの作成と移動

コマンド
mkdir test
cd test

npm install

npm init -y
npm i aws-sam-local aws-sdk --save-dev

sam-localが使用するYAMLの作成

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

localstack用のYAMLファイル作成

docker-compose.yml
version: '2.1'
services:
  localstack:
    image: localstack/localstack
    ports:
      - 4567-4583:4567-4583
      - 8080:8080

スクリプトの用意

index.js
'use strict';

const AWS = require('aws-sdk');
const S3 = new AWS.S3({endpoint: 'http://<ローカル端末のIP>:4572', s3ForcePathStyle: true});


exports.handler = (event, context, callback) => {
    console.log(`EVENT is ${event}`);
    uploads3().then(() => {
        callback()
    });
};

const uploads3 = () => {
    return new Promise((resolve, reject) => {
        let param = {
            Bucket: "xxxxxxxxxxxxxbbb",
            Key: "test2.txt",
            Body: "fugafuga"
        };
        console.log(param);

        S3.putObject(param, (err, data) => {
            if (err) {
                console.log(err, err.stack);
            } else {
                console.log(data);
            }
            resolve();
        });
    });
};

ダミーイベント作成

コマンド
sam local generate-event dynamodb > event.json

local-stackの起動(バックグラウンド起動)

コマンド
docker-compose up -d

lambdaのローカル実行

コマンド
sam local invoke lambdaFunction -e event.json 
  • アップロード用のS3バケットのダミーは最初に作っておくこと。
  • samが呼んでくるlambda動かすdockerからlocalstackへのネットワーク疎通が通らなかったからEndpointは端末のIP指定している。

ローカルでCLI使ってlocalstackは疎通出来るのに、docker上で動いてるLambdaスクリプトから接続ができなくてすっごいハマった。

参考

[新ツール]AWS SAMをローカル環境で実行できるSAM Localがベータリリース

AWS SAM Local と LocalStack を使って ローカルでAWS Lambdaのコードを動かす

続きを読む

Serverless FrameworkでAPI Gatewayバイナリサポートを設定する

API Gatewayでバイナリを扱いたい場合、バイナリサポートを有効にする設定が必要になります。
その設定をServerless Frameworkで定義しました。

ServerlessFrameworkのデフォルトではバイナリサポートの設定パラメータが用意されていないためプラグインを使用します。

調べたところ現時点では以下の2つのプラグインが見つかりました。

一つ目のserverless-apigw-binaryは試してみたときに、デプロイは成功していてもAPI Gatewayに反映されていないということがあったため、二つ目のserverless-plugin-custom-binaryを使うことにしました。

環境

$ npm -v
5.5.1

$ serverless -v
1.22.0

設定方法

プラグインのインストール

$ npm install --save-dev serverless-plugin-custom-binary

設定を追加

serverless.yml
plugins:
  - serverless-plugin-custom-binary

custom:
  apigatewayBinary:
    types:
      - multipart/form-data

デプロイ! :beer:

$ serverless deploy

デプロイ完了後、API Gatewayのコンソールで確認するとちゃんと設定されています。
スクリーンショット 2018-02-03 22.20.23.png

以上です。

続きを読む

iperfでAWSのEC2インスタンスの速度を測定した

自己紹介

最近本腰を入れて技術の勉強をするようになりました、dtd root と言います。
私の投稿では、主に私の勉強の過程を記録し、可能ならば皆さまに知識を分けていただこうという趣旨の元投稿を行います。
至らない点や間違いが数多くありますが、どうぞご容赦ください。

AWSでTCPの最大レートを測定

環境は以下

測定リージョン
東京-東京間
東京-ソウル間

インスタンスタイプ
t2.micro

OS
Amazon Linux AMI 2017.09.1 (HVM), SSD Volume Type

入力コマンド

クライアント側
iperf -c -t 60 -p

※宛先IPはパブリックIPです。

サーバー側
iperf -s -p

実行結果
[ ID] Interval Transfer Bandwidth
[ 4] 0.0-60.2 sec 235 MBytes 32.8 Mbits/sec
[ 5] 0.0-60.0 sec 3.37 GBytes 482 Mbits/sec

Qita1.png

所感
ソウルを跨いだ方が帯域幅が低くなるのは当然の結果かと思われますが、理論値の算出方法がどうにもわかりませんでした。
ググってみてもうまくAWS-EC2の理論帯域が出てこないので、そちらとの比較が出来なかったのが残念だと思っています。
そしてこの値はどうすれば良くなるのか、どうすれば悪くなるのか、といったところも全く分からない状況なので、
今後手探りで知識を得ていければいいなと思っています。

参考文献

[1]Amazon Web Services 基礎からのネットワーク&サーバー構築
[2]ネットワーク測定ツールiperfの使い
https://qiita.com/takish/items/bff7a1df712d475432df
[3]EC2でiperfを使ってネットワークスループットを計測してみた。
https://dev.classmethod.jp/etc/ec2-iperf/

続きを読む

HDP 2.6.3をAWSにインストール 乞食版

ゴール

AWSの超安いインスタンスに、HDPをインストールして遊ぶ。

インスタンス初期化

Ambari

t2.nano

[ec2-user@ip-172-31 ~]$ free -m
              total        used        free      shared  buff/cache   available
Mem:            990          80         731          12         179         739
Swap:             0           0           0

AWS Amazon Linux スワップファイル作成によりSwap領域のサイズを増やす
https://qiita.com/na0AaooQ/items/278a11ed905995bd16af

現在は1GBあるので、8GBのSwapメモリを追加

grep Mem /proc/meminfo
grep Swap /proc/meminfo
free
uname -a
# /swapfile1 に保存
sudo dd if=/dev/zero of=/swapfile1 bs=1M count=8192
grep Swap /proc/meminfo

ll /swapfile1
sudo chmod 600 /swapfile1
sudo mkswap /swapfile1
ll /swapfile1
swapon -s
free
sudo swapon /swapfile1
free
grep Swap /proc/meminfo

メモリ追加しました。

[ec2-user@ip-172-31 ~]$ free -m
              total        used        free      shared  buff/cache   available
Mem:            990          77          64          12         848         731
Swap:          3083           0        3083
[ec2-user@ip-172-31 ~]$

t2.micro instance作成

Ambari:1台
Master:1台
Slave:3台

image.png

注意事項

RHEL 7.4

Red Hat Enterprise Linux 7.4 (HVM), SSD Volume Type – ami-26ebbc5c

AWS setting

t2.micro instance

Storage setups —

Ambari: EBS 15G
NN/DN: EBS 20G

image.png

image.png

セキュリティ設定

All Traffic, Allow, HDPのセキュリティグループID指定(内部通信を全部許可)
All Traffic, Allow, MyIP (管理者のIPを許可)
これでOK

ssh private key

scp -i amuisekey.pem amuisekey.pem ec2-user@ec2-54-234-94-128.compute-1.amazonaws.com:~/.ssh/id_rsa
# 全部サーバーにアップロード

hosts

自分のMBP /etc/hosts

    127.0.0.1 localhost.localdomain localhost
    ::1 localhost6.localdomain6 localhost6

#外部IP
    10.110.35.23 hdpmaster1.hdp.hadoop hdpmaster1
    10.191.45.41 hdpmaster2.hdp.hadoop hdpmaster2
    10.151.94.30 hdpslave1.hdp.hadoop hdpslave1
    10.151.87.239 hdpslave2.hdp.hadoop hdpslave2
    10.70.78.233 hdpslave3.hdp.hadoop hdpslave3
    10.151.22.30 ambarimaster.hdp.hadoop ambarimaster

AWSサーバーの /etc/hosts

    127.0.0.1 localhost.localdomain localhost
    ::1 localhost6.localdomain6 localhost6

#外部IP
    10.110.35.23 hdpmaster1.hdp.hadoop hdpmaster1
    10.191.45.41 hdpmaster2.hdp.hadoop hdpmaster2
    10.151.94.30 hdpslave1.hdp.hadoop hdpslave1
    10.151.87.239 hdpslave2.hdp.hadoop hdpslave2
    10.70.78.233 hdpslave3.hdp.hadoop hdpslave3
    10.151.22.30 ambarimaster.hdp.hadoop ambarimaster

Install

https://community.hortonworks.com/articles/14512/ambari-on-ec2.html

image.png

続きを読む

{AWS(CloudFront+S3)+Node.js} 署名付きURLの使用したプライベートコンテンツの配信

はじめに

短期間のみ有効な署名付き URL を使用してプライベートコンテンツを配信するにあたり、Node.js環境下での情報が公式にはのっていなかったので、その対応方法をメモとして残します。

公式ガイド
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html

環境準備

  1. プライベートコンテンツを格納するS3のバケットを作成する
  2. 上記バケットを非公開とする
  3. CloudFrontのディストリビューションを作成する
    • CloudFront経由に限り上記S3バケットにアクセス出来る用に設定する
  4. 署名付きURL生成のためにCloudFront のキーペアを作成する
    • この処理だけはAWSアカウント(ルートアカウント)が必要

〇参考URL
https://dev.classmethod.jp/cloud/aws/cf-s3-deliveries-use-signurl/
http://blog.mekachan.net/?p=105

コード実装

現在JavaScriptのaws-sdkライブラリではCloudfrontの署名付きURL生成がサポートされていないため、「aws-cloudfront-sign」ライブラリを活用して対応する

aws-cloudfront-sign

https://www.npmjs.com/package/aws-cloudfront-sign

サンプルコード

// 30分だけ有効な署名付きURLを生成するコード
var cf = require('aws-cloudfront-sign')
var options = {
  keypairId: 'XXXXXX',
  privateKeyPath: 'XXXX/XXXXXX-private-pk-XXXXX.pem',
  expireTime: (new Date().getTime() + 30 * 60 * 1000)
}
// CloudFrontの「Domain Name」を指定する
// https://${Domain Name}/${Origin path(S3バケット内のパス)}
var signedUrl = cf.getSignedUrl('https://dXXX.cloudfront.net/example.mp4', options);
console.log('Signed URL: ' + signedUrl);

options(オプション)の説明

項目 内容
expireTime 有効期限(任意設定:省略時は30秒)指定する際はミリ秒で指定する
keypairId 作成したクラウドフロントキーペアのアクセスキー ID
privateKeyString
または
privateKeyPath
作成したクラウドフロントキーペアの秘密鍵ファイルパス

参考 S3上で署名付きURLを利用するの場合

このケースではクラウドフロントを介しません。
S3上で生成した署名付きURL経由で非公開バケット中のリソースへアクセスする方式です。
特別なライブラリは不要でaws-sdkで対応可能です。

const AWS = require('aws-sdk')

AWS.config.update({
  accessKeyId: 'XXXXXX',
  secretAccessKey: 'XXXXXX'
  // ,
  // region: 'ap-northeast-1'
})
const s3 = new AWS.S3()

const url = s3.getSignedUrl('getObject', {
    Bucket: 'private-bucket',
    Key: 'example.mp4',
    Expires: 60 // 単位は秒
})

console.log(url)

参考(AWS-CLI)の場合

aws cloudfront sign
 --url http://dXXX.cloudfront.net/example.mp4
 --key-pair-id XXXXXX
 --private-key file://C:/XXX-private-pk-XXXXX.pem
 --date-less-than YYYY-mm-dd

続きを読む

AWSのEC2とRDS(mysql)を他アカウントへ移行してみるテスト

方針

ちょっとだけサーバを止める
移行前=>VPC1 / AP1 / DB1
移行後=>VPC2 / AP2 / DB2
って名前にする
ロードバランサなどについては特に記述しない

移行手順

  • VPC2を作る
  • VPC2とVPC1をピア接続する
  • AP2を作る
  • AP2からDB1へ接続する
  • DNSサーバをAP1からAP2へ向き先を変える
  • 浸透を待ち、AP1止める
  • DB2を作る
  • DB1からDB2へDBを移行(ダンプとかで)
  • データ移行が終わった段階で、AP2を止める
  • AP2の向き先をDB2へ変更
  • DB2を親にする
  • AP2を起動する
  • (゚∀゚)

作成

vpc2を作る

以降元とprivate-ipが被らないようにする

ピア接続

こちらを参考に作成しました
https://dev.classmethod.jp/cloud/aws/vpc-peering-different-awsaccount/

  • vpc2からvpc1へピア接続を作る
  • vpc1のアカウントIDとvpc-idを設定する
  • vpc1アカウントのvpc=>ピア接続で、リクエストを承認する
  • vpc1とvpc2双方のルートテーブルへ、お互いのip範囲でターゲットなピア接続を追加

EC2の移行

こちらを参考に作成しました
http://keisukeohta.hatenablog.com/entry/2016/03/01/210556

  • AP1のインスタンスからイメージを作る
  • AMIのイメージパーミッションの設定で移行先アカウントIDを追加する
  • 移行先アカウントのAMI=>プライベートイメージに共有されているので、それを使ってEC2を作成
  • ap2からdb1へピア接続出来ることを確認する
    => db1がパブリック接続許可の場合、パブリックIDで接続しに行ってしまうので、ローカルIDで接続する

以上

これで「AP2からDB1へ接続する」から先が作業可能となります

続きを読む

AWS EC2作成からTeraterm接続まで

※AWSアカウントを持っていて、ログインできる方が対象です。

VPCの構築

・1つのお城のようなイメージ
・参考URLに沿って作成する

VPCとはAWSアカウント上に複数作成することが出来るプライベートなネットワークの単位です。一軒家を建てる為の土地全体といったところでしょうか。
VPCの配下には、AZがあり、その配下にはサブネットがあります。またAZは1つ以上のサブネットを保持することができます。AWS上で初めてネットワークを構築するときは最低でも1つのVPC、1つのAZ、1つのサブネットを作成する必要がします。
AZは建造物エリア、サブネットは建造物を設置するための基礎といったイメージです。

参考URL:https://engineers.weddingpark.co.jp/?p=523

EC2の作成

・これも下記URLに沿って作成する
参考URL:https://engineers.weddingpark.co.jp/?p=523

・ただし、インスタンスのパブリックIPが勝手に設定されていますが、私の時は設定されていなかった
→Elastic IPを取得して、割り当てる必要あります。下記参照

image.png

image.png

画面を閉じて、取得したElastic IPを選択→アクション→アドレスの関連付け
→インスタンスに先ほど作成したEC2を選択し、関連付け
※Elastic IPはEC2に関連付けしないと課金されるので注意

関連付けるとパブリックDNS、IPが記載されるのでそちらでSSH接続する。

SSH接続(Windows)

Teratermでアクセスしました。
下記参照。ファイルの種類を「すべてのファイル」にしないと秘密鍵を選択できないので注意

参考URL:https://dev.classmethod.jp/cloud/aws/aws-beginner-ec2-ssh/

image.png

ping応答設定

EC2に紐づいているセキュリティグループに「ICMP」を追加する

参考URL:http://a1-style.net/amazon-web-service/ping-icmp-setting/

続きを読む