トレタ開発者ブログ

飲食店向け予約/顧客台帳サービス「トレタ」、モバイルオーダー「トレタO/X」などを運営するトレタの開発メンバーによるブログです。

トレタはRubyKaigi2018にスポンサーとして参加します & 【仙台版】トレタMapのご紹介

f:id:m_nakamura145:20180525145955p:plainサーバーサイドエンジニアの中村です。

私たちトレタは今年のRubyKaigi2018にスポンサーとして参加します!

rubykaigi.org

5/31(金)〜6/2(日)の3日間、会場となる宮城県仙台国際センターにてブース出展しています。是非お気軽にお立ち寄りください!

【仙台版】トレタMapを作りました!

https://rubykaigi2018.toreta.in/

杜の都仙台市はトレタ導入店も多いこともあり、会場で出会った方達が飲みにいかれる際のお店探しに役立つ「【仙台版】トレタMap」というグルメMapを作りました!

トレタMapって何?

私たちトレタは、飲食店向けの予約/顧客管理に特化したクラウド型サービスを提供しています。 「トレタMap」とは、仕事上もプライベートも、急な飲み会や2次会探しが多いトレタメンバーからの「今いる場所から近いお店が知りたい。そしてせっかくならトレタ導入店に行きたい」そんなニーズから作られた、トレタ導入店で構成されるグルメMapのことです。

この「トレタMap」はこれまで社内のみで公開していたのですが、今回スポンサーとして参加するRubyKaigiの会場が仙台で開催されることとあって、会場にお越しになる皆さんに、少しでもお店探しのお役に立てればと「【仙台版】トレタMap」として一部カスタマイズして限定公開することにしました。

トレタMapの特徴

  • GoogleMap上から直接お店情報が確認できる
  • お店情報からウェブ予約ページに遷移してそのまま予約できる

f:id:m_nakamura145:20180523104542p:plain

そう、この「トレタMap」の一番の特徴は、そのまま空席検索&予約ができてしまうこと!24時間予約可能なので「予約したいのに営業時間外」だったり「移動中で電話できない」時などにとっても便利です!(「トレタかんたんウェブ予約」を設定している店舗に限ります)

配布場所

当日会場のブースにてQRコード付きのチラシを配布いたします。

※ブースに来てくれた方限定の配布と思っていましたが、事前にお店を知りたい方も多いと思いこちらでもURLを配布します(ブースにも是非遊びに来てください!)

▼「【仙台版】トレタMap」

https://rubykaigi2018.toreta.in/

掲載店舗

今回Map上に掲載される店舗一覧です。お店探しの参考してください。

docs.google.com

※ブログ作成時の最新情報を記載しています。ご利用時に情報が変更になっている場合は何卒ご了承ください。(掲載期間は6/3まで)

使ってくれた皆さんへのお願い

今回はもともと社内ツールだったものをお試し限定公開しています。実際に使っていただいた感想を是非伺いたいと思っています。ツイッター等で #rubykaigi #toretamap のハッシュタグでご意見、ご感想をお願いします!

グルメMap仲間のご紹介

私たち以外にも参加者の皆様に向けたグルメMapをご紹介されているスポンサーさんがいらっしゃったのでご紹介いたします。

SmartHRさん

tech.smarthr.jp

2年連続「自腹で作るグルメマップ」を公開されています。素敵です。 「【仙台版】トレタMap」と合わせれば3日間のお店探しはもう困りません。

私たちは仲間を募集しています

私たちトレタはまだまだたくさんの「やりたいこと」「叶えたい世界」があります。 日本が誇る食の世界をITの力で一緒に幸せにしてくれる仲間を募集しています。

ぜひ仙台でお会いしましょう!

git pushでサーバを構築する

2018年あけましておめでとうございます。

新年早々ひどい肩こりに悩まされていましたが、最近ようやく回復してきましたインフラの山田です。

去年の振り返り

f:id:tyamada112:20180125110027p:plain

さて、2017年の振り返りになりますが、おかげさまで昨年は99.996%のシステム稼働率を記録することが出来ました。 今年も飲食店様を支えるインフラとして、この稼働率をキープしていきます。

git push起点でインフラをつくる

トレタではInfrastructure as Codeに積極的に取り組んでいます。 全てのインフラリソースをコード化出来ているわけではありませんが、 git pushでインフラができあがる の考えのもと仕組みを作っています。 さて、今回はサーバの構築に関して紹介します。

使っているツール

以前のブログでも紹介させて頂いていますが、サーバ周りを運用を回すのには以下のツールを使っています。

これらのツールをCircle CIを起点として実行しています。 処理の流れについて順を追って書いてみます。

1. AMIをつくる。

最初にPakcerでサーバの種となるAMIを作ります。

f:id:tyamada112:20180125110241p:plain

絵の通り、git pushをして、あとは放っておけば単体テストまでが完了したAMIが自動で出来上がってきます。いわゆるゴールデンイメージです。 AMIのImage nameにはtimestampを付与しているので、「あ。MW周りの設定を3日前の状態に戻したいなー」とかあれば戻しは楽です。 当然、AMIを作るだけというのはアレなので、以下の条件を満たすAMIは、削除をする仕組みを入れています。

  • 保存日数を超過している。
  • 保存世代数を超えている。

さて、実際のtemplateの中身はこんな感じです。

{
  "variables": {
    "sample1_aws_access_key": "xxxxxxxxxxxxxxxxxxxx",
    "sample1_aws_secret_key": "xxxxxxxxxxxxxxxxxxxxxxxxx",
    "sample2_aws_access_key": "xxxxxxxxxxxxxxxxxxxx",
    "sample2_aws_secret_key": "xxxxxxxxxxxxxxxxxxxxxxxxx"
  },
  "builders": [{
    "name": "sample1",
    "access_key": "xxxxxxxxxxxxxxxx",
    "secret_key": "xxxxxxxxxxxxxxxx",
    "region": "ap-northeast-1",
    "source_ami": "xxxxxx",
    "vpc_id": "xxxxxx",
    "subnet_id": "xxxxxx",
    "associate_public_ip_address": xxxxxx,
    "type": "amazon-ebs",
    "instance_type": "t2.medium",
    "ssh_username": "ubuntu",
    "ami_name": "toreta-sample1 / sample_service / {timestamp}}"
  },{
    "name": "sample2",
    "access_key": "xxxxxxxxxxxxxxxx",
    "secret_key": "xxxxxxxxxxxxxxxx",
    "region": "ap-northeast-1",
    "source_ami": "xxxxxx",
    "vpc_id": "xxxxxx",
    "subnet_id": "xxxxxx",
    "associate_public_ip_address": xxxxxx,
    "type": "amazon-ebs",
    "instance_type": "t2.medium",
    "ssh_username": "ubuntu",
    "ami_name": "toreta-sample2 / sample_service / {{timestamp}}"
  },

~~
~~

  }],
  "provisioners": [
    {
      "type": "shell",
      "scripts": ["base_scripts/base.sh"]
    },
    {
      "type": "ansible",
      "playbook_file": "ansible/initialize.yml"
    },
    {
      "type": "file",
      "source": "serverspec",
      "destination": "/tmp/serverspec"
    },
    {
      "type": "ansible",
      "playbook_file": "sample1_inventory.yml",
      "extra_arguments": [ "--extra-vars", "/xxxxx/xxxxx/xxxxx/xxxxx" ],
      "only": ["sample1"]
    },
    {
      "type": "shell",
      "scripts": ["scripts/sample1_spec.sh"],
      "execute_command": "{{ .Vars }} sudo -E bash '{{ .Path }}'",
      "only": ["sample1"]
    },
~~
~~

privisionersでの処理について、全部書くと大変な量になってしまうので1role分のみ書きます。

①パッケージ周りの更新

ここでは主にpackegeのupdate/upgradeの処理を実行します。 全roleのサーバで共通して流します。

sudo sed -i".bak" -e 's/\/\/archive.ubuntu.com/\/\/ftp.jaist.ac.jp/g' /etc/apt/sources.list
sudo apt-get -y update
sudo apt-get -y upgrade

② Ansible

playbookは汎用/専用の2種類を用意しています。

まずは全サーバに同じ処理を施すための汎用playbookを実行します。 packageのインストールや、rbenv, pyenvなどのインストール、ユーザ周りの整備などの処理を行います。 尚、ここで実行する内容は、全roleで共通して流す内容であることと、管理の二重化を避けるためにansible-galaxyで共通化しています。

次にrole毎に処理内容の異なる専用playbookを流して、Ansibleの処理は完了です。

③Serverspec

仕上げに、Serverspecでテストを行います。 事前に/tmpにserverspecをまるごと送り込んであるので、該当するspecファイルをシェルスクリプト経由で実行します。

#!/bin/sh

TARGET="xxxxx"
SPEC_ENV="xxxxxxxxxx"

cd /tmp/serverspec && /usr/local/rbenv/shims/bundle install --path .bundle
cd /tmp/serverspec && export TARGET=${TARGET} && export SPEC_ENV=${SPEC_ENV} && /usr/local/rbenv/shims/bundle exec rake spec

全てのspecを通過したら、AMIが完成します。 尚、ここで出来上がったAMIにはアプリケーションコード(Rails)は含ませていません。(Packerの中に特定時点のコードを含めること事故につながるため。)

2. サーバをつくる。

次にTerraformでサーバをつくります。

f:id:tyamada112:20180125110252p:plain

絵の通り、ここもgit pushをするだけです。 CircleCI経由でTerraform applyまで完了し、サーバが出来上がります。事前にPackerの中でテストも完了しているので、即サービスインできます。

resource "aws_launch_configuration" "sample-lc-blue" {
  name            = "sample-lc-blue"
  image_id        = "${var.sample1_blue}"
  instance_type   = "t2.medium"
  key_name        = "${var.samplekey}"
  security_groups = [
    "${aws_vpc.xxxxxxxxxxxxx}",
    "${aws_security_group.xxxxxxxxxxxxxx.id}",
~~
~~

変数周りはtfvarsファイルで別管理しています。 なので、AMI-IDをvar.sample1_blueに埋め込んで、terraform applyしてやるだけです。 (尚、トレタではAuto Scaling を使用してインスタンスを動的にスケールをさせているため、aws_launch_configurationを定義しています。)

EC2が起動してきたら、Packerの中に含むことができなかったRailsアプリケーションを流し込みます。 この流し込みには、userdataを利用しており、リポジトリをローカルにcloneし、local deployします。

deployが正常に完了したことを確認したら、Mackerelの監視が有効化されます。 Railsアプリケーションを流し込んでいない状態で監視を有効化すると、Rackサーバが未起動、workerが未起動状態など不完全な状態となるため、重大障害扱いとなってしまいます。そのためPacker buildの中では、Mackerel起動時の初期監視パラメータを on_start = "standby" としています。

サービスインが完了すると、slackに成功メッセージがpostされ、サーバ構築は完了です。

まとめ

今回はインフラのサーバの構築について紹介させて頂きました。 git pushでインフラができあがる の考えのもと仕組みを作っているので、シンプルなオペレーションができています。

また、今回は運用に関しては紹介をしていないんですが、運用についてもできるだけシンプルな運用なできるような仕組を作り心かげています。また次回ご紹介させて頂ければと思います。

それでは今年も一年、トレタの開発者ブログをよろしくお願いします。

トレタの障害対応

この記事はトレタ Advent Calendar 2017の24日目の記事です。

サーバサイドエンジニアの中村です。 トレタのようなSaasを提供する企業に関わらず、サービスを提供する会社において障害対応フローを決めておくことは非常に重要です。

今回の記事では、トレタで障害が発生してしまったときにどのようなフローで対応し、全国の飲食店の方々への影響を最小限にしているかをまとめてみたいと思います。

トレタにおける障害とは?

お客様の業務影響があるものを指します。例を挙げると以下のような事象です。

  • トレタにつながらない
  • ウェブ予約ができない
  • メールが送信できない/受信できない
  • FAXが送信できない
  • SMSが送信できない

アプリからAPIサーバにつながらないなどの重大な障害のときに、飲食店の最低限オペレーションを可能にするためにオフライン時にもアプリ側で予約情報を見れるようになっています。

f:id:m_nakamura145:20171204095411p:plain

障害検知の方法

以下の3パターンがあります。どのパターンにおいてもエンジニアが最初に調査し、障害かどうかを判断します。

監視サービスからslackへの通知

トレタでは以下の監視サービスを使っています

これらの監視サービスが異常を検知したら特定のslack channelに通知します。 また、トレタにアクセスできないなどの重大な異常を検知したら pagerduty からエンジニアに連絡がいくようになっています。

エンジニア以外の社員が障害に気づき、緊急でエンジニアを呼ぶ場合にはslackからpagerduty経由で連絡が行くような仕組みも作っています。

f:id:m_nakamura145:20171204095451p:plain

お客様からの問い合わせ

お客様からカスタマーサポートチームへのお問合わせの中で、バグと思われる挙動のお問合わせが来た場合はすぐにエンジニアが調査を行います。

調査の結果、障害だと判断された場合は障害対応フローに移ります。

社員がトレタの各種プロダクトを触っている際に気づく

自分たちで発見するパターンです。すぐにエンジニアに連絡し調査を行います。

障害対応フロー

トレタでは何度かの障害対応の経験を経て、障害対応フローを改善してきました。 現在は以下のフローになっています。

障害発生の事実確認

上述の障害検知からエンジニアに連絡が入り、調査を開始します。

エンジニアの調査と平行し、カスタマーサポートチームでも似たような現象のお問い合わせが来ていないかを調査します。

社内共有

エンジニアによって障害だと判定された場合はslackで社内全員に連絡をします。 このタイミングで報告するのは以下のような内容です。

  • 障害の内容
    • 例: Web予約が使えない、SMSが送信できない
  • 障害時間
  • 影響範囲
    • 店舗数や日本の店舗か、海外の店舗かやWeb予約したユーザに影響があるかなど
  • 影響するプロダクト
    • トレタはiPadアプリの他にも店舗向けのWebアプリやユーザ向けのWeb予約、他幾つものオプションサービスを提供しています。プロダクト名を書くことで他のプロダクトには影響ないことを連絡します
    • 例: iPadアプリ、Web予約など
  • 復旧対応内容
    • 誰が何時にhotfixをProduction Deployするか?

社内共有後にエンジニアはhotfixの準備を行います。並行してカスタマーサポートチームは該当店舗への連絡の準備、影響範囲によってはAPI連携を行っている外部の企業様の担当の方へも連絡を行います。

飲食店へご連絡する

障害の復旧が遅れる場合は、障害発生の第1報を飲食店・お客様に現在復旧対応中の旨をご連絡します。障害対応が既に完了している場合は、その旨をご連絡します。

連絡方法は

  • トレタのサービスサイトに障害情報を掲載
  • トレタアプリのお知らせ欄に掲載
  • トレタにログインしているアカウントのメールアドレスにメールで送信
  • カスタマーサポートチーム・担当セールスから直接電話でご連絡する

のような方法で早急にご連絡します。

復旧作業

  • アプリケーションコードの修正の場合はhotfix deploy
  • データの不整合の場合は本番オペレーションにてデータの不整合を復旧
  • アクセス急増などによるパフォーマンス低下の場合はインフラの増強作業

を行います。無事復旧したら再度社内共有を行い、飲食店にご連絡を行います。

再発防止対策

トレタでは社内情報共有にesaを利用しています。その中の 障害情報 カテゴリに障害情報を記録しています。記録する内容は、

  • 現象
  • 復旧対応
  • 障害時間
  • 原因
  • 影響範囲
  • 再発防止策

を全て詳細に書いています。また、障害復旧の翌週の全社員が集まるホームルームでも障害報告を行い、再発防止に努めています。

まとめ

トレタではSaaSを提供する企業として障害を発生させないために日々全力を尽くしています。しかし、万が一障害が発生したときのために、対応フローを明確に決めておくことで、実際に障害が発生したときのお客様への影響を最小限にする工夫をしています。

今回はトレタの障害対応事例をまとめましたが、私個人としても、各企業の障害対応のフローに興味があるので、この記事を読んだ方々に自分の企業ではこんな風に対応しているというのを共有していただけたらと思います。

© Toreta, Inc.

Powered by Hatena Blog