ゆるふわカウンターアタック

Qiitaっぽい時はQiitaで、slideshareっぽい時はslideshareで、preziっぽい時はpreziで、ブログっぽい時はここで

AWS構成図を無料で描く draw.io

draw.ioというドローイングのWebサービスをご存知でしょうか?

https://www.draw.io/

結構使ってる人も増えているようです。私は今回初めて使ってみました。 個人的な所感を書いた後に、簡単な使い方を書いて終わりにしたいと思います。

所感

いいところ

  1. 無料で登録もないから簡単にスタートできる。

  2. 操作が簡単。多分10分くらいいじってれば操作できちゃうと思う。

  3. PDFや各種画像にエクスポートできる(普通有料だったりする)。

  4. Visioであったレイヤーの概念作れる。

  5. 素材が豊富。特に今回使いたかったAWS関連素材。PollyやAlexaやPinpointのアイコンもあるぞあるぞ。

新し目のサービスのOrganizationとかもありますね。

f:id:pioho:20170323110155p:plain

Webアイコンなんかあるのはいいですね。

f:id:pioho:20170323103119p:plain

電気図もある!そういえばおれ電気工学科だった。。懐かしい・・

f:id:pioho:20170323102140p:plain

もうちょい

  1. ステンシルのレイヤーを"前に"や"後ろに"はあるのですが、"最前面"や"最背面"がないのがちょい辛い。

  2. 補正が少し強いように感じた。矢印の調整時に他のステンシルに引っ張られる感覚があった。込み入った図を書く時少し心配。

  3. プレゼン用に全画面表示があったらよかった。

  4. ん〜、あとはなんだろ、また思いついたら付け足します。

使い方

はじめに

操作は全てブラウザで行います(アプリもあるみたい)。
まずはじめにブラウザでDraw.ioを開くと以下のページになります。
データの保存先はDraw.ioには持ってないのでWebストレージやローカルを選んでください。すでに使ってるWebストレージがあれば連携できて逆にうれしい仕様です。

f:id:pioho:20170323094204p:plain

右下の地球っぽいアイコンをクリックすると言語を日本語にも変更できます。日本語を選んでブラウザをリロードします。

f:id:pioho:20170323094616p:plain

Webストレージは後でも選ぶことができるので後でも構わない場合は"あとで"を選びます。

f:id:pioho:20170323094801p:plain

次の画面になります。

f:id:pioho:20170323094924p:plain

一般のステンシルで書いてみる

ブラウザの画面から左側に各種ステンシルがあります。"一般"の"シリンダ"を画面中央あたりにドラックアンドドロップしてみます。

f:id:pioho:20170323100646p:plain

それ以外のものも同じ要領です。簡単ですね。
テキストも"Text"をドラックアンドドロップで持ってこれます。または何もないところをダブルクリックすることでもテキストステンシルを出現させることができます。
矢印も同じように持ってこれます。矢印を曲げたい場合は画面のように対象の矢印をクリックしたあと、メニューから"カーブ"のタイプを選びます。

f:id:pioho:20170323101111p:plain

f:id:pioho:20170323101414p:plain

自動補正もしてくれます。

f:id:pioho:20170323103506p:plain

f:id:pioho:20170323103513p:plain

AWSの構成図

AWSのステンシル追加

左側のステンシルメニューの一番下の"その他の図形"をクリック。

f:id:pioho:20170323102637p:plain

シェイプが複数出てくるので、"AWS"にチェックを入れて保存する。そうするとAWSのステンシルが追加されます。

f:id:pioho:20170323102847p:plain

あとはこんな風に図が書けます

基本は同じ要領です。好きなステンシルを使って貼っていってください。

例えばこんな感じの図を描くことができます。

ブラウザ上での表示↓

f:id:pioho:20170323101831p:plain

PNG画像↓

f:id:pioho:20170323101735p:plain

AWSステンシル豊富

f:id:pioho:20170323103719p:plain

シートを増やせます

画面下部の"プラスマーク"をクリックすることでシートを増やせます。

f:id:pioho:20170323102331p:plain

ダブルクリックでテキストステンシル出る

f:id:pioho:20170323103619p:plain

ステンシル探すのは検索が便利

検索結構使えます。
pinpoinのアイコンなんかすげー

f:id:pioho:20170323103936p:plain

ステンシルの整列やグループ化

ステンシルをshiftを押しながらクリックで複数選択。 その状態でメニューの"アレンジ"、"整列"できれいに整列させられます。 同じアレンジのメニューにある"グループ化"をすることでステンシルを1つのグループにすることもできます。

f:id:pioho:20170323104510p:plain

テーブル作成

図にテーブルを作れます。画面のルートテーブルとして描いてるものがそれです。
“その他"ステンシルにあります。
対象テーブルをダブルクリックし、行や列の増減などを行えます。操作は画面の右下箇所にあります。

f:id:pioho:20170323120731p:plain

レイヤー構成作れます

メニューの"表示"から"レイヤー"を選択

f:id:pioho:20170323104108p:plain

レイヤー構成を作れます。例えば通信フローの矢印を書いてそれを”通信フロー"レイヤーと定義しておけば、通信フローが見たいときにだけ表示させたり、不要なときは対象のレイヤーを無効にすることで矢印を消すことができます。
見る人によって見やすい図に変更可能な図が一元的に作成できます。Visioなどではよく駆使してました。

“通信フロー"レイヤを表示してる状態です。

f:id:pioho:20170323120534p:plain

”通信フロー”レイヤを非表示にした状態です。

f:id:pioho:20170323115237p:plain

セキュリティグループとかもレイヤ化すると見やすいかもですね

f:id:pioho:20170608100006p:plain

読み取り専用でパブリッシュできます

ファイル->Publish->リンク、これで図をパブリッシュできます。

f:id:pioho:20170323124228p:plain

今回の作成した構成図をパブリッシュします。 リンククリック後、"新しいウィンドウで開く"としてもらえれば編集も可能です。是非お試しを。

https://www.draw.io/?lightbox=1&highlight=0000ff&edit=_blank&layers=1&nav=1&title=sample_cloud.xml#R7V1bc6s4Ev41PMaFJK6Pdm6zVXO2ssepOjvz4sIg21QIeAEn8fn1KwHCRpIdPBZOQshDYjdCl08f3a1Wo2jo%2BvntPvXWqx9JgCMN6sGbhm40CB0dkN9UsC0Fho1KwTINg1IEdoJp%2BBtXQr2SbsIAZ42CeZJEebhuCv0kjrGfN2RemiavzWKLJGq2uvaWWBBMfS8Spb%2FCIF9Vw4LWTv4HDpcr1jKw3PLK3POflmmyiav2NIgWxU95%2BdljdVUDzVZekLzuidCthq7TJMnLT89v1zii0DLYyvvuDlyt%2Bp3lWzaSKPGfML0KNDRhvU9xnLepDpY3vHjRBrPxcPUXY60b8FK%2Fmkwyk2gSeNmqvpblafKEr5MoSYtbkV78kCuLMIqYPE5icvtkmXpBSHrJiWmFD16e4zQuaoX6rmY2UVA60AqZF5zm%2BG1PVA38HifPOE%2B3pMhbk4oVg%2B3q6%2BuODq5ZyVZ7VLCsSuhVFFzWNe%2BAJh8qrOW4m6pw1xXh3gnCRhNhAEWIbUsCsWkogBjpnXL7znRvTOsMbjukK0ZnyPPQmyL0CEARekMFuxH6HvQ2myAjEwggQ9sVQYbAPR9k5xvT227BbihRLErYDYxvwW6gt2C3IwEZ6grYDd3P7ZlQeqPCO6F%2FO5qC2oaxKZD4KLVsfwpqS3vOFFjvz0CDyav8OWJ4r7w1LfL8tqSrh5H3mqHRS5jmGy%2BardPwxcvxzI%2BSTcBNQaF5HBNZx%2BehblMByBanS3QoYGxKDCWyzkfYVoxwGFN24ny2JPi%2BetvTwVWAJ2IWrwLUFTlrSWyiDRVoZmUu35fSzMBx2mlmYKgAGbwP8kmsXeP0OcyyMIkzkbA37tg2wOW0Qa05GbYylSuBFpkKkG2xKuwPsoitEi6ALANSGbJpkM2C%2BSyMs9yLfSyiC29tNHE6VbQAgSagEjVguCNThNRSYLtgizXeOZDO6J9gvp09b6I8nHm%2FPwRji7HvYzBusdI4zQVb%2B7PY%2B1j%2FAOpN2hLzdTEHoQOPq2SrRL8WUBrdQmm9rwFk8TULnQ8lauEG9MDX4mM8Ul9LFuMBSAFfWR399AgMbqVwSV8LqVatnwtZp4nsJX0tpDxu8AmMlmk1Ab2k0UL9MlqGa3FGy7yY0QItguYnQYkjL8tDfxYlXjCbexGBNYyXHxR3MUew6a1CXYTWtmTeqqsA3DY7EieB623yZJb5XnQY0m6pimw0svkFgBgFt6ULgB3QZz38Iqj%2FHj8SwX2lDXmEydDyJrYpzsLf3rwoQGFfJ2GcF10yJ5p5Qz0zAnRWuWb0axQuaYw7wgtaFcUrJLMwrsR5sqYztvYo1R%2Fpl5sro6O1gSR46Eq3HBQgLe449Bhpk1mmD0DaEMO0v%2FCc3DV%2BINIpTskw%2BoU2tJpoG6boPtRRXeVwiyu1nsPNuxiGKdrB7uAW12w%2Fb6ZE8GM7%2Fc%2Bf%2FQKaj%2Bkalgi0fItYAc5itLy3OFsQfhzOqtdz843%2FhHPRobvVTWigTh06h0uLMtlY3lt7ABW%2BnCF6GA%2BbeRT6VA1v5jHOxezOL01boHNLPZYZcgk9bIpeBoe2yOMvjbZhckEfXXTpukNbdDIeyjyP70LuOmn1InCLTgYPd8%2FZbUpy%2FrqDW4wWPyZP24SIfuJlmMR9w7oBtS1RJF2tDU3Rqxv%2F3TPN4XJOiGMI8BpdwSs6c%2BO%2Fe6cpOMUsCTB3hq8Yq5%2FSNNFJ6fP2CmfBmXZFHsuSU5XgLEkPvnU1sgZyx9qtoU3utDHQbpHmIM01qw%2Fjm%2BrD5FocPvMWwyycs%2Bk5%2Fu6UJTqYwgTjOBjTt9XINz%2Fysox4n43pxm9h%2Fl861WR9UX77a%2B%2FKA05DAg1Otf1dcrbDTZdKpPvptqpAh0zwVyFAdQG%2BHnH0DM8s2aR%2B1feKyrmXLjHjSBW2wkHj7TqRIvvJs7IXfCpZiiMvD19wg4EyXlQtPNCnQdsLFzcIKDCrHE110%2F5McvXwrxPYXD0lBEI9BUnrQbfirSW6ySdz5igLoNkgQYNixj7HCGEc5wDP2vGDkWGfICxt%2F5MQxGB9ZAzh3%2F9oy5B6k5JVxO%2BUK6SI6NqroAhjQZMCZxFApiFYZz8NAdyRtfdjGxwfmpf5PebW9GD5FfUuIVW%2Fux%2FIJQMqZEuLNMwz2DJqqgz3kMZovG2zb5SaJsl1D5kkypdp1eUkzVfJMom96HYnnfib9OXIe85SgkIJQdGnIii0wTGCGlDO31MJClx91NRgBtJHluMYiHxAlmvzGQAHKEqIRLdC62KVf3pwfIB3xpF%2BtKMW9zoOV57uWhU9%2BMfPS4u8r7MMsE204h7nr%2FSRrjsHWV8%2FZ5ZrNJ40yzhdN38SShvQkSq%2FWufCf8Zhw%2BXim3yKtUKt2mLP4wyWgKZWdA5rxZOWB53oUPQFjDw6Tjg%2BCa8t4UydI5zdjnCn6kiT67CpH9eRwNGPlT9fR8oSDq2IhhfyIjQB9XmSBrjct7P%2Bt6FnmUzA7mNj5uvrtJdmo5BP2l17QVDkd%2B0VNRqlds8cE1aVj8lFVmupGWt2SS6VXb7ykyjy1hkuy9Tf9hq0ltXfcsTzJNgKwlTar93ZMLQZundJ29Ag8mzfpXkBVVeaF9nxMY1%2BVkNYvxWPY0SmpijrOvMFBEd6u6K8q2I%2Fu2JFcEi46QZneRiTJ4%2FGr8v7CTVoFWdU%2BljqiWP1UWHaFtKz0AiYBNhwhMCIGGPSOLD2exIcvuvPxPeio2VPGsohdmBvAQOkiAB1F%2FWRXo1XbzlcLt1N1bDVDIdJ5kK774zqxBulQ6NCmR6g8lIjMjnnJIgBXi7poXr40SR5wekiKtwJWoRIdm%2FPHHf72kdsr7iIrSFJ%2BpMaaqDi3AxLlh88mJXBrAxmZTArg1n5umbF5N6RrE9ZuoxZEbcCfyabHD9SBD9T5sAiiXP2AqylyqKbXFRPkuncVWIo2yWTAi%2FGS%2FoFvM1nPiNJijnoCnnZLuLgSQ2e1OBJ9dqT%2Bld1vhf1pX4NvlQffSneoIOL%2BlIsUi416XrPTfoVF1YHSIS%2BO5Mu7uNPsb9Jw3x7T1i2FrAXR3x6BpvdYjP0jEM2FwsFh2waGr%2BVRtPc6lPV9YNkECa%2BiVYJ%2BEEyIG5NA2UvU8iO0KgZctbZvrLUwsHB652DV%2BSjQpqtWn4YGyxn1Vbn8O2q5NJgHYe1j9ilifpm95Jud83a2vhOc8hoTc2daBN4vNmdB1Dm%2BDpgL8fX1ByTVvvJnKE%2FHh8fWro%2Fj9d1yZNdJ6et79jW2%2BzauWp30tcpblfntoD7RxHSY6qk%2FylChSUQPbLBRFcmmT9QVOIqI9l7SkDFv5dwhhjMYKIHEz2YaHUmenoPBtN8mg3g1%2BwIXNI2y5bPgwnonQngnsszde5RNXLRugd98q6rLznTQfZKK1KhTWSn%2Fw%2FapIfa5B1XatAmfdEmvHdSx3UvoU5anBr8TQMHgNPySDIt0qNk1MT2hzTYb6Hnh8BBbwMH1QmTd%2BNNmqTe0d6pCSEgpLdNieHciyGI8L494F85BmIqX3cxBMlBNoM16J81mN43tNjg9X8bdWJIjh9T5PSTr2lCZ6%2B%2Bdk%2BP2f2RBJiW%2BD8%3D

クラッチパッド

ステンシルをコピーしたものを幾つか置いておける場所(パッド)。
例えば下図のルートテーブルの表をドラッグアンドドロップで、画面左側の"スクラッチパッド"に入れる(コピー)。
そしていつでもそこから戻せる(コピー)。
複数ステンシルを"スクラッチパッド"に格納(コピー)できて、同じようにいつでも戻せる(コピー)。(あー、言葉で伝えづらい系だなこれは)
何度もコピペするような時に楽かも。

f:id:pioho:20170323211429p:plain

他にも有用なものがあれば追記できたらと思います

see you..

入社3ヶ月経ちました(I have passed since joining 3 months)

とりあえずクビにならず生きています。

新人らしく「なんでもやる」「失敗したらあやまる」「そしてまたトライ」
※トライしないんだったら転職しないし

こんな感じで周りにご迷惑を撒き散らした3ヶ月をすごし、おかげでチームをはみ出すくらい結構たくさんトライできました(もう半年くらい経ったのかと思ってました^^;)。


そんなこんなでやっていけてるのは本当に周りの仲間がエエ人だから。ただエエ人ってことではなくて、社内には文化がしっかりあって皆同じ志を持ってます。韓国の同僚も同じことを言ってたのがブッ刺さりました。

今は、すぐやらないといけないこと真っ只中なので、引き続きがんばります!
「Still Day One」(毎日が初日)
ジェフベゾスの言葉ですが好きな言葉の1つになりました。


疲れた時は柚子ちゃんに癒してもらってます↓
ではまた。≡≡≡ヘ(*--)ノ f:id:pioho:20161019174354j:plain

遅刻はなんでいけないんだっけ?と言う稚拙な話

f:id:pioho:20160613094529j:plain

「遅刻はなぜいけないか?」(稚拙な話でごめんなさい。。)
※もちろん体調不良や電車遅延とかは除きます


「小さいころ先生や親に怒られたから」って言う人は
とりあえず遅刻してないならそれでもいいかと;


ただ大人になると良くも悪くもストレス耐性が付いてきます。

ちょっと怒られても響かなくなります(これはこれでチャレンジングに成長する為に必要な能力でもありますが)。


ちなみにうちのチームの勤怠はとてもいいです。

今まで居たメンバーも含めて朝の出勤もそうですが、会議へ遅れや欠席もほぼ皆無と言っていいかもしれません。


以前は定常的に遅刻するメンバーがいたこともありました。

遅刻すると・・

  1. 会議や朝会に遅れる場合
    複数人の稼働を同時に使う議論や決議をする時間が減ります。チームやプロジェクトの意思決定の質を下げることになります。

  2. 帰りが遅く朝起きれない場合
    計画したタスクがうまくいってないか、緊急な作業を抱えてしまっています。それを定点チェックする仕組か本人がしっかり上長にアラートを上げる文化が必要です。
    (うちのチームは各自やばい時はアラート上げる文化有り、逆に夜間対応したなら「今日は早く帰りな」とか言います)

  3. そもそも定常的に遅刻している場合
    約束を守れない人に大きい仕事は任せられません。その人は会社との最初の約束を果たしていません。
    入社した時に出勤時間についての条件に合意したはずですよね?

  4. 待ってる人はモチベーション下がります
    楽しく待つ人はいないでしょう。それが朝一の朝会からだと一日が・・

  5. 習慣化もできない
    自身の学習についても支障をきたします。学習は習慣化できてこそ効果が大きくなります。自身が決めた時間に遅れても誰も怒ってくれません。自分との闘いです。甘え1つで習慣的な学習ができず成長が鈍化します。

    ※人間、楽な方がいいので周りが遅刻してても何も言われなければ、朱に交わって赤くなりますよね。


・・・以前定常的に遅刻していたメンバーにこのことをしっかり説明したところ、遅刻は改善されていきました。

チームも数年に渡り成果を出し続けております。

遅刻自体は一人が怒られて「ごめんなさい」で済むことに思われがちです。

でも実際は上記のようにチーム全体のパフォーマンスに影響を与えています。
チームが成果を出すかどうかに関わってます。


先日、後輩から「いいチームってなんですか?」と聞かれたことがありました。

いいチームは"成果を出すチーム"です。
ビジネスをやっている以上それ以外にはありません。

その後輩は勤怠はとてもいいです。
もし成果を出すチームにしたいなら、自分がリーダーでなくてもマネージャーでなくても普段考えないディティールについて考えてみるのもいいかもしれませんね。


もちろん遅刻しないだけで成果出るわけではないので^^;

そして私はこれでもう遅刻できなくなった\(^_^)/

朝会で進捗共有はやらない

f:id:pioho:20160403223510j:plain

朝会で進捗共有する。どこの現場も多いと思います。

必要ですかね??

うちのチームでは朝会で進捗共有はやってません。

進捗のステータスはだいたい3つだと思ってます。

  1. 「オンスケ」

  2. 「早く終わった」

  3. 「ちょっと遅れそう」



そもそも3ヶ月くらい先の仕事がある程度チームでスケジューリング出来てる前提ですが
出来てなかったらマネージャがいないかマネージャが無能のどちらかです。

または、明日には明日の風が吹く現場だったらそもそも朝会とかマクロな話してる場合じゃないです。。

  1. 「オンスケ」これは明らかにいらないですね。朝会で全員の稼働を使っての共有?。。いらんいらん。だって問題ないんだもん。

  2. 「早く終わった」と「遅れてる」という状況は朝会ですべきじゃないです。それじゃ遅い。特に後者は。それがわかった時の新鮮な状態で教えて。なんで朝会待つの??
    だいたい「ちょっと遅れそう」はずるずる行くんだし・・。

  3. 進捗は"Redmine"というツール(ツールはなんでもいい)で可視化してるので、進捗を把握しなければいけない人が任意のタイミングで見たほうがいい(なにも全員でやんなくてもいいし、プロジェクトの規模次第なとこもあるけど)。



じゃあ何をやろうか??

うちのチームは若いチームでまだまだキャッチアップが必要なので
「出来るようになったこと」
を共有することにしました。

「出来るようになったこと」
は教えた人と教えられた人とで完結してしまいがちです。

出来るようになったことのレベル感で言うと、会社でよくあるようなスキルシートに書かれる項目(JavaとかMySQLとかとか?)とかよりもずっと小さいレベルでいいです(粒度を小さくしないと毎朝やるのは辛くなりますね。ちなみにうちは週3で朝会してます)。

例えばNagiosへの監視設定が出来るようになったとか、サーバー構築出来るようなったとか、もっと小さくてもいいと思います。

且つそれは技術者にとって喜びでもあります。

それを朝会の短い時間で共有することで
新しい仕事をメンバーに振る材料にもなるし
他のメンバーも作業のヘルプを誰に頼んでいいかの判断する材料になります

あと、普通は数ヶ月とか経って感じる
「あいつ成長してるな」「自分もがんばらなきゃ」
って刺激や喜び、このサイクルを短くできてると思います
これ成長を加速させる1つのサイクルなんですよね。喜びと刺激って。
現場でインプットアウトプットのサイクルを加速させられてるなら、その共有サイクルもせっかくなので加速させてみてはどうでしょう。

理想ですが、毎日毎日成長を感じられる環境にできたらすんばらしいですね。

Centos6でAnsibleを1から2にしたら 「ERROR! Unexpected Exception: 'AnsibleLoader' object has no attribute 'dispose'」

Ansible2をCentOS6にインスト 今までは1.9系でした

yum install python-jinja2-26 --enablerepo=epel
yum --enablerepo=epel-testing install ansible

とりあえずsudo:yesは以下にしとこう become: yes become_user: root

そしてAnsibleを1.9から2.0にしたら以下エラーが出た

[root@ansiblesvr01 ansible]# ansible-playbook -vvv test.yml -i ./hosts --check
/usr/lib64/python2.6/site-packages/pycrypto-2.6.1-py2.6-linux-x86_64.egg/Crypto/Util/number.py:57: PowmInsecureWarning: Not using mpz_powm_sec.  You should rebuild using libgmp >= 5 to avoid timing attack vulnerability.
  _warn("Not using mpz_powm_sec.  You should rebuild using libgmp >= 5 to avoid timing attack vulnerability.", PowmInsecureWarning)
Using /etc/ansible.cfg as config file
ERROR! Unexpected Exception: 'AnsibleLoader' object has no attribute 'dispose'
the full traceback was:

Traceback (most recent call last):
  File "/usr/bin/ansible-playbook", line 86, in <module>
    sys.exit(cli.run())
  File "/usr/lib/python2.6/site-packages/ansible/cli/playbook.py", line 128, in run
    inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory)
  File "/usr/lib/python2.6/site-packages/ansible/inventory/__init__.py", line 85, in __init__
    self.parse_inventory(host_list)
  File "/usr/lib/python2.6/site-packages/ansible/inventory/__init__.py", line 141, in parse_inventory
    group.vars = combine_vars(group.vars, self.get_group_variables(group.name))
  File "/usr/lib/python2.6/site-packages/ansible/inventory/__init__.py", line 506, in get_group_variables
    self._vars_per_group[groupname] = self._get_group_variables(groupname, vault_password=vault_password)
  File "/usr/lib/python2.6/site-packages/ansible/inventory/__init__.py", line 524, in _get_group_variables
    vars = combine_vars(vars, self.get_group_vars(group))
  File "/usr/lib/python2.6/site-packages/ansible/inventory/__init__.py", line 704, in get_group_vars
    return self._get_hostgroup_vars(host=None, group=group, new_pb_basedir=new_pb_basedir)
  File "/usr/lib/python2.6/site-packages/ansible/inventory/__init__.py", line 743, in _get_hostgroup_vars
    results = combine_vars(results, self._variable_manager.add_group_vars_file(base_path, self._loader))
  File "/usr/lib/python2.6/site-packages/ansible/vars/__init__.py", line 560, in add_group_vars_file
    (name, data) = self._load_inventory_file(path, loader)
  File "/usr/lib/python2.6/site-packages/ansible/vars/__init__.py", line 528, in _load_inventory_file
    data = loader.load_from_file(new_path)
  File "/usr/lib/python2.6/site-packages/ansible/parsing/dataloader.py", line 114, in load_from_file
    parsed_data = self.load(data=file_data, file_name=file_name, show_content=show_content)
  File "/usr/lib/python2.6/site-packages/ansible/parsing/dataloader.py", line 93, in load
    new_data = self._safe_load(new_data, file_name=file_name)
  File "/usr/lib/python2.6/site-packages/ansible/parsing/dataloader.py", line 150, in _safe_load
    loader.dispose()
AttributeError: 'AnsibleLoader' object has no attribute 'dispose'

どうやらlibyamlが先に入ってないとダメなようで、今回入ってなかったので一度Ansible2をアンインストールして、 そのあとにlibyamlを入れてからAnsible2を入れ直した。 libyamlだけ追加で入れてもダメでした。おそらくライブラリを見てる先が変わってしまってるのかな

ちなみにpython-yamlはAnsibleと依存関係があり同時にインストされます

[root@ansiblesvr001 ansible]# rpm -qa | grep yaml
python-yaml-3.09-3.el6.rf.x86_64
libyaml-0.1.3-4.el6_6.x86_64

Rundeck はじめました

うちのワンコ初めてカットしました。スッキリです。

f:id:pioho:20160214091218p:plain

cronやJenkinsでがんばってたジョブスケジューリング機能を一元管理する為"Rundeck"を構築しました。

cronはアレなんでやめたいし、Jenkinsは気が付けばあだ名が付くくらいたくさん居るし、執事やとい過ぎだわ

まぁとは言えプラットフォームごとに出来てしまうのは仕方ないとこもあるので、事前にオンプレもAWSも繋がる便利なVPCを作っておきました。
そこにJenkinsでもいいのですが、「おれの仕事CIだし」って聞こえて来そうなのでやめときます。

最近は、AzkabanやらAirflowやらOozieやらジョブスケジューラー界隈が活況ですが、GUIがある程度充実してて必要最低限のスケジュール機能でいいのと冗長化ができるもので、誰でも使えそうって基準でRundeckに決めました。


今の最新は2.6.2がGAとして出ています。

f:id:pioho:20160214091025p:plain

Javaで動くスケジューラーなので手元にあるMacWindowsでも試せます(やったことないけど。。)
Salesforceドリコムやインティメート・マージャーで使ってるようです。

"Rundeckを入れよう"とサブミッションっぽくカジュアルに切ったチケットを見ると1/22に開始している。はや一ヶ月強かかってしまった。
かなり放置して時期もあったが開発側も協力してくれて先週辺りから一気に進んだ。

ググりヒット感で言うと、結構でてきますが、使ってどうこうって話はあまり多くないかなという印象です。
他で書かれてない情報を書ければと思います。

特徴としては

  1. OSSJava/Groovy製でオーケストレーション機能あり

  2. エージェントレス SSH接続できればジョブを実行できます。Ansibleと同じノリ

  3. ジョブネットを作成可能 ジョブAが正常に終わらないとジョブBを実行したくないと言った依存関係を設定できます。

  4. cronと同様の記述が可能 移行が簡単的な感じです。そこまでメリットかはわからないですが

  5. その他 ジョブの再実行、タイムアウト値、ステップ(あとで説明)ごとのエラーハンドラ設定、ジョブ実行や失敗や成功のメールやWebhookでの通知、ジョブの並列度(やりかたはいくつか)設定ができる

※この辺は他の記事にいっぱいあります

Rundeck用語としては

  1. プロジェクト(project)
    ジョブをまとめる単位がプロジェクトです。 プロダクトごとやその本番/ステージング/開発環境ごとに作るのが一般的かなと

  2. ジョブ(job)
    Rundeckがスケジューリング可能な実行単位です。これは特定のプロジェクトに紐付きます。別プロジェクトのジョブを実行することはできません。 ジョブは1つ以上のステップを持ちます。ジョブの実行結果はあとから閲覧できます。

  3. ノード(node)
    ノードはジョブを実行する対象ホストです。 これもプロジェクトに紐付くため、別プロジェクトのノードを利用することはできません。

  4. ステップ(step)
    ステップはジョブを構成する最小単位です。リモート先ノードに配置したシェルやコマンド、ローカルにあるシェル、ローカルにあるシェルを転送してリモート先で実行、シェルが置いてあるURLを指定するとそこからダウンロードしてリモート先で実行とか選べます。
    また作成したジョブをステップとして登録できます。ジョブの中にジョブをネストする感じです。カオスの臭いがしてきますね;
    ただ、これでジョブネットを実現することになると思います。

f:id:pioho:20160225181514p:plain

構成

f:id:pioho:20160225182424p:plain

冗長構成ですが、アクトスタンバイとしました。

rundeck01(アクティブ機) Nginx(Started),Rundeck(Started/Active)
rundeck02(スタンバイ機) Nginx(Stoped),Rundeck(Started/Passive)
  1. スタンバイ側のRundeckはPassiveモード(スケジュールジョブ実行不可)にしておく
  2. アクティブ機が障害が起ったのを検知した際にActiveモード(スケジュールジョブ実行可能)にする
  3. さらにTakeover(実行ジョブの引継ぎ処理)をすることでrundeck02がジョブスケジュールも全て引継ぎアクティブな状態と遷移する

ちなみにAPI使ったActiveモードへ移行はこちら(xxxxxxxxxxはトークン)(アカウントごとにトークン発行可)(disableでpassiveモード)

curl -H 'X-RunDeck-Auth-Token:xxxxxxxxxx' -H "Content-Type: application/xml" -d '' -X POST http://rundeck02:4440/api/14/system/executions/enable

APIを使ったTakeoverはこちら

curl -H 'X-RunDeck-Auth-Token:xxxxxxxxxx' -H "Content-Type: application/xml" -d '<takeoverSchedule><server all="true"/><project all="true"/></takeoverSchedule>' -X PUT http://rundeck02:4440/api/14/scheduler/takeover


プラグインはログをS3に置く"rundeck-s3-log-plugin"と
EC2インスタンスを探してくれる"rundeck-ec2-nodes-plugin"を入れてます
おそらく定番です。

rundeck-plugins · GitHub

その為、ジョブ実行ログはS3にあり、プロジェクト情報はRDSにあり、ノード情報はec2プラグインで動的に取ってくるのでほとんど共有できてるのですが、手動でノード登録が必要なDC側のサーバーだけは共有する必要があります。
こちら

/var/rundeck/projects/プロジェクト名/etc/resources.xml

あと/etc/rundeck/ですね。この辺でACL設定とかします。
プロジェクトをプロダクトごとに分けてマルチテナント的に使う時とかは他の自身のプロジェクトしか見えないように権限付けます(うちがそうです)
なのでバックアップも/etc/rundeck/
一式取ればOKかと
うちはAnsible側に持たせてます

消えないログ

逆に肥大化してくポイントがいくつかあります。問題点ですね。

この辺でがんばってる方いますので参考になると思います
うちもマネてとりあえず手を打ちましたが絶賛模索中です

https://gist.github.com/unicolet/af648a97163ce6b44645
http://www.phwitservices.com/2015/05/clearing-rundeck-log-files/

/var/lib/rundeck/logs/*のジョブ実行ログは消えません。
S3にあるジョブ実行ログも消えません。
RDSにあるジョブ実行関連の情報も消えません。
GUIからBulkdeleteが出来るのですが1度に最大20行しか選べず・・
この辺のテーブル

log_file_storage_request
base_report
execution

リンクを参照し30日を過ぎたジョブ実行IDをfindして
ローカルファイルとDBのレコード削除をしています。
対象テーブルは網羅されてる自信なしです><

#!/bin/sh
cd /var/lib/rundeck/logs/rundeck

JOBS=`find . -maxdepth 3 -path "*/job/*" -type d`

for j in $JOBS ; do
        echo "Processing job $j"
        ids=`find $j -mtime +30 -iname "*.rdlog" | sed -e "s/.*\/\([0-9]*\)\.rdlog/\1/" | sort -n -r`
        declare -a JOBIDS=($ids)

          for job in ${JOBIDS[@]};do
             echo " * Deleting job: $job"
             echo "   rm -rf $j/logs/$job.*"
             rm -rf $j/logs/$job.*
              mysql -h YOURDB -uxxx rundeck -pxxx -e "delete from log_file_storage_request where execution_id=$job"
              mysql -h YOURDB -uxxx rundeck -pxxx -e "delete from base_report where jc_exec_id=$job"
              mysql -h YOURDB -uxxx rundeck -pxxx -e "delete from execution where id=$job"
          done
done

あとはシンプルにAPIから消すことはできます。
が、いついつ以前を削除みたいなことはできず指定JOBIDの実行ログ全て消えます。

curl -H "X-RunDeck-Auth-Token: $RD_OPTION_TOKEN" -H "Content-Type: application/xml" -X DELETE http://rundecksvr:4440/api/12/job/$RD_OPTION_JOBID/executions

$RD_OPTION_TOKEN には権限のあるユーザーのトークン
$RD_OPTION_JOBID には対象のジョブID

 cat /etc/rundeck/apitoken.aclpolicy
description: API project level access control
context:
  project: '.*' # all projects
for:
  resource:
    - allow: '*'
  adhoc:
    - allow: '*'
  job:
    - allow: '*'
  node:
    - allow: '*'
by:
  group: api_token_group

※注意としてはトークン用のACLファイルが別にあるのでそちらにもDELETE権限を付与してあげる必要がありますがとりあえず上記はapi_token_groupに全権限付与してます
※ここ改善されると信じてます。簡単に標準機能であってほしい;;

KeyStorage

これ便利かも
プロジェクトごとに対象の鍵を選択するだけで済むし、RDS側で鍵を持ってくれるので冗長性もあるのでうれしい。

f:id:pioho:20160226121616p:plain

プロジェクト横断

プロジェクト横断したジョブスケジュール設定したいって絶対でますよね。。

プロジェクトを横断したジョブ連動は、今実現するとなると多分・・

  1. ファイルができたことを検知するシェルを1つ目のステップに登録したジョブを作る (ループさせてファイルがあったらexitするよな感じで)
  2. ファイルがあったら別プロジェクトの前段のジョブが終わってるとして、自分のジョブを走らせる

感じかと
めんどくさそうですが汎用性あるジョブにしてしまえば流用可能かと思います。

もっといい方法あれば教えてください><

ジョブが増えてくるとDBサーバーがCPUリークする

CPUリークします。1ヶ月スパンくらいでCPU使用率が右肩上がりで

これはworkflow_workflow_stepというテーブルにインデックスが張られてないことが原因です。workflow_commands_idにインデックス張ります。劇的に改善します。

 ALTER TABLE workflow_workflow_step ADD INDEX workflow_commands_id(workflow_commands_id);

Rundeck との闘争 - 日々是ウケ狙い

外部からキック

外部のサーバーとの連携したい場合はAPI経由でRundeckのジョブキックが可能です。

ジョブID特定
(ローカルからですが・・)

# curl -H 'X-Rundeck-Auth-Token: xxxxxxxxxxxxxxx' "http://rundeck01:4440/api/15/project/test001/jobs"
<jobs count='2'>
  <job id='3a15fbcb-53f3-4cc4-b689-d6f96a9bxxxx' href='http://rundeck01:4440/api/15/job/3a15fbcb-53f3-4cc4-b689-d6f96a9bxxxx' permalink='http://rundeck01:4440/project/test001/job/show/3a15fbcb-53f3-4cc4-b689-d6f96a9bxxxx'>
    <name>てすと01</name>
    <group />
    <project>test001</project>
    <description>てすと詳細</description>
  </job>  
</jobs>

ジョブ実行

# curl -X POST -H 'X-Rundeck-Auth-Token: xxxxxxxxxxxxxxx' "http://rundeck01:4440/api/12/job/3a15fbcb-53f3-4cc4-b689-d6f96a9bxxxx/executions"
<executions count='1'>
  <execution id='6635' href='http://rundeck01:4440/project/test001/execution/show/6635' permalink='' status='running' project='test001'>
    <user>admin</user>
    <date-started unixtime='1455688116789'>2016-02-17T05:48:36Z</date-started>
    <job id='3a15fbcb-53f3-4cc4-b689-d6f96a9bxxxx' averageDuration='985' href='http://rundeck01:4440/api/15/job/3a15fbcb-53f3-4cc4-b689-d6f96a9bxxxx' permalink='http://rundeck01:4440/project/test001/job/show/3a15fbcb-53f3-4cc4-b689-d6f96a9bxxxx'>
      <name>てすと01</name>
      <group></group>
      <project>test001</project>
      <description>てすと詳細</description>
    </job>
    <description>ls -l</description>
    <argstring />
    <serverUUID>xxxxxxxx-400a-403a-828c-xxxxxxxx46ff</serverUUID>
  </execution>
</executions>

※どちらもRundeckのCLIもあります

所感

私はジョブスケジュール設計とか素人なのですが
公式ページにも書いてあったのですが、データドリブンな設計がいいと

様々なコマンドやスクリプトをジョブ化できます。 しかし全てのユースケースに対応するジョブを作ろうとすると、 スクリプトの呼び出し方が少し違う程度のジョブを大量に作ること になってしまうでしょう。 それらの違いとは、往々にして環境やアプリケーションバージョンに関連します。 そのほかの部分については人が必要な情報を与えてジョブを実行しているにすぎません。 スクリプトやコマンドをデータドリブンにしましょう。 そうすればより一般化でき、他のコンテキストでも再利用できます。 同じプロセスの変数をメンテナンスするより、 ジョブが外部データからのオプションモデルで駆動するようにすることで、 よりよい抽象化とカプセル化を期待できます。



ジョブの成功か失敗がファイルを出力できたかどうかというのはキレイな設計な気がします。

IMのまっつさん!構築中のアドバイスありがとうございましたmm

という訳で隣の席の同僚がジョブを作りたくなっているのがうれしいです。
作業をカプセル化して運用が楽になったら幸せです。

GCP Autoscalerで遊ぶ

日曜は犬と留守番をしていたので、時間をもてあましたので犬とオートスケールで遊ぶことにした

f:id:pioho:20160201185421p:plain

GCPのオートスケール機能Autoscalerの正式版は去年の9月ころ出たようです。

www.publickey1.jp

ウォームアップ不要ってところがAWSとの差別化ですね。5分以内に1000台一気に増やせるってすごくて怖い・・w
SSL終端できないとかもありますがが
まだマネコンにメニューもなくAPIのみの提供で、AWSの最初の頃のAutoscaleみたいな感じ、、って思ってたらインスタンスグループなるところにあった!

AWSのAutoscalingGroupのような感じですねきっと。

HTTPロードバランサを使ったAutoscalerで設定するものは以下

  • Global IP(HTTPロードバランサで使う場合タイプをグローバルにする)
  • Image File(オートスケールする際の作られるサーバーの元イメージ、これをもとにサーバーが増えていく)
  • Instance Template(マシンタイプ、Image File、ディスクタイプ、ディスクサイズ、所属ネットワークなどのインスタンスにまつわる情報をまとめたもの)
  • Instance Group(Instance Template、ゾーン、オートスケールのオンオフや閾値設定)

※この下はどちらかというとHTTPロードバランサの構成要素

  • Health Check(URLパス、ポート、間隔、タイムアウト)
  • Target Proxy(URLマップ、プロキシタイプ)
  • Global Transfer Rule(外部IP、プロトコル、Target Proxy)
  • Backend Service(リッスンプロトコルタイムアウト値、バックエンドとなるInstance Group、Health Check)
  • HTTP Load Balancer(Backend Service、Global Transfer Rule)

項目多いし文字だとわかりづらいので図にしてみる、が、やっぱわかりはずらい。。 ただこういう機能なんでこんなもんかと

f:id:pioho:20160131203954p:plain

ぽちぽちは大変なので、Terraformでやってみる
(テンプレは↓の方に張ったので変数を変えてよしなに試してみてもらえるとうれしい)

グローバルIPを作る場合、画面からだと以下のようにタイプを地域かGlobalかを選ぶところがある(どちらもグローバルIPではあるが、HTTPロードバランサにはグローバル指定のIPしか使えない)
※多分リージョン跨ぎのロードバランシングの為だと思うが今回は割愛
Terraformで使うResourceは地域IPの場合"google_compute_address"でグローバルIPの場合"google_compute_global_address"と分かれていて最初オプションで指定するものと勝手に思ってたから迷った><

f:id:pioho:20160201155653p:plain

AutoScalerどうだったか?

あたりまえだがAutoScaleしたw

インスタンス台数の最小値、最大値は設定できます。
とりあえず最小値4台、最大値16台、チェックはCPU50%とかで
InstanceGroup単位でCPU使用率を見ますが、4台のうち2台を100%にしました。
予想は行っても60%くらいかと思いきやグラフは一瞬80%くらい行きました。

結果的に無事インスタンスがAutoでScaleしましたがInsntance Groupのメトリクスがどういう計算になってるのか

最初の4台状態↓

f:id:pioho:20160201180729p:plain

CPU負荷かけて増えた状態。
10台に増えた。

AWSだと1度の増加台数を決めれるけどGCPはよしなに増やすっぽい。
だからスパイクにも強いってことだろう。最大数は決めれるけど

10台に増えてる↓

f:id:pioho:20160201180846p:plain



Instance Groupにある初期遅延時間(最初のヘルスチェックまでの時間)がデフォは300秒だけどTerraformだと変えられないっぽい?(いやどっかにある気がするがInstanceGroupとAutoscalerにはなかった。。)

なので多分ですが初期遅延時間(300s)+Cool Down(180s)の8分とインターバルのタイミングなので8分強。

CPU負荷を止めて、ぼーっとF5押しながらストップウォッチ見てたら10分弱くらいで減っていった↓

f:id:pioho:20160201180910p:plain



Cooldown値はあるのですが、AWSでは出来た一度に増設する台数とかきめ細かい設定はGCPはない(?)っぽいですね。
あと、LBのメトリクスがそもそも少ないw
あと、MultiZoneのAutoScaleはできない??これもAWSではできたけどもしできないなら痛い、

ほんとに出来ないかは不明、、Zoneの最小単位となるBackendを同じパス(/とか)で複数選択出来ればいいのだが、"URL MAP"設定でBackendを複数指定する場合、同じパス名でマップすると怒られる。なので同じパスにBackendを複数設定が出来なそうと思ったが違うかなぁ、、来週GCPUGおじゃまするので聞いてみよ。

※自己解決しました。HTTPLBのバランシング範囲はRegionでNWLBのバランシング範囲はZoneなのですね。

eventdots.jp

ちなみにTerraformのVarsとTemplateはこちら

構成としては

GCPのCredentialファイルは各自環境のものをカレントに置いといてね

### GCP
project_name = "test-project01"
region_asia = "asia-east1"
zone_asia1 = "asia-east1-a"
zone_asia2 = "asia-east1-b"

### GCE
server_name = "test-op01"
machine_type = "f1-micro"
image_name = "image-1"

### NW
http_port = "80"
ssh_port = "22"
any_port = "0.0.0.0/0"
kyoten_ip = "xx.xx.xx.xx"
ip_op = "test-opip01"
ip_lb = "test-lbip01"
fw_name = "test-allow-web"
## vars
variable "project_name" {}
variable "region_asia" {}
variable "zone_asia1" {}
variable "zone_asia2" {}
variable "server_name" {}
variable "machine_type" {}
variable "image_name" {}
variable "any_port" {}
variable "http_port" {}
variable "ssh_port" {}
variable "kyoten_ip" {}
variable "ip_op" {}
variable "fw_name" {}
variable "ip_lb" {}


provider "google" {
    credentials = "${file("account.json")}"
    project = "${var.project_name}"
    region = "${var.region_asia}"
}


## Global IP Address

resource "google_compute_address" "default1" {
    name = "${var.ip_op}"
    }

resource "google_compute_global_address" "default1" {
    name = "${var.ip_lb}"
    }


## Instance

resource "google_compute_instance" "default1" {
    name = "${var.server_name}"
    machine_type = "${var.machine_type}"
    zone = "${var.zone_asia1}"
    disk {
        image = "${var.image_name}"
    }
    network_interface {
        network = "${google_compute_network.default.name}"
        access_config {
            nat_ip = "${google_compute_address.default1.address}"
        }
    }
}


## Firewall

resource "google_compute_firewall" "default1" {
    name = "${var.fw_name}"
    network = "${google_compute_network.default.name}"
    allow {
        protocol = "tcp"
        ports = ["${var.http_port}"]
    }
    source_ranges = ["${var.any_port}"]
    source_tags = ["test-any"]
}

resource "google_compute_firewall" "default2" {
    name = "test-allow-ssh1"
    network = "${google_compute_network.default.name}"
    allow {
        protocol = "tcp"
        ports = ["${var.ssh_port}"]
    }
    source_ranges = ["10.10.0.0/16"]
    source_tags = ["op01"]

}

resource "google_compute_firewall" "default3" {
    name = "test-allow-ssh2"
    network = "${google_compute_network.default.name}"
    allow {
        protocol = "tcp"
        ports = ["${var.ssh_port}"]
    }
   source_ranges = ["${var.kyoten_ip}"]
    source_tags = ["test-office"]

}


## Network Address

resource "google_compute_network" "default" {
    name = "test-nw"
    ipv4_range = "10.10.0.0/16"
}

### LB
## HTTP Health Check

resource "google_compute_http_health_check" "default" {
    name = "test-check"
    request_path = "/"
    check_interval_sec = 5
    timeout_sec = 5
}

## TargetPool

resource "google_compute_target_pool" "default" {
    name = "test-pool"
    health_checks = ["${google_compute_http_health_check.default.name}"]
    region = "${var.region_asia}"
}


### AutoScaler
## Instance Template
resource "google_compute_instance_template" "default" {
    name = "test-template"
    machine_type = "f1-micro"
    disk {
        source_image = "image-1"
    }
    network_interface {
        network = "${google_compute_network.default.name}"
    }
}


## Instance Group

resource "google_compute_instance_group_manager" "default1" {
    name = "test-instansgrp1"
    instance_template = "${google_compute_instance_template.default.self_link}"
    target_pools = ["${google_compute_target_pool.default.self_link}"]
    base_instance_name = "test-svr"
    zone = "${var.zone_asia1}"
}


## Autoscaler

resource "google_compute_autoscaler" "default1" {
    name = "test-as1"
    zone = "${var.zone_asia1}"
    target = "${google_compute_instance_group_manager.default1.self_link}"
    autoscaling_policy = {
        max_replicas = 16
        min_replicas = 4
        cooldown_period = 180
        cpu_utilization = {
            target = 0.5
        }
    }
}


resource "google_compute_backend_service" "default1" {
    name = "test-backend1"
    description = "Hello World 1234"
    port_name = "http"
    protocol = "HTTP"
    timeout_sec = 10
    region = "${var.region_asia}"
    backend {
        group = "${google_compute_instance_group_manager.default1.instance_group}"
    }
    health_checks = ["${google_compute_http_health_check.default.self_link}"]
}


### LB

resource "google_compute_target_http_proxy" "default" {
    name = "test-proxy"
    description = "a description"
    url_map = "${google_compute_url_map.default.self_link}"
}


resource "google_compute_url_map" "default" {
    name = "test-urlmap"
    description = "a description"
    default_service = "${google_compute_backend_service.default1.self_link}"
    host_rule {
        hosts = ["mysite.com"]
        path_matcher = "allpaths"
    }
    path_matcher {
        default_service = "${google_compute_backend_service.default1.self_link}"
        name = "allpaths"
        path_rule {
            paths = ["/*"]
            service = "${google_compute_backend_service.default1.self_link}"
        }
    }
}

## Forwarding Rule

resource "google_compute_global_forwarding_rule" "default" {
    name = "test-forward"
    target = "${google_compute_target_http_proxy.default.self_link}"
    ip_address = "${google_compute_global_address.default1.address}"
    port_range = "${var.http_port}"
}

ちなみにAWSでオートスケール

AWS側のイメージとしては以下は多少参考になるかも。本番実装までしたので。ってか3年前かぁ、、古すぎる・・

www.slideshare.net