無印吉澤

Site Reliability Engineering(SRE)、ソフトウェア開発、クラウドコンピューティングなどについて、吉澤が調べたり試したことを書いていくブログです。

Ansible で文字列比較の結果を boolean 変数に代入する方法

f:id:muziyoshiz:20160331232512p:plain:w300

きっかけ

今回は、時々つまづく Ansible の変数の仕様に関するメモです。

最近、Amazon Linux 1(そろそろ完全に廃止しないといけない……)と Amazon Linux 2 で処理を分岐させたいことがあり、同僚にこういう書き方でできるよと教えてもらいました。

- name: Task for Amazon Linux 2
  debug: msg="Task for Amazon Linux 2"
  when: (ansible_distribution_file_variety == "Amazon" and ansible_distribution_major_version == "2")

以前は ansible_distribution_major_version がいずれも NA になっていたようなのですが、現在は Amazon Linux 2 なら "2" が返されるようです。

ただ、毎回この長い when を書くのは面倒なので、以下のように playbook の冒頭で定義するようにしてみました。

- hosts: hogehoge
  vars:
    amzn2: (ansible_distribution_file_variety == "Amazon" and ansible_distribution_major_version == "2")
  tasks:
    - name: Task for Amazon Linux 2
      debug: msg="Task for Amazon Linux 2"
      when: amzn2
    - name: Task NOT for Amazon Linux 2
      debug: msg="Task NOT for Amazon Linux 2"
      when: not amzn2

しかし、この書き方をすると、以下の DEPRECATION WARNING が出てしまいます。

TASK [Task for Amazon Linux 2] ***************************************************************************************
[DEPRECATION WARNING]: evaluating (ansible_distribution_file_variety == "Amazon" and
ansible_distribution_major_version == "2") as a bare variable, this behaviour will go away and you might need to add
|bool to the expression in the future. Also see CONDITIONAL_BARE_VARS configuration toggle.. This feature will be
removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
ok: [hogehoge] => {
    "msg": "Task for Amazon Linux 2"
}

TASK [Task NOT for Amazon Linux 2] ***********************************************************************************
skipping: [hogehoge]

なるほど。じゃあ、面倒ですけど、警告文にあるように |bool を書き足します。

- hosts: hogehoge
  vars:
    amzn2: (ansible_distribution_file_variety == "Amazon" and ansible_distribution_major_version == "2")
  tasks:
    - name: Task for Amazon Linux 2
      debug: msg="Task for Amazon Linux 2"
      when: amzn2|bool
    - name: Task NOT for Amazon Linux 2
      debug: msg="Task NOT for Amazon Linux 2"
      when: not amzn2|bool

すると、DEPRECATION WARNING は出なくなったのですが、実行結果が期待と真逆になってしまいました……なんで?

TASK [Task for Amazon Linux 2] ***************************************************************************************
skipping: [hogehoge]

TASK [Task NOT for Amazon Linux 2] ***********************************************************************************
ok: [hogehoge] => {
    "msg": "Task NOT for Amazon Linux 2"
}

結論

文字列比較の結果を代入する際に "{{ }}" で囲むと、文字列ではなく boolean として代入されます。DEPRECATION WARNING にある |bool は不要です。

上の例で言うと、

  vars:
    amzn2: "{{ ansible_distribution_file_variety == \"Amazon\" and ansible_distribution_major_version == \"2\" }}"

と書くと、以下のように DEPRECATION WARNING が出ず、実行結果も期待通りになりました。

TASK [Task for Amazon Linux 2] ***************************************************************************************
ok: [hogehoge] => {
    "msg": "Task for Amazon Linux 2"
}

TASK [Task NOT for Amazon Linux 2] ***********************************************************************************
skipping: [hogehoge]

実験

文字列比較の内容は何でもいいので、("1" == "1") という単純な条件式で実験します。以下の実験は、Ansible 2.9 の最新版(2.9.6)で行いました。

いろいろな方法での代入

まず、代入した値をそのまま debug モジュールで出力してみます。

playbook:

- hosts: localhost
  connection: local
  vars:
    var1: True
    var2: False
    var3: "True"
    var4: "False"
    var5: ("1" == "1")
    var6: ("1" == "1")|bool
    var7: "{{ ('1' == '1') }}"
    var8: "{{ ('1' == '1')|bool }}"
  tasks:
    - name: Print vars
      debug: msg="{{ item }}"
      with_items:
        - "{{ var1 }}"
        - "{{ var2 }}"
        - "{{ var3 }}"
        - "{{ var4 }}"
        - "{{ var5 }}"
        - "{{ var6 }}"
        - "{{ var7 }}"
        - "{{ var8 }}"

結果:

% ansible-playbook test.yml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match
'all'

PLAY [localhost] *****************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [localhost]

TASK [Print vars] ****************************************************************************************************
ok: [localhost] => (item=True) => {
    "msg": true
}
ok: [localhost] => (item=False) => {
    "msg": false
}
ok: [localhost] => (item=True) => {
    "msg": true
}
ok: [localhost] => (item=False) => {
    "msg": false
}
ok: [localhost] => (item=("1" == "1")) => {
    "msg": "(\"1\" == \"1\")"
}
ok: [localhost] => (item=("1" == "1")|bool) => {
    "msg": "(\"1\" == \"1\")|bool"
}
ok: [localhost] => (item=True) => {
    "msg": true
}
ok: [localhost] => (item=True) => {
    "msg": true
}

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
変数名 代入方法 結果
var1 True を代入 boolean true
var2 False を代入 boolean false
var3 "True" という文字列を代入 boolean true
var4 "False" という文字列を代入 boolean false
var5 条件式を代入 条件式の文字列
var6 条件式を |bool 付きで代入 条件式の文字列
var7 条件式を "{{ }}" で囲んで代入 boolean true
var8 条件式に |bool を付けた上で "{{ }}" で囲んで代入 boolean true

条件式を "{{ }}" で囲めば、その結果が boolean として代入されるし、囲まなければ文字列として代入されることがわかります。いずれにせよ、代入の時点で |bool の有無は全く関係ないようです。

when 節への文字列の渡し方

代入時に boolean になっている場合は当然成功するので、ここからは代入時に文字列になってしまった場合のみを考えます。

|bool の有無と、結果が True になるかどうかの4通りで実験しました。Playbook が長くなるので、以下には var1 のタスクだけ記載しています。

---
- hosts: localhost
  connection: local
  vars:
    var1: ("1" == "1")
    var2: ("1" == "1")|bool
    var3: ("1" == "2")
    var4: ("1" == "2")|bool
  tasks:
    - name: 1. var1 should be printed
      debug: msg="{{ var1 }}"
      when: var1

    - name: 2. var1 should NOT be printed
      debug: msg="{{ var1 }}"
      when: not var1

    - name: 3. var1 should be printed
      debug: msg="{{ var1 }}"
      when: var1|bool

    - name: 4. var1 should NOT be printed
      debug: msg="{{ var1 }}"
      when: not var1|bool

    - name: 5. var1 should NOT be printed
      debug: msg="{{ var1 }}"
      when: not (var1|bool)

    - name: 6. var1 should be printed
      debug: msg="{{ var1 }}"
      when: "{{ var1 }}"

    - name: 7. var1 should NOT be printed
      debug: msg="{{ var1 }}"
      when: "{{ not var1 }}"

# Template error
#    - name: 8. var1 should NOT be printed
#      debug: msg="{{ var1 }}"
#      when: not "{{ var1 }}"

    - name: 9. var1 should be printed
      debug: msg="{{ var1 }}"
      when: "{{ var1|bool }}"

    - name: 10. var1 should NOT be printed
      debug: msg="{{ var1 }}"
      when: "{{ not var1|bool }}"

    - name: 11. var1 should NOT be printed
      debug: msg="{{ var1 }}"
      when: not "{{ var1|bool }}"

結果はこうなりました。

% ansible-playbook test.yml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match
'all'

PLAY [localhost] *****************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [localhost]

TASK [1. var1 should be printed] *************************************************************************************
[DEPRECATION WARNING]: evaluating u'var1' as a bare variable, this behaviour will go away and you might need to add
|bool to the expression in the future. Also see CONDITIONAL_BARE_VARS configuration toggle. This feature will be
removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
ok: [localhost] => {
    "msg": "(\"1\" == \"1\")"
}

TASK [2. var1 should NOT be printed] *********************************************************************************
skipping: [localhost]

TASK [3. var1 should be printed] *************************************************************************************
skipping: [localhost]

TASK [4. var1 should NOT be printed] *********************************************************************************
ok: [localhost] => {
    "msg": "(\"1\" == \"1\")"
}

TASK [5. var1 should NOT be printed] *********************************************************************************
ok: [localhost] => {
    "msg": "(\"1\" == \"1\")"
}

TASK [6. var1 should be printed] *************************************************************************************
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{
var1 }}
ok: [localhost] => {
    "msg": "(\"1\" == \"1\")"
}

TASK [7. var1 should NOT be printed] *********************************************************************************
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{
not var1 }}
skipping: [localhost]

TASK [9. var1 should be printed] *************************************************************************************
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{
var1|bool }}
skipping: [localhost]

TASK [10. var1 should NOT be printed] ********************************************************************************
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{
not var1|bool }}
ok: [localhost] => {
    "msg": "(\"1\" == \"1\")"
}

TASK [11. var1 should NOT be printed] ********************************************************************************
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: not
"{{ var1|bool }}"
skipping: [localhost]

まとめると、1番の when: varX または 6番の when: {{ varX }} の書き方をすると、DEPRECATION WARNING は出るが、想定通りの結果になりました。それ以外は、文字列の中身に関わらず同じ結果になりました。

when の書き方 var1 var2 var3 var4
1. varX ok ok skipping skipping
2. not varX skipping skipping skipping skipping
3. varX|bool skipping skipping skipping skipping
4. not varX|bool ok ok ok ok
5. not (varX|bool) ok ok ok ok
6. {{ varX }} ok ok skipping skipping
7. {{ not varX }} skipping skipping skipping skipping
9. {{ varX|bool }} skipping skipping skipping skipping
10. {{ not varX|bool }} ok ok ok ok
11. not {{ varX|bool }} skipping skipping skipping skipping

結局、この DEPRECATION WARNING で |bool を付けろ、と言っている意味はわからずじまいでした。誰か詳しい人いたら教えてください……。

[DEPRECATION WARNING]: evaluating (ansible_distribution_file_variety == "Amazon" and ansible_distribution_major_version == "2") as a bare variable, this behaviour will go away and you might need to add |bool to the expression in the future. Also see CONDITIONAL_BARE_VARS configuration toggle.. This feature will be removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

過去の「Ansible のこの仕様なんなん?」と思って書いた記事

muziyoshiz.hatenablog.com

muziyoshiz.hatenablog.com

muziyoshiz.hatenablog.com

SRE NEXT 2020 の個人的おすすめセッション動画

f:id:muziyoshiz:20200127000336p:plain:w640

SRE NEXT 2020 のセッション動画が公開されました!

SRE NEXT 2020 の参加者には、2/23(日)に「SRE NEXT 2020 参加者特典のご案内(セッション動画限定公開)」という Subject のメールが届いていると思います。

このメールに書かれている YouTube の URL から、全セッションの動画を見ることができます!

いい機会なので、今回は SRE NEXT 2020 のセッションのなかから、個人的に動画を見ることをおすすめしたいものをご紹介します。これらの動画は3月中旬以降に一般公開される予定ですので、SRE NEXT に参加されていなかった方はひとまずプレゼン資料を読んでお待ちください 🙇

※2020-03-16追記
動画の一般公開が始まりましたので、この記事にも、セッション動画へのリンクを追加しました。

今回のおすすめの基準

有志の方がまとめてくださった 【SRE Next 2020】発表資料まとめ - Qiita から辿って、プレゼン資料を一通りすべて読みました。

そして、そのなかで自分が特に参考にしたいと思った(=僕の現状にマッチした)セッションの動画を 1.5 倍速で再生して見まくりました。今回は、その中で特に参考になったものをおすすめとしてご紹介します。ちなみに、全員見ていそうな基調講演やパネルディスカッションは除外しました。

今回ご紹介していないセッションについても、どれも濃い内容でしたので、一通りスライドを読んで、興味のあるキーワードを含むセッションの動画を見てみることをおすすめします。

※2020-03-16追記
SRE NEXT 公式サイトのタイムテーブルにも、各セッションのスライドと動画が表示されるようになりました。スライドを見るなら、いまはこちらから見たほうが楽です。神アプデ!

sre-next.dev

SRE 入門

[A7] サイト信頼性エンジニアリングの原則

ymotongpoo.hatenablog.com

SRE NEXT サイト内の紹介文

Google の山口さんによる講演。SRE が守るべき基本的なセオリーを1つずつ取り上げて解説されている講演で、SRE 入門としておすすめです。特にポストモーテムの重要性を詳しく解説しています。

スライドは公開されていないのですが、上記のブログ記事でその内容が詳しく紹介されています。

メルカリのマイクロサービスの事例

個人的に、メルカリのマイクロサービス化は先進的な事例として以前から注目しています。今回も非常に勉強になりました。

メルカリの SRE は、マイクロサービスの基盤を担当する Microservices Platform チームと、サービス開発者と協働する SRE チームに分かれているのですが、SRE NEXT 2020 ではそれぞれのチームの方による発表がありました。

[B7] SRE Practices in Mercari Microservices

SRE NEXT サイト内の紹介文

Microservices Platform チームのテックリードの deeeet さんによる講演。

Microservices Platform チームの活動でどういうことを工夫しているかを、SLI/SLO, On-call, Toil という3つの観点から紹介されていました。個人的にはこちらが今回のベストセッションでした!

以下は内容のメモです。

  • そもそもなぜメルカリがマイクロサービス化を進めているか
    • Successful Software Developmentの三角形
      • マイクロサービス化によって可能になることをシンプルな図で表しているもの
      • ArchitectureがOrganizationを可能にし、このArchitectureとOrganizationが、Processを可能にする
        • 実現したいのはProcess=Continuous delivery/deployment
      • マイクロサービスはその技術だけじゃなく、どういう組織を作るかということが重要
    • SRE と Platform Team の違いを KPI から説明
      • SRE は、SLI/SLO を KPI として追ってる
      • Platform Team は、deploy/developer/day など、開発効率の指標を KPI として追ってる
    • 2つの信頼性
      • Reliabilities for platform → 講演前半の話
      • Reliabilities for microservices → 講演後半の話
  • SLI/SLOを導入するにあたって重要だと考えている点
    • 適切なプロジェクトマネジメントが行われているかどうか。プロダクトバックログ、スプリント、といったフローに沿って開発しているかどうか
      • 好き勝手に各自が開発していたら、SLI/SLOは機能しない
    • プロダクトバックログの優先度を決める基準の一つとしてSLI/SLOが使われてこそ意味がある
  • SLI/SLO
    • SLO Document
    • ここで重要なのは Approver(s) と Revisit date
      • Approver(s): SLOを満たせなかったときに、実際に開発を止める判断をできる人
      • Revisit date: SLI/SLO を更新する日。定義した時点で Revisit dateを決めて、Google Calendarに登録してしまう
    • SLI specification と implementationを分けて書くのも良いプラクティス
      • エンジニアだと how を先に考えがちだが、what を先に考えるべき
    • このドキュメントを GitHub に置いて、GitHub のプルリクで更新
    • SLO Documentの具体例:Spinnaker(Platformチームが、社内のエンジニアに提供するサービス)
      • マイクロサービスのデプロイの基盤として使っている
      • Spinnaker に対する SLO を設定している
        • パイプラインの成功率、パイプラインの実行時間
    • SLI/SLO の revisit meeting
      • 社内の Slack に対するエゴサーチと、開発者に対する Google Form でのアンケート
      • SRE Workbook の SLO Decision Matrix に従って SLO を更新している
  • On-call
    • オンコールを誰がするかは、マイクロサービスによってどういう組織に作っていきたいかによる
    • メルカリでは、運用を含めたソフトウェアサイクルを自分たちで回せる、クロスファンクショナルなチームを作っていくこと。だからサービスチームがオンコール対応する
      • 100個くらいあるマイクロサービスを運用チームが見るのは現実的に不可能
    • k8s のネームスペースを、サービス用と、基盤用で分けている。そこを責任分界点にしている
    • アラートの設定基準
      • RED でアラート、USE で調査
      • Actionable Alert=Alert 1個につき、必ずPlaybookを1個用意する
        • コンポーネントのPlaybookもGitHubで管理している
  • Toil
    • 自分たちはあまりToilという単語を使っていなくて、外部要因で発生するタスクのことをReactive Taskと呼んでいる
      • Toilもその1つとして扱っている
      • サービスが成長し続ける限り、reactive taskはゼロにはならない、ということを念頭に置くのが大事
    • PlatformチームがReactive Tasksへの向き合い方をどう変化させてきたか?
  • マイクロサービスのreliabilityのために僕らが取り組んでいること
    • Platformチームがベストプラクティスを提供し、サービスチーム自身がソフトウェアサイクルを回せるようになってもらう(self-service)
    • 2つのベストプラクティス:Design Doc, Production Readiness Check
      • マイクロサービスの開発前にDesign Docを書いてもらう(テンプレートを提供している)
      • 本番運用のために、アプリケーションが満たすべきことをチェックリスト(Production Readiness Check)で確認
        • Production Readiness Checkは、GitHubのissue templateとして準備している
        • サービスチームはリリース前にissueを作り、それを自分たちでチェックして、そのレビューをSREなどに依頼できるようになっている

[C1] 絶え間なく変化するメルカリ・メルペイにおけるSREの組織と成長

SRE NEXT サイト内の紹介文

前半はメルカリの SRE チームの EM を担当されている渋谷さん、後半はメルペイの SRE の EM を担当されている高木さんによる講演。ちなみに、渋谷さんは SRE NEXT 2020 のコアスタッフとして Web サイトなどを担当してくれました。

前半の講演のなかで、SRE チームのこれまでの組織体制と、今年の1月に行われた SRE チームの編成のマイナーアップデートについてご紹介されていました。僕は前半の組織体制の話について、興味深く聞きました。

以下は前半の内容のメモです。

  • メルカリ・メルペイそれぞれのチーム体制
    • SREチームとMicroservices Platformチームの住み分け
    • SREもマイクロサービス化に貢献している→chocon(チョコン)というプロクシを開発
  • メルカリのマイクロサービス移行の進捗 (2019年冬) - Mercari Engineering Blog
  • いままではSREが本番環境を支えるいわば「門番」だった
    • 門番モデルではSREチームがボトルネックになるリスクがある
    • マイクロサービス化により開発チームのスケーラビリティが上がっていくのに追従していけるよう、SREチームの体制もアップデートしたいと考えた
  • 今月(2020年1月)から、SREチームの編成をマイナーアップデートした
    • SRE Core:DatastoreやMail/SMS deliveryなどの共通基盤を担う
    • SRE Edge:クライアントから直接リクエストを受ける部分に近いCDN、ロードバランサ、ゲートウェイなどを担う
    • SRE Advocacy:マイクロサービス開発チームの一員として、信頼性向上やオペレーションを担う

負荷テスト

[B2] 計画的に負荷リスクを排除するためのキャパシティプランニング

SRE NEXT サイト内の紹介文

タップル誕生の SRE の赤野さんによる講演。

負荷試験の実行環境を、バックエンドエンジニアなら誰でも作れるようにセルフサービス化しています。さらに、その負荷試験の結果を施策の導入可否にまで影響させているとのこと。ここまで実現しているのは本当にすごい!

以下は内容のメモです。

  • タップルSREが負荷的な観点でのセキュアベースになるための取り組み
  • 定期的に負荷試験を実施できる環境づくり
    • 負荷試験用のAWSアカウントを別に用意
      • できるだけ本番環境に影響が出ない、という安心感を得るため
      • LocustクラスタをFargateで稼働
      • バックエンドエンジニアなら誰でも負荷試験環境を構築できるようにスクリプトを整備
    • 限界値を把握するためのロードテスト、スパイクテスト
      • いくつかのテストの種類
      • ECSタスク数ごとのスパイク限界値を測定→予定されたスパイクアクセスに対応できるか確認したいため
      • 性能劣化をチェックするテスト→SREは実施前のテスト計画のレビューと、テスト結果のレビューのみしている
    • SREが決めたSLOはあったが、UXを考慮したSLOではなかった
    • レイテンシSLOを決めるにあたって、API遅延体感チェック会を実施
      • SLOを満たさない場合はリリースしないようにしたい、という目的でこの会を開催した
      • 「全体リクエストのレイテンシのp90が223ms以下で、1ヶ月のうち99%以上稼働」に決定
      • 現在もこのSLOで運用している
  • 施策開発フローに負荷レビューを組み込む
    • 施策のロードマップを立てた段階で、SREが、負荷の観点から実現可能かをチェック
    • すべての施策についてはレビューしきれないので、「DAU増加」か「カードのフリック数の増加」を狙いとした施策のみレビューしている
    • レビューに必要な情報はプランナーに提出してもらっている
    • PUSHについてはレビュー結果をもとに、ECSタスク数や、PUSHを分割する・しないを判断する

障害対応

[A3] freee のエンジニアは障害から何を学び、どう改善しているのか?

SRE NEXT サイト内の紹介文

freee の SRE 坂井さんによる講演。過去に発生した障害をきっかけに、障害対応フローをどのように整備したかを解説してくださいました。自分たちの障害対応フローを見直すうえで、とても参考になりそうです。

以下は内容のメモです。

  • 今日のゴール
    • 障害対応に課題を感じている人が、改善のための第一歩を踏み出そうと思えるようになること
  • freeeのプロダクトは、お金や人に関する情報を扱うものが多い
    • 会計freeeは電子決済等代行業に当たる
    • 2019年に上場し、以前にも増して、障害に対してよりシビアな対応が求められる
  • 障害をゼロにすることは難しい
    • 障害を受け入れながらも、安定したプロダクト、という相反するものを目指す
  • 自分が入社した頃(2016年)から、障害対応フローがどう変わってきたか
    • 徐々にポストモーテムを書くようになるが、フォーマットや情報の粒度、書く場所もバラバラ → 障害対応の学びが属人的
    • SOC1取得に向けた準備を始めた2018年に、準備の一環で障害対応フローが策定された(レベル1〜5の障害定義など)
    • 2018年10月(月末)に起きた障害で全サービス停止
    • 障害から得られた組織としての学び
      • 障害対応フローのブラッシュアップ(初動対応、役割、社内外コミュニケーション)
      • 障害対応エリアの設置(物理的に集まれるエリア「ブリッジ」)
      • 初動の省力化(チャットボットでのドキュメント検索、ポストモーテムの自動作成、関係者への通知の自動化)
  • 振り返りのためのいろいろな取り組み
    • freeeの開発文化「失敗して攻めよう」
    • 失敗.js
    • 割れ窓を改善し隊
    • alertを振り返り隊(今年から始めた新しい取り組みで、成果が出るかはこれから)
  • まとめ
    • 自分たちの組織やプロダクトに合った障害対応フローを作る
    • 大きな障害は学びの宝庫
    • 障害からの学びが属人的にならないように工夫する

SLI/SLO

[C4] SLO Review

SRE NEXT サイト内の紹介文

Quipper の SRE であり、SRE NEXT 2020 のコアスタッフでもあった chaspy さんの講演。

2019年に Quipper 社内で SLO をどうやって徐々に導入していったか、という事例紹介です。内容ももちろん勉強になるんですが、chaspy さんはとにかく話がうまくて、聞いてて面白いです。

以下は内容のメモ。

  • 最近受講した:Coursera の Site Reliability Engineering: Measuring and Managing Reliability コース
  • エラーバジェット導入に向けて、SLO導入をどういうステップを踏んで実現したか
    • エラーバジェット導入は今後の課題
  • reliabilityとagilityのバランスを取るためのツールがSLO
    • マイクロサービスに取り組むなら必須のツール
    • 依存先のサービスの信頼性を、依存元が超えることはできない
  • Quipperでのケーススタディ
    • いろいろなツールでメトリクスを取り、すべてをDataDogに送っている
      • Synthetics Clients:Pingdom
      • Frontend:Centry
      • Load Balancer:Nginx, envoy
      • Application:New Relic
    • 今年のSREチームの目標:Self-Contained
      • 開発チームが自分たち自身のみでプロダクト開発を完結できること、を目指している
      • そのための支援をSREチームがしていく
      • すでに提供している:Design Doc、Production Readiness Check、インフラ管理の移譲(Terraform)
      • その延長でSLI/SLOにも取り組んでいる
    • 2019年に行った取り組み
      • Define the Ownership
        • 多拠点に複数の開発チーム。各マイクロサービスに誰がオーナーシップを持つのかの定義から
        • Design Docでステークホルダーを明確化(Design DocはSREがレビューする)
        • オーナーを決める文化が根付いてきたので、この活動はおすすめ
      • SLO review by myself
        • まずは自分(chaspyさん自身)でやってみた
        • 誰でもできる方法
          • 週1でSlackにリマインダを飛ばして、その時点でのSLIをDataDog上で確認し、GitHub Issueに記録する
        • Availability Table、どれくらいの稼働率が良いのかの肌感を得た(99.9%くらいが良さそう)
        • SLO reviewや、ペアプロやユニットテストのような「良い習慣」なのではないかと気づいた
      • SLO review with Devs
        • 開発者からいろいろ要望が出てきて対応した
          • Dos detector(Rate limitting)がSLIのノイズになる
          • マイクロサービスで同じドメイン名を共有している(パスは違う)場合に、ログにパスを付与
      • Set Error Budget Policy
        • 今年の4月くらいからエラーバジェットを決めて、エグゼクティブと合意してやっていけたらと思ってる
  • SLO導入に向けておすすめするポイント
    • 最初のSLIはSREが設定したほうがいい。プロダクトに詳しいのは開発者だが、今取れる情報についてはSREのほうが詳しい
      • AvailabilityやLatencyなど、当然見ると思われるものを最初に設定しておけばよかったと反省している
    • SLI/SLOの設定もコードしたほうが良い(Terraform)
    • 少ない時間で成果を出すことを意識する
      • ドキュメントを最初から書いておけば楽だったと思う
      • 15チームにそれぞれ説明して、徐々に導入していった

開発者と SRE

[C6] Designing fault-tolerant microservices with SRE and circuit breaker centric architecture

SRE NEXT サイト内の紹介文

Cookpad の海外チームの SRE を担当している渡辺さんによる講演。

この講演での話題は、新しい技術スタック(機械学習関係)を採用した、試作的なプロダクトを導入するケースです。その試作的なプロダクトがメインのサービスに与える影響の範囲を限定しつつ、どうやって試作を行うチームの生産性を損なわないようにしたか、という事例紹介でした。

マイクロサービスの特徴がうまくマッチした事例として、こういうケースがあるのか!と参考になりました。

以下は内容のメモです。

  • Cookpad Global(Cookpad のグローバルサービス)
    • 23 backend developers
    • 5 SREs
  • Search-v2, ML APIs:新規機能、実験的な機能
    • これを入れていくときのアプローチについての講演
    • 特殊な状況での事例紹介
  • 独立性の高いチームと、既存のチームの間での衝突を少なくするために、circuit breaker、SLOを導入している
  • technology stackをcookpadでは制限している
    • しかし、新しい機能では、rails以外の言語を使う必要が出てきた
  • 24/7サポートには8人のエンジニアが欲しい。いろいろな本で8人と書かれている
  • 関係者の間での調整のためにdesign documentを書く
  • それにプラスアルファで、目的別の対策
  • Delegation and resource isolationも必要
    • AWSアカウントを分離して、VPC peering
    • 自分たちが使う技術の範囲は自分たちで運用する(SREが管理するのではなく、MLのdevelopersが管理する)
  • circuit breaker
    • Traefik
    • SLOに応じて設定。そのSLOはDesign Docで調整
  • 開発者がSLOを決めるのは難しい。だからSREがavailability classを提供している
    • availability classを定義し、それぞれのサービスの目標値を決める。それをcircuit breakerの設定に反映させる
  • PrometheusとAlertmanagerのコンフィグはJsonnetで書いている
    • よく使う設定はSREがライブラリ化してる
  • Search-v2についてはオンコール対応不要にした
    • 動かないときはSearch-v1にフォールバックするようにした
  • Bonus Track
    • オンコールローテーションルールは、そのチームのメンバーの好き好きによって決めるべきで、組織全体の統一ルールを作るべきではない
    • Cookpadのバックエンドエンジニアは世界中にいるので、1日を午前午後で分けて、営業時間内だけオンコール対応している
    • SREも日本とイギリスで分散しているので、同様にローテーションしている

[D4] 100万回線のIoT通信を支えるソラコムにおけるOpsDevの実践

SRE NEXT サイト内の紹介文

ソラコムの OpsDev エンジニア(DevOps エンジニアの誤記じゃないです)の酒井さんによる講演。開発者が全員で運用し、サポートまで行う現場の事例紹介でした。

以下は内容のメモです。

  • OpsDev Engineer≒SRE
  • 開発と運用の基本原則
    • 開発者:全員がDevOpsを実践。運用もする
    • OpsDevエンジニア(≒SRE):運用作業の傍ら、運用作業省力化のための開発をする
    • チーム全体で運用に責任を持つ
  • 運用しやすいシステムを作るための基本的な原則
    • Horizontal Scalability:小さいサーバを横に並べることでスケールアウトできる設計
    • Built-in Resilience:障害を前提とした設計、障害が起きたシステムを単独でプロセス再起動できる設計
  • サポートプライマリ制度:サポート・運用タスクについてはエンジニアが交代制で対応する
    • お客様と直接コミュニケーションすることで改善点に気づける、モチベーションが上がる、自身の問い合わせスキルが上がる
  • 一部のエンジニアは嫌がるのでは?トレードオフがあるのでは?
    • ソラコムのリーダーシップステートメントで、上記のような行動を推奨
      • リーダーシップステートメントに沿って行動することで評価も上がる
    • サポート・運用タスクのタスクコントロールを工夫
  • インシデント対応
    • なにか怪しいことがあったら #andon チャンネルで報告。間違った報告でも責めない
    • チャットボットで障害対応をサポート(障害報告書のひな型作成など)
    • ポストモーテム:2週間のイテレーションの最後に関係者全員で andon 振り返り

ちなみに、過去に SRE Lounge #8 で酒井さんの講演を聞いたことがあって、その時の内容を以下の記事にまとめています。SRE NEXT の講演に含まれていない内容もありますので、興味が湧いた方はこちらもどうぞ。

muziyoshiz.hatenablog.com

SRE NEXT 2020 にスタッフ参加しての感想(ロゴデザイン、CFP レビュー、司会などの裏話)

f:id:muziyoshiz:20200127000336p:plain:w640

SRE NEXT ご参加いただきありがとうございました!

sre-next.dev

1月25日(土)に、SRE に関する国内初の大規模テックカンファレンス、SRE NEXT 2020 が開催されました。私も、こちらのイベントにコアスタッフとして参加していました。参加者、登壇者、スポンサーおよびすべてのスタッフの皆様、本当にありがとうございました。お疲れさまでした!

発表内容は全然聞けていない(詳しくは後述)ので、内容についての感想はまだ書けません。しかし、「参加ブログを書くまでが SRE NEXT」と言われてしまったので、取り急ぎスタッフとしての感想を書いてみます。

スタッフ参加の経緯

元々 SRE Lounge のボランティアスタッフだったので、こういうイベントを開催したいというアイディアは北野さんや小熊さんから聞いていて、最初から参加させてもらってました。

本格的に動き出したのって、4月頃の飲み会でしたっけ?(うろ覚え)

この頃に、プロジェクト管理に Backlog を使うことを僕から提案して、SRE NEXT のための Backlog スペースを用意しました。最初に作られた課題(チケット)を見てみたら、作成日は2019年4月14日でした。

スタッフとして担当したこと

先に自分がやってないことから書くと、イベント全体のディレクションや、当日の設備周りなどは、他の優秀なメンバーに任せっきりにしてしまってました。

あとから考えると、僕は勉強会の運営側にまわったことがほとんどなくて、「SRE NEXT をどうしたい」というビジョンが全然無かったなぁと。SRE Lounge みたいな話がたくさん聞けるイベントがあったらいいなあ、くらいでしたね。

そのため、僕はサポート役として「面倒だけどやらないとまずい」系のタスクを色々拾ってました。

  • SRE NEXT の Backlog スペースのアカウント管理
  • ロゴデザインの発注
  • Tシャツデザイン、サイズ確認、発注、配布
  • ステッカー発注
  • CFP のレビュー(複数人でのレビュー会に参加)
  • Room A(メイン会場)の司会

ロゴ、ノベルティデザイン

デザイン関係については、いままで全くやったことがなかったので、四苦八苦しながら進めました。

新しくイベントを始めたい場合、僕と同じように困る人も多いと思うので、ロゴとノベルティに関する情報をまとめておきます。「SRE NEXT みたいにいい感じに作ってよ」 と言われた場合、以下の通りにすればなんとかなります。

ちなみに、以下の情報は全部 Backlog の課題に記録しておいた情報から引っ張ってきました。Backlog は素晴らしいサービスですね! なんと SRE も東京福岡京都で募集中みたいですよ!(SRE NEXT ツールスポンサー関係者による熱いダイレクトマーケティング)

ロゴ

EmbulkFolio のデザインの事例を見て、ここでよさそうということで発注先を 99designs に決定。

色々プランがあって悩んだのですが、ロゴコンペのブロンズプランを利用しました。「非公開コンペ」などのオプションは付けませんでした。

そして説明文を書いて発注。公開コンペなので、具体例はこちらから確認できます。

99designs.jp

優秀なデザインが集まるか不安だったのですが、最終的にはデザイナー15名から応募がありました。説明文は日本語で書いたのですが、デザイナーに日本人はいなかったようで、やり取りは結局すべて英語でした。

その多数のデザインから最終案まで少しずつ絞っていくのが大変で、もらったデザインの画像を Slack に貼り付けて、poll 機能で投票してもらう、という作業を何回も繰り返しました。

99designs 自体にもアンケート機能があるのですが、選択肢が最大8個までという制限があります。99designs では1人のデザイナーが、1個のデザインの複数のバリエーションを投稿してくるので、そのなかから大体の方向性を絞りたい、という段階では全然使えませんでした。最終選考のときだけは使えたかもしれませんけど……。

Tシャツ

Tシャツは、僕の方でロゴを加工して、いくつかデザイン案を作って、Slack の poll 機能で選考。デザイン決定後、僕が以前に使ったことのある FirstBall に発注しました。

デザインのベースは TR180/Trysail5.9oz Tシャツ。色はスタッフ用がサックスブルー、プレゼント用(登壇者、個人スポンサー)がブラック。スタッフ用は「スタッフが見つかりやすいように目立つ色」「SRE 本が青だからやっぱり青系でしょ」というコンセプトでした。

FirstBall では、印刷してから3ヶ月なら版の追加料金がかからないため、「試しに1枚刷る→問題なければ全員分刷る」というステップを取りました。実際、最初の試し刷りでは、実際に着てみるとロゴが大きすぎることに気づいたので、このステップを取ってよかったです……。

f:id:muziyoshiz:20200126232601j:plain
一歩間違えたらスタッフ全員に配布されていたクソデカロゴT

ステッカー

ステッカーって、扱ってくれる会社も多いし、選べるオプションも多くてホントに困りました。そのため、以下の基本方針を決めてから、いくつかのサイトを見て回りました。

  • ノートパソコンに貼ったときに剥がしやすい
  • 光沢のある感じよりは、マットな感じにしたい
  • 発注枚数は1000枚(参加者分だけなら500枚で足りるが、少し余分に作る)

この条件を満たすなかで、一番安かったのはデジタ でした。以下のオプションで発注すると、SRE NEXT ステッカーと同じ感じになります。

  • アート紙
  • 再剥離のり
  • マットラミネート
  • 四角形裁ち落とし
  • 5x5cm
  • 裏スリットなし
  • シートの形は40パス以内無料
  • 7営業日

Sのところでステッカーの外枠もカーブしてるのが素敵。こちら、スタッフの奥さん(デザイナーの方)のアイディアで、パスの調整までしてくれました。

f:id:muziyoshiz:20200126233252j:plain
Sのところでステッカーの外枠もカーブしてるのがチャームポイント

CFP のレビュー

スタッフの仕事の中で一番楽しかったのが、CFP のレビューでした。

SRE NEXT に来場した方はわかると思うのですが、実績があって、プレゼンも面白いエンジニアからの CFP が本当にたくさん届きました!

そういう優秀なエンジニアが書いた CFP の具体例にたくさん触れるのは勉強になりましたし、更にそれを自分と同様に SRE をしているメンバーと「ここがよい」「この点ではこちらがよい」と議論するのは楽しかったです。ここだけで、苦労の元が取れた気がしました。

反省点としては、自分にとっての面白さだけでセッションを投票してしまって、SRE NEXT 全体としてのバランスにはあまり配慮できなかったことでした。そのあたりは他のメンバーに助けられましたが、そういう意識が最初からあれば、もっとうまくできたのでは……と反省したところです。

Room A(メイン会場)の司会

いままで、小さな勉強会の司会くらいしか経験したことなかったので、それと同じくらいの気分で「Room A はメイン会場だから、最初から最後まで面白いセッションが聞けるだろう」と立候補しました。ただ、もう全然そんなことなかったですね。面白くなかった、という意味ではなくて、全然集中できなかった、という意味で……。

今回は参加者が400名を超え、メイン会場のキャパは Room A〜B を繋いで大部屋にした状態で300名。これが小さな勉強会と同じはずもなく、

  • セッション開始時以外にもたくさんある各種アナウンス
  • 音響スタッフとの、オープニング動画を流すタイミングの調整
  • 登壇者への段取りの説明
  • 質疑応答をする・しないのタイムスケジュール管理
  • インカムからの指示による臨時のアナウンス追加

などなどがあり、講演を聞いてる最中もまったく集中できませんでした(気づくのが遅い)。

途中で代わってもらえたら、もうちょっとイベント自体を楽しめたかもですね。前日に急遽決まったオペレーションも多かったので、司会業をうまくマニュアル化できず、複数人で分担できなかったというのが今回の反省点でした。1人で仕事を抱える SRE はダメな SRE……。

聞いていた方はどうだったんでしょうね。耳障りでなければよかったんですけど。とりあえず今日になって #srenext 司会 で検索して、特にネガティブなコメントはなかったので一安心してるところです。

f:id:muziyoshiz:20200126233556j:plain
基調講演に使われたメイン会場(photo by weekendcycler

SRE NEXT プロジェクト全体を通しての感想

大変でしたけど、大規模なテックカンファレンスの裏側を体験することができて面白かったです。また、自分の興味がある技術分野で、同じ分野にいる同業者と知り合いになれて、普段会わない人(特に自分より若い人)の考えを聞く機会がたくさん得られました。

SRE NEXT 2021 が開催されるかはまだわかりませんが、SRE として働いていて(あるいはまだ働いていないけど興味があって)、この分野の技術コミュニティに参加したいという方には、スタッフとして参加することをお勧めしたいと思います。もし SRE Lounge に参加したことがなければ、まずはこちらに参加してみてください。SRE Lounge の Slack ワークスペース に入ってもらえたら、次回の開催情報もそのうち流れると思います。

さて、これからしばらくは全講演のスライドを見て、感想ブログを読み漁る生活だ……。

2019 年に SRE をしながら考えが変わったこと

f:id:muziyoshiz:20191230205919p:plain

今回の記事は年末スペシャルです。

僕が SRE をしながらやってきた取り組みについては、今年も会社のテックブログに色々書かせてもらいました(職場の理解のおかげです。いつも感謝してます)。

ただ、それぞれのブログ記事の間を埋めるストーリーというか、その背景にあることについてはなかなか書く機会がありませんでした。なので、今回はそれらの記事を引っ張りながら、今年 SRE をしながら考えていたことをつらつらと書いていこうと思います。

この1年で考えが大きく変わったこと

SRE のあるべき組織体制について、1年前はこう考えていました。

  • 複数の開発チームをまたぐ形で SRE をマトリックス的に配置して、SRE はアプリの開発状況を細かく把握しながら監視・運用すべき

ただ、この1年で考えが変わり、いまはこう考えています。

  • SRE をマトリックス的に配置するのは、確かに、開発速度を一時的に上げるのには効果的
  • ただ、そんなスキルがある SRE をたくさん集めるのは難しいし、集められたとしてもそんな働き方をさせたらすぐ疲弊して退職しかねない
  • 持続性を優先するなら、アプリの監視・運用の責任は開発チームが持ち、SRE はそれを支えるシステム作りに労力を割くべき

こう書くと、なんか、結局当たり前の結論に帰ってきてしまった感じがしますね……。SRE って元々そういうものだろ、と言われそうな気もします。ただまあ、どういう過程を経てそういう考えに落ち着いたのかを振り返ってみます。

1年前(2018年末)に考えていたこと

去年の年末の時点で、僕個人はこういう状況でした。

  • SRE は複数の開発チームをまたぐ形でマトリックス的に配置されていた
  • 僕個人は、Play 化プロジェクトに関わる開発チームに参加して、監視・運用全般を担当していた

2018年前半から、「SRE をマトリックス的に配置したほうがうまくいくだろう」という議論があり、それまで1つの SRE チームだったものを複数の開発チームにまたがる形にしました。Dev と Ops が分離してしまっていた当時の状況では、それが最適なチーム構成だろう、と僕も強く同意していました。

f:id:muziyoshiz:20191230210236p:plain
SRE Lounge #5 の発表資料からの引用

このあたりの話に興味のある方は、SRE チームの黎明期を知るメンバに繰り返しインタビューして書いた発表資料やブログ記事がありますので、そちらをぜひどうぞ。

muziyoshiz.hatenablog.com

nulab.com

で、この人員配置の中で、僕は2018年4月から今年の7月まで「Play 化プロジェクト」というリプレイスプロジェクトに参加してました。もちろん、SRE 同士の横の連携はありましたが、このプロジェクトの状況を熟知して動いていた SRE は1人だけという状況でした。

backlog.com

開発チームに SRE が入り、インフラとアプリの両方に目配せすることで、いろいろな問題を未然に防げたという手応えはありました。その一方で、このプロジェクトで SRE として1人頑張り続けることのつらさも強く感じていました。2018年末はそんな状況でした。

2019 年に考えていたこととやったこと

そこから1年経って、2019年末(現時点)の状況はこう変わりました。

  • SRE は開発チームから出て SRE チームに所属する。SRE チームは開発チームを支援するかたわら、SRE 主導での改善プロジェクトも進める
  • アプリの監視は、開発チームに徐々に移行しつつある
  • 僕個人は、改善プロジェクトの1つを進めている(※この内容も、いずれテックブログに書きます)

SRE と開発チームの分離は、2019年の年始に、SRE が改善活動を主導できる体制作りを目的に行われました。実は、僕は当初この分離には反対していました。

しかし、リプレイスプロジェクトでの経験を経て、SRE を特定の開発チームに割り当てるのは、短期的には有効だけど、長期的には持続可能じゃないという考えに変わりました。

考えが変わった理由の第一は、開発速度が早い開発チームに SRE として張り付け続けるつらさを実体験したからです。リリースが少ない安定したサービスならともなく、リリースが日々活発に行われるサービスでは、張り付けられた SRE の負荷が大きすぎる。これでは SRE はすぐ疲弊して、退職されてしまうだろうと……。どれくらい大変かの具体的な話は、リプレイスプロジェクトが終わったときのブログ記事に書いたので、よかったらこちらをどうぞ。

backlog.com

考えが変わったもう一つの理由は、SRE Lounge などの勉強会で、いろいろな他社事例に触れたことです。特にメルカリの Microservices Platform Team の事例では、開発チームへの監視・運用の移行がここまで現実に可能なのかと驚かされました。例えば、いろいろな勉強会で触れられている microservices-starter-kit について以下のイベントで初めて知り、懇親会でメルカリのエンジニアに詳しい話を聞いて感銘を受けました。

muziyoshiz.hatenablog.com

それまでは、マイクロサービスは自分の現場に合うのかどうかがずっと疑問でしたが、「SRE とアプリ開発者の責任分界点を明確にするため」という目的さえブレなければ、マイクロサービス化を推し進めていいのではないかと考え始めました。

メルカリの事例に強く影響を受けて、その後、自分の現場でも、アプリ開発者に監視業務を移行するためのアラート通知システムを整備しました。マイクロサービス化まではまだ進んでいませんが、責任分界点を明確にするためには、これからマイクロサービス化を段階的に進めていく必要があると思っています。

f:id:muziyoshiz:20191230210434p:plain:w600
開発チームを巻き込んだ監視システムの全体像(下記ブログから引用)

backlog.com

ちなみに、開発チームに1年以上いたおかげで、アプリ監視の業務設計ができて、結果的にこのアラート通知システムも作れました。その点は、1年以上悪戦苦闘したのも無駄な努力ではなかったのかな、と。

来年1発目のイベントは SRE NEXT

上記でメルカリの事例について軽く触れましたが、SRE の業務について考えるにあたって、他社の事例を聞くのはとても参考になると実感した1年でもありました。

僕は去年から SRE Lounge というコミュニティのスタッフとして参加しているのですが、同じコミュニティ主催の大規模イベント SRE NEXT がとうとう来年1/25(土)に開催されます。いまのところ、僕は Room A の司会としてスタッフ参加している予定です。

すでにチケットは売り切れてしまっています(すみません!)が、発表スライドは後ほどいろいろな登壇者が公開してくれると思います。僕もイベント当日は見てる余裕がなさそうなので、あとから発表スライドやレポートブログなどをゆっくり読ませてもらうつもりです。

来年末も、今とはまたいろいろ考えが変わってるのかなあ。どうなんだろう……。