ほわいとぼーど

ぷろぐらまのメモ帳

雑にAWSリソースにboto3でタグつけてみたのだが

既存のAWSリソースに管理のためにタグ付け直すことになり
それ用のスクリプトを適当に書いたのだが、
なんでリソース毎にAPIが全然違うのか、という気分になったのでメモる。
ちなみにboto3です。

EC2

read ec2 tag

client = boto3.client('ec2', "ap-northeast-1")
resp = client.describe_instances()
for resv in resp['Reservations']:
    for inst in resv['Instances']
        print(inst['Tags'])

write ec2 tag

client = boto3.client('ec2', "ap-northeast-1")
resp = client.create_tags(
    Resources=[ec2id],
    Tags=[
        { 'Key': 'Env', 'Value': 'production' }
    ]
)

取得はInstanceと一緒に出来るので比較的楽。
むしろReservationsって何って感じだが今回は割愛。
付与は専用だがこれも比較的素直

RDS, ElastiCache

read rds tag

client = boto3.client('rds', "ap-northeast-1")
resp = client.describe_db_instances()
for rds in resp['DBInstances']:
    resp2 = client.list_tags_for_resource(
        ResourceName="arn:aws:rds:ap-northeast-1:accountid:db:" + rds['DBInstanceIdentifier']
    )
    print(resp2['TagList'])

write rds tag

client = boto3.client('rds', "ap-northeast-1")
resp = client.add_tags_to_resource(
    ResourceName="arn:aws:rds:ap-northeast-1:accountid:db:" + dbidentifier,
    Tags=[
        { 'Key': 'Env', 'Value': 'production' }
    ]
)

Tag操作は取得も別メソッド。かつ、リソースの指定方法がARN。

ELB

read elb tag

client = boto3.client('elb', "ap-northeast-1")
resp = client.describe_load_balancers()
for elb in resp['LoadBalancerDescriptions']
    resp2 = client.describe_tags(
        LoadBalancerNames=[elb['LoadBalancerName']]
    )
    for tagdesc in resp2['TagDescriptions']:
        if tagdesc['LoadBalancerName'] == elb['LoadBalancerName']:
            print(tagdesc['Tags'])

write elb tag

client = boto3.client('elb', "ap-northeast-1")
resp = client.add_tags(
    LoadBalancerNames=[elb_name],
    Tags=[
        { 'Key': 'Env', 'Value': 'production' }
    ]
)

取得する方はタグも複数形で帰ってくる。
ではと、複数ELBを指定して一気にとって後で突き合わせればと思ったのだが、
一度に指定できる数が20までと怒られたので結局1個ずつ処理した。
Documentにも上限書いてないのだが・・・
Listタイプのメソッドは結果がページングになっていることはあるが、
入力も分割必要なのは結構ダルい。

付与する方はほぼEC2と一緒。

Kinesis

read kinesis tag

client = boto3.client('kinesis', "ap-northeast-1")
resp = client.list_streams()
for stream_name in resp['StreamNames']:
    resp2 = client.list_tags_for_stream(StreamName=stream_name)
    print(resp2['Tags'])

write kinesis tag

client = boto3.client('kinesis', "ap-northeast-1")
resp = client.add_tags_to_stream(
    StreamName=stream_name,
    Tags={ 'Env': 'production' }
)

一見、RDSに近い(ARNではないが)ように見えるが、
付与する際のTagsの形状が異なることがお分かりになるだろうか。
あと、付与時に複数に連続処理していると、
必ず10個連続実行の後にRateLimitExceptionになったのでtime.sleep挟むようにした。
他のAPIでは待たされることはあってもエラーとなることは無かったので何でコレだけ・・・

Redshift

read redshift tag

client = boto3.client('redshift', "ap-northeast-1")
resp = client.describe_clusters()
for cluster in resp['Clusters']:
    print(cluster['Tags'])

write redshift tag

client = boto3.client('redshift', "ap-northeast-1")
resp = client.create_tags(
    ResourceName="arn:aws:redshift:ap-northeast-1:accountid:cluster:" + cluster_name,
    Tags=[
        { 'Key': 'Env', 'Value': 'production' }
    ]
)

取得は一緒にとれる。付与はARNタイプ

S3

read s3 tag

