【スライド・動画あり】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年も新たな挑戦をたくさんしていきたいと思います。

Web開発経験ゼロの新卒が入社半年を経て気付いてしまったこと

こんにちは、18年度新卒の田島です。前回は新人研修の模様についてお話しさせていただきましたが、今回は私が入社半年を経て気付いたことについてまとめたいと思います。

はじめに

私は現在メディアユニットに配属し、Milly や暮らしニスタなどの運用保守や機能改善を行っています。Web メディアという媒体の特性上開発するべき機能は大きくないものの大量に存在するため、常に優先順位付けを行いつつ着手しています。リリースしたものから順に効果検証を行い、更なる変更や改善を行うこともあります。そのため、非常にスピード感のあるアジャイル開発といってもよいのかもしれません。

そんなめまぐるしい環境で学んだことの中から特に感じたことを、設計や開発の観点から3つ紹介いたします。

コーディング規約の重要性

入社前私は個人で Java などのコーディングを行っていたのですが、入社前と入社後で最も大きく違いを感じたのはチーム開発であることによるコーディングに対する意識の違いでした。特に、コーディング規約が開発スピードや成果物の質に非常に影響を及ぼすということに気付きました。コーディング規約が守られているコードはそうでないコードと比べて読みやすさが段違いであり、読んでいてとても理解しやすいものでした。また機能拡張を行う際にどのような場所にどのようにコーディングすれば良いのか明確であるために実装もとても捗ることが分かりました。

入社当初はその重要性に気づかず、正直なところ周りのコードに合わせてなんとなく規約に違反しないよう実装するだけでしたが、最近はソースコードやモデルの持つ役割を考えて適した実装ができるように心がけています。またこれは余談ですが、レスポンスの変数名や形式などが統一されていない外部 API に苛立ちが湧くようになりました。

f:id:tajima-ryo:20181205173725p:plain

プルリクエストのテンポ感

次に強く感じていることは、コードレビューのためのプルリクエストは早く出せば出すほど良いということです。もちろんプルリクエストを出す前に規約違反やつまらないミスなど、レビュアーに指摘されると恥ずかしい(+そもそもレビュアーの時間を取らせてしまい申し訳ない)点を修正する確認作業は必要です。しかし、指摘を恐れて必要以上に自分のコードを点検したりプルリクエストを出すのをためらうのは良くないことだと気付きました。

入社から数ヶ月経ち最近は自分自身も他の人のプルリクエストをレビューするようになりました。そこで特に感じることは、レビュアーがコードレビューに取れる時間やタイミングは限られているということです。プルリクエストを遅らせることはレビューのタイミングを遅らせることになり、アドバイスの数やタイミングも遅くなってしまいます。特に期日が明確なタスクではテンポ感を大事にしていきたいと感じました。

f:id:tajima-ryo:20181205173753p:plain

テストの難しさと重要性

そして、最後の気付きはテストの難しさと重要性についてです。十分なテストは非常に難しく、フロント側のテストはある程度フォーマット化して進めようとしても抜け漏れが発生してしまう場合があります。また API に対してはテストコードを書いているのですが、想定されるデータや考えるべき状況を把握しなければならないのは非常に大変です。

しかしテストを十分に行うことで、リリース後に不具合が発生することを抑えられるのはもちろん、実装した機能が今後拡張された際にうまく動かなくなるということを避けることができます。そのため、テストを行うことは非常に意味のあることだと感じました。まだまだ自分のテストには抜け漏れが多いのですが、今後も継続的に取り組むことで解消していきたいです。

終わりに

今回まとめたことは熟達したエンジニアの方々にとっては当たり前のことかもしれません。しかし、こういった当たり前の気付きを自分の実体験として重ねていくことでエンジニアとして一歩一歩成長できるものと考えております。今後もこういった当たり前の気づきを糧に成長できるように努力を続けていきます。それでは、次回もよろしくお願いいたします!

HTTPS の Wordpress を AWS LightSail に移行

経緯

弊社で運用している一部のサーバはクラウド事業者の VPSWordPress 環境を構築し、そこに証明書を入れて HTTPSWordPress を運用していました。 ただ、VPS の月額料金や証明書の更新に関わる購買や更新手続きといったコストといった点が問題視されていました。

無料の証明書である Let's Encrypt も考えましたが、できるだけ仕掛けを作らずに証明書の更新作業を自動化したいと考えました。 VPS の月額コスト見直しのタイミングもあったので、AWS LightSail に移行し証明書を自動更新する仕組みに切り替えました。

AWS LightSail とは

LightSail とは、AWS が提供する VPS サービスで、SSL アクセラレータ機能のあるロードバランサー(以下 LB )も使えます。 この LB には DNS 認証による無料の SSL/TLS 証明書を簡単に組み込むことができます。

SSL アクセラレータとは

SSL アクセラレータとは通信を TLS/SSL で暗号化する際に、暗号化や複合化の処理を専門に行う機能のことです。

  • 証明書管理の一元化
  • 負荷分散

といった効果があります。

今回の通信経路を図にすると以下のようになります。

f:id:kobayashi-ryotaro:20181127155450j:plain

LightSail ロードバランサー 作成

  1. AWS のコントロールパネルから LightSail のホーム画面に入ります。 f:id:kobayashi-ryotaro:20181127163621p:plain
  2. 「ネットワーク」→「ロードバランサーの作成」と進みます。 f:id:kobayashi-ryotaro:20181127164020p:plain
  3. 作成画面でリージョンや名前を設定して「ロードバランサーの作成」を押下します。HTTPS の設定は後で行います。 f:id:kobayashi-ryotaro:20181127164345p:plain
  4. ロードバランサー管理画面の「インバウンドトラフィック」で証明書の設定を行います。必要な項目を設定してください。 f:id:kobayashi-ryotaro:20181127165554p:plain
  5. ドメインの認証が終われば証明書の組み込みが完了します。 f:id:kobayashi-ryotaro:20181127165948p:plain

LightSail インスタンス作成

  1. ホーム画面から「インスタンス」→「インスタンスの作成」を押下します。 f:id:kobayashi-ryotaro:20181127170755p:plain
  2. 今回はWordPressの移行ということでバージョンの差異を懸念し、インスタンスイメージは「 OS のみ」「Amazon Linux」にしました。 f:id:kobayashi-ryotaro:20181127171149p:plain
  3. インスタンスプランを選んで名前を設定し、「インスタンスの作成を」押下してしばらくお待ちください。 f:id:kobayashi-ryotaro:20181127171316p:plain
  4. 作成が完了したら、先ほど作成したロードバランサーのターゲットインスタンスとして設定してください。 f:id:kobayashi-ryotaro:20181127172335p:plain
  5. 作成されたインスタンスにはパブリック IP で SSH 接続ができます。 f:id:kobayashi-ryotaro:20181127172544p:plain

WordPress の移行

WordPress はデフォルトだと ApachephpMySQL ですが、今回の環境は nginx+php-fpm + MySQL です。 各ミドルウェアのインストールや設定は割愛します。

移行に関しては基本的に

を移行すれば大丈夫です。

WordPressHTTPS

設定を間違えるとリダイレクトループしたりレイアウトが崩れるので注意してください。

リダイレクトループ対策

リダイレクトループとは、以下のようなループ現象です。

  1. LB が http で受ける
  2. LB が Web サーバに http で渡す
  3. Web サーバが301を返して https にリダイレクト
  4. LB が https で受ける
  5. LB が Web サーバに http で渡す
  6. Web サーバが301を返して https にリダイレクト
  7. 4に戻る

これを避けるために、nginx のコンフィグの server ディレクティブに以下の設定を追記します。 証明書に関する記述があれば削除してください。

   if ($http_x_forwarded_proto != https) {
      return 301 https://$host$request_uri;
    }

世の多くの LB や CDN は、自身を通過したときに http の拡張ヘッダである http_x_forwarded_proto に値を入れます。 これは配下のサーバが、もともとのアクセスが http なのか https なのかを判断可能にするためです。

この値を利用することで以下のような流れになり、ループを回避できます。

  1. LB が http でリクエストを受ける
  2. LB が http_x_forwarded_proto に http を入れて Web サーバに http で渡す
  3. Web サーバが http_x_forwarded_proto を評価し、http なので301を返して https にリダイレクト
  4. LB が https でリクエストを受ける
  5. LB が http_x_forwarded_proto に https という値を入れて、Web サーバに http で渡す
  6. Web サーバが http_x_forwarded_proto を評価し、 https なのでバックエンドにリクエストを渡す

WordPress の設定

こちらは設定を間違えるとレイアウトが崩れたりします。

wp-config.php に以下の設定を追記します。 php のアプリケーションは $_SERVER['HTTPS'] を評価してプロトコルを判定していることが多いためです。WordPress も例外ではありません。

  if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
      $_SERVER['HTTPS'] = 'on';

WordPressCSS の作成で自己参照することがあるのですが、こうすることでレイアウト崩れを防ぐことができます。

効果

証明書の自動更新機能で運用コストの削減ができました。 また DNS サービスである Route 53 を使えば AWS アカウントですべて管理でき、とても便利です。

まとめ

nginx や wordpress の移行作業が手間ではありますが、今回の移行により証明書の管理から解放されました。 手軽に HTTPSWordPress を作成したい場合は LightSail を検討してはいかがでしょうか。

AWS Elasticsearch Serviceの古いインデックスをcuratorを利用して削除してみました!

はじめに

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

今回、 curator を利用して AWS Elasticsearch Service に登録されているインデックスを削除するようにしてみたのでご紹介します!

curator とは

Elastic 社が提供する Elasticsearch の運用管理ツールで、インデックスのリスト表示や削除などが手軽に行えます。

curl を使用した場合のインデックスリスト表示

[user@hostname ~]# curl -XGET https://vpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxap-northeast-1.es.amazonaws.com/_cat/indices?v
health status index                       uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   api-nginx-access-2018.11.10 NtPFJq7gQ06fDZ8xtqarOA   5   1      35248            0      2.9mb          2.9mb
yellow open   api-nginx-access-2018.11.08 2zAfE-neQ0-2ghTfZQkxsA   5   1      40706            0      4.1mb          4.1mb
yellow open   api-nginx-access-2018.11.07 uxd-OGsbQq-k4qoteAPaGw   5   1      40406            0      4.1mb          4.1mb
yellow open   api-nginx-error-2018.11.03  9bAwxr8lSJSe1J3UE5AUfg   5   1        521            0    222.6kb        222.6kb
yellow open   ap-nginx-access-2018.11.05  VowpBW7SStmPm94xbG044A   5   1        168            0    223.3kb        223.3kb
yellow open   api-nginx-error-2018.11.04  rgKkhzhcR06eFnerLx54aw   5   1          1            0        8kb            8kb
yellow open   ap-nginx-access-2018.10.31  2LznB-GoTBm5fjb_T4bN9w   5   1        175            0    310.4kb        310.4kb
yellow open   api-nginx-access-2018.11.09 ysINQk6vRUO8FLGOiRcmnA   5   1      38718            0      3.8mb          3.8mb
yellow open   ap-nginx-access-2018.11.09  mU3ABP35Ste0VsJU64jpHQ   5   1        214            0    412.6kb        412.6kb
yellow open   ap-nginx-error-2018.11.08   wJIVXbnpSUGlpRr4KwcmwQ   5   1          8            0     61.2kb         61.2kb
yellow open   ap-nginx-access-2018.11.08  9aE7-pCTQtWbauq_7aI7xg   5   1        230            0    378.2kb        378.2kb
yellow open   api-nginx-error-2018.11.10  ZchNOQfCS4GKZ3FKWW1cfg   5   1          6            0     35.9kb         35.9kb
yellow open   api-nginx-access-2018.11.04 7D0J_NXVT6Wkmaf83B-kQw   5   1      35703            0      3.1mb          3.1mb
yellow open   api-nginx-error-2018.10.31  gnFgi1UGQbKHqCS1-m6eRg   5   1        883            0    320.6kb        320.6kb
yellow open   ap-nginx-access-2018.11.13  5VaWNCv9SNauh_1FCWSLrw   5   1          7            0     49.7kb         49.7kb
yellow open   api-nginx-access-2018.11.03 CBYDBAniRHiY-KzKiz8eiA   5   1      36741            0      3.2mb          3.2mb
yellow open   api-nginx-access-2018.11.02 RvdI42J0TrmC-lycFNWHjg   5   1      38100            0      3.6mb          3.6mb
yellow open   api-nginx-error-2018.11.09  qHjKeVtMTyOcbePYSVF5sA   5   1        538            0    220.2kb        220.2kb
yellow open   api-nginx-error-2018.11.05  _3PJCIgMT9mlbVh9jGzJNg   5   1          2            0     14.9kb         14.9kb
yellow open   ap-nginx-access-2018.11.01  IzjvuxKxRomqQdElicP10Q   5   1        157            0    260.2kb        260.2kb
yellow open   api-nginx-error-2018.11.01  oJnvclQkQtmr-btW9WkcIA   5   1          8            0     55.7kb         55.7kb
yellow open   ap-nginx-access-2018.11.03  kjFlEFifQEKXkVmfeomniw   5   1         96            0    227.8kb        227.8kb
yellow open   ap-nginx-access-2018.11.07  q4GQX8pORZS1slQSzJlsbQ   5   1        131            0    252.5kb        252.5kb
yellow open   ap-nginx-access-2018.10.30  Et4smDEyQuSLawlLOdnkHQ   5   1        144            0    294.3kb        294.3kb
yellow open   ap-nginx-access-2018.11.11  Owe3aa4gQ7aCs5mkkIA3kw   5   1         19            0    133.4kb        133.4kb
yellow open   api-nginx-access-2018.11.12 9n4sfrfFT4yCa7Kp5IFZNg   5   1      40121            0        4mb            4mb
yellow open   api-nginx-access-2018.10.31 6YxRk1kkRuWDAGDrndXApA   5   1      40941            0        4mb            4mb
yellow open   api-nginx-access-2018.10.30 bRZ_7_YeT0SZSyC0j1i7mg   5   1      38288            0      3.6mb          3.6mb
yellow open   api-nginx-access-2018.11.11 VfaS5hVKTDyFXLdjHVSecQ   5   1      35786            0      3.1mb          3.1mb
yellow open   api-nginx-error-2018.11.06  vC_QtLPmTRugJZsR7du4_w   5   1        289            0    278.6kb        278.6kb
yellow open   ap-nginx-access-2018.11.12  c97C6639SNatlNJpsVKFeA   5   1        355            0    364.2kb        364.2kb
yellow open   ap-nginx-access-2018.11.06  tV7vbxDXR_aEXwbKhWp0Sw   5   1        183            0    298.4kb        298.4kb
yellow open   api-nginx-access-2018.11.01 4UHB-q-hSCWnTaQgoDmizQ   5   1      40240            0      3.9mb          3.9mb
yellow open   api-nginx-access-2018.11.05 2Jhq-KLEQLm3HtJNrf6j6w   5   1      38685            0      3.7mb          3.7mb
yellow open   api-nginx-error-2018.11.07  99-0rOfVS42rH1vm-9CDnw   5   1        312            0    161.4kb        161.4kb
yellow open   api-nginx-error-2018.11.02  KHLZjLKRTK-wDnCLcD7Fdw   5   1        550            0    302.8kb        302.8kb
yellow open   ap-nginx-access-2018.11.02  7iB_pIGEQlygM7OQrs2CVA   5   1        136            0    230.7kb        230.7kb
yellow open   api-nginx-error-2018.11.12  Sg7P8WneQz2H_gTzwAKxfw   5   1        277            0    145.2kb        145.2kb
yellow open   api-nginx-access-2018.11.06 zwYwZHYZQcKVY90MgI3jgA   5   1      41895            0      4.2mb          4.2mb
yellow open   api-nginx-error-2018.11.08  qhH5k3cqRb-Lu9qvPh_FNw   5   1        537            0    220.4kb        220.4kb
yellow open   api-nginx-error-2018.10.30  HhB_3KPJRZe6lJBOpz9cEQ   5   1         41            0      255kb          255kb
green  open   .kibana                     -mBnXlR2QQGCuTDFEScqng   1   0         11            1     30.3kb         30.3kb
yellow open   ap-nginx-access-2018.11.04  Zh-SgjiITye2tW1krPgT0g   5   1         96            0    264.7kb        264.7kb
yellow open   api-nginx-access-2018.11.13 Ztu6V_jsTfqAx7HVcFuRNw   5   1        709            0    209.6kb        209.6kb
yellow open   api-nginx-error-2018.11.11  W44PXSWTQ9aTdE2TtMN2LQ   5   1        266            0    122.6kb        122.6kb

curator を使用した場合のインデックスリスト表示

[user@hostname ~]# curator_cli show_indices
.kibana
ap-nginx-access-2018.10.30
ap-nginx-access-2018.10.31
ap-nginx-access-2018.11.01
ap-nginx-access-2018.11.02
ap-nginx-access-2018.11.03
ap-nginx-access-2018.11.04
ap-nginx-access-2018.11.05
ap-nginx-access-2018.11.06
ap-nginx-access-2018.11.07
ap-nginx-access-2018.11.08
ap-nginx-access-2018.11.09
ap-nginx-access-2018.11.11
ap-nginx-access-2018.11.12
ap-nginx-access-2018.11.13
ap-nginx-error-2018.11.08
api-nginx-access-2018.10.30
api-nginx-access-2018.10.31
api-nginx-access-2018.11.01
api-nginx-access-2018.11.02
api-nginx-access-2018.11.03
api-nginx-access-2018.11.04
api-nginx-access-2018.11.05
api-nginx-access-2018.11.06
api-nginx-access-2018.11.07
api-nginx-access-2018.11.08
api-nginx-access-2018.11.09
api-nginx-access-2018.11.10
api-nginx-access-2018.11.11
api-nginx-access-2018.11.12
api-nginx-access-2018.11.13
api-nginx-error-2018.10.30
api-nginx-error-2018.10.31
api-nginx-error-2018.11.01
api-nginx-error-2018.11.02
api-nginx-error-2018.11.03
api-nginx-error-2018.11.04
api-nginx-error-2018.11.05
api-nginx-error-2018.11.06
api-nginx-error-2018.11.07
api-nginx-error-2018.11.08
api-nginx-error-2018.11.09
api-nginx-error-2018.11.10
api-nginx-error-2018.11.11
api-nginx-error-2018.11.12

curator を導入するに至った背景

ウィルゲート ではログ基盤として EFK ( Elasticsearch + Fluentd + Kibana ) を構築しています。

EFK を運用するにあたり、ログを絶え間なく Elasticsearch に蓄積していくためデータ量が膨大になっていき、結果的に Kibana のレスポンスが悪くなったり最悪表示ができなくなってしまうという問題がありました。

f:id:tkhttty:20181112182226p:plain

curator を導入する以前は、 古いインデックスに対して curl -XDELETE をひたすら投げるシェルスクリプトを実行して削除を行っていたのですが、古いインデックスが綺麗に削除されなかったり、 curl プロセスが大量に生成され負荷が上昇したりと運用において大きな課題となっていました。

そこで、前述した Elasticsearch の運用管理ツールである curator を利用して古いインデックスの削除を試みてみました。

導入方法

curator のインストールおよび設定には 構成管理ツールである Ansible を利用しています。

AWS の Elasticsearch へ接続する際に IAM Role を使用するため、最初に必要なモジュールである「requests_aws4auth」をインストールしてから elasticsearch-curator をインストールします。

また、curator の設定ファイルは Jinja2 テンプレートとして作成しています。

最後に 毎日 3 時に実行するように cron を設定すれば完了です。

Ansible Playbook

---

- name: install requests_aws4auth
  pip:
    name: requests_aws4auth
    state: latest

- name: install elasticsearch-curator
  pip:
    name: elasticsearch-curator
    state: latest

- name: mkdir .curator
  file: path=/root/.curator state=directory owner=root group=root mode=0755

- name: configure curator
  template: src={{ item.src }} dest={{ item.dest }} owner=root group=root mode={{ item.mode }}
  with_items:
    - { src: 'curator.yml.j2', dest: '/root/.curator/curator.yml', mode: 644 }
    - { src: 'delete_old_index.j2', dest: '/root/.curator/delete_old_index', mode: 644 }

- name: set cron curator
  cron: name={{ item.cron_name }} minute={{ item.cron_minute }} hour={{ item.cron_hour }} day={{ item.cron_day }} month={{ item.cron_month }} weekday={{ item.cron_weekday }} job={{ item.cron_job }} user={{ item.cron_user }}
  with_items: "{{ cron_list }}"

vars

cron_list:
  - cron_name: Run curator
    cron_minute: '0'
    cron_hour: '3'
    cron_day: '*'
    cron_month: '*'
    cron_weekday: '*'
    cron_job: 'curator /root/.curator/delete_old_index'
    cron_user: root

curator.yml.j2

client:
  hosts:
    - AWS ESのエンドポイント(例: vpc-kibana-xxxxxxxxxxx.ap-northeast-1.es.amazonaws.com)
  port: 443
  url_prefix:
  use_ssl: True
  certificate:
  client_cert:
  client_key:
  ssl_no_validate: False
  http_auth:
  timeout: 30
  master_only: False
 
logging:
  loglevel: INFO
  logfile:
  logformat: default
  blacklist: ['elasticsearch', 'urllib3']

delete_old_index.j2

actions:
  1:
    action: delete_indices
    description: >-
      このアクションの説明
    options:
      ignore_empty_list: True
      timeout_override:
      continue_if_exception: False
      disable_action: False
    filters:
    - filtertype: pattern
      kind: prefix
      value: 対象インデックスの接頭語(例:web-error-log-)
      exclude:
    - filtertype: age
      source: name
      direction: older
      timestring: '%Y.%m.%d'
      unit: days
      unit_count: 何日以上経過したら消すか(例:10)
      exclude:
  2:
    action: delete_indices
    :
    : 以下、対象のインデックス分追記していく
    :

導入してみて

前述したように、これまで curator ではなくシェルスクリプトから curl を投げ続けるという方法でインデックスを削除していたため、サーバの負荷が上昇してしまったり、綺麗に古いインデックスが消せずに蓄積し続けてしまうなど課題が山積みとなっていました。

今回 curator を導入してからというもの、綺麗に古いインデックスを削除しつつ全くと言っても良いほど負荷もかからないので、素晴らしくサーバ(と心の)の平穏が保たれています。

f:id:tkhttty:20181112182259p:plain

また、 curator のインストールや設定を Ansible によりコード化しているので、同様に EFK を運用している別サービスにも手軽に適用できるようになりました。

おわりに

curator を利用することにより、 AWS Elasticsearch Service に登録されている古いインデックスを綺麗に削除でき平穏が訪れてきました!

同じような悩みをお持ちの方は curator を利用してみることをオススメします!

Firebaseを利用したプッシュ通知の実装

こんにちは。メディアチームの吉田です。 暮らしニスタのアプリにFirebase Cloud Messaging(以下、FCM)を使用したプッシュ通知を導入したので、FCMの紹介と導入の経緯を説明していきたいと思います!

FCMとは

googleが提供しているメッセージを無料で確実に配信するためのクロスプラットフォーム メッセージング ソリューションです。 FCMでは管理画面上からユーザーセグメント毎の配信や個別の端末への送信ができます。 また、アプリケーション側からFCMのAPIを叩くことで任意のタイミングでプッシュ通知を送信できるようになります。

暮らしニスタのアプリにプッシュ通知を挿入した背景

暮らしニスタのアプリには以前から、プッシュ通知を送信する仕組みは導入されていました。しかし、全端末に同じ内容の送信しかできず、個人向けの通知を送ることができませんでした。 そこで、個別のプッシュ通知を送信できる仕組みの導入を行うことになりました。 暮らしニスタにはステキやコメントといった機能があり、アプリ内の通知欄には投稿した記事にコメントやステキがつくと通知が届くようになっていました。これらの通知をアプリを使っているユーザーにはプッシュ通知でお知らせすることにしました。

導入方法

FCMにはFirebase Console上で送信する方法と、APIを利用した方法の2種類があります。 Firebase Console上から送信する方法の場合、アプリ側の実装のみで送信や、開封率の取得ができるようになります。 APIを利用した方法の場合、アプリ側とアプリケーション側の実装が必要になりますが、APIで送信ができるので任意のタイミングで送信することができるようになります。一方で、開封率などは取得できないでの独自で実装する必要が出てきます。

今回の実装は、一斉送信する際は、Firebase Console上から送信する。個別のプッシュ通知はAPIを使って実装する方針に決まりました。

アプリケーションサーバーからプッシュ通知を送信する

Webアプリケーション側からプッシュ通知を送信する際にはトークンの情報が必要なので、起動時とログイン完了時にトークンを取得するようにしました。そのトークンの情報とユーザーIDを紐付けて送信する際に使用します。

単一端末へのプッシュ通知の送信

単一端末への送信は下記のようにして送信ができます。トークンと本文を設定することで送信をおこなうことができます。暮らしニスタでは通知の配信と同じタイミングで送信をするように実装しました。

https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key=API_KEY
{
  "to": "送信先のトークン",
  "notification" : {
    "body": "通知本文",
  }
}

データをアプリに渡す

プッシュ通知を送信する際にデータをアプリ側に渡すことができます。 暮らしニスタの場合、プッシュ通知を開封した際に、開くページを変える必要がありました。 そこで送信の際に開くページを一緒に送信し、アプリ側で開封の際に開くページを変更する実装を行いました。 dataの中で送信した値をアプリ側で取得することができます。

https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key=API_KEY
{
  "to": "送信先のトークン",
  "data": {
    "openUrl": "/articles"
  },
  "notification" : {
    "body": "通知本文",
  }
}

画像付きアプリケーションを送信する

iOS10以降では通知に画像をつけることができるようになりました。 FCMでは画像付きのプッシュ通知を送信することもできるようになっています。 データの送信と同様にdataの中で画像のurlを指定します。そしてmutable_contentにtrueを入れて送信します。 アプリ側ではNotification Service Extensionを使って受信した際に画像を表示する実装をおこないます。 f:id:yoshhhy:20181107112123p:plain

f:id:yoshhhy:20181031173845j:plain

最後に

FCMを使用することで簡単にプッシュ通知を送信できるようになりました。 一斉送信はもちろん、APIを用いることで個人あてのプッシュ通知の送信も実装ができるので、プッシュ通知を導入する際にはFCMを使ってみてはいかがでしょうか。

「Hacker's GATE LT & 交流会 #2」を開催しました!!【写真あり】

こんにちは!2018年新卒エンジニアの田島です。

今回は10月25日に開催された「Hacker's GATE LT & 交流会 #2」の模様をお届けしたいと思います!

Hacker's GATE とは

ウィルゲートでは、毎月1回「Hacker's GATE」という名称で社内勉強会を行っております。

最近では社内にとどまらず、社外の方をお招きしてのイベントも開催してきました。

tech.willgate.co.jp

tech.willgate.co.jp

前回のイベントからは connpass でイベントページを開設し、幅広いフィールドのエンジニアの方々と交流しています!

willgate.connpass.com

「Hacker's GATE LT & 交流会 #2」の様子

今回のテーマは「新卒入社『約』3~5年目のホンネ」ということで、お集まりいただいた発表者のみなさまに様々な「ホンネ」を語っていただきました!

f:id:tajima-ryo:20181030094805j:plain

f:id:tajima-ryo:20181029105150j:plain

f:id:tajima-ryo:20181029185524j:plain

f:id:tajima-ryo:20181029105253j:plain

f:id:tajima-ryo:20181029104951j:plain

同じエンジニアといえど辿ってきた道は千差万別。一つの業務を経て得た知見から様々な働き方のお話まで、どの LT も様々な観点から作られたバラエティに富んだ内容で、皆さんとても興味深く聞き入っている様子でした。

f:id:tajima-ryo:20181029105325j:plain

f:id:tajima-ryo:20181031153021j:plain

f:id:tajima-ryo:20181029185028j:plain

また、交流会も終始和気藹々とした雰囲気で進行し、活発な交流の場となっていました。

LT 会に参加して下さった方も、LT をしていただいた方も、本当にありがとうございました!

最後に

今後も Hacker's GATE 運営では、社外への発信を目的として LT 会や交流会を開催していく予定です。 LT をしたいという方はもちろん、色々な方の LT を聴きたい、様々な人と交流したいという方も歓迎です!

またウィルゲートでは「Hacker's GATE もくもく会」と題して、毎週木曜日にもくもく会の開催を行なっております。 こちらも参加者募集中となっておりますので、よろしくお願いいたします!

willgate.connpass.com

皆様のご参加を、心よりお待ちしております!