Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

AWS のコスト管理をちゃんとしたくてやったこと

437 views

Published on

2019年2月16日(土) 第85回Ruby関西勉強会 発表資料

Published in: Technology
  • Be the first to comment

  • Be the first to like this

AWS のコスト管理をちゃんとしたくてやったこと

  1. 1. AWSコスト管理をちゃんとしたくて やったこと 2019/02/16 @cuzic
  2. 2. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 1自己紹介 Tomoya Kawanishi a.k.a cuzic ENECHANGE株式会社 チーフエンジニア エンジニア、積極採用してます! Ruby関西の中のひと みなさん、登壇お願いします! Otemachi.rb の中のひと 2月20日(水) Otemachi.rb #14 を開催します 各線東京駅・大手町駅・日本橋駅・三越前駅至近
  3. 3. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 事業部制を採用する ENECHANGE 2 低圧事業部 一般のご家庭、小規模の事業所など向けの電気の比較・切替サービス 高圧事業部 ビル、工場など向けの電気の切替サービス プラットフォーム事業部 電力会社向けに、顧客獲得プラットフォームを提供 SIM事業部 格安SIM の比較・切替サービス ・ 事業部単位に、大幅に権限を委譲し、個々の事業部で独立採算で収益管理する ・ 意思決定の迅速化、意思疎通の円滑化、意欲の向上などの効果が期待できる 一般的な事業部制の特徴、メリット 費用と事業部との関連付けが必要 多くの事業を展開する ENECHANGE
  4. 4. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 エンジニア費用を例にした原価計算の例 3 ・ 開発エンジニアは各事業部に所属 ・ 工数管理の上、エンジニア費用を計上 エネチェンジ の事業部制 低圧(家庭・商店) 高圧(ビル・工場) プラットフォーム Simchange (例) エンジニア 費用の原価 プロフィットセンター コストセンター コーポレート(人事、経理ほか) インフラエンジニアは、コーポレート に所属。 ・ プロジェクトに紐づいた活動は 直接原価として各事業部で計上 共通費として計上 全社共通費として各事業部に配賦 では、 AWS費用はどう扱うか? 事業部別の原価計算の例
  5. 5. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 事業部別コスト管理の定石 4 事業部 低圧(家庭・商店) 高圧(ビル・工場) プラットフォーム Simchange AWSアカウント 低圧用アカウント 高圧用アカウント プラットフォーム用アカウント Simchange 用アカウント コーポレート 全社共通アカウント AWS ではアカウントを分割しても、請求・支払いは親アカウントへの一元化が可能。 メリット: 事業部別に明確にコストを把握できる デメリット: 事業部をまたぐような作業をするとき、運用上の手間がかかる ※ 運用面のデメリットは、AWS Organization などの機能を使うことで緩和可能 事業部別コスト管理の定石は AWS アカウントの分割 アカウント分割の概要・メリット・デメリット
  6. 6. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 ENECHANGE では単一AWSアカウントで管理 5 ENECHANGEは、単一の AWSアカウントを全社で使用 事業部 低圧(家庭・商店) 高圧(ビル・工場) プラットフォーム Simchange AWSアカウント コーポレート 全社共通 アカウント ・ 当初は、事業部の数は多くなく、分ける必然性が大きくなかった。 ・ 創業当初は事業部制ではなく、職能別組織だった。 ・ その当時は、Organization がなく、運用上の手間・煩雑さが無視できないと感じた ・ あとからアカウントを分割することは可能ではあるが、作業負荷も大きく現実には困難。 単一アカウントとした理由
  7. 7. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 用語の整理と、目標 6 できる限り多くのリソース費用を 直課 させる! 直課 該当のリソースのコストを直接その事業部に関連付けて集計 すること 配賦 一定の配賦基準に基づいて、該当のリソースの費用を各事 業部に紐づけること エネチェンジでの AWS 費用の配賦の際は、直課した費用の比率で配賦率を決定 ほかの主要なコスト配賦基準としては ・ 所属人員の頭割り ・ 各事業部の売上の比率 などで決定する方法があります。 目標
  8. 8. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 コスト配分タグを利用したコスト把握 7 コスト 配分タグ リソース(EC2、EBS、AMI、ELB、RDS など)に付与された どの事業部(プロジェクト)の費用かを識別するためのタグ AWS費用の多くはコスト配分タグで事業部に直課可能 ・ Reserved Instance ・ Data Transfer ・ サポート費用 ⇒ 直課できない費用は、各事業部に配賦して事業部ごとの AWSコストを計算 コスト配分タグで、分類できない費用の例 ・ 割引(AWS Activate プログラム)など ・ 消費税 ・ コスト配分タグがついていないリソース コスト配分タグを付与する仕組みを構築し、 タグのないリソースを極力減らす
  9. 9. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 エネチェンジのコスト配分タグの付与の仕組み 8 EC2 EBS スナップ ショット AMI ENI EIP EC2 手動で、1個ずつタグを付与。 ASG なども適切にタグ付けされるように設定 EBS、AMI など EC2 と同じタグを自動付与するスクリプトを作成。 定期的に EC2 の状態と同期させる ・ AutoScalingGroup などのリソースを 再生成したときは、タグの再設定も必要 ・ DataPipeline で定期実行。 定期実行する理由・方法 ・ EC2 を起点に各リソースの関係を、 ツリー構造と見立て、トポロジカルソート ・ このツリー構造を元にタグ情報を伝搬 内部動作の解説 タグ付けスクリプトを定期実行し、省力化
  10. 10. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 トポロジカルソートとは グラフ理論でのアルゴリズムの1つ。 依存関係を順に処理したいときとかに使える Ruby には標準ライブラリの tsort がある 9 トポロジカルソート(英: topological sort)とは、グラフ理論に おいて、有向非巡回グラフ(英: directed acyclic graph, DAG)の各ノードを順序付けして、どのノードもその出力辺の 先のノードより前にくるように並べることである。 Wikipedia での説明
  11. 11. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 トポロジカルソートの利用例 Set#divide Rubygems Bundler Ruby on Rails ( Rails::Railtie ) initializer の before、after などの 順序を正しく処理するために使われている Rukawa @joker1007 さん作の Ruby 製ワークフローエンジン 10 require 'set' numbers = Set[1, 3, 4, 6, 9, 10, 11] set = numbers.divide { |i,j| (i - j).abs == 1 } p set # => #<Set: {#<Set: {1}>, # #<Set: {11, 9, 10}>, # #<Set: {3, 4}>, # #<Set: {6}>}> Set#divide の使用例
  12. 12. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 処理内容 ①: aws describe-instances コマンドで、 ・EC2 と EBS と ENI の関係を取得 ・EC2 に付与されたタグをすべて取得 ②: aws describe-snapshots コマンドで、 EBS と スナップショット ID の関係を取得 ③: aws describe-images コマンドで、 AMI と スナップショットID の関係を取得 ④: ①~③の結果生成されたグラフ構造を元に、 関連する EC2 に付与されたタグを EBS、ENI、スナッ プショット、AMI にも同様に付与する 11
  13. 13. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 tsort の使い方 (1/3) tsort_each_node:グラフの各ノードを巡回するメソッド tsort_each_child:引数のノードの子ノードを順次処理するメ ソッド 12 class AwsTSort include TSort def tsort_each_node @edges.each_key do |key| yield key end end def tsort_each_child(node) @edges.fetch(node, []).each do |child| yield child end end … end TSort の使用例(定義)
  14. 14. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 tsortの使い方(2/3) 今回は Hash でグラフ構造を表現 tsort 自体は任意のオブジェクトを使えるが Hash が便利 Tree に見立てると、key が親、value が子の関係。 13 @edges = Hash.new{|h, key| h[key] = []} each_tag_ebs_eni do |instance_id, tags, ebs, eni| @edges[instance_id].push *ebs @edges[instance_id].push *eni … end each_ebs_snapshot do |volume_id, snapshot_id| @edges[volume_id].push snapshot_id end each_snapshot_ami do |snapshot_id, ami_id| @edges[snapshot_id].push ami_id end TSort の使用例(グラフ構造の構築)
  15. 15. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 tsort の使い方 (3/3) each_strongly_connected_component_from で、 強連結結合のノードを順に取得できる 今回の例だと、あるインスタンスを親とする子孫全部を 取り出すということができる。 14 def resources_from(start) [].tap do |resources| each_strongly_connected_component_from(start) do |nodes| resources.push *nodes # nodes は Array end resources.delete(start) end end TSort の使用例(強連結結合の取得)
  16. 16. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 15リソースへのタグ付成功! さまざまなリソースにタグ付けすることができた! だ、け、ど、 実行してみたところ、わりと時間がかかった 5分くらい もっと速くしたい! aws コマンドの実行に時間を要しているのは明らか aws コマンドを並列実行するともっと速くできる!
  17. 17. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 処理内容 遅いのは、AWS リソースの情報取得のところと、 タグ付のところ 特に、タグ付のところが遅かった 16 グラフ構造の構築 トポロジカルソート AWS リソースのタグ付 AWS リソース一覧の取得 (AWS コマンドの発行) AWS コマンドを 4回発行 describe-instances describe-network-interfaces describe-images describe-snapshots AWS コマンドを リソースの数、 タグの数に応じて、繰り返し実行
  18. 18. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 リソース一覧の取得(メインスレッド側) Threadを使った内部実装は意識させない設計 引数: aws コマンドの引数 ブロック引数: aws コマンドの実行結果(標準出力)の各行 Thread#join を各スレッドで実行。情報取得終了を待つ 17 def each_ebs_snapshot query = "Snapshots[].[VolumeId, SnapshotId]" aws_lookup(%(ec2 describe-snapshots --query "#{query}")) do |line| volume_id, snapshot_id = line.chomp.split("¥t") yield volume_id, snapshot_id end end ワーカスレッドで 実行される def join_lookup_threads @lookup_threads.each &:join end 呼び出すとき 各スレッドの終了を待つとき @lookup_threads は ワーカスレッドの配列
  19. 19. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 リソース一覧の取得(ワーカスレッド側) スレッド内では Thread.new の引数だけを使用 そのスレッド内でのローカルコピーが作られる 他のスレッドでの更新が原因での不具合とかが起きない aws コマンドを実行し、出力結果を1行ごとに ブロック引数として呼び出し元に渡す 1つのコマンドを1つのスレッドで実行 あとで待ち合わせするため Thread を配列に保持 18 def aws_lookup(command) @lookup_threads << Thread.new(command) do |cmd| cmdline = "aws #{cmd} --output text" IO.popen(cmdline, "r+") do |io| io.each_line do |line| yield line end end end end Thread 中で使う command を引数と している
  20. 20. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 タグ付(メインスレッド側) タグ付けでは、異なるリソースを対象に繰り返し AWS コマンドを発行する ワーカスレッドで、AWSコマンドを並行実行する スレッド間通信には Queue を使用する Ruby 2.3以降は組み込みライブラリ Queue#enq を利用 出力結果は使用しない AWSコマンドの成功/失敗も気にしない(Fire and Forget) 複数リソースに対するタグ付けを1回で処理 shellwords ライブラリの Array#shelljoin メソッドを使用 19 def create_tags(resources, tags) return if tags.empty? args = ["--resources", resources.shelljoin, "--tags", tags.shelljoin] @aws_queue.enq %(ec2 create-tags #{args.shelljoin}) end
  21. 21. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 AWS リソースのタグ付(ワーカスレッド側) Queue#deq で、キューからオブジェクトを取り出せる while command = queue.deq は Thread 処理でよく使うイデ ィオム nil 以外の場合、ループの中の処理を行う nil を受け取るとループから抜ける 20 def start_aws_thread Thread.start do |t| while command = @aws_queue.deq cmdline = "aws #{command}" system cmdline end end end end nil 以外の場合はループの中を実行 nil のときは、ループを抜ける
  22. 22. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 タグ付(メインスレッド側) 開始と終了 ワーカスレッドを開始すると、配列に保持する ワーカスレッドを終了するため、nil を Queue に渡す それぞれの Thread が終了するのを join で待つ 21 # ワーカスレッドの開始 def start_tagging_threads @thread_num.times do @tagging_threads << start_aws_thread end end # ワーカスレッドの終了 def join_tagging_threads @thread_num.times do @aws_queue.enq nil end @tagging_threads.each &:join end スタートしたスレッドを配列に保持 ワーカスレッドの数だけ nil をキューに送信 ワーカスレッドの終了を join で待つ
  23. 23. 第85回Ruby関西勉強会 発表資料 「AWSコスト管理をちゃんとしたくてやったこと」 22まとめ 事業部制はメリットが多い 調整コストの低下、意思決定の迅速化 AWS を事業ごとに管理するのは大変 まずはリソースと事業部を紐づける(直課する)ところから 紐づけを1つずつするのは大変 tsort を使って、連鎖的にタグを自動的に設定する thread を使ってタグ付け作業を高速化
  24. 24. 23 ご清聴ありがとう ございました

×