client = boto3.client('s3', "ap-northeast-1")
resp = client.list_buckets()
for bucket in resp['Buckets']:
    tags = []
    try:
        resp = client.get_bucket_tagging(Bucket=bucket['Name'])
        tags = resp['TagSet']
    except:
        pass
    print(tags)

write s3 tag

client = boto3.client('s3', "ap-northeast-1")
resp = client.put_bucket_tagging(
    Bucket=bucket_name,
    Tagging={
        'TagSet': [
            { 'Key': 'Env', 'Value': 'production' }
        ]
    }
)

意味不明ぽいがTagにアクセスして存在しなかった場合Exceptionになるので
仕方なしにこの形になった・・・
boto3Document一通り眺めたけどすぐには他に思いつかなかず。
ちなみに他のプロパティも同様の挙動をしました。

付与する方も少し階層が他と異なる。

感想

もちろん、処理方法は1種類しかないわけじゃないので違う書き方もできるし、
見落としてる部分もあるかもしれない。
とりあえず各リソースの一覧+タグを拾ってきて、それを更新するのを雑に書いてみた結果です。
ただboto3になったのここ1年くらいだったと思うので思いのほかバラついてるなぁと思った次第。

開発環境をDockerにした話

若干釣りタイトルっぽい。
どの開発環境かという話だけど、自分の場合、

  • インフラ用途のちょっとしたPythonスクリプトの開発
  • Terraformをローカルから実行する
  • 開発したAnsibleのRoleをローカルで試す
  • golangの開発をローカルで行う

みたいなのをこれまではVagrantVirtualbox上で行ってきた。
主な理由として、

  • 家のPCはWindowsLinux開発をローカルで実施しにくい
  • 会社のMacでもローカルを汚したくない
  • 家と会社の環境を共通化したい

みたいなのがある。
TerraformやgolangMacローカルにも入れてたのだけど、
BrewCaskでの更新が危うく、やはりローカル直は管理ダルイよねと。
Vagrantでも回っていたんだけ思考。

でDockerでやることにしたんだけど、 やるだけならぶっちゃけ簡単で
Docker Toolboxさえ入れておけば、あとは
python:2.7.11-slim」とか「golang:latest」
とか引っ張ってきてほぼ終了なのだが、
利便性のためにいくつかのツールを同梱するようにした。

  • direnv
  • peco
  • ghq

direnvはAWS複数アカウント切替のため。
direnv allowの結果を保持するのでユーザホームもマウントしている。
peco+ghqはレポジトリ管理をgopath方式にしていて便利に使うため。
$GOPATHをマウントする。捗る。

あと一番やりたかったのはAnsibleで1.9系と2.x系の移行期をDockerで切り抜けたいのだが、
実はココはまだうまくいってない部分がある。

そんなわけで雑なDockerfileを量産体制に入りつつ、
余勢を駆ってあわよくばアプリもどうにかしていきたいと画策しているところ。
Mac for Dockerはまだ試してません。

Docker Toolboxで時刻を合わせる話

Docker ToolboxでDocker使っていて時刻がずれて
直し方をなんだかんだで何度か調べているのでメモっておく。
(自分が欲しい方法が一発で検索されない)

ググると何種類か方法が出てくるのだが自分が直したい場面はそんな致命的じゃなくて
スリープ直後に時間がずれてAWS APIとか叩くと怒られた時くらいなので  

docker-machine ssh default "sudo ntpd -q -p 1.jp.pool.ntp.org"

Docker Toolboxの裏側のboot2docker vmssh経由でntpdコマンドを実行する。
これをMacはalias、Windowsはシェルで置いておいて、
怒られたら一旦containerから出て(もしくは別窓開いて)実行する。

元コマンドは次を参考にしました。
MacでDockerを動かす際に気をつけること

Windosw環境のDocker Toolboxでshared foldersのpermission設定する話

最近、VagrantをDockerに置き換え始めてるのだけど、 以前*1と同じ問題が発生したので対応した。

Docker Toolboxも裏側はVirtualbox + boot2dockerなので基本は一緒なのだが、
Docker Toolxoxだと今のところ設定でどうにかする方法は用意されてなさそうなので、
(前回のmount_optionはあくまでVagrantの機能実装)
作成されたVMを権限変えてマウントしなおす。

docker-machine ssh default "sudo umount c/Users"
docker-machine ssh default "sudo mount -t vboxsf -o uid=0,gid=0,fmode=0666,dmode=0777 c/Users /c/Users"

この作業はVMをcreateしたりstop-startする度にやる必要があって、
さすがに面倒だったのでクジラの絵を出してるシェルを適当にハックした。

C:\Program Files\Docker Toolbox\start.sh

この中でVMが存在するかチェックしてcreateする部分と、
VMのstatusをチェックしてstartする部分があるので

if [ $VM_EXISTS_CODE -eq 1 ]; then
  "${DOCKER_MACHINE}" rm -f "${VM}" &> /dev/null || :
  rm -rf ~/.docker/machine/machines/"${VM}"

(中略)

  "${DOCKER_MACHINE}" create -d virtualbox "${VM}"
fi

VM_STATUS="$(${DOCKER_MACHINE} status ${VM} 2>&1)"
if [ "${VM_STATUS}" != "Running" ]; then
  "${DOCKER_MACHINE}" start "${VM}"
  yes | "${DOCKER_MACHINE}" regenerate-certs "${VM}"
fi

この2箇所の後ろに2行ずつ追加すればよい。

  "${DOCKER_MACHINE}" ssh "${VM}" "sudo umount /c/Users"
  "${DOCKER_MACHINE}" ssh "${VM}" "sudo mount -t vboxsf -o uid=0,gid=0,fmode=0666,dmode=0777 c/Users /c/Users"

これで次に起動したりする際には権限を変えてマウントされる。
なお、これはdefault VMの設定なので、自分でcreateした場合には自分で対処する必要がある。
あとDocker Toolboxを更新するときにリセットされそうな気もする。

参考: Dockerにホストのフォルダをマウントしたい!

2段階認証+Windows10+SourceTree+Github

先日、「AWSとGitHubに2段階認証の導入」という記事を見かけたのと
同僚が2段階認証を啓蒙していたので設定することにした。
MFA用のアプリはGoogleAuthenticatorをこれまで使っていたのだけれど、Authyに変更した。
多数並んだ時にアイコン付きで非常にわかりやすそうで、
更にバックアップ面でも効果がありそう。

入れ方はココを参照した。

  • 若干UIが変わってる部分があったが流れを読めばさほど問題ない
  • GoogleChromeExtensionと連携する際にアプリ側で受け入れる設定をする箇所があった
  • GoogleChromeExtensionがアプリ側で設定した更新の一部がうまく反映されないような・・・
    • 入れなおしたら反映されたのでバージョンとかあるかも、、Authyの公式から順に入れよう
  • 登録内容は暗号化されてサーバに保管されるので携帯交換が起きてしまってもAuthyから復旧できるらしい

Githubを2段階認証にするとhttps方式でアクセスしていた人はそのままではダメで、
アクセストークンを設定する必要があるそうなのだが、
ここはオーソドックスにSSH認証に変更する。
更に複数アカウントの人の場合はssh_config等で工夫する必要があり、
Linux的には普通だが自分の場合はWindowsだったので少し手間取った。

Windows10、SourceTreeを利用した設定をメモしておく。

基本的には次の通り
Windows+SourceTree+SSHに関してはこれ

  • msysgit導入
  • SourceTree設定で「システムGitを使用」
  • SourceTree設定で「PuTTY/Plink」ではなく「OpenSSH」を設定する
  • C:\Users\username.ssh\config にssh_config設定
    • C:\Program Files\Git\etc\ssh\ssh_config でもよいかもしれないが権限変更が必要だったので回避

何でOpenSSH設定でいけるのかちゃんと調査してないが、
msysgitを導入すると使えるようになった気がする。
というのはSourceTreeの「ターミナル」からsshコマンドを実行できているので。

2015年振り返り

適当メモ

雑感

SIerから事業会社に転職して1年以上が経ちました。
転職自体はおおむね満足しています。
やりたい事がやれる、というと若干語弊があるのですが、
不足しているものはいくらでもあって気づいた人が手を上げればやれる、という感じでしょうか。
インフラ的ポジションになってこちらも1年強ですがやりたいことは尽きないです。
前に戻りたい要素は無いですね。
自分の技量面の不足は圧倒的に感じます。

仕事の内容で見ると前半は仕組みを作ろうと少しずつやってたのですが
後半は運用雑務に追われてしまったように思います。
夏からチームメンバーが増えたので自分が運用保守している間に
なにかしら新しいものを作ってもらうことが出来るようにはなってきました。
2016年はもっと柔軟な構成をとれるように土台の仕組みづくりしていきたいです。

ざっくりやったこと

  • AnsibleでSetup
  • AWSもAnsibleで
  • mackerelで監視
  • fluetdでログバックアップ(S3)とログ可視化(Kibana)
  • AlertもERRORログSlackへ
  • hubot+Slackでデプロイ、Setup、一部状態管理等

AWSPython、Ansible、Hubotばかりやっている印象でした。
同僚も「最近nodeJSばかり書いてる」と言ってた時期がありましたが自分はもっと・・・

AnsibleをSlackから実行するようになって未来感あるかと思ったけど
結果使う人が限定されかけていて負債化しかけているような。
作ったもの全般的にそうですね、普及施策が不足orやり方が悪いです。

スケールという意味で伸び悩み

プルリクはmackerel-agent-pluginsにいくつか出来たけど思ったより出来なかったです。

勉強会参加

2/13 第8回elasticsearch勉強会
3/12 道玄坂LT祭り第2回(統計、機械学習、データ抽出)
4/15 SmartNews Tech Night Vol.2 ~クラウド事業者に就職する以外の インフラエンジニアの生きる道~
5/26 mackerel meetup #4
6/3 norikra meetup #4
6/26 IPROS Tech Meetup!インフラ系SaaSカジュアルトー
7/2 サポートエンジニアNight
7/26 JTF
8/19 rebuild meetup
8/20-22 YAPC
9/17 mackerel meetup #5
10/9 次世代クラウド勉強会 Docker、DevOpsを取り巻くマイクロサービスのコンセプト
10/10 渋谷Java
10/18 次世代Webカンファレンス (ustream)
12/14 Workflow Hacks #1
12/15 Embulk meetup #2

今年は運よく1度発表させてもらえました。皆様には非常に感謝しています。
コミュ障なんで外部勉強会行っても知り合い増えない(懇親会参加しない)ですが、
発表する立場になると話しかけてもらえるという利点はありました。
開発力が無いので共有できるとしたら運用とかになるのでしょうが、
現状は同僚にもうまく共有できてないので悩ましいです。

勉強会はモチベーションアップか現場の温度感を感じに行くことが多いのですが
今年はそういった意味では面白いのが多かったですね。
rebuildからYAPCの盛り上がりが個人的にも大きかったです。
podcastもっと流行りそうですね。rebuild supportersお勧めです。
自分はrebuild.fm, mosaic.fm, admins.bar 聞いてます。

全般的に参加の方向性は完全にインフラ側に寄りました。

社内勉強会

http://takezoe.hatenablog.com/entry/2015/12/26/163807

毎週開催してもらえて頭の下がる思いです。
岡本さんの回がYAPCで見れなかったのが残念。

社内では1度発表させたもらったのと、
エンジニアチームで主催している社外勉強会の一環でAnsibleのハンズオンをしました。
教えるための資料作りは知識が体系化されるのでいいですね。
しかし代償に精神の疲弊が半端ないす。

買った本

  • WEB+DB PRESS 85
  • Webエンジニアが知っておきたいインフラの基本
  • 実践ドメイン駆動設計
  • WEBエンジニアの教科書
  • WEB+DB PRESS 88
  • たのしいインフラの歩き方
  • Nginxリファレンス

相変わらずの積読・・・
情報はネットで仕入れまくってるとはいえ、
どこかで体系的には抑えておきたいものです。

その他

婚活ェ・・・
プライベートは全然だけど仕事が好転したので今後に期待したいです。
Griffon隣にあるんで一人飲みも覚えるべきか。

映画

あんま見てない、、、
後はベイマックスを友人宅で見たか。
Amazon Fire TV Stickを買ったのでもっと家に篭りそうです。

ゲーム

最近は携帯携帯でしかやってなくて、
携帯のゲームは時間を気にしすぎるのでそれも止めました。
FF7remakeを果たしてどうするか

2016年はもっと時間が効率的に使えるようになれるといいなぁ。


Mackerelで予測する的な話を試したり発展させたりする

『年末年始のディスク容量アラートを回帰分析で回避しよう』という最高の記事が公開されたので試してみました。また、追加で自分が試してみたいことを試してみた話。

経緯

MackerelでAlertが出たらSlackの特定チャンネルにメンションするという運用にしているのですが、
DiskやMemoryのAlertはショボい理由*1で発生することも多く
サーバ数が増えるに従って頻度も増えるし手が回らなくなってきたのでどうにかしたい、
予測みたいなことで対処できないかと思っていました。

そこでid:stanakaさんの記事を試してみたり、
応用例について考えてみたという内容になります。

用意

自分のような人間にはだいたい準備が大変です。
仕事の環境(AWS/Amazon Linux)を意識してCentOS6で環境を作ったので、
Ubuntuならあるいはもっと楽に出来るかも知れませんん。
欲張って慣れないpyenv-virtualenv環境でやったのもハマリポイントでした。

とりあえず雑にVagrantfile作りました。
Vagrantだとグラフは見れないけど予測プログラム試すだけならコレで出来るはず。*2

実行

id:stanakaさんのプログラムをコピーして実行してみます

$ export MACKEREL_APIKEY="(your own mackerel key)"
$ python mackerel_estimate_filesystem_lifetime.py
INFO:__main__:fetching ip-xxx-xxx-xxx-xxx (1/xxx)
INFO:__main__:fetching ip-xxx-xxx-xxx-xxx (2/xxx)
...
...
ip-xxx-xxx-xxx-xxx:xvda1, size: 277.73 GB/422.62 GB, full in 12d21h21m35.429102s
ip-xxx-xxx-xxx-xxx:xvda1, size: 4.46 GB/8.32 GB, full in 17d22h39m20.554903s
...
...

こんな感じでDiskFullまでの時間が短いものから表示されます。
あくまで予測ですが候補が提示されるのは非常に助かります。
何日か連続でチェックすれば変動に幅があるものもケアできるでしょう。
毎日1回とか仕込もうかなとか画策中です。

metricsを収集する範囲は1週間で利用してます。

(APIの叩く頻度は数秒に1回程度にご配慮ください)

とのことなので、API実行後に time.sleep(2.0) とかして実行してます。

Memoryでも試してみました。
他のmetricもいい感じに確認できるようになるといいですね。

とりあえずこれで長期的な予測はしやすくなりました。
デプロイ前後の挙動変更とか元々使用量が高い場合とかいくつか難しい課題はあるのですが、
こういった手段の枠組みが提供されたことは喜ばしいことです。
更に
『もう少しすると、今までの傾向を分析して予測に基づいた監視が出来るようになりそうなので、ぜひご期待ください!』
(Mackerelが大切にしているエンジニアを”ワクワク”させることについて)
とあるので期待せざるをえません!

応用例

もう1つ出来たらいいなと思っていたことがあって、
それは閾値を超えたら緊急度を判定して通知してくれないか、というもの。
WARNING Alertをトリガーに分析した結果を通知する方向で考えてみました。

方法

流れとしては、

  • Alert APIでAlertを定期的に取得する
  • 未処理のDisk WARNING Alertを判定
  • 短時間のmetrics値を元に前出の分析を実行
  • 結果(DiskFullに到達するまでの時間)が一定の値よりも短い場合はSlackメンションする

分析には前出のプログラムを流用します。
プログラムは適当にcronで監視させます。

f:id:a3no:20151227213921p:plain

こんな感じでDisk使用量が増加すると、

f:id:a3no:20151227213931p:plain

Alert出現時に分析も行って結果を表示して、寿命が短い場合はメンションも実施します。

逆に寿命に猶予がある場合にはメンションしないようにします。
MAXまで1日以上かかるような場合は平日であればメンションせずとも対応可能なのではないでしょうか。

試したコードはサンプルとして貼っておきます。
https://gist.github.com/ki38sato/7f2b1a81423a55a0bbef
分析期間やAlert判定閾値は適当です。

チューニングはまだまだこれから*3、場合によって分析方法も、、ですが、
こういった仕組みを用意することで分析の得意な人に改善してもらえる土壌ができます。(他人任せ)

以上、Mackerelで予測したりする話でした。

補足

filesystemを分析するスクリプトVagrant VMに対して試す場合は注意が必要です。 /dev/mapper/VolGroup-lv_root がMackerelサーバでは mapper_VolGroup-lv_root に変換されています。

*1:ちょっとしたエラーを放置してログが溢れるとかリークを放置するとか

*2:ただし初回起動に1時間くらいかかる気がする Docker欲しい案件

*3:ddでファイル作って試しましたが傾きを調整できずなかなか、、、