サーバコストダウン!AWS EC2 を cron & php で自動停止

f:id:tkhttty:20190318170859p:plain

はじめに

こんにちは! インフラチームの高畑です。

新卒で入社して早くも 2 年目に突入しそうで時間の流れが最近早く感じています。

今回、弊社で運用している標準開発環境(※)について、自動起動・停止するようにしてインフラコストダウンを計ってみたお話しをします!

※ ウィルゲートの開発室でエンジニアに割り当てられる、個々人が自由に使うことができるAWSのEC2上の開発環境のこと。詳しくは下記の記事をご覧ください tech.willgate.co.jp

これまでの運用

これまで標準開発環境は曜日時間問わず基本的にはずっと起動したままで運用を行っていました。

弊社のエンジニアは現在約 40 人ほど在籍しており、標準開発環境も人数分起動しています。

標準開発環境は現在全てのインスタンスAWS オレゴンリージョンの t3.medium インスタンスなのですが、大体月あたり $1,200 ほど( EBS、EIP をの除く)コストがかかっている状態でした。

f:id:tkhttty:20190318132831p:plain

そこで、今回はこのコストをなるべく減らすため、標準開発環境インスタンスを平日夜 22:00 、土日(全日)に自動停止をするようにしてみました。

自動停止させるために行ったこと

自動停止をするにあたり、まず PHP で起動、停止ができるスクリプトを用意しました。

この時の起動するしないのステータスは EC2 インスタンスのタグで管理しており、 activeinactive かで切り替えを行っています。

SDK を使えという声が聞こえてきますが試作品なのでということにしておきます)

<?php

if ($argc < 2)
{
    exit("Please specify an argument. Valid arguments are 'start', 'stop' or 'show'.\n");
}

$today = date('Ymd');
$dayOfTheWeek = date('w');

$startHoliday = date('Y1229');
$endHoliday = date('Y0103', strtotime('1 year'));

$instances = json_decode(shell_exec("aws ec2 describe-instances --query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`State`].Value|[0]]' --profile aws_profile"), true);

switch ($argv[1])
{
    case 'start':
        foreach ($instances as $instance)
        {
            // ステータスがアクティブかつ、土日・年末年始期間でなければ起動
            if ($instance[1] === 'active' && ($dayOfTheWeek != 0 && $dayOfTheWeek != 6) && ($today <= $startHoliday || $today >= $endHoliday))
            {
                shell_exec('aws ec2 start-instances --profile aws_profile --instance-ids ' . $instance[0]);
            }
        }
        break;

    case 'stop':
        foreach ($instances as $instance)
        {
            shell_exec('aws ec2 stop-instances --profile aws_profile --instance-ids ' . $instance[0]);
        }
        break;

    case 'show':
        foreach ($instances as $instance)
        {
            var_dump($instance);
        }
        echo $dayOfTheWeek;
        break;

    default:
        exit("Invalid arguments.\nPlease specify an argument. Valid arguments are 'start', 'stop' or 'show'.\n");
        break;
}

あとはこれを cron などで定時実行させることで自動起動・停止が実現できます。

また、初期状態では全てのインスタンスが自動停止はしても自動起動はしないという状態となっており、これだと定時バッチを標準開発環境で起動しているといった人などが困ってしまうため、標準開発環境ダッシュボードというものを作成しました。

f:id:tkhttty:20190318140826p:plain
標準開発環境ダッシュボード

上記画面より、インスタンスの再起動、停止、起動が行えるほか、自動起動するしないを設定することができるようになっています。

運用方法を変えてみて

月半ばにこのような変更を行ったため、具体的にどれほどコストが下がったかは現状出ていませんが、約半数ほどのインスタンスが 1 日起動しないことがほとんどとなったため、コスト的には半額くらいにはなりそうな雰囲気を醸し出しています。

また、AWS EC2 を利用しているインスタンスについては応用ができると思いますので、夜などは利用しないテスト環境などにもうまく利用ができればと思っています。

同じようなことでお悩みの方がいらっしゃいましたら、参考にしていただけると幸いです!

メンバーの主体性が変化 ~ 組織改革と品質改善 ~

f:id:willgate-yokouchi:20190227232324j:plain

Hacker's GATE 運営チームの石川です。

今回は先日開催した、「Hacker's GATE Presents サービス品質向上しナイト ~ みんなでテスト!10年続くチームと品質 ~」で登壇した鶴飼にインタビューをしたので、そちらの模様をお届けします。

まだ、イベントの開催レポートやスライドを見ていない方はこちらです! tech.willgate.co.jp speakerdeck.com

当日のイベントページ willgate.connpass.com

インタビュー

―― 登壇お疲れ様でした。登壇を終えての感想を教えてください

テーマの品質と組織づくりを組み合わせてお話しさせていただいたのですが、組織づくり自体は品質のためだけに行っていたわけではなかったので、どうやって品質に結びつけたらいいか、という難しさはありました。 なので、登壇に向けて過去の取り組みについて整理をしている時に、組織課題を解決するための活動が結果として、品質向上に向けた取り組みだったと改めて実感することができましたね。

―― 入社した2015年当時、ウィルゲートの開発組織というのはどのように映っていたのでしょうか?

開発のプロセスを見てみると、リリースまでのフローやナレッジも整っていなくて、今でこそ当たり前のように利用されている、デプロイツールがようやく導入されたというタイミングでした。 エンジニアとしても、事業部の方針に沿って物をつくるだけという形だったので、開発室としての組織づくりや、戦略を立てた成長計画、組織として知見を集約するような習慣がなく、他の事業にも応用するといったことは少なかったと思います。

そのため、事業ごとに開発のアプローチが形成され、課題が生じても解決手段の共有が進まなければ、チームのメンバーだけで解決しなければいけない、そういう風潮がありました。

f:id:willgate-yokouchi:20190228113533j:plain

――自分も含めエンジニアは技術や新しいことへのチャレンジが好きな人が多いと思うのですが、当時のお話を聞く限りだと、業務においてそういったチャレンジはなかったんですか?

なかったですね(笑)

サグーワークスについても、入社から1年以上経過し、開発室として事業部に働きかけられたことから、PHPや利用していたフレームのバージョンアップデートが行えました。 なので入社当時というのは技術的なチャレンジができるような環境ではなかったと思います。

それこそ入社当時というのは、会社としても、開発室としても紆余曲折があったタイミングで、

「自分たちの体制をどう立て直すか、どうやって良いプロダクトを作っていく強い組織にしていくか」

という課題がありました。

tech.willgate.co.jp tech.willgate.co.jp

f:id:willgate-yokouchi:20190228113530j:plain

―― そこから、2016年開発室としての3カ年計画がスタートしました。発足した経緯について教えてください。

登壇中にも話した通り、当時の管掌役員との毎週の1 on 1がきっかけで開発本部の活動がスタートしました。

当初は開発室全体の課題の整理や認識を合わせて、どうやって会社の課題を解決していこうかという形で議論していて、開発としてどのチームも同じQCD(Quality, Cost, Delivery)を改善していくことを目標としていました。ただ、QCD全てを目標として置いた時に、事業フェーズやプロダクトの成長度合いに応じて注力ポイントが異なっていて、課題にマッチした打ち手が打てない状態でした。

そこで、事業軸と技術の軸を作り、各軸で課題に対する打ち手に取り組めるようにしました。事業ごとの軸が作れるので、QCDの中で注力する点を作り、各事業ごとにアサインされたエンジニアのセクション担当者が検討・推進、その知見を吸収・共有できるような開発本部を設置することにしました。

―― 実際行ってみて、主観的に見て、客観的に見て、変化したところはありましたか?

開発本部が出来た当初から、フロントエンドやグロースといったセクションを設けて、各事業活動で得たエンジニアの知見だったり、経験を蓄積する体制を整え、事業とエンジニアリングの双方を掛け合わせて、より良いプロダクトを目指したいと考えていました。

運用が開始してからは、多くのメンバーの主体性が大きく成長してきたかなと思います。一人一人が各セクションのスペシャリストとして、技術トレンドのキャッチアップに意欲的になったり、どうやったらウィルゲートの事業に取り入れられるのかということを主体的に考えて行動するようになったと思います。また現場メンバーからのボトムアップで組織が変わってきたり、チーム間の情報共有が頻繁に行われるようになったり、お互いのナレッジを生かしながら仕事をするようになってきた光景を見ると、大分変化したと感じています。

それだけ、今は新たなチャレンジ領域を作ってあげられるような環境になって、みんなが意見をだして推進できる環境になったことはよかったなと思っています。

tech.willgate.co.jp

―― 今後について、教えてください!

現在ウィルゲートだとQAと呼ばれる部署やセクションはなく必要とは感じつつも、すぐに動き出せるということはなくて、試験的に各チームが取り組んでいる、品質を高めるような開発の取り組みをちゃんと吸収して、他チームに展開をどうするかということが重要だと思っていて、引き続き事業フェーズや、チームの状況をみて、それぞれの課題に向き合っていければなと思います。

またWGの開発室、エンジニアが変えていけること、人の効率や生産性、事業を変えていけることがまだまだあると思ってます。テクノロジープッシュで事業をブーストさせていきたいですね。

最後に

「Hacker's GATE Presents サービス品質向上しナイト ~ みんなでテスト!10年続くチームと品質 ~」で登壇した、鶴飼のインタビューの模様をお届けいたしました。

私自身エンジニアとしてプロダクトの品質にどう関わっていくか、何ができるのかなど見つめ直すきっかけになりました。

引き続きウィルゲートではより良いものづくりを楽しむギークな仲間を増やして、エンジニアを含めた「四方よし(※)」を目指していければと思います。

※ 「四方よし」とは 近江商人の「三方よし」が指す三方の、「売り手」、「買い手」、「世間」、に加え「作り手」であるエンジニアを指してます。

Hacker's GATEでは引き続き、エンジニアがワクワクするような、技術交流の場やイベントを提供できるよう、活動していきます。 今後の活動についてもTwitterで告知していきますので、ぜひフォローしてみてください! twitter.com

「Hacker's GATE Presents サービス品質向上しナイト ~みんなでテスト!10年続くチームと品質~ 」を開催しました

どうも!Hacker's GATE運営の石川です。

昨日、株式会社チームスピリットさん、株式会社ウエディングパークさんと共同で、「Hacker's GATE Presents サービス品質向上しナイト ~ みんなでテスト!10年続くチームと品質 ~」を開催しました。 この記事では当日のイベントの模様をお届けします。

willgate.connpass.com

開催の主旨

プロジェクトの規模が小さい状態だと、個人の力量でカバーできたサービスの根幹を支えるサービスの品質も、サービス規模や組織の拡大など、様々な要因で属人化してしまい、品質の担保が難しくなった、といった課題を感じている方もいるのではないでしょうか。

そこで、各社の仕組みや体制づくりなど、自社の経験を役に立ててほしい、という思いで、今回のイベントを開催しました。

当日の様子

3社の組織的な取り組みやQAの仕組み、応募した質問からパネルディスカッションを開催しました。

株式会社ウエディングパーク 斉藤 健太さん

「ウェディングメディアを支えるQAチームの取り組み」

f:id:char1129:20190214150215j:plain

斉藤さんの発表では、開発組織におけるQAチーム発足以前のこと、発足後の導入のお話をしていただきました。 発表中、仕様理解からの改善というアプローチをプロジェクト化して、開発時の品質向上につながったことが印象的でした。 関係各所だけでなく、役員含め関わる人すべてに理解を持ってもらうことで、全員の理解向上、品質が改善する素晴らしい取り組みですね!

f:id:char1129:20190214160637j:plain

当日のスライド speakerdeck.com

株式会社ウィルゲート 鶴飼 吉行

「品質向上に向けた組織改革と成功失敗例」

続いて、ウィルゲートの品質向上に向けた開発での取り組みについて発表をしました。

f:id:char1129:20190214160657j:plain

f:id:char1129:20190214160712j:plain

発表では、2016年当初の開発組織としての課題について、組織としての動きの説明。 各セクションごとの成功・失敗例とともに、説明させていただきました。 この取り組みについては後日記事にしてお届けしようと考えております。

当日のスライド

speakerdeck.com

株式会社チームスピリット 生井 龍聖さん

「チームスピリットにおける品質保証の仕組み」

f:id:char1129:20190214160734j:plain

最後の登壇は、生井さん。 QA組織としての継続的な取り組みや体制作りについてお話しいただきました。 QAの未来像であったり、状況に応じた適応であったり、というのは体制を整えても難しい課題なんですね。

f:id:char1129:20190214160749j:plain

当日のスライド speakerdeck.com

パネルディスカッション

f:id:char1129:20190214160907j:plain

パネルディスカッションでは、事前に募集したアンケートからテーマをピックアップ、登壇してくださった3名に質問してみました。

当日のディスカッションテーマごとに、当日のツイートからまとめてみました。

属人化からの脱却で失敗したエピソード

各社の失敗談いろいろありますね。 やはり、足並みを揃えるときが必要そうですね。

テーマあえて属人化した状態を容認することは?

属人化の許容は、初めは許容しているというWGの回答とともに、ツイッター上でも同じような声がいくつか上がっていました。 ただ、属人化が進めないような仕組みが大切になってきますね。

QA チームとして課題に直面したときに判断軸として大事にしている考え方

f:id:char1129:20190214160849j:plain

ここではチームスピリット・生井さんの障害に対する重要度や発生頻度の考え方について、ツイッター上で多くの共感の声が上がってました。

そして、斉藤さんが行った過去2年分の分析というのはすごいですね。

テストエンジニアやQA はどのようなキャリアパスを描ける?

どのフィールドにおいても、品質を担保できるエンジニアが求められるのはみんな共通の考えなのでしょう。

そして、こんな質問に。

QAを担う人たちの評価がこの時間のトレンド、前日に開催された勉強会でも話題になっていたんですね。

生井さん曰く、テストフェーズにおけるサイクルを評価に加えているようで、現在この評価方法に納得して取り組んでいるということです。

懇親会

f:id:char1129:20190214160936j:plain

f:id:char1129:20190214160953j:plain

懇親会の様子

発表・パネルディスカッションの熱気を保ったまま、懇親会が始まりました。 改めて、品質保証に関するトピックに興味関心ある人が集まった会だったため、各社の取り組みや、チャレンジ、課題相談など、素晴らしい交流の時間になりました。

私自身、懇親会で聴講していた方とお話しさせていただいて、QAの部署の評価について興味があって参加した人や、品質の改善に向けた組織的な取り組みに興味ある人が多い印象で、 有意義な会だったという声をいただけました。

最後に

今回「Hacker's GATE Presents サービス品質向上しナイト ~みんなでテスト!10年続くチームと品質~ 」にご参加いただいた、みなさま、ありがとうございました。 参加していただいた方に「よかった」「いい会だった」という声が多く聞けて、運営として嬉しく思います。

また当日会場を利用させていただいた株式会社チームスピリットさん、 イベント開催にご協力いただいた株式会社ウエディングパークさん、 ご登壇いただいた、斉藤さん、生井さん、ありがとうございました!

Hacker's GATEでは引き続き、エンジニアがワクワクするような、技術交流の場やイベントを提供できるよう、活動していきます。 今後の活動についてもTwitterで告知していきますので、ぜひフォローしてみてください! twitter.com

SAML 2.0 + LDAP + AWSで複数アカウントのSSOを実現した話

はじめに

こんにちは! インフラチームの高畑です。 最近インフルエンザが流行っていて毎年かかっている私も、もうすぐかかるのではないかと日々怯えながら過ごしています。

今回は SAML 2.0 ID プロバイダ(IdP) と LDAP を連携して複数アカウントで管理している AWS の SSO(シングルサインオン)化についてお話しします!

これまで何が問題だったのか

これまで弊社では AWS コントロールパネルへのログイン情報を社内サーバを使ってオンプレで運用している社内専用 wiki で管理しており、都度該当のアカウント情報をコピーしてログインを行なっていました。

そのため、法令停電などの影響で wiki を見ることができずコントロールパネルに入れないという問題や、サービス毎に AWS のアカウントを分けているため、今後もアカウントが増え続け管理が大変になるといった問題もありました。

これらの問題を解決するため、SAML 2.0 IdP (今回は SimpleSAMLphp を使用)を構築して、元々社内でアカウント管理に使用していた LDAP サーバ と連携した SSO を実現しようと動き出しました。

SAML 2.0 IdP / SP の構築

f:id:tkhttty:20190121152652p:plain
SAML 対応のシングルサインオンについて処理の流れ

SimpleSAMLphp について

SimpleSAMLphp とは、 IdP や サービスページ( SP )を構築できる OSS です。 PHP + Web サーバが動作する環境であれば構築ができ、別途ミドルウェアが立ち上がったりもしないため手軽に導入することができます。

github.com

SimpleSAMLphp のインストール

ダウンロードページより最新版( 2019/01/17 時点での最新版は 1.16.3 )を入手してサーバに配置してください。

[root@hostname ~]# tar xvzf simplesamlphp-1.16.3.tar.gz
[root@hostname ~]# mv simplesamlphp-1.16.3 /var/www/simplesamlphp

SimpleSAMLphp 初期設定

[root@hostname ~]# vim /var/www/simplesamlphp/config/config.php
// SimpleSAMLphp の IdP 機能を有効にする
:
    'enable.saml20-idp' => true,
:

IdP 証明書を作成

[root@hostname ~]# openssl req -newkey rsa:2048 -new -x509 -days 3652 -nodes -out server.crt -keyout server.pem
Generating a 2048 bit RSA private key
............................................+++
.............+++
writing new private key to 'server.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:国名
State or Province Name (full name) []:都道府県名
Locality Name (eg, city) [Default City]:市名
Organization Name (eg, company) [Default Company Ltd]:組織名
Organizational Unit Name (eg, section) []:部署名
Common Name (eg, your name or your server's hostname) []:IdPドメイン
Email Address []:メールアドレス
 
[root@hostname ~]# mv server.* /var/www/simplesamlphp/cert/

証明書、認証方法の設定

[root@hostname ~]# vim /var/www/simplesamlphp/metadata/saml20-idp-hosted.php
:
        'privatekey' => 'server.pem',
        'certificate' => 'server.crt',
:
        'auth' => 'ldap',
:

接続先LDAPの設定

LDAPに関する設定を /var/www/simplesamlphp/config/authsources.php に追記

[root@hostname ~]# vim /var/www/simplesamlphp/config/authsources.php
: //↓新規追加
    'ldap' => array(
        'ldap:LDAP',
 
        // Give the user an option to save their username for future login attempts
        // And when enabled, what should the default be, to save the username or not
        //'remember.username.enabled' => FALSE,
        //'remember.username.checked' => FALSE,
 
        // The hostname of the LDAP server.
        'hostname' => 'ldaps://LDAPドメイン',
 
        // Whether SSL/TLS should be used when contacting the LDAP server.
        'enable_tls' => FALSE,
 
        // Whether debug output from the LDAP library should be enabled.
        // Default is FALSE.
        'debug' => FALSE,
 
        // The timeout for accessing the LDAP server, in seconds.
        // The default is 0, which means no timeout.
        'timeout' => 0,
 
        // The port used when accessing the LDAP server.
        // The default is 389.
        'port' => port,
 
        // Set whether to follow referrals. AD Controllers may require FALSE to function.
        'referrals' => TRUE,
 
        // Which attributes should be retrieved from the LDAP server.
        // This can be an array of attribute names, or NULL, in which case
        // all attributes are fetched.
        'attributes' => NULL,
 
        // The pattern which should be used to create the users DN given the username.
        // %username% in this pattern will be replaced with the users username.
        //
        // This option is not used if the search.enable option is set to TRUE.
        'dnpattern' => 'uid=%username%,ou=people,dc=example,dc=org',
 
        // As an alternative to specifying a pattern for the users DN, it is possible to
        // search for the username in a set of attributes. This is enabled by this option.
        'search.enable' => TRUE,
 
        // The DN which will be used as a base for the search.
        // This can be a single string, in which case only that DN is searched, or an
        // array of strings, in which case they will be searched in the order given.
        'search.base' => 'Base DN',
 
        // The attribute(s) the username should match against.
        //
        // This is an array with one or more attribute names. Any of the attributes in
        // the array may match the value the username.
        'search.attributes' => array('uid'),
 
        // Additional LDAP filters appended to the search attributes
        'search.filter' => '特定の属性を持っていれば許可する等のフィルタを記述',
 
        // The username & password the SimpleSAMLphp should bind to before searching. If
        // this is left as NULL, no bind will be performed before searching.
        'search.username' => 'Bind DN',
        'search.password' => 'password',
 
        // If the directory uses privilege separation,
        // the authenticated user may not be able to retrieve
        // all required attribures, a privileged entity is required
        // to get them. This is enabled with this option.
        'priv.read' => FALSE,
 
        // The DN & password the SimpleSAMLphp should bind to before
        // retrieving attributes. These options are required if
        // 'priv.read' is set to TRUE.
        'priv.username' => NULL,
        'priv.password' => NULL,
 
    ),
:

SP 側の設定

[root@hostname ~]# vim /var/www/simplesamlphp/config/authsources.php
:
    'default-sp' => array(
:
        'entityID' => 'https://SPドメイン/simplesaml/module.php/saml/sp/metadata.php/default-sp',
        'idp' => 'https://IdPドメイン/simplesaml/saml2/idp/metadata.php',
:

管理画面ログイン用アカウントのパスワードを変更

[root@hostname ~]# vim /var/www/simplesamlphp/config/config.php
:
    'auth.adminpassword' => 'P@ssw0rd',  // 初期値123
:

Apache の設定をする

[root@hostname ~]# vim /etc/httpd/conf.d/vhost.conf
<VirtualHost *:443>
    ServerName IdPドメイン
    DocumentRoot /var/www/simplesamlphp/www
 
    ErrorLog /var/log/httpd/idp-error.log
    CustomLog /var/log/httpd/idp-access.log combined
 
    Alias /simplesaml /var/www/simplesamlphp/www
</VirtualHost>
 
<VirtualHost *:443>
    ServerName SPドメイン
    DocumentRoot /var/www/simplesamlphp/www
 
    ErrorLog /var/log/httpd/sp-error.log
    CustomLog /var/log/httpd/sp-access.log combined
 
    Alias /simplesaml /var/www/simplesamlphp/www
</VirtualHost>

https://SPページのドメイン/simplesaml にアクセスができればOKです!

【管理者ユーザID】admin

【パスワード】設定したもの

管理者ログインできることも確認しましょう!

IdP、SP のメタデータを設定

(1) 上記URLより管理者でログイン

(2) 連携タブを開くと下図のようになっているか確認

f:id:tkhttty:20190121160128p:plainSAML 2.0 SP メタデータ」と「SAML 2.0 IdP メタデータ」の両方が表示されていない場合は設定が抜けているので再確認しましょう!

(3) それぞれのメタデータをコピーし、「XML を SimpleSAMLphp メタデータに変換」から変換し、

IdPメタデータ → /var/www/simplesamlphp/metadata/saml20-idp-remote.php

SPメタデータ → /var/www/simplesamlphp/metadata/saml20-sp-remote.php

にそれぞれ記載

AWS 側での設定

(1) IAMのページからIDプロバイダーを作成

f:id:tkhttty:20190121160457p:plain

(2) プロバイダータイプは「SAML」、プロバイダ名は適宜、メタデータドキュメントはsimpleSAMLphpのメタデータを選択

f:id:tkhttty:20190121160616p:plain

(3) IAMロールを作成

SAMLプロバイダーは (2) で作成したプロバイダを選択し、「プログラムによるアクセスとAWSマネジメントコンソールによるアクセスを許可する」にチェック f:id:tkhttty:20190121160832p:plain

アタッチするポリシーでは「AdministratorAccess」を選択 ※実際には許可するポリシーを選択してください f:id:tkhttty:20190121161135p:plain

ロール名に分かりやすい名前を入力

SAML認証した後に表示されるロールの選択画面で表示される名前なので、サービス名など分かりやすい名前にしましょう! f:id:tkhttty:20190121161416p:plain

作成したロールの arn をコピーしておく(simpleSAMLphpの設定で使用します) f:id:tkhttty:20190121161548p:plain

SimpleSAMLphp でロール、プロバイダの設定を行う

[root@hostname ~]# vim /var/www/simplesamlphp/config/config.php
 
 857     'authproc.idp' => array(
                  // n は連番でよしなに
                  // https://aws.amazon.com/SAML/Attributes/Role の部分は、 ロールのarn,SAMLプロバイダのarn      ←カンマ区切りにするのを忘れずに!
                 n => array(
                     'class' => 'core:AttributeAdd',
                     'https://aws.amazon.com/SAML/Attributes/Role' => array('コピーしたロールのarn,arn:aws:iam::アカウントID:saml-provider/プロバイダ名')
                 ),
                :
                :
                複数アカウントがあれば同様にここへ追記
                :
                :

以上で設定が完了です! https://SPドメイン/simplesaml/saml2/idp/SSOService.php?spentityid=urn:amazon:webservices にアクセスして LDAP ユーザで認証ができれば OK !

認証が問題なければ以下のようなロール選択画面に移動するので、ログインしたい AWS アカウントのロールを選択してログインができます! f:id:tkhttty:20190121162609p:plain

SSOを導入してみて

今回 SAML 認証を利用して AWS の SSO を設定したことで、複数アカウントの管理が楽になり、停電などの影響も受けなくなりました!

常日頃利用している LDAP のユーザ ID とパスワードで AWS のコンソールにログインすることができるので、一々 ID やパスワードを確認する必要がなくなりちょっとだけ負担を軽くすることに成功したと思っています。

同じようなことで悩んでいる方がいらっしゃれば参考になると幸いです。

Gmailストレージ容量との戦い~GoogleAppsScriptを使った効果的な取捨選択~

開発グループPMO(プロジェクトマネジメントオフィス)の大嶋です。 実はウィルゲートのエンジニアでは最古参なことに最近気づきました。

そんなわけ(?)で、今回は組織の在籍期間が長くなってくると遭遇しがちな情報資産の氾濫という側面から「一足遅いですがこれを大掃除して新年を迎えよう!」というテーマでGmail資産の整理についてお伝えします。

GoogleAppsの容量が逼迫している

ウィルゲートでも、かねてより業務上のメールやファイル共有を中心にGoogleAppsを活用してきています。 近年ではSlackなどチャットサービスへの移行によりメールによるコミュニケーションは減ってきているものの、「フォーマルな連絡はメール」であったり「社内外のシステムからの通知はメール」といった形で、Gmailを使う機会はまだまだあるのではないでしょうか。

GoogleAppsは他のストレージサービスと比べても普通に使うには十分なストレージ容量がありますが、長く在籍しているとどうしても容量上限との戦いになってきます。 GoogleAppsは通常で30GB(無償版は15GB)の容量があり、追加で月額課金の形式で容量を増やすことはできるので短期的には「物理あるいは札束で殴る」的な解決をすることも可能です。

f:id:oshima106:20180907150822p:plain

ですが、仕事をやりくりできる人は得てして限られた時間の中で取捨選択してうまくやりくりしているのではないかと思います。 そこで限られた容量の中でGmailを効果的に運用する方法について考えてみます。

容量を逼迫させる原因

Gmail容量を逼迫させる原因であり、削除するべき対象は大きく分けて以下の2つと考えられます。

  1. 単独で大きなサイズを占めている
    • メールに添付ファイルや解像度の高い画像がついているようなもの
  2. 一つ一つは小さくても同様の内容が大量に存在している
    • メルマガやシステムアラート通知など

このあたりはデータや画像を圧縮して処理したり、N+1問題のような実装を避ける、といったシステム開発における 性能改善の考え方にも通じるものを感じます。

サイズの大きなものを特定

Gmailでは条件を指定したメールの検索ができるので、これを活用して特定していきます。

  • 『larger:3m』のようなサイズ指定で探す
    • この例では、主に添付ファイルを含む3MB以上のサイズのメールが抽出されます
    • 自身の業務に関連性が低いものを中心に削除していきます
  • 『filename:pptx』 のような拡張子で探す
    • 必要な添付ファイルは個別にローカルに保存するなどしてメールは削除してしまうのも一つの手です

これらを『before:2018/01/01』のような日付指定と組み合わせて抽出することで、過去のサイズの大きなファイルをまとめて削除する、といったこともできます。

f:id:oshima106:20190109174756p:plain

1つ1つが小さくても件数がかさんでいるものを特定

こちらが今回の本題です。 サイズや拡張子であたりを付けられる探し方に比べると、特定が難しいことがあります。

主なあたりの付け方としては、メールタイトル、送信元、送信先メーリングリスト)で検索して大量に来ていないかを調べることになります。 あたりをつけるのが難しい場合は、直近何日かの期間に来ているメールを対象に絞って傾向を調べてみましょう。

とはいえざっと見ても数100通くらいはあって目視ではシンドいのと、この先毎回同じことをするのも避けたいので、GoogleAppsScript のコードを実行することで集計してみました。 この例では、ここ5日以内に送信されたメールを対象に送信元アドレスごとの件数をカウントしています。

/**
 * 所定の条件でメールを検索して送信元ごとの件数を集計する
 */
function processMailFromCount() {
  // メールの検索条件を設定(5日前より新しいメール)
  var SEARCH_CONDITION =  "newer_than:5d";

  // Gmailを指定条件で検索する
  var resultThreads = GmailApp.search(SEARCH_CONDITION);

  var resultCounts = {};  // 送信元アドレスごとのカウント用配列
  var messagesInThread  = {};  // スレッド内のメッセージ取得用配列
  var mailFrom = "";  // 送信元メールアドレス
  
  // 見つかった件数を記録
  Logger.log('検索条件:' + SEARCH_CONDITION);
  Logger.log('対象スレッド件数:' + resultThreads.length);
  Logger.log('========集計開始========');
  
  // 検索結果で取得したスレッドを順に処理し、送信元アドレスごとの件数を集計
  for each(var thread in resultThreads){
    messagesInThread = thread.getMessages();
    // スレッド内のメッセージを順に見て送信元アドレスを取得
    for each(var message in messagesInThread){
      mailFrom = message.getFrom();
      var mailAddress = mailFrom.match(/<.*@.*>/); // 送信者名 <hogehoge@gmail.com> 形式のメールアドレス部分を抽出
      if (mailAddress != null){
        mailFrom = mailAddress[0].substring(1,mailAddress[0].length - 1); // 角括弧を除いて整形
      }
     // 送信元アドレスごとの件数をカウントアップ
      if (mailFrom in resultCounts) {
          resultCounts[mailFrom] += 1;
      } else {
        resultCounts[mailFrom] = 1;
      }
    }
  }
  
  // 件数を降順にソートする
  var keys=[];
  for(var key in resultCounts){
    keys.push(key);
  }
  keys.sort(function(a,b){
    return resultCounts[b]-resultCounts[a];
  });
  
  // ログに送信元:件数 のフォーマットで書き出す
  for (key in keys){
    Logger.log(keys[key] + ': ' + resultCounts[keys[key]]);
  }

  Logger.log('========集計終了========');
};

結果どのくらい減らせたのか

直近5日(GoogleAppsScriptの仕様で一度に最大500件)を対象にメールの送信元を集計すると、自社メディアサービス「Milly」のシステムから送信されているものをはじめ、システムから通知されているものが大多数を占めていることが判明。

f:id:oshima106:20190109182339p:plain

実際に来ていた内容は外部API連携処理のエラー通知や、広告運用状況の通知など。特定の画面にアクセスする際に出力されるランタイムエラー情報のアラート通知など直接的な悪影響がないため対策が後回しになっているものでした。 StackTraceログがメールに貼り付けられているものもあるため、メール1通あたりのサイズもそこそこ大きくなっていました。

これらを順に削除していくことで、1.5GBくらいの容量を空けることができました。大掃除というにはちょっと物足りないですが、当面半年くらいはやりくりできそうです。

f:id:oshima106:20190109190057p:plain

おわりに

今回は日常業務にちょっとしたエンジニアリングを活用した事例のご紹介でした。 今後もウィルゲートではこういったライトなものから、現場のコアな技術のことまで引き続きお伝えできればと思います。

【スライド・動画あり】PHP Conference 2018 で Laravel × レイヤードアーキテクチャについて発表しました

PHP Conference 2018 / Laravel × レイヤードアーキテクチャを実践して得られた知見と反省

10 月から開発グループ直下の所属となりました。岡田(okashoi)です。

先日 12/15(土)に開催された PHP Confernece 2018 にて「Laravel × レイヤードアーキテクチャを実践して得られた知見と反省」というテーマで登壇させていただきました。

PHP Conference 2018 の様子

f:id:okashoi:20181217103911j:plain
PHP Conference 2018 のテーマは「GROWTH

今年は「GROWTH」をテーマに合計 38 のセッション + 10 を超える LT がありました。

どのセッションも興味深い内容であり、当日の来場者はおよそ 1000 人にものぼったそうで、たいへん盛り上がりました。

当日の盛り上がりは twitter からも見て取れると思います。

twitter.com

発表内容

www.slideshare.net

youtu.be

今年度に取り組んだ 2 つのプロジェクトでレイヤードアーキテクチャを実践した振り返りが主たる内容です。

レイヤードアーキテクチャを実践したことについてすべてが上手く言ったとは思いません。というより、反省点はたくさんありました。

ですが、実践の中で得られた知見/成長がたくさんあり、結果として組織にとってプラスになった取り組みだと信じています。

この発表の締めくくりには「不正解」を選ぶことを恐れるあまり挑戦を避けるのではなく、自分たちが選んだ選択肢を自分たちの手で「正解」に変えていきましょう、というメッセージを込めました。

時間の関係で具体的な実装レベルの話をするのは避けましたが、そちらについてはどうにか別の機会を得て話したいと思っています。

おわりに

私個人として、PHP Conference への登壇はの 2018 年の大きな目標のひとつでした。

この目標を達成できたことについて、一緒にレイヤードアーキテクチャに向き合って試行錯誤してくれたプロジェクトメンバー、発表資料のクオリティ向上に協力してくれた開発室のみなさん、そして何より PHP Conference 運営に携わるすべてのみなさまに感謝を述べたいと思います。

本当に、ありがとうございました!

新卒から1年半でチームリーダになるまでに経験したこと

こんにちは!ウィルゲート開発室執行役員の鶴飼です。 本日は、入社して1年半でリーダに昇格した吉田君にインタビューしたいと思います。 ウィルゲートでは複数事業とプロダクト開発を行っているので、挑戦機会がたくさんあります。 そんな挑戦機会を得て成長してきた吉田君が、実際どのような事を経験し、成長してきたかを紹介したいと思います。

入社前と入社後のイメージって1年半経った今、改めて感じる事ってありますか?

f:id:m_yokomichi:20181206132454j:plain ▲左がインタビューする鶴飼 右がそれに答える吉田

入社前の印象としては、漠然と「色々な事が出来る雰囲気はある」という感じでした。 実際何が出来るのかや具体的な仕事のイメージはあまり無かったのですが、裁量は大きく持たせて貰える雰囲気は感じ取れました。 入社後はメディアチームに配属され、主にフロントエンド開発を中心にサービス開発を行っていました。 もちろんフロントエンドとしても技術的なチャレンジもあり、先輩の技術に追いつくだけでも精一杯ですが、少しづつ出来る部分が増えるとそれに合わせて、踏み込んだ開発をさせて貰えるようになってきました。

入社して3ヵ月ぐらいで、テストコード導入の推進してたよね?

そうですね、メディアチームではグロースが多い為、小さい開発をリリースする事がたくさんあります。 その為、品質担保の為のテストコードの導入が検討が進んでいたのですが、その際に私が研修で作成した実装方針でおこなう事が決まったので、 チームでのテストコード導入を推進しました。 実際にチームで導入していく際に、実装方針に漏れが多々あり、それらをチームで話し合いながら決めていけたので勉強になりました。 また同時に、そこまで考えていなかった自分の甘さに気づきました。

チームで話し合って決めた事って何を決めたの?

どういったテストを書くべきか。具体的には共通化や定数化のルールを決め、過去のテスト漏れや障害から、何を最優先で担保すべきかを決めていきました。 そのように共通の認識を取り始めると、コストを掛けてでもテストコードを書くべきか、過剰になるのか、いかに使いまわせるかなどのディスカッションができたので 自分だけで考えたよりも深く練り込まれたテストコードの導入推進ができたと思います。 また、上流工程でしっかりと考えておかないと実装の際に手戻りが発生してしまうことを身をもって経験しました。

導入した事でメリットはあった?

特に改修の多い画面や、ログイン系はテスト仕様書に沿って各人にお願いするより圧倒的に速度も上がりましたし、自分がやっているテスト以上の品質が担保されているので、安心してリリースできるようになりました。

新規メディアのプロジェクトマネージャも新卒の時だよね

今年の初めからは花時間というメディアのプロジェクトマネージャを任してもらえました。 元々、上長にはチャンスがあればプロジェクトマネジメントをやりたいと言っていたので、新規メディアの話が上がった時に真っ先に手を上げました。 規模も大きすぎず、メンバーも経験豊富な方を入れていただきながら新卒の1年目からPMを任せてもらえて、今までとは違う視点で開発業務に取り組むことができるようになりました。 今までは振られたタスクを納期までに実装するというスタイルでしたが、PMを経験したことで、なぜその機能が必要なのか、他の実装方法はないのかを常に考えるようになりました。 また、他のメンバーのタスクも管理していたので、スケジュールの管理の大切さを学びました。

スケジュール管理の大切さってどういう所かな?

当初予定していた通りに進められれば良かったのですが、途中でメンバーが別のプロジェクトのトラブルで時間を割けなくなってしまいました。 その時に、全体のスケジュールを見直してタスクの割り振りを変え、優先度を再定義する事で新しく入ってくるメンバーがやりやすい場所を作る事ができ、 全体のスケジュールを変えずに完了する事ができました。 スケジュール管理は進捗管理だけではなく、流動的にメンバー配置を変えたりするのにも重要な役割を果たすと感じています。

2年目に入って新しくチャレンジした事ってある?

これまでアプリの開発を行なったことがありませんでした。そんな私ですが、暮らしニスタのアプリのプッシュ通知を任せてもらえました。 会社にアプリのコードをかける人が1人しかいなかったことも挑戦の機会をもらえるきっかけになりました。 いざ実装に着手するとわからない点ばかりだったので、会社の先輩に聞きながらどんな処理が書かれているのかを理解するところから始めました。 また、アプリの技術顧問の方に週に1度質問をすることができるので、実装方法で不明な点を質問しながら進めました。 周りのサポートの体制が充実しているので、初心者でもプッシュ通知の機能の実装を完成させることができました。

プッシュ通知作ってみてユーザの反応はどうですか?

今まで全体に対するプッシュ通知はありましたが、今回は個別のプッシュ通知を送信できる仕組みを導入した事もあり開封率はかなり高いです。 暮らしニスタのアプリをインストールしてログインしてくれているユーザに毎日アプリを開くきっかけを作れたのは良かったです。

他にも業務でやっている事あるかな?

ウィルゲートが運営しているメディアはフルスクラッチで作成しているものが多いですが、WordPressで動いているサービスもあります。 これまでWordPressはほとんど触ったことがなかったですが、運用保守を任せてもらえています。 趣味程度のものは作ったことがありましたが、業務レベルとなると求められている部分が違うなと感じています。

f:id:m_yokomichi:20181206132937j:plain ▲色々と深ぼって聞く様子

趣味と業務で求められる事の違いってどんな事?

先ずはセキュリティ周りが大きく違います。趣味レベルで作っていた時には管理者用ログイン画面も特にIP制限やベーシック認証などかけずにいましたが、そんな簡単な事からも違いを感じています。 また、プラグインの選定に関しても、自分で作っているものは自分が使いたいように選べばよかったものに対し、事業部やクライアントが扱いやすいものを選定したり、更新が止まっているものは選定から落としたり、使う人の目線で構築するというのも新しかったです。 とはいえ、ユーザファーストでの考え方が業務を通じて身に染みているので当たり前にやらなければいけない事ですね

目まぐるしく色々経験しているけど、何が一番印象深い?

花時間のPMが印象深いです。 メンバー2人(先輩と年上)にしっかりコミュニケーションを取る事、先輩だろうとしっかり言わないといけない事もあるという気付きを得たました。

初めてのPMは上手くいった?

初めての時は何とか上手くできたと思います。どちらかというとやったに近いのかもしれません。 とはいえ、先ほども言った通り規模も大きすぎず経験豊富なエンジニアアサインなど上長が行ってくれたので、 プロジェクトが複雑になった時の対応力とかまだまだ経験してない事がたくさんあり、これからも経験を積んでいきたいと思います。

PM今後もやりたいですか?

LDRとPMはしっかりやっていきたいと思っています。同じように見えてどっちも違うと感じます。 LDRはメンバマネジメント中心、PMはプロジェクトマネジメント中心なので、近しいと思いますがどちらも経験してチームに貢献していきたいと思います。

1年半を振り返って

f:id:m_yokomichi:20181206133106j:plain これまで1年半とは思えないほど色々な学びを得ることができました。 10月からはチームリーダとして更なる高みを目指していきたいと思います。 今まではプロダクトの成長を考えるだけでしたが、今後は人も見る必要があります。 人を見て、人を活かし、どうやって成長させてあげられるかを考えるのもリーダの仕事の一つだと思います。

課題は見えてる?

まだまだ足りない事ばかりですが、とにかく情報量が足りないです。 業務に関する事だけではなく、事業の事や組織の事それらのインプット量を増やしていく事で、良いアウトプットが出来ると思います。

最後に3年後はどうなっていたい?

フロントエンドが元々メインなので、技術キャッチアップは忘れずにスペシャリストと会話が出来る状態でありたいし、自分でもコードが書ける状態で居続けたいです。 上長がサイト責任も行っているので、事業も作れるエンジニアになっていきたいです。

ウィルゲートはやりたい!と手を上げればどんどん挑戦することができる環境がそろっています。 挑戦することで今までになかった知識や技術が身についていくと思うので、これからの1年も新たな挑戦をたくさんしていきたいと思います。