起動後のEC2にIAM Roleを付与する【cloudpack 大阪 BLOG】

待望の機能追加があったので実際にやってみました。
これまで起動後のec2インスタンスにはiam-roleが付与できなくて不便な思いをしてきましたがやっと開放されそうです

現時点ではawscliからのみしかできません。
またawscliの更新が必要になりますので気をつけてください。

以下に手順を記載します。ec2にアタッチするroleについては作成されているものとします

①roleアタッチ

aws ec2 associate-iam-instance-profile --instance-id ${InstancdId} --iam-instance-profile Name=${profile_name}

②アタッチ確認

aws ec2 describe-iam-instance-profile-associations

③roleデタッチ

aws ec2 disassociate-iam-instance-profile  --association-id ${associationId} 

※${associationId}については②で確認できます

また、stop中のインスタンスについては、画面のEC2のrole項目は更新されませんでしたが、起動後に正しく表示されました。

rsyslogで中継サーバ経由してログ送信を行う【cloudpack 大阪 BLOG】

以下のような構成でrsyslogを使用してログをログ収集サーバへ集約させる要件がありました。
検証で動作確認を実施してみたので、備忘録としてやり方を残しておきたいと思います。

f:id:cloudfish:20170126190943p:plain,w400,h250

やりたいこと

webサーバの/var/log/messagesをログ中継サーバを経由させてログ収集サーバへ送信する
ユースケースとしてはログ収集サーバが別のVPCや外部DCにあるケースを想定しています。

構成

サーバ IP
webサーバ 172.31.0.1
中継サーバ 172.31.0.2
ログ収集サーバ 172.31.0.3

webサーバの設定

■/etc/rsyslog.config

*.info;mail.none;authpriv.none;cron.none                /var/log/messages
*.info;mail.none;authpriv.none;cron.none                @@172.31.02      ←追加

# 以下コメントを解除(73-78行目)
$WorkDirectory /var/lib/rsyslog # where to place spool files
$ActionQueueFileName fwdRule1 # unique name prefix for spool files
$ActionQueueMaxDiskSpace 1g   # 1gb space limit (use as much as possible)
$ActionQueueSaveOnShutdown on # save messages to disk on shutdown
$ActionQueueType LinkedList   # run asynchronously
$ActionResumeRetryCount -1    # infinite retries if host is down

中継サーバの設定

■/etc/rsyslog.config

# 以下コメントを解除
$ModLoad imtcp
$InputTCPServerRun 514

$AllowedSender TCP, 127.0.0.1, 172.31.0.0/24   ←送信元を指定

*.info;mail.none;authpriv.none;cron.none                /var/log/messages
*.info;mail.none;authpriv.none;cron.none                @@172.31.03       ←追加

#コメントを解除(73-78行目)
$WorkDirectory /var/lib/rsyslog # where to place spool files
$ActionQueueFileName fwdRule1 # unique name prefix for spool files
$ActionQueueMaxDiskSpace 1g   # 1gb space limit (use as much as possible)
$ActionQueueSaveOnShutdown on # save messages to disk on shutdown
$ActionQueueType LinkedList   # run asynchronously
$ActionResumeRetryCount -1    # infinite retries if host is down

ログ収集サーバの設定

■/etc/rsyslog.config

# 以下コメントを解除
$ModLoad imtcp
$InputTCPServerRun 514

$AllowedSender TCP, 127.0.0.1, 172.31.0.0/24   ←送信元を指定

#フォーマット指定
$template message_log,"/var/log/message.d/%fromhost%_%$year%%$month%%$day%.log"   ←追加
*.info;mail.none;authpriv.none;cron.none     -?message_log             ←追加

上記設定後にwebサーバでmessagesにログを出力し、ログ収集サーバに転送されていれば正常に設定されています。

logger logtest

Terraformで[Error reading config for xxxx : Invalid dot index found:]エラー【cloudpack 大阪 BLOG】

最近Terraformを触っていて少し躓いたので備忘録として残しておこうと思います。
現象としては、mapping定義にドットで参照しようとしてエラーが発生しました

variable "vpc_subnet_cidr" {
     default = {
       public-a  = "10.1.10.0/24"
       public-c  = "10.1.20.0/24"
       private-a = "10.1.100.0/24"
       private-c = "10.1.200.0/24"
     }
}

上記のようなmapping定義に対して以下のように変数を参照したとことタイトルのエラーが発生しました。

output "cidr" {
  value = "${var.vpc_subnet_cidr.public-a}"
}


発生したエラーの全文です。

Error loading config: Error loading terraform_test/main.tf: Error reading config for output cidr: Invalid dot index found: 'var.vpc_subnet_cidr.public-a'. Values in maps and lists can be referenced using square bracket indexing, like: 'var.mymap["key"]' or 'var.mylist[1]'. in:

エラーメッセージ内容から下記のように書き直せばいいのは分かるのですが、別案件で稼働実績のあるソースを持ってきたので何故動かないのか気になりました。

output "cidr" {
  value = "${var.vpc_subnet_cidr["public-a"]}"
}

調べてみるとCHANGELOGに記載がありました。
terraform/CHANGELOG.md at master · hashicorp/terraform · GitHub

原因はterraformのバージョン違いによるものでした。別案件で使用していたterraformは0.6系でしたが自分が利用している
terraformは0.7でした。後方互換のない変更がはいったようです。

f:id:cloudfish:20161222025343p:plain

基本的な参照方法を変更するとはなかなか思い切った変更ですね。
0.6系で作ったterraformソースを0.7以降で利用する場合は気をつける必要がありそうです。

Json形式からYaml形式に変換するWebサービスを作った【cloudpack 大阪 BLOG】

タイトルのとおりなんですが、json形式をyaml形式に変換するWebサービスを作りました。
きっかけは、CloudFormationがyaml対応したのでyaml形式で書き初めたのですが、AWSのユーザーガイドにjson形式しか記載されていなかったので、手軽に変換できるようにWebサービスを作りました。

作ったサービス

j2y.link

使い方

JSONのテキストエリアに変換したいデータを貼るとYAMLのテキストエリアに変換されて表示されます。ちなみにjavascriptで変換しているためサーバーへデータはアップしていません。
f:id:cloudfish:20161024144300p:plain

YAMLのすぐ横にあるアイコンをクリックすると結果をコピーできます。
f:id:cloudfish:20161024144423p:plain:w400

このサービスを公開した直後に、CloudFormationのユーザーガイドを確認したところ、YAMLのサンプルも表示されているという切ない結果になりましたが、jsonyamlに変換するという需要はあると思いますのでぜひ使ってみていただけたらと思います。

AWS Certificate Managerでサブドメインを発行する時に承認メール送信先を変更する【cloudpack 大阪 BLOG】

AWS Certificate Managerで証明書を発行する際のドメイン認証については、現在、メール承認のみとなっています。
例えばexample.comサブドメインSSL証明書を発行した場合で、ドメイン管理者が管理者のメールアドレスを公開していないと、デフォルトで以下のようにサブドメインがメールドメインの宛先に承認確認メールが送信されてしまいます。この場合メールを受信できないことが多いため、これをメインドメインへ承認メールを送信する方法を紹介します。

サブドメイン
 stg.example.com
◆メール送信先
 admin@stg.example.com
 postmaster@stg.example.com
 administrator@stg.example.com
 webmaster@stg.example.com
 proxy@whoisprotectservice.com
 hostmaster@stg.example.com

現在、AWSコンソールからは制御ができませんので、aws cliを使用してACMを発行します。

発行対象ドメイン:stg.example.com
メール送信先対象ドメイン:example.com

とした場合、以下のようなコマンドで発行が可能です。

aws acm request-certificate \
 --domain-name stg.example.com \
 --domain-validation-options DomainName=stg.example.com,ValidationDomain=example.com

エラーがでなければ、AWSコンソールから発行したACMについて、承認メール送信先が意図したものとなっているか確認してください


よくある質問 - AWS Certificate Manager(簡単に SSL/TLS 証明書を作成、管理、配置) | AWS
request-certificate — AWS CLI 1.10.67 Command Reference

AWS Lambda(Python)を手っ取り早く高速化する方法【cloudpack 大阪 BLOG】

aws lambdaでは、CPUの使用時間に対し100ミリ秒単位で課金されるため、処理を高速化できるとその分料金も下がります。今回は簡単にLambda(Python)を高速化する方法を紹介します。

方法

処理系をJITコンパイル機能を持つPyPyに変更します。
これだけです。特にソースを見なおすとかではないので手軽に試せます。

PyPyとは
PyPy(パイパイ)は、プログラミング言語Pythonの実装の1つであり、Pythonで記述されたPythonの処理系であることが特徴の1つである(セルフホスティング)。PyPyは、実行速度と効率、およびオリジナルのPython実装であるCPythonとの互換性に重点を置いている。

PyPy - Wikipedia

環境構成

OS:Amazon Linux
PyPy:5.1.1 x86_64:

PyPyのインストール

公式サイトではredhat系のバイナリが提供されていませんので、以下ページで提供されているportable-pypyをダウンロードします。今回は、「PyPy 5.1.1 x86_64」をダウンロードしました。
GitHub - squeaky-pl/portable-pypy: Portable 32 and 64 bit x86 PyPy binaries for many Linux distributions.

ファイル構成

ダウンロードしたpypy-5.1.1-linux_x86_64-portable.tar.bz2を解凍してpypyにリネームしておきます。

ファイル構成は以下のとおりです

├── lambda_function.py    ・・・lambdaから呼び出されてrun.shを実行する
├── run.sh       ・・・main_functionをpypyで実行する 
├── main_function.py  ・・・実際の処理が書かれたpython
└── pypy        ・・・portable-pypy
lambda_function.py

run.shを実行するだけのlambda関数です

# coding: utf-8
import commands

def _(cmd):
    return commands.getoutput(cmd)

def lambda_handler(event, context):
    main()

def main():
    print _('sh ./run.sh')
run.sh

pypyで対象のpythonを実行します。

#!/bin/sh

echo exec pypy
./pypy/bin/pypy main_function.py
main_function.py

実際に実行したい処理をここに記述します。
今回はパフォーマンス測定用に大量のリストを追加する処理としました。

# coding: utf-8

def main():
  rangelist = range(1,100000)

  for var in range(0, 100):
     func(rangelist)

  print('main func finish')

def func(rangelist):
    list = []
    for var in rangelist:
        list.append(var)

if __name__=='__main__':
    main()

ファイルを全て準備できれば、ディレクトリごとzipで固めてlambdaへアップします。pypy-portableの容量が大きいのでs3経由でないとアップできませんでした。

パフォーマンス結果

以下測定結果です。上記のmain_function.pyをデフォルトで実行した時とPyPyで実行した時とで、それぞれ5回測定して平均を取りました。PyPyの場合初回が遅くなるかと思いましたがあまり変わりませんでした。

PyPy デフォルト
1 5085.81 13523.69
2 5655.01 13497.07
3 4984.38 15315.06
4 4931.47 14630.05
5 4981.22 13615.74
平均 5127.57 14116.32

単位:ms

まとめ

今回のケースの場合、処理時間が約1/3になったのでかなりの高速化の効果がありました。
lambdaで重い処理を実行している場合など、PyPyでパフォーマンス改善を試しててみるのもいいかもしれません。
ただし、全てのケースで早くなるわけではなく処理が軽いlambdaで試した場合は、PyPyで実行した時のほうが逆に遅かったです。また、デフォルトのCpythonとは互換性がない部分もありますので、実際に切り替える場合はしっかりとテストが必要になると思います。今後、パフォーマンス改善が必要になった場合に、1つの手法として試してみたいと思います。

pythonのimaplibでメールのAND/OR検索【cloudpack 大阪 BLOG】

pythonでimaplibを使ってGmailを取得しようとして対象メールの検索をしてみたのですが、AND検索やOR検索でうまく検索できずに少しハマりましたので備忘録として残しておきます。

事前設定

まずは対象のGmailアカウントで以下を参考にアプリパスワードを取得します。通常のパスワードではログインできません。また、imapを有効にしておく必要があります。
support.google.com

実行コード

今回実行するコードは以下

import imaplib,email,email.Header

GMAIL_USER=YOUR_GMAIL_ACCOUNT
GMAIL_APP_PASSWORD=YOUR_GMAIL_APP_PASSWORD  #取得したアプリパスワード

def decode(src):

    result = ''
    decodefrag = email.Header.decode_header(src)
    
    for frag, enc in decodefrag:↲
        if enc:
            result += unicode(frag, enc)
        else:
            result += unicode(frag)
    
    return result

if __name__ == "__main__":

    gmail = imaplib.IMAP4_SSL(host=HOST)
    gmail.login(GMAIL_USER, GMAIL_APP_PASSWORD)
    gmail.select(LABEL)

    search_option = 'ここに検索条件をセット'
    typ, data = gmail.search(None, search_option)

    for num in data[0].split():
        typ, data = gmail.fetch(num, '(RFC822)')
        
        msg = email.message_from_string(data[0][1])
        subject = decode(msg.get('Subject'))

検索条件

件名で検索
search_option = '(SUBJECT "testmail01")'
AND 検索

件名と日付のFROM-TOでAND検索

search_option = '(SUBJECT "testmail01" SENTSINCE "09-Apr-2016" SENTBEFORE "10-Apr-2016")'
OR 検索

件名とFromでOR検索

search_option = '(OR (SUBJECT "testmail01") (FROM "test@gmail.com"))'
AND・OR 検索

件名でOR検索し日付のFROM-TOでAND検索

search_option = '((OR (SUBJECT "testmail01") (FROM "test@gmail.com")) SENTSINCE "01-May-2016" SENTBEFORE "03-May-2016")'

検索条件についてはRFCを読みましたが、実際の表記形式がよく分からなかったので試行錯誤しました。また、検索方法には括弧を付与する方法と付与しない方法がありましたが、付与しない方法ではうまく検証できませんでした。

注意するポイント

  • 外側も括弧がないとエラーになるので括弧で囲ってください。
  • スペースの有無も重要。半角1文字分のスペースが必要でした。2文字以上空けるとエラーになるます。
  • 検索日付はUTCで(Gmailの場合)