エブリーエンジニアブログ エブリーエンジニアブログ

ansibleとterraformって何が違うんですか?

ansibleとterraformって何が違うんですか?

f:id:kajidai:20201208174411j:plain

はじめに

弊社ではインフラは主にAWS(一部GCP)を利用しており、構成管理にansibleとterraformを使用しています。 新しく入社された方や、これまでインフラをあまり触ってこなかった方がこれらに触れる際、本件表題のような質問をされることが何度かありました。

私はこのたぐいの質問をされるたびにそれぞれの成り立ち、歴史的背景、ソフトウェアとしての実装と振る舞いの違い、そして弊社での使われ方について説明をしてきました。 大抵はそれで納得してその後は疑問なく使い分けができるようになっていく(ように見える)のですが、やはり中には腑に落ちないようであったり、使い分けに悩まれる様子がみられる方もいます。

説明している最中、自分でも「この説明で適切なのだろうか」「そもそもなぜこれらが混同されやすいのだろうか」と疑問に思うことがよくあり、良い機会ですので今回文章としてまとめました。

この文章が表題の疑問の回答になり、今後の学習のお役に立てれば幸いです。

作っただけでは動かない

ansibleやterraformの話をする前に、基礎の話から押さえておきましょう。 インフラエンジニアであったり、サービスの保守運用の経験がある方であれば「何を当たり前のことを」と思うかもしれませんが、アプリケーションは作っただけでは動きません

なぜでしょうか?「アプリケーションは完璧に仕様を満たしています!動かせばいいだけじゃないか!」そう思われますか?

そう、動かせばいいだけなのです!

しかしながら、アプリケーションを動かすためには、アプリケーションの他にもたくさんのものが必要になります。

それらは、普段手元のパソコンで開発していると当たり前のように存在しているために気づかないものであったり、インターネットを通してたくさんの人にサービスを届けるために必要なものであったり、様々です。 ひとまずこの文章内では、これらのことをひとまとめに「リソース」と呼ぶことにしましょう。インフラとはリソースの集合であると言えます。

リソースという言葉は色々な場面で色々な意味合いで用いられます。 ここでいう「リソース」はこの文章内ではこのように名前をつけて呼ぶ、という程度の意味で捉えてください。

リソースの例をあげていけばきりがないのですが、いくつか代表的なものを取り上げましょう。

コンピューター

あなたの手元にはコンピューターがありますか?いえ、答える必要はないですね。この文章を目にしているということは、そういうことですね。

当然のことですが、アプリケーションを動かすためにはコンピューターが必要です。

オンプレミスであれば機器を購入するかレンタルするかして、データセンターに配置しなければなりません。あるいはVPSを契約してもいいかもしれません。 もちろんAWSやGCPなどのクラウド環境で仮想コンピューターを用意しても良いでしょう。

ネットワーク

あなたのコンピューターは何かしらのネットワークに繋がっていますか?いえ、答える必要はないですね。この文章を目にしているということは、そういうことですね。

インターネットを通じてサービスを提供するのであれば、何かしらインターネットへの接続性が必要になります。 あるいは、既存のネットワーク内に配置するのであれば、多少のネットワーク構成の変更が必要になるかもしれません。 また、接続性を確保することと同様に、不必要な接続を遮断する設定も重要です。

このノリももう飽きてきませんか?私は飽きました。ですので、あとはまとめていくつか紹介しましょう。

ロードバランサー、DNS、TLS証明書……、etc

これらは必須というわけではありませんが、ほとんどの場合必要になるでしょう。

どれも購入・あるいは契約し、設定し、配置しなければなりません。

動かし続けるのはもっと大変

さてアプリケーションを動作させるために必要ないくつかのリソースを確保しました。アプリケーションは正しく動作し、目的を完全に達成しました。

素晴らしいことです!ではこれで全ては解決でしょうか?

そうならばどれほど良かったでしょう……。

f:id:hueless:20201208105626p:plain

ほとんどの場合、アプリケーションは変更され続けます。あなたは今アプリケーションを変更しました。ではそれをどのようにすれば反映できますか?

変更前のアプリケーションは動いていて、以前と変わりなく使われています。これをダウンタイムなく新しいものに置き換えるためにはどのような手順が必要でしょうか?

あるいは、あなたのアプリケーションは非常に人気が高く、多くのユーザーの要求を満たすために、100台のサーバで動いているかもしれません。 どのようにして100台のサーバに同時に、齟齬なく変更を反映させれば良いでしょうか?

このようなシナリオはたくさん考えられます。もちろんありうる全てのシナリオを想定するのは不可能ですし、コストに見合いません。 しかしながら、日常的に発生するようなシナリオに対してはどのように対処するかを想定しておくべきでしょう。

アプリケーションを作ることだけが仕事ではない

これまで紹介してきた通り、アプリケーションは作る場面だけでなく、実際に動作させる場面でもたくさんの考慮すべきこと、行うべきことがあります。 いうまでもなく、それは知識や経験、技術が必要な、専門的な作業です。

ansibleやterraformは、アプリケーションを動作させるために必要になるこれらの作業を錯誤なく、確実に、簡単に行えるようにするためのソフトウェアです。

ansibleとterraform

ansibleやterraformはどのようにこのような作業の役に立つのでしょうか?

それを説明するためにはまずInfrastructure as Code(以後IaCと省略)の概念を説明する必要があります。 なぜなら、ansibleとterraformはIaCを実現するためのツールだからです。

そもそも、Infrastructure(口語ではもっぱらインフラと省略されますので、この文章でも以降インフラと表記します)とは何でしょうか?

前項であげたリソースの例はどれもインフラを構成する要素ですが、他にもデータベースやミドルウェアなどを含む場合もあります。 あるいはCI環境などもインフラの一部だと捉える人もいるかもしれません。

はっきりとこういうものだ、という定義は難しいのですが、私は「アプリケーションを動作させるに足る環境」であると理解しています。

つまり

サービス=アプリケーション+インフラ

であると言えます。

IaC

サービスを提供するためのインフラを準備する時、IaCを用いず従来通りの手法で行う場合、一般的にはドキュメントやチェックシートによって管理することになります。 小規模かつ変更の少ないインフラであればこのような手法でも十分に運用可能です。

しかし、インフラの規模が大きくなるにつれ、それぞれのリソースの相互作用が増え、構造が複雑になっていきます。 それだけでなく、管理するリソースが増えるということは、それだけ変更が必要になる頻度も上がります。

このような場合、ドキュメントやチェックシートによる管理は実際のリソースとの差異が生まれやすくなり、その差異を確認することも困難になっていきます。

この課題を解決するための手法がIaCです。 アプリケーションは何らかの表現形式で記述したコードによって表現されています。 IaCは、この考え方をインフラに応用した手法と言えます。

考え方としては単純で 「インフラを構築するためのアプリケーションを作り、それによってリソースの変更を人間の手ではなく、コンピューターにやらせよう。 インフラが正しく構築できるかどうかはそのアプリケーションのコードの正しさによって管理しよう」 というものです。

この手法によって、インフラ構築の自動化・均質化・明文化・履歴管理が可能になります。また、これらが可能になることにより再現性が非常に高く保てます。

自動化

従来手法では人間が手で行なっていた変更作業を、コンピュータが行うことで自動化が可能になります。 また、原則的には記述されたことと実際の差異が生まれないため、リソースの管理が容易になります。

均質化

従来手法ではドキュメントや実際の変更作業のクオリティ、読みやすさ・漏れ・ミスが担当の人間の経験に左右されていたのが、ある程度均質化されます。 もちろんコードであっても担当の人間によってクオリティは多少揺らぎは生まれますが、自然言語による文章表記よりもその幅は大きく減少します。

明文化

自然言語文章ではどうしても人間の解釈次第になってしまい、曖昧になってしまったり、当たり前に行うことなのでわざわざドキュメントに書かないというようなことがあります。 IaCでは書かれたコードの解釈も実行もコンピューターが行うため、曖昧さが排除され、インフラを構成するリソースのあるべき状態を明文化することが可能になります。

履歴管理

これは厳密にはIaCの特性というわけではないのですが、実際には改善することがほとんどです。 現代ではアプリケーションのコードは何かしらのバージョン管理システム(多くの場合gitでしょう)によって履歴管理が行われ、版ごとの差分や変更の意図などを記録することが可能になっています。 IaCではインフラを構成するリソースはコードによって表現されるので、従前より利用しているこのようなバージョン管理システムを利用することで、アプリケーションと同様に履歴を管理することが容易になります。

IaCの2つのアプローチ

現在、IaCには主に手続き型と宣言型の2つのアプローチがあります。 これはアプリケーションコードを記述する手法に手続き型・オブジェクト指向型・関数型のようにいくつかのアプローチがあるのと同じような状況です。

手続き型

手続き型はその名の通り、インフラを構築していく手順を記述していくアプローチです。

メリットは、単に手順をそのままコードに書き下していくような形になるため、最初の障壁が低く、初学者でも詰まりにくいことです。 また、コードも従来アプリケーション開発で用いられてきた汎用のプログラミング言語であることも多く、自由度が高いことも挙げられます。

デメリットは、冪等性の担保に対してのサポートが弱いことです。また、手順の積み重ねになるので、全体としての意図の見えにくくなる点や、大きな変更に弱いという点も挙げられます。 そのほか、自由度が高いが故にバグが入りうることもデメリットと言えるでしょう。

宣言型

宣言型はインフラを構成するリソースの状態を記述していくアプローチです。現在の状態から宣言された状態への差分を自動的に埋めるように処理が行われます。

メリットは、最終的にリソースがあるべき状態を記述するため、バグが起こりにくく、冪等性も担保されやすい点や、全体としての意図が見えやすくなる点が挙げられます。

デメリットは、専用のDSLが用いられることが多いことや、手続き型より抽象的な記述になるため、最初の障壁が高いことが挙げられます。 また、手続き型よりも自由度が低いことが多く、アプリケーションコードを書きなれた人間からすると、フラストレーションを感じることが多いように思います。

ansibleとterraform

さてこの時点までざっと5000字ほどあるのですが、ようやく本題です。みなさんこの文章の本題を覚えていますか? 私は忘れかけていました。なので改めて記載しますが、この文章は「ansibleとterraformって何が違うんですか?」という疑問の答えになることを目標に書かれています。

では具体的に何が違うのでしょうか? ここまでの文章を読んだのであればある程度想像がつくでしょうが、それぞれIaCを実現するアプローチが手続き型と宣言型であるという点が一番大きな差異であると言えます。

ansible

ansibleは手続き型アプローチを採用しており、構成手順をplaybookと呼ばれるファイルにYAMLで記述するのが特徴です。 ansible自体はPythonで記述されており、プラグインもPythonで記述することができます。

類似の手続き型アプローチを採用したツールとして、chef、puppet、fabricなどがあります。これらの中でのansibleの特徴は、よりシンプルで扱いやすい点が挙げられます。 ただ、これらのツールでできることにはそれほど大きな違いはない印象です。各々の組織の要件にあったものを用いると良いでしょう

terraform

terraformは宣言型アプローチを採用しており、hclという独自言語でtfファイルにリソースを宣言するのが特徴です。 また、terraformはリソースの状態を管理するためにstateファイルというjson形式のファイルを用います。 このため、既存のリソースをterraformでの管理に切り替えるのには比較的手間がかかります。 リソースをterraformで管理したいのであれば、多少手間でも最初からterraformを使って定義することをお勧めします。

terraform自体はGoで記述されていますが、プラグイン(実際にはproviderやprovisionerと言います)はterraform本体のプロセスとgrpcで通信を行う別のプロセスとして実行されるため、各自好きな言語で記述することができます。

使い分け

これまで述べてきたように、ansibleとterraformではIaCに対するアプローチが異なります。ansibleは手順を自動化し、terraformは状態管理を自動化します。 弊社では主にterraformをインフラの構築全般に使い、ansibleはサーバ単体の構築に用いています。

サーバ単体の構築は大抵の場合、リソース間の相互作用がそのサーバ単体の中で閉じられているため、全体像がそれほど複雑になりません。 また、サーバの中に配置したいものは一般的なミドルウェアであったり、あるいは自前で開発したバッチスクリプトであったり、多岐に渡るため、シェルスクリプトと一対一のように記述できるansibleが扱いやすく、採用の動機になります。

対して、VPCやセキュリティグループ、RDBなどはリソースごとに相互作用があり、どこかで定義した値を別の場所で使う、ということが多くあります。このようなシーンではterraformはうまく相互関係を解決してくれます。 また、稀にではありますがごく一時的に手作業でパラメータを変更してしまう場合もある(実際はこのような作業はあまりよくないですが、軽微な変更の検証など)ので、冪等性をツール側で担ってくれる点も採用理由の一つです。

弊社ではこのように使い分けをしていますが、近年はほとんどのサービスをECSかEKSの上に構築しており、サービスの管理はECSであればecs-deploy、EKSであればkustomizehelmを使っており、個々のコンテナはDockerfileで管理されているため、相対的にansibleの利用頻度は下がっています。

おわりに

以上、ansibleとterraformの違いについて、それぞれの特徴の説明と、弊社での使い分けについて解説をしました。

今回はそれぞれのツールの具体的な使い方やプラクティス、tipsなどの説明には踏み込めませんでしたが、いずれ機会があればそのあたりにも触れてみたいと思います。

DELISH KITCHEN WEB を構成する技術のお話

f:id:kajidai:20201130160617p:plain

DELISH KITCHEN WEBについて

はじめに

はじめまして。DELISH KITCHENバックエンドチームの梅木です。 DELISH KITCHENのバックエンドチームはアプリ向き合いとWEB向き合いのチームとで別れており、自分はWEB向き合いのチームに配属されています。 担当業務としては、DELISH KITCHENのWEBフロントの開発はもちろん、APIサーバーやインフラと、WEBサービスに関しての改修では境界を設けずに、開発・運用・監視を日々行なっています。

本日はDELISH KITCHENのWEBサービスのシステムについて、ご紹介できればと思います。

DELISH KITCHEN WEBで使われている技術スタック

DELISH KICTEHEN WEBで使用されている技術スタックはこちらになります。

delishkitchen web

  • フロント
    • Nuxt.js(Universal mode): 2.14
      • アプリケーションサーバー & BFF: express 4.x
      • ランタイム: node 12.x
      • コードフォーマッター: prettier / stylelint / eslint
      • バリデーション: vee-validate 3.x
      • テストフレームワーク: jest
      • エラー監視: sentry
      • ビデオプレイヤー: Videojs
      • 状態管理: vuex
      • ページ遷移: vue-router
      • ページのメタ情報生成: vue-meta
      • SSRレンダリング: vue-server-renderer
  • APIサーバー
  • インフラ
    • AWS ECS
    • AWS Route53
    • AWS Cognito
    • AWS API Gateway
    • AWS s3
    • AWS Lambda
    • AWS CloudFront
    • Elasticsearch
    • ansible
    • docker
  • パッケージ依存関係解消ツール
    • renovate
  • ログ/分析
    • TreasureData
    • redash
  • 開発/運用ツール
    • Github
    • CircleCI
    • Datadog
    • terraform

DELISH KITCHEN WEBでは、基本的にNuxt.jsのフレームワークのルールに従って開発しています。 vuex、vue-router、vue-metaやvue-server-rendererなどのライブラリも、最初からNuxt.jsの中に組み込まれているものを使っています。 Universal modeのNuxt.jsはBackend for Frontendとして機能するため、GolangのAPIサーバーとは別々で管理されており、Nuxt.jsアプリケーションだけを考えて開発を行うことができます。

Nuxt.jsとGolangのAPIサーバーをそれぞれdockerコンテナ化し、そのコンテナ化したマイクロサービスをAWS ECSでec2インスタンスにデプロイするという構成で運用しています。 他にも、メールアドレスログインでAWS Cognito、検索や絞り込みシステムでElasticsearch、レシピのサムネイルを縮小化しwebp拡張子で配信するシステムでAPI Gateway x Lambdaを組み合わせたサーバーレスアプリケーションを利用するなど、WEBチームでは、WEBフロント開発だけでは終わらずクラウドインフラを多く使い、裁量が広い範囲でWEBサービスの開発を行なっています。

Nuxt.jsを採用した理由

現在、DELISH KITCHEN WEBはNuxt.jsで構成されておりますが、Nuxt.jsで運用しているのは下記のような背景があります。

背景

DELISH KITCHEN WEBの1stリリースでは、Riot.jsというSPAライブラリで構築されていました。普通にブラウザで動かすSPAアプリケーションとしては何も問題なかったのですが、DELISH KITCHEN WEBはメディアサイトであるため、ユーザーだけではなくSEO対策としてクローラーのことも意識して開発する必要があります。クローラーがページにアクセスしたときは、ブラウザからアクセスされたときと同じjsが返却されるわけですが、当時のクローラーのレンダリングエンジンはjs解析にそこまで強くなく、クローラーにページの内容を読み取ってもらうことができませんでした。その為クローラーからのアクセスだった場合は静的なhtmlのページを返す必要があり、Express(nodejsのアプリケーションサーバー)がhtmlを生成してクローラーに読み取ってもらうという方針を取っていました。

問題

上記の背景により、Riot.js + Expressの構成でプロジェクト運用していましたが、ユーザー向けのブラウザで実行するコード(SPA用のコード)とクローラーに向けのコード(SSR用のコード)の2重管理をしていたので、特に新規ページや新規機能の開発、確認や運用コストが大きいという問題がありました。クローラーからのアクセスを考慮すると、クローラとユーザーごとに返却するHTMLを変えることが、SEO効果に悪い影響があるのか未知でした。そのような問題があるなか、事業側から新しい施策に打ち出したいと話があり、要件としてWEBサービスにメールアドレスログイン機能や課金機能が必要でした。コードが2重管理されているプロダクトでそのような大きい機能を無事に実装し運用できるかという不安がチーム内にありました。

他にも当時の構成について、下記のような意見もありました。

  • Riot.jsを本番運用しているプロダクトが少なく、開発で困ったときに参考にできる知見もあまりない。

  • 当時のDELISH KITCHENは、ユーザーからのインタラクションでdomを表示/非表示の切り替えが発生する機会が少なく、リッチなアニメーションもないため、WEBサービス自体がブラウザでレンダリングさせるSPAアプリケーションで構成する必要がない。

ユーザーへはSPAである必要がなく、クローラーを考えるとSSRが必要ということで、ユーザー側にもクローラーにも最初から同じコードからSSRで生成されたhtmlを返したほうがいいのではないかと考えました。大きな機能をWEBサービスに入れる前に、Universalアプリケーション(SSR + SPA)の開発ができる技術を使ってシステムリプレースをすることになりました。

検討

フレームワークレベルでUniversalアプリケーション開発が担保されている技術を検討したところ、Angular Universal / Next.js / Nuxt.jsの選択肢が出てきました。その選択肢の中からNuxt.jsを選びましたが、理由は下記となります。

  1. 当時のバックエンドチームには、バックエンドに強いメンバーがほとんどでwebフロント開発に長けているメンバーは多くなかったため、Nuxt.jsのような薄いフレームワークが取り掛かりやすいのではないかと考えた。
  2. バックエンドチームのメンバー内でVue.jsの開発経験者が一名在籍していた。
  3. Riot.jsのSFC(Single File Component)の作りが、Vue.jsでのコンポーネントと同じであるため、システムリプレースもしやすいのではないか。(template / script / styleとブロックを分ける構成がほぼ同じ。)

下はレシピのサムネイルとタイトルを表示するコンポーネントです。

Riot.jsのSFC

<delish-recipe-item>
  <a href="/recipes/{ opts.recipe.id_str }">
    <img riot-src="{ utils.resizeImg(opts.recipe.square_video.poster_url, opts.size) }" />

    <div class="item__title-wrap">
      <p class="item__title">{ getTitle() }</p>
    </div>
  </a>

  <style type="scss">
    .item__title-wrap {
      text-align: left;
      flex: 1;
      margin-left: .75em;
      padding: 0 1em .5em 0;
      border-bottom:  1px solid @color5;
    }
  </style>

  <script>
import utils from '../../misc/utils';

this.utils = utils;

this.getTitle = () => {
  let str = this.opts.recipe.lead + this.opts.recipe.title;
  if (str.length < 29) {
    return str;
  }

  return str.slice(0, 27) + '...';
};
  </script>
</delish-recipe-item>

Vue.jsのSFC

<template>
  <div class="delish-recipe-item">
    <nuxt-link :to="`/recipes/${recipe.id_str}`">
      <img :src="utils.resizeImg(recipe.square_video.poster_url)" />

      <div class="item__title-wrap">
        <p class="item__title">{{ recipeTitle }}</p>
      </div>
    </nuxt-link>
  </div>
</template>

<script>
import utils from '../../misc/utils';

export default {
  props: {
    recipe: {
      type: Object,
      required: true,
    }
  },

  computed: {
    recipeTitle() {
      const str = this.recipe.lead + this.recipe.title;
      if (str.length < 29) {
        return str;
      }

      return str.slice(0, 27) + '...';
    }
  }
}
</script>

<style type="scss" scoped>
.delish-recipe-item {
  .item__title-wrap {
    text-align: left;
    flex: 1;
    margin-left: .75em;
    padding: 0 1em .5em 0;
    border-bottom:  1px solid @color5;
  }
}
</style>

実際に移行してみてどうか?

  • はじめに課題として上げた、ユーザ向けとクローラ向けのコード二重管理がなくなり、同じコンポーネントで一元管理できるようになったため、開発やQAのコスト削減を実現しました。 Nuxt.jsにリプレースしてから、SEO対策向けに多くの機能リリースを行ったことから、これらのコストを下げられたのは良かったと思っています。
  • Nuxt.js(Vue.js)の豊富なドキュメント、ライブラリや活発なコミュニティの恩恵を受けられ、開発して困る問題も大半は解決されました。多くの事例を参考にしながら開発をスムーズに行うことが出来ています。
  • 追加で、webpackもNuxt.jsに組み込まれているため、ページ単位のjs分割やコンポーネントのdynamic importも可能となり、パフォーマンス対策もできています。
  • Nuxt.jsはフレームワークであり一定のルールに沿って開発するため、UIライブラリのRiot.jsと違い、チームメンバーの間で認識を揃えながら開発もできます。

最後に

今回はDELISH KITCHEN WEBで使われている技術スタックと弊社でNuxt.jsを採用した理由をまとめてみました。

DELISH KITCHEN バックエンドチームでは、WEBフロント開発だけではなく、APIサーバーやクラウドインフラの運用も行なっていきます。プロダクトを良くするのに必要であれば、自ら提案し新しい技術に触れられる環境です。

現在運用が安定してきた中、これからも新規機能をリリースしたり、テストやtypescript導入するなど開発改善を行うことも考えています。

このブログでDELISH KITCHEN WEBについて少しでも知っていただけたら幸いです。最後までお読みいただき、ありがとうございました。

DELISH KITCHEN のサービスとバックエンドシステムのお話

自己紹介

はじめまして。DELISH KITCHENバックエンドチームのマネージャーをやっている内原です。

本日はDELISH KITCHENにおける、バックエンド観点でのシステム紹介を行います。この紹介によりDELISH KITCHENの開発に興味を持ってもらえると嬉しいです。

はじめに

DELISH KITCHENのサービス全体像とバックエンドシステムの構成や仕様などを紹介します。

ご覧の通り、複数のマイクロサービスが様々なミドルウェアを利用しつつ、DELISH KITCHENサービスの提供を実現しています。

DELISH KITCHENのサービス全体像

サービス全体像

DELISH KITCHENの一番主要な機能は、レシピ動画を提供することでお客様の料理体験をよりよいものにすることです。

これだけ聞くと、単に動画を配信しているだけのサービスのように思われるかもしれませんが、実際には料理にまつわる様々な事柄をサポートするシステムで、多くの機能を提供しています。

DELISH KITCHENを提供しているプラットフォーム

料理を作ろうと思った時や買い物をしている時、なんとなく流行りのレシピを知りたいと思ったときなど、色んなシチュエーションでご利用いただけるように、以下のプラットフォームでDELISH KITCHENを提供しています。

  • iOS/Android アプリ
  • WEB
  • 小売店でのデジタルサイネージ
  • Amazon Echo

DELISH KITCHENが提供しているサービス

単に料理を作る際に役立つだけではなく、特売情報をお知らせしたり買い物リストと連携することでお買い物をサポートします。

DELISH KITCHENが提供している主なサービスは以下の通りです。

  • 人気、特集、新着、パーソナライズされたリコメンドなど、能動的なレシピ提案
  • カテゴリ内検索、キーワード検索など、受動的なレシピ提案
  • 各地域の小売店特売情報と、特売商品を用いたレシピ提案
  • レシピのお気に入り管理
  • レシピのレビュー
  • レシピ材料の買い物リスト管理
  • プレミアム会員向け機能やプレミアム会員限定レシピの提供
  • DELISH KITCHENポイントによるポイント交換、ポイントがもらえるクーポン機能
  • 機種変更時や複数端末での同期用にメールアドレス/SNSによるログイン機構
  • プッシュ通知

DELISH KITCHENのバックエンドシステム全体像

複数のシステム構成

DELISH KITCHENは複数のマイクロサービスで構成されており、それぞれが別のシステムとして独立しています。

個々のシステムにおいては共通している部分も多いですが、提供している機能や使用しているサービスには差異があります。

共通の基盤/利用サービス

インフラ構成図

DELISH KITCHENの各サービスで共通的に利用している基盤や外部サービスは以下の通りです。

  • Golang, echo
  • インフラ
    • AWS ECS
    • AWS RDS
    • AWS AutoScaling
    • AWS ElastiCache
    • AWS S3
    • AWS CloudFront
    • AWS Route53
  • ログ/分析
    • fluentd
    • redash
    • TreasureData
    • Databricks
  • 開発/運用
    • github
    • CircleCI
    • terraform
    • ansible

共通APIサーバ

iOS/Android/WEB/サイネージなど、クライアント向けに提供しているAPIサーバです。お客様に対して提供される機能は、すべてこのAPIサーバを経由しています。

各種内部向けAPIサーバへの中継もここで行われます。

WEBシステム

DELISH KITCHEN WEB

WEBにおけるDELISH KITCHENサービスを提供しています。

レシピなどのデータは共通APIサーバを参照しています。共通APIサーバと通信する構成であるため、BFF(Backends For Frontends)として稼働しています。

検索システム

DELISH KITCHEN 検索

レシピ情報の検索を提供するサーバです。

検索エンジンには Elasticsearch を利用しています。

特売情報システム

DELISH KITCHEN 特売情報

特売情報を提供するサーバです。

データとしては店舗、特売商品、チラシなどを扱っています。

別途、店舗側にて特売情報を入稿するためのtoC向けシステムも存在しますが、今回は省略します。

サイネージシステム

DELISH KITCHEN サイネージ

小売店舗に設置しているサイネージ端末が利用するサーバです。

個々のサイネージに対し、レシピ/広告を指定した配信設定が可能です。レシピ情報は共通APIサーバを参照しています。

別途、店舗側にて配信設定を管理するためのtoC向けシステムも存在しますが、今回は省略します。

ポイントシステム

DELISH KITCHEN ポイント

デリッシュポイントという、DELISH KITCHEN内でお得に使えるポイントを管理するサーバです。

ポイントを別商品に交換するにはドットマネーを利用しています。

クーポンシステム

DELISH KITCHEN クーポン

デリッシュポイントをもらうことができるクーポンサービスを提供するサーバです。

外部のクーポンサーバとやり取りをしています。

課金システム

プレミアムサービスを利用可能とするため、ストア決済、キャリア決済を実現するサーバです。

プレミアムサービスはサブスクリプション形態であるため、アプリ外で購読状態を管理しています。

プッシュ通知システム

DELISH KITCHEN プッシュ通知

アプリ向けにプッシュ通知を提供するサーバです。

サーバの実態としてはmercari社製のgaurunを利用しています。

最後に

上記のように、DELISH KITCHENは多くのシステムで構成されたサービスです。

開発、運用で使用しているインフラ技術、外部サービスも多岐に渡りますので、興味を持ってもらえると嬉しいです。

ここまでお読みいただき、ありがとうございました。

DELISH KITCHENのAndroidアプリの今と変遷

はじめに

DELISH KITCHENでクライアントグループのマネージャーをやっている今井です。 クライアントチーム初のブログということで、DELISH KITCHENの Androidアプリの今の構成の話と、 アプリを作って4年が経とうとしてる中での変遷を紹介していきます。

なお、このブログは全体の構成の雰囲気を掴んでもらうことを目的にしておりますので、 細かい設計の話や採用技術の細かい特徴の紹介は割愛させていただきます。 それらはまた別の機会に紹介できればと思います。

現在の構成

ここでは現在のプロジェクトの構成とアプリで採用しているアーキテクチャの紹介をしていきます。

プロジェクトの構成

DELISH KITCHENのAndroidアプリではMultiModuleを採用しており、 大きく app core features の3種類のModuleに分かれています。

  • app いわゆるメインモジュールです。feature間をつなぐためのRouterの実装や、 ライブラリの初期化等を行っております。 歴史上の理由でここにもまだまだfeature要素が残ってしまっていますが、 徐々にfeatureモジュールに切り出しています。

  • core 各モジュールの共通で使う拡張関数やユーティリティクラスなどを入れています。 モジュール間の遷移に使ってるRouter等もここでInterfaceを定義しており、 実態はappモジュールで実装、DIで各モジュールに配布しています。

  • features 実際にfeaturesというモジュールがあるわけではなく、 機能ごとにfeatureモジュールとして分割しています。 各featureモジュールではcore以外のmoduleのimportを禁止しており、 強制的に参照不可にすることで依存をなるべく減らしています。

アーキテクチャ

アーキテクチャとしてはMVVM+レイヤードアーキテクチャを採用しています。

No Image

図の通りですが、Android Architecture Component(以下、AAC)を全面採用し、 MVVM+レイヤードアーキテクチャを構成しています。 ViewModelはそのままAACのViewModelを採用しており、 ViewModelからViewへのデータの公開はLiveData、 ViewからActionの受け付けはシンプルにメソッドコールにしています。 通信部分はKotlin Coroutineで繋いでいます。

この構成にいたるまでいろいろ変遷してきているので、 その一部を次で紹介します。

変遷

この4年間でKotlinがGoogleに正式にサポートされたり、AACやJetpackが登場したり Android界隈で大きくデファクトが変わってきました。 DELISH KITCHENのAndroidアプリではそれに対して比較的柔軟に採用技術を変更してきました。 その中で大きく変更があった3点を紹介します。

1. MonoModuleからMultiModuleへ

コード量が増えてきてビルド時間が長くなってきたので検討し始めました。 副産物的な感じでしたが、参照をあえて出来なくすることで依存関係を意識せざるを得ない状況になり、チーム全体の依存に対する意識が向上しました。また、その事に頭を使わなくて良くなったのでとても良かったです。 分割し始めた当初はInstant AppやDynamic Feature Moduleも検討していました。

2. Android Architecture Componentの採用とRxの置き換え

リリースから1年くらい経つと、機能が乗ってしまったいわゆるSuperActivity/Fragmentが出現し始めたので、 MVVMやFluxの導入を考えていたところAACが発表されたため即採用しました。 またAPI通信まわりは各レイヤーの繋ぎにとどまっていたRxをKotlinCoroutineとLiveDataに置き換えることで、 AACの恩恵をフルで受けれるような構成に変更しました。

3. Viewへのアクセス周りの変遷

ここが一番紆余曲折あったところです。 ざっくりと KotterKnife → Kotlin Android Extension → Databinding → ViewBinding と変更してきました。 初期はJavaのButterKnifeの流れでKotterKnifeを採用してたものの、 型安全じゃないとかFragmentで使えないなどの理由から、Kotlin Android Extensionに移行しました。 その後すぐにnullableになってしまうのが辛くなったのと、xml上で値を設定できる便利さからDataBindingを採用しました。 DataBinding自体は全然問題なかったんですが、あまり双方向Bindingを生かす場面がなかったのと、 ロジックがxmlにも一部分散することでコードレビューが大変になったので、現在はViewBindingを採用しています。 加えてViewBindingはDataBindingビルドが速かったり、型安全だったりと、しばらくはViewBindingで落ち着きそうです。

(おまけ) Dagger → Koin

人類にはDaggerは早かった(笑) っていうのもありますが、Daggerの機能をそんなに活かしきれていなかったのと、 誰でも比較的簡単にライブラリの挙動が理解できるようにKoinに変更しました。 設計自体に影響が大きくあった訳ではないですが、コードの変更量が膨大で、 変更作業が一番辛かったのでおまけとして紹介させてください(笑)。 そんな中、今年出たDaggerHiltへの変更を検討中だったりもします😇。

まとめ

DELISH KITCHENのAndroidのアプリに関して少しでも知っていただけたら幸いです。 今回ご紹介した設計がベストだとは考えていませんし、まだまだ発展途上です。 アプリの規模にかかわらず、良いものであれば積極採用することはぶらさず、 開発してて楽しい環境を作りながら、より良いアプリをより早く提供できるように努めていければと思ってます。

エブリーのインターンに参加してみた

はじめに

はじめまして。2020年3月からエブリーでインターンをしている田村です。
私はデータエンジニア・データサイエンティストとしてインターンシップに参加し、データ関連部門に配属され、データ業務を担当しています。
今回は、エブリーにインターンとして入社し約4ヶ月間で感じたことをまとめていこうと思います。

目次

1.エブリーのインターンに参加した経緯

2.インターンを通して学んだこと

1.エブリーのインターンに参加した経緯

私は機械学習を主とする統計分野に興味があり大学院に進学したのですが、査読した論文を検証できるデータを保持するインターン先を探す中で、DELISH KITCHENを運営しているエブリーと出会いました。 面談の前にオフィスツアーをしたのですが、まず驚いたのは東京タワーの見える六本木グランドター38階のオフィスです。
食のメデイアを運営していることから、本格的なキッチンスタジオがあり、フードスタイリストの方が日々料理動画を撮影しています。

f:id:kthimuo:20201008145828j:plain

作業エリアは集中できる雰囲気なことや、CTOとのカジュアル面談時に大量のデータを扱うことが出来そうだと期待してインターンとして入社することに決めました。

2.インターンを通して学んだこと

私がデータエンジニアとしてインターンの業務を通じて学んだことを書いてみます。  

・DIKW

まず、初日にデータチームのマネージャーに教えられたことはDIKWモデルというデータがどのように事業に貢献するかというモデルです。詳しい記事はこちらをご覧ください。

・Arm Treasure Data / Databricks / Redashなどのデータプラットフォーム

DELISH KITCHENのログデータの分析だけでも膨大な量で、これらのビッグデータを処理できる計算基盤が必須です。
所属しているデータ部門では、Databricksと呼ばれるApache Sparkをバックエンドとした分析プラットフォームを用いて、データクレンジングなどの前処理や機械学習の処理を実装しています。
またこちらの記事でもあるように、sql,scala,pythonなどの複数の言語を組み合わせて処理を書けるためこれらの言語の基本文法はマスターできました。学校ではPythonを利用した研究開発だけを実装しており、Python以外の言語に触れる機会が無かったのですが、SQLが特に重要だと教えられ、今では自分のやりたい事は大体実現できるようになりました。
インターン生でもエブリーの全てのデータに自由にアクセスでき、分析する基盤まであるのはとても良い環境だと思います。

・他部門との連携

私の所属するデータ関連部門では、エブリーが運営している複数のメディアから発生するデータ分析依頼や要望を引き受けています。
「●●を知りたい」などの抽象的な課題を具体的な課題に落とし込んだ後、どんなデータを提供したら良いのか、どんな見せ方をしたらいいのかを考え、Redashのダッシュボードを提供したり統計的な手法で知見を伝えたりします。
他部門の業務を経験が浅いインターンが他部門の業務や課題を理解するのは難しいですが、エブリーではインターン生も他部門の議事録や組織図をconfleneceやカオナビで把握できます。

・リモート環境

コロナの影響でエブリーでは3月からインターンも含めリモートワークを推奨しています。
私もリモートでのインターンは初めてで、移動時間がなくなったり服を選んだりする手間がなくなったりメリットが多いなと思いました。意思疎通が対面よりもスムーズにできないという問題がありますが、私のチームでは毎日30分程のミーティングを行い、課題の共有やコミニケーションを行うようにしています。
会議に参加できなくても録画しておけば後から見直せるので便利です。
最近では半年に1回の社員総会もリモートで行いこちらに詳しい記事があります。

最後に

エブリーではデータ関連部門以外でもエンジニアのインターンを募集しています。
メディアの運営に携わってみたい、アプリの開発に携わってみたいという方はこちらをご覧ください。