AWSのAuto Scalingグループの概要について(概念に関する用語とスケーリングポリシーの種類)
今週はAuto Scalingグループの概要について調べました。
Auto Scalingグループ
EC2 AutoScaling と Auto Scalingグループ はなんのためにあるのか
EC2のインスタンスは起動時間に対して料金が請求される従量制の課金形式となっています。 なので、1日の負荷のピークなど必要なときは多くの台数に、必要ないときは少ない台数にしておけるといいですよね。
CloudWatchからのアラートや事前のスケジュール設定をもとにEC2の台数を増減してくれるのがEC2 AutoScalingです*1。
EC2 AutoScaling
はプログラムにより自動的にEC2のインスタンスを立ち上げるので、
- 起動したい数、最小数、最大数
- どういったインスタンスを起動するのか
- どういった条件で台数を増減するのか
といった設定が必要になります。Auto Scaling グループはそれらの設定と台数を増減させるEC2インスタンスの集合を管理する単位です。
利用するために必要なものやその呼び方
上の説明の段階でもふれたのですが、Auto Scalingグループは基本的に負荷に応じたEC2の台数増減をプログラムにやってもらおうという趣旨のものなので
- 起動したい数、最小数、最大数
- どういったインスタンスを起動するのか
- どういった条件で台数を増減するのか
を事前に「Auto Scalingグループ」のインスタンスに設定しておく必要があります。
「起動したい数、最小数、最大数」はAuto Scalingグループを作成する際、「EC2インスタンスの希望する数(desired count), 最小数, 最大数」としてAuto Scalingグループ自身の属性として設定します。
「どういったインスタンスを起動するのか」については、
- AMI ID
- インスタンスタイプ
など自分たちがEC2インスタンスを手動で起動する際にも必要となるパラメータをまとめた「起動テンプレート」*2を作成し、どの起動テンプレートを利用するかをAuto Scalingグループの属性として指定します。
「どういった条件で台数を増減するのか」については、条件の種別に応じて設定する項目が異なります。
増減を行わず一定の台数を維持したい場合*3は、「EC2インスタンスの希望する数(desired count), 最小数, 最大数」の設定で可能です。
午後7時にテレビで紹介されるから暖機を含めて午後6時半から起動したい、といった事前にスケーリングしたいタイミングがわかっている場合は、Auto Scalingグループに対して Scheduled Action(スケジュールされたアクション)
を作成することで対応できます*4。
その時々のグループ内のEC2インスタンスの状態によって台数を追加したり減らしたい場合は、 スケーリングポリシーという単位で設定し、これをAuto Scalingグループのインスタンスに追加します。
スケーリングポリシーは、スケールイン用とスケールアウト用に別個に作成する必要があります。
EC2 Auto Scalingのスケーリングポリシーには
- Target tracking scaling
- Step scaling
- Simple scaling
の3種類があります*5。少しスケーリングポリシーの概要についてもふれておきましょう。
EC2 Auto Scalingのスケーリングポリシー
3種類のスケーリングポリシーの中で一番古くからあるのは、Simple Scalingです。Step Scalingが次に出て来ました。 この二つの違いですが、
- Simple Scalingはアラートをうけてスケーリング中に追加のアラートを受け取ることができませんが、
- Step Scalingは追加のアラートを受け取ることができます*6
また、この二つのポリシーではスケーリングの値のために監視しているメトリクスの値によって、一度に増やす台数を調整するためのステップ調整値*7があります。
- Simple Scalingはステップ調整値として1つの値しかスケーリングポリシーに設定できませんが
- Step Scalingは複数のステップ調整値をスケーリングポリシーに設定できます
これがどういうことかというと、ステップ調整値は、スケーリングの際にいまの台数から何台調整するかというのを調整値とすると、調整値を適用する範囲と適用する調整値そのものの組からなります。
ステップ調整値が一つしかないSimple Scalingの場合、一つのステップ調整値でアラートが来る全部の範囲を賄う必要があるので
- アラートが来たら常にN台増やして/減らして
- CPU利用率が51%のときも99%のときも10台ずつ増やして、的な
となってしまうのですが、Step Scalingの場合、
- メトリクス値が50以上60より小さいとき 下限: 0, 上限: 10, 調整: 0
- メトリクス値が60以上70より小さいとき 下限: 10, 上限: 20, 調整: 10
- メトリクス値が70以上のとき 下限: 20, 上限: null, 調整: 30
のように複数ステップ調整値が設定できて、たとえばこのように設定した場合、
- アラートが来ているといっても、メトリクスが60より小さいときはまだ見守るだけでdesired countを増やしたりしない
- メトリクスが60になった場合、現在の台数より10%追加(PercentChangeInCapacity の場合 *8 )
- さらにメトリクスが70にまでなった場合、11台の30%(PercentChangeInCapacity の場合)、3台を追加
といった具合に、メトリクスの値による増減台数の調整が可能となります。また、 PercentChangeInCapacity
という単語が出て来ましたが、増減させる時の台数をどうやって計算するか(今の台数基準/絶対値など)の方法を スケーリング調整タイプ
という項目で設定します。
さて、最後に出てきたスケーリングポリシーが、Target tracking scalingです。
Target tracking scalingの場合は、メトリクス値がいくつのときに何台増やすか、ではなく、ターゲット値として指定したメトリクスが指定された値になるように自動的にスケーリング調整値を計算する、といったもので、ステップ調整値の設定が簡素化できるようです*9。
現場からは以上です。
*1:他のサービスでもAutoScalingを利用できるんですが、細かく差異を調べている余裕はなかったのでドキュメント読んだEC2 AutoScalingに限って話を進めます
*2:https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/create-asg-launch-template.html
*3:正確に言うとスケーリングではないですが、Amazon Auto Scalingはこの目的でも利用できます。インスタンスの集合の中に不具合が生じたインスタンスを自動的に入れ替えるなどの使い方で「オートヒーリング」と呼ばれるそうです。 https://www.nttdocomo.co.jp/corporate/technology/rd/tech/nfv/nfv01/05/03.html
*4:https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/schedule_time.html
*5:https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/as-scale-based-on-demand.html
*6:https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/as-scaling-simple-step.html
*7:公式ドキュメントによるとスケジューリング調整値ともいうみたい https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/as-scale-based-on-demand.html
*8:https://docs.aws.amazon.com/ja_jp/autoscaling/application/userguide/application-auto-scaling-step-scaling-policies.html
*9:https://docs.aws.amazon.com/ja_jp/autoscaling/application/userguide/application-auto-scaling-target-tracking.html https://aws.amazon.com/jp/about-aws/whats-new/2017/07/introducing-target-tracking-scaling-policies-for-auto-scaling/
いままでのECSの起動モード(EC2起動モード)のネットワーク設定(bridge ネットワークモード)とFargate起動モードを利用した場合のネットワーク設定関連で嬉しいことについて
2017年11月14日にAWSがAmazon ECSのTask Networkingを発表*1し、その恩恵を受ける Fargate 起動タイプが2018年7月4日に東京リージョンでサービス開始となりました*2。
自分の職場でも一部サービスでFargate(with awsvpcモード)の採用が始まったのをレビューで見たのはいいものの、いままでのECSのネットワークモードとの違いがよくわからず、最初のPRについては「俺を信じるお前を信じろ」になってしまったため、ドキュメント見て少し調べたメモです。
目次
- いままでのECSの起動モード(
EC2
)のネットワーク設定(bridge ネットワークモード)について- ECSが利用しているEC2のネットワーク設定
- Dockerのデフォルトの
bridge
ネットワークモードをECSで利用する場合にタスクのネットワークに関して起きること - ECSでEC2起動モードで利用するDockerのデフォルトの
bridge
ネットワークモードを利用することで起きる制限
- Fargate起動モードで利用する
awsvpc
ネットワークモードについてawsvpc
ネットワークモードでは、ecs-agent
が利用するCNIプラグインを利用してタスクにENIをアタッチするawsvpc
ネットワークモードの利用で嬉しいこと- ECSで
awsvpc
ネットワークモードを利用する場合の制限の話
- 参考
いままでのECSの起動モード( EC2
)のネットワーク設定(bridge ネットワークモード)について
実は、 Fargate
起動モードや awsvpc
ネットワークモード以前に、既存の EC2
起動モードや EC2
起動モードの際に前提とされてる気がするDockerのデフォルトの bridge
ネットワークモードについてよく知らなかったのでそこから確認しました。
ECSが利用しているEC2のネットワーク設定
ECSのコンテナインスタンスはかなり大雑把にいうと ecs-agent
が動作し、ECSに登録されたEC2インスタンス*3のことを指しますが、ECSのネットワークに関係する設定はEC2のネットワーク設定の方法に依存しています。
なので、最初にEC2のネットワーク周りのことをおさらいしました。
EC2を起動するには、AWS ドキュメント » Amazon Elastic File System (EFS) » ユーザーガイド » Amazon Elastic File System の開始方法 » ステップ 1: EC2 リソースを作成し EC2 インスタンスを起動するに記載されている通りVPCの利用が前提となっています。
そのVPC内のEC2インスタンスは自分たちでsshした後にコマンドを叩かなくても、VPCのルーティングテーブルに設定が登録されており、VPC内の他のインスタンス + 外部エンドポイントにアクセス可能なわけですが、これを実現しているのがENI(Elastic Network Interface)と呼ばれるVPC内の仮想的なネットワーク・インタフェースとなっています。
ENIはすべてのEC2インスタンスに1つ以上アサインされ、EC2インスタンスの起動時に自動的にアサインされる1つのENIを プライマリネットワークインタフェース
と呼びます。
EC2インスタンスのネットワーク設定にあたる各種属性( IPアドレスやセキュリティグループなど
)は、実際はEC2インスタンスにアサインされているENIに設定される属性です。
Dockerのデフォルトの bridge
ネットワークモードをECSで利用する場合にタスクのネットワークに関して起きること
ECSではいままでDocker側で用意されている3種類のネットワークモード*4が利用できました。
https://aws.amazon.com/jp/blogs/news/introducing-cloud-native-networking-for-ecs-containers/ では、そのうち、bridgeモードについて説明されていたので、この記事でもそれに沿って考えることにします。
ECSでは、同じタスク定義のコンテナ一式は同じコンテナインスタンスの中で動作し、さらに1つのコンテナインスタンスの中で複数のタスクが動くことがあります*5。
このとき、ECSのコンテナとして動くコンテナの間で利用するネットワークインタフェースは共通( docker0
のブリッジが接続されているインタフェース)なので、コンテナたちはすべて同じネットワークインタフェースを経由して通信を行い*6、ENIとそれに伴うネットワーク設定も共有します。
また、コンテナ同士で外部からアクセスされる際に経由するネットワークインタフェースを共有するので、外部から来た通信をそれぞれのコンテナに接続する際に同じ定義のタスクでも違うポート番号を割り振らなければいけないことに関するややこしさがありました。
ECSでEC2起動モードで利用するDockerのデフォルトの bridge
ネットワークモードを利用することで起きる制限
前節で述べたことをもとに考えると、これまでのECSのネットワーク設定では
同じコンテナインスタンス上のコンテナはすべて同じENI(の裏のネットワークインタフェース)を経由する前提なので
- 比較的ネットワークリソースの干渉が起きやすく、複数のコンテナが1つのホストに配置された場合、ネットワークが詰まってパフォーマンスが出ない場合もありそう
- また、同じ定義のタスクが同じコンテナインスタンスで動く際のネットワーク設定がややこしかった
同じホスト上のコンテナはすべて同じENI(に紐づいたネットワーク設定)を利用する前提なので
- セキュリティに気を使うコンテナとそうでないコンテナの設定が一緒くたになってしまう
といった問題が発生していたみたいです。
Fargate起動モードで利用する awsvpc
ネットワークモードについて
EC2起動モードの際に利用するネットワークモードについて確認したところで新しい awsvpc
ネットワークモードについて確認します。
awsvpc
ネットワークモードでは、 ecs-agent
が利用するCNIプラグインを利用してタスクにENIをアタッチする
ネットワークの名前空間には名前空間ごとにルーティングテーブルが用意できるだけでなく、ネットワークデバイスを追加することも可能*9ですが、 awsvpc
ネットワークモードでは、タスクごとにネットワークの名前空間を作成し、ECSのコンテナインスタンス上にある、ホストマシンのプライマリネットワークインタフェース以外のENIをそのタスク用の名前空間に追加します*10。
つまり、 awsvpc
ネットワークモードではタスクごとに専用のネットワークインタフェース(ENI)が用意されます。
一方、bridge
ネットワークモードの時は、ECSのコンテナインスタンス上にあるホストマシンのプライマリネットワークインタフェースにあたるネットワークデバイスしか利用してなかった*11、つまり、同じホストで動くコンテナ全体で1つのENI*12しか用意されていませんでした。
awsvpc
ネットワークモードの利用で嬉しいこと
タスクごとに専用のENIを用意すると何が嬉しいのでしょうか。
ENIにネットワーク設定がアサインされているので、タスクごとにネットワーク設定ができるようになり、1つのコンテナインスタンスで複数同じタスクが動く場合の設定のややこしさも解消されました。
さらに、同じホストで動くタスクの間でネットワークリソースの干渉が減少し、ネットワークで詰まっていたアプリケーションがあったとしたら、ネットワークモードの変更だけでパフォーマンスが改善する可能性があります。
また、ENI(いままでのEC2のネットワーク関係の設定や追跡機能が紐づいているもの)とタスクが1対1で対応しているので、タスクごとの通信内容がVPCフローログなどで既存のEC2のネットワーキング機能を利用して確認できるようになります。
ECSで awsvpc
ネットワークモードを利用する場合の制限の話
今までのネットワークモードより便利そうな点が多い awsvpc
ネットワークモードですが、タスクごとにENIを割り当てることに関連していると思しき制限もあります。
この記事では、その中の印象的だったもの*13をメモして〆たいと思います。
- いままで利用していた
link
設定が利用できない - タスクごとにネットワークインタフェースをアタッチしているので、クラスタで利用しているEC2インスタンスのインスタンスタイプで設定されている
ENIの数 - 1
以上にタスクをコンテナインスタンスに配置できない タスクごとにネットワークの名前空間を作成し、ECSのコンテナインスタンス上にある、ホストマシンのプライマリネットワークインタフェース以外のENIをそのタスク用の名前空間に追加する
の部分をecs-agent
のawsvpc
モード用に用意されたCNIプラグイン達を通して行う*16からか、手動でawsvpc
ネットワークモードのタスクが動くコンテナインスタンスに対して ENIのアタッチをしていて、他に余っているENIがなければ、awsvpc
ネットワークモードのタスクはPROVISIONING
=>DEPROVISIONING
=>STOPPED
に移行して動かない
制限やEC2起動モードとの違いの詳細には、 https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-networking.html を確認してください。
参考
この記事を書き始める前に重点的に読んだもの。他の参考記事は注釈部に。
- Amazon ECSコンテナにCloud Native Networkingが登場
- 詳解: Amazon ECSのタスクネットワーク
- AWS ドキュメント » Amazon EC2 Container Service » 開発者ガイド » Amazon ECS タスク定義 » タスクネットワーキングと awsvpc ネットワークモード
- AWS ドキュメント » Amazon EC2 » Linux インスタンス用ユーザーガイド » ネットワークとセキュリティ » Elastic Network Interface
VPCとALBについてもう少し詳しくなりたいけど、業務的に火急なのはElasticCacheで自分は何をやっているんだ...、現場からは以上です。
*1:https://aws.amazon.com/jp/blogs/news/introducing-cloud-native-networking-for-ecs-containers/
*2:https://aws.amazon.com/jp/blogs/news/aws-fargate-tokyo/
*3:https://aws.amazon.com/jp/blogs/news/under-the-hood-task-networking-for-amazon-ecs/ の図など
*4:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/create-task-definition.html と https://docs.docker.com/engine/reference/run/#network-settings より
*5:http://www.slideshare.net/AmazonWebServicesJapan/aws-blackbelt-2015-ecs の20ページとかみたいに
*6:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html より今まで使えた設定でもhost ネットワークモードを使えば話は違うみたいですが、たぶん設定がややこしかったのでは
*7:https://aws.amazon.com/jp/blogs/news/introducing-cloud-native-networking-for-ecs-containers/
*8:http://www.slideshare.net/AmazonWebServicesJapan/aws-blackbelt-2015-ecs 69~70ページあたりで2015年時点のその辺の様子を確認できます。ポート番号が被らないように発展編の設定を使ったり、同一Taskは一つのコンテナインスタンスに一つまで、と制限したり
*9:https://docs.openstack.org/liberty/ja/networking-guide/intro-network-namespaces.html
*10:https://aws.amazon.com/jp/blogs/news/under-the-hood-task-networking-for-amazon-ecs/
*11:https://aws.amazon.com/jp/blogs/news/introducing-cloud-native-networking-for-ecs-containers/ の 「コンテナはこのブリッジを利用し、それが実行されているインスタンスのプライマリネットワークインタフェースを使う」 から
*12:ENIは仮想的なインタフェースで論理的に分割されている可能性もあるんでしょうが、インスタンスタイプによってENIの数変わるし、物理的にもある程度そのような気はする...
*13:主にレビューの時に「へぇ」といったり、個人的にトラブルシューティングで使いそうな目処がついたもの
*14:https://qiita.com/taishin/items/84122ad85bedf8b8a682
*15:上の記事とは関係ないんですが、もともとlinkはポート番号が使えないから利用したい機能でポート番号がアプリケーションに対応した番号で固定で使えるならいらないでしょ + アプリケーションが設定しているポートを見て設定するようになるとELBやセキュリティグループの設定で混乱がなくなる、みたいな考えでもあるのか?
*16:https://aws.amazon.com/jp/blogs/news/under-the-hood-task-networking-for-amazon-ecs/
AWS SQSのvisibility timeoutとdelay queueのdelayの違いについて
今週の復習です。
consumerがキューからメッセージを受信するリクエストを送った後、
- 通信の問題で結局受け取れなかった
- consumer側で処理中にエラーになって結局最後まで処理できなかった
などの事態に備えるため、SQSのキューにあるメッセージはconsumerが受け取った時点では消えない。
consumerはメッセージを受信して処理した後、キューに対してメッセージ削除のリクエストを送る必要がある。
また、
- SQSのキューにある1つのメッセージを複数のconsumerが受信してもおかしくない
ので、
- SQSのキューの仕組みとして: キュー上のあるメッセージに受信リクエストが来た後、指定の秒数の間は他のconsumerにそのキューを見せない
visiblity timeout
を設定する*1 - 実装側として: 複数のconsumerが同じメッセージを処理しても問題ない実装にしておく
ということを考える必要がある。 visiblity timeout
はデフォルトだと 30秒の設定となっている*2。
visiblity timeout
を利用している場合、SQSのキューに溜まっているメッセージの数は
ApproximateNumberOfMessagesNotVisible
(あるconsumerがそのメッセージを処理しているかも)ApproximateNumberOfMessagesVisible
(どのconsumerもまだそのメッセージを処理していないかも *3 )
の合計となる。
上記がSQSのふつうのキューを使った場合で、キューを使った非同期で動くシステムの中には、キューにメッセージを送った直後はそのメッセージを消費して欲しくない、という場合がある*4。その場合は、delay queueを利用する。
SQS delay queueを利用した場合、
- standard queueでキューから取り出そうとしたメッセージに対して
visiblity timeout
の設定を利用した場合: あるconsumerが受信リクエストを送った後、指定の秒数他のconsumerからメッセージが取得できなくなる
のに対し
- delay queue に追加されたメッセージの場合: producer からメッセージをキューに追加された後、delayで指定した秒数consumerからメッセージが取得できなくなる
の違いがある。また、
visiblity timeout
の設定はキューに詰めるメッセージに個別に指定- delay queueのdelayの設定はキューに対して指定(=>キューに入るメッセージ全体に適用)
される。
delay queueにおいて、全体に適用されるdelayの設定は固定ではなく、メッセージによってはdelayの値を変えたい、といった場合は message timer の delay seconds の指定で上書きが可能*5。
delay queueのユースケースがわからないので、もやりとしていますが、現場からは以上です。
*1:というより、デフォルトで30秒に設定されている
*2:https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html
*3:これはconsumerがメッセージを処理するのに必要な時間に応じたvisibility_timeoutを設定している想定で、この辺が適切でなかった場合はその限りではない
*4:このケースについて自分では調べててよくわからなかったんですが、sidekiqなどジョブ管理システムのキューにSQSを利用していて、デフォルトではリトライの時にちょっと時間をおいて欲しいとか、短時間のうちにキャンセルのリクエストがくる可能性があるジョブのリクエストを待つとか...? でも、キャンセルのメッセージがリクエストのメッセージと同じconsumerで処理されなければ意味がなくない...?
*5:https://www.slideshare.net/AmazonWebServicesJapan/aws-31275003 の27ページ目
ECSのタスク、サービス、クラスタ、コンテナインスタンスの意味についてまとめました
ECSのタスク、サービス、クラスタ... といった言葉の意味がいまいちよくわからなかったので、それぞれの言葉が指すインスタンスを作成するときに何を設定するかに基づいてまとめたメモです。
もとの説明をいい感じに引用して... とかの時間がなかったのでひとまずポスト。
クラスタ
- ネットワークとか、リソース管理の仕方(EC2使う or Fargate*1, EC2の調達の仕方)とか*2
- リソースの管理の仕方 => クラスタに属する EC2 の設定も管理している*3。特定のインスタンスタイプのEC2を決まった台数、特定のネットワーク内に調達することに関心がある*4
ECSのコンテナインスタンス
- ECSのコンテナインスタンス = Amazon ECS コンテナエージェントが入ったEC2インスタンス*5
- クラスタのところで設定した項目はほぼコンテナインスタンスに適用される。クラスタはそこに所属するコンテナインスタンスの設定を管理してる
- 登録解除 != 停止. 登録解除しただけだと前のコンテナ起動した時のローカルファイルが残ってるので注意
- ECSのコンテナインスタンスを確保 => ECSのコンテナインスタンス中のコンテナエージェントがタスク実行のリクエストを受け付ける
タスク定義
- クラスタが所定の台数Dockerの動くEC2のインスタンスを確保してくれているはずなので、そこにdocker-composeで投げるdocker-compose設定ファイル的なもの*6*7
- docker-composeの内容を書く = その内容は
docker-compose 投げた
先のEC2インスタンスがどういう性能を持っていないといけないか知っている
ECSタスクのスケジューリング *11
- 長期実行するステートレスサービスおよびアプリケーション用(要するにrailsのフロントとか)を常に指定した台数起動したい => サービススケジューラを使う
- サービススケジューラがタスクの実行台数を管理する単位がサービス
- service taskはサービスで管理されてるタスク
タスク = docker-composeで動く一連のコンテナの単位
の数をスケーリング != EC2インスタンスの数(こっちに対して課金)をスケーリング
- その場で実行する => 単発で実行されるバッチジョブとか RunTask
*1:この起動タイプはタスクを作成するときにも設定できる
*2:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ECS_clusters.html#cluster_concepts
*3:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/create_cluster.html
*4:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/scale_cluster.html 2015 年 11月24日以降に作成したクラスターなら、 AWS CloudFormation スタックに関連付けた Auto Scaling グループを作成すると管理画面から何台起動させるか、といったことが変更できる
*5:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ECS_agent.html AMIで指定する単位だからほぼEC2だろう
*6:クラスタが何台分、と決めている枠の中でタスクを割り振る。クラスタの中にコンテナインスタスタンスが5台起動していて、タスクが3つなら、そのタスクで定義されたプロセスは3つしか動かないし、逆にクラスタの中にコンテナインスタンスが3台でタスクが5つなら複数のタスクが動くコンテナインスタンスが出てくる?
*7:同じタスク定義の中で定義されているコンテナは必ず同じインスタンスで動く http://www.slideshare.net/AmazonWebServicesJapan/aws-blackbelt-2015-ecs の36ページ
*8:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html#constraints (インスタンスタイプの指定はdockerで元になるOSが入ったimageを指定イメージに近い)
*9:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html#task_size
*10:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs_services.html
*11:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs_services.html
APNsのプッシュ通知で利用するプロバイダ証明書関連の各種ファイル形式について調べてみたメモ
前の記事では、APNsとプロバイダの間の接続信頼の話をしました。この記事では、接続信頼の確認に使う証明書関係のファイルの話をします。
複数の鍵や証明書をまとめて扱うための個人情報交換( .p12
)
まず、Push通知の証明書関連で調べているとよく出てくる .p12
という拡張子のファイルですが、これは日本語では 個人情報交換 と呼ばれています。
個人情報交換は、その内部に複数の鍵や証明書をまとめて格納することが可能で、パスワードでそれらのファイルを保護します。
たとえば、よくある1つのiOSアプリ用に使うプッシュ通知用の証明書だと、キーチェーンから書き出した .p12
ファイルの中にPEM形式の鍵と証明書が含まれています。なので、こちらの記事のように、 .p12
のファイルから .pem
のファイルを書き出したりします。
証明書のデータ構造のエンコーディング( PEM
, DER
)と公開鍵基盤用の規格 X.509
PEM
形式の鍵、証明書は鍵、証明書のデータの部分がBase64でエンコーディングされています*1。
これに対し、鍵、証明書のデータの部分がバイナリエンコーディングされているのが DER
形式の鍵・証明書で、 PEM
, DER
形式のファイルに含まれる証明書・鍵のデータは ASN.1(アセンワン)
という言語で定義されています*2。
もう少しかっちり書くと、 X.509
という公開鍵証明書と証明書失効リストを含む公開鍵基盤(PKI)について定義される規格があり、その中で PKI
用証明書のエンコーディングには ASN.1 DER
エンコーディングが使用されるように定義されています*3。また、 X.509
に基づいて作成・運用される証明書が X.509 証明書
と呼ばれているみたいです*4。
APNS - プロバイダ間の接続信頼を確認する際は、この X.509
証明書のデータを利用します。その際、エンコーディングされた文字列ではなく ASN.1
で定義された型のオブジェクトまでデコードする必要があります。
証明書署名要求( CSR
)を使ってAppleからの署名によりApple公認のプロバイダであることを証明する
順番はやや異なりますが、ここまで
X.509
という公開鍵基盤(PKI
)について定義する規格があるX.509
の公開鍵証明書はASN.1
という言語で*5型が定義されている個人情報交換
(.p12
のファイル) で、証明書のデータをエンコーディングしたPEM
と鍵のデータをエンコーディングしたPEM
などを合わせて格納する
という話をしました。では、鍵と証明書*6の .pem
ファイルが中に入った .p12
ファイルでありさえすれば、どんなものでも APNsとの間の接続信頼の確認に使えるのでしょうか。
もちろん、そうではありません。
APNsとの間の接続信頼を確認するためには、Appleと契約を結んだ組織に属していることを証明する必要があります。そして、そのために接続信頼の確認に利用する証明書にはAppleの署名が必要です。
公開鍵証明書に特定の組織(公開鍵基盤の言葉でいうと、認証局)の秘密鍵で電子署名をしてもらう。そのために認証局へ提出するファイル*7を 証明書署名要求(CSR: certificate signing request) といいます。
CSRを用いたApple側の署名入り証明書作成手順について備考
最後に、公開鍵基盤(PKI)の証明書署名要求(CSR)を用いた証明書の作成手順をAPNsの具体事例にあわせておさらいしておきましょう。
まず、IPAの資料によると証明書の発行プロセスは大別して
- 加入者(証明書が発行される側。APNs - プロバイダ間でいうとプロバイダ、アプリ開発者のほう)が鍵ペアを生成する方式
- 登録局が一括して鍵ペアを生成する方式
の2通りあります。
この記事などの手順にあるように、APNsから証明書発行してもらうプロセスはプロバイダ側がキーペアを含めたCSRを作成するところから始まるので1の方ですね。
まず、1. の手順に「加入者が鍵ペアを生成する」について。APNsの証明書を作成する場合は、「キーチェーンアクセス > 認証局に証明書を要求...」から .certSigningRequest
ファイルを作成します。
作成した .certSigningRequest
ファイルをApple開発者アカウントの管理画面からAPNsのシステムへアップロードすることが、KPIでいう加入者の認証局に対する証明書の発行申請にあたり、アップロード後にダウンロードした .cer
ファイルが Apple側の署名がなされた証明書となっています。
ところで、「加入者が鍵ペアを生成する」の文言と 「「キーチェーンアクセス > 認証局に証明書を要求...」から .certSigningRequest ファイルを作成」 の内容があってないですね。
実は「キーチェーンアクセス > 認証局に証明書を要求...」をクリックしたときの画面をみてみると
のようになっており、 .certSigningRequest
ファイルを作成する前に秘密鍵と公開鍵のキーペアを生成しているようです。
この秘密鍵はキーペアを生成したMac(システム)に配置され、キーチェーンからのみアクセスできるようで、他のMacに移行したりプッシュ系のmBaasを利用する場合などはAppleから発行された証明書( .cer
ファイル)に秘密鍵を含めて .p12
ファイルに書き出す必要があります*8。
参考
- https://developer.apple.com/jp/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html
- https://www.ipa.go.jp/security/pki/034.html#_Toc3020776
- https://qiita.com/kunichiko/items/12cbccaadcbf41c72735
- http://www.geocities.co.jp/SiliconValley-SanJose/3377/
- https://www.sambaiz.net/article/135/
- https://dev.classmethod.jp/smartphone/iphone/apple-certificates-summary-and-etc/
*1:余談ですが、Base64でエンコードすると最後に=ってつくことありますが、それはデータがエンコード文字列の長さで表せる量に対して中途半端に短かった時の穴埋めなんだそうな https://ja.wikipedia.org/wiki/Base64
*2:DERの仲間にBER, CERがあり、DERはBERのサブセット http://www.geocities.co.jp/SiliconValley-SanJose/3377/
*3:https://www.ipa.go.jp/security/rfc/RFC2459JA.html
*4:みたいですってなんやねんって話ですが、PEMとかファイル形式で説明されていることが多くてちょっとだけ自信がない
*5:X.509証明書以外にもASN.1で定義されているものはあります http://www.geocities.co.jp/SiliconValley-SanJose/3377/
*7:データさえ渡せればいいので、ファイルとして送る必要は特にないが、Appleの開発者管理画面の画面がファイルとしてアップロードする形だったのでファイル表記
*8:https://dev.classmethod.jp/smartphone/iphone/apple-certificates-summary-and-etc/
APNsを利用する際に必要な2種類の接続信頼について
APNsを利用する際に必要な2種類の接続信頼
APNsを利用する際には証明書やトークンが必要ですが、それは認証のためです。
ドキュメント*1には、暗号化されたデータが正しく復号できるか、途中で改ざんされていないかみたいな確認にあたる暗号化検証とあわせて 接続信頼 と呼ばれています。
この接続信頼には
- プロバイダ - APNs間の接続信頼
- APNSにリクエストを送ってきた人がプロバイダー(=プッシュ送りたい人、アプリ作った人)であることを証明する
- これが確認できないと、プロバイダとAPNsの間でやりとりはできない
- APNs - デバイス間の接続信頼
- APNsから通知を受信するデバイスが、認証を受けたもののみであることを証明するためのもの
の2種類があります。
プロバイダーAPNs間の接続信頼
まず、プロバイダーAPNs間の接続信頼の話をします。
プロバイダーAPNs間の接続信頼には「トークンベースのプロバイダ接続信頼」「証明書ベースのプロバイダ接続信頼」があり、それぞれ接続信頼を確認するために必要な手順やプロバイダのサーバに配置するファイルが異なります。
トークンベースのプロバイダ接続信頼
- WWDC2016で公表された方式。
- こちらの記事の手順で管理画面で Apple Push Notification Authentication Key(Sandbox & Production) を発行し、その際にダウンロードする
.p8
ファイルをサーバーに配置Apple Push Notification Authentication Key
の 有効期限は無期限 です(こちらの操作により無効にすることも可能)
- こちらの記事 に書いてあるような手順で
.p8
ファイルから秘密鍵を取り出し、時刻を利用して認証に使うトークンを生成します - バンドルIDが記載されているすべてのアプリケーションにおいて同じ
Apple Push Notification Authentication Key
を使うことが可能です - 余談として、ドキュメントの セキュリティアーキテクチャ > プロバイダ-APNs間の接続信頼 > トークンベースのプロバイダ接続信頼に
鍵ペアを生成し、公開鍵をAppleに渡してください。秘密鍵はプロバイダ側で保持し
と書いてあるものの、公開鍵をどうこうした覚えはなくて若干戸惑っていたり。。- これは推測ですが、秘密鍵がそのときDLする
.p8
ファイルに入っているので、多分公開鍵はApple Push Notification Authentication Key
を発行した時にAPNs側に保管されているのでしょう。。
- これは推測ですが、秘密鍵がそのときDLする
トークンベースの接続信頼を利用する場合に送るリクエストの例
HEADERS - END_STREAM + END_HEADERS :method = POST :scheme = https :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0 host = api.development.push.apple.com authorization = bearer eyAia2lkIjogIjhZTDNHM1JSWDciIH0.eyAiaXNzIjogIkM4Nk5WOUpYM0QiLCAiaWF0I jogIjE0NTkxNDM1ODA2NTAiIH0.MEYCIQDzqyahmH1rz1s-LFNkylXEa2lZ_aOCX4daxxTZkVEGzwIhALvkClnx5m5eAT6 Lxw7LZtEQcH6JENhJTMArwLf3sXwi apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b apns-expiration = 0 apns-priority = 10 apns-topic = <MyAppTopic> DATA + END_STREAM { "aps" : { "alert" : "Hello" } }
- ヘッダーに接続信頼用の
authorization
キーがあります。 Apple Push Notification Authentication Key
は開発者アカウントと紐付いているすべてのアプリと紐付いているので、どのアプリ宛かを指定するためのapns-topic
の指定があります。- デバイストークンの指定は、
:path
で行われています。
証明書ベースのプロバイダ接続信頼
- 証明書ベースのプロバイダ接続は、プロバイダ証明書(具体的には .p12 ファイルや .pem の中に含まれているデータ)で指定されている特定の1つのアプリケーションのためのものです
- 接続信頼の確認に利用する証明書は事前に作成します
- 証明書ベースの信頼を利用する場合、APNsが証明書失効リストを作成、管理しています*4
- 証明書ベースでプロバイダ接続信頼を行う場合、証明書を使うのはTLS接続確立までで、個々のリモート通知リクエストの時は通知先のデバイストークンだけヘッダにつければよいです
- トークンベースの接続信頼で使う
Apple Push Notification Authentication Key
と違い、証明書ベースの接続信頼で使うSSL証明書(.p12ファイル)は1年の有効期限があります
証明書ベースの接続信頼を利用する場合に送るリクエストの例
HEADERS - END_STREAM + END_HEADERS :method = POST :scheme = https :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0 host = api.development.push.apple.com apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b apns-expiration = 0 apns-priority = 10 DATA + END_STREAM { "aps" : { "alert" : "Hello" } }
- トークンベースの場合と違い、
authorization
キーはありません。 - 基本的に、証明書ベースの場合、証明書の中にどのアプリ用の証明書か含まれているため、証明書の中に記載されたトピックへのリクエストとして処理できるため、
apns-topic
の指定がありません- 複数のtopic用の証明書の場合は
apns-topic
の指定が必要です。
- 複数のtopic用の証明書の場合は
- デバイストークンの指定は、
:path
で行われています。
APNs-デバイス間の接続信頼
次にAPNs - デバイス間の接続信頼の話をします。
大枠を言うと
- iOSなどのデバイスの利用開始設定(アクティベーション時)に接続信頼に利用される暗号化証明書と秘密鍵がOSから提供される
- OSから提供された暗号化証明書と秘密鍵はキーチェーンに格納され、アプリケーションとは関係なしにAPNsとデバイスとの間の接続信頼に利用される
- (= デバイスとAPNsとの接続信頼のために、開発者がなにかする必要はない)
となります。
そうすると自分(プロバイダ)として関心があることは、このAPNs - デバイスが接続された上で、デバイスへのリモート通知リクエストに必要なトークンを取得することですが、この部分については開発者側で実装や設定が必要です。
iOSおよびtvOSでのデバイストークンの取得などを参考にアプリケーションがリモート通知リクエストを送るためにAPNsへリクエストを送り、結果を受け取る実装をし、また、Enable push notificationsを参考にアプリケーションがプッシュ通知を利用する設定が必要です。
参考
- Apple Push Notification サービス
- リモート通知サポートの設定
- Enable push notifications
- Golangで「プロバイダー認証トークン」を生成して、APNsにプッシュを送ろう
- Apple Push Notification Authentication Keyを発行しよう
*1:https://developer.apple.com/jp/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1
*2:かといって接続のたびに再発行してほしいわけではない
*3:アプリのリモート通知以外にもVoIP通知などの用途があり、その場合アプリのbundle IDに .voip がついた値をtopicに指定する https://developer.apple.com/jp/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1
*4:これは、開発している時にはPush屋さんが失効時の挙動テストする時にAPNsのサンドボックスでの失効が遅い...(なんかSANDBOXの場合、半日くらい待ってる気がする) というくらいしか縁がないのではないか...
EMRのHiveのドキュメントを読むのが不自由だったので読み方からメモ
仕事で若干AWS EMR上のHiveにさわったので少しだけメモ。
ドキュメントの読み方とか頭いっぱいになってるとすっこ抜けて死んでいますが、EMRの他のサービスについても似たような感じに気をつければいいはずだ。。
マネージドサービスとはいえ、設定できる項目については基本の元々のソフトウェアの設定ファイルの名前とかが割と使えるようになっているかもしれないとか。。
EMR上に入っているHadoopその他のバージョンについて
RDSにはMySQLやPostgresをはじめとしたRDBSが、Elastic CacheにはRedisなどキーバリューストアがあらかじめインストールされているように、EMRには基本的にHadoopやApache Sparkがインストールされています。
このEMRにインストールされているバージョンはソフトウェアのバージョンはEMRのリリースバージョンごとに管理されていて、EMRのリリースバージョンに対するHadoopやApache Sparkのバージョンは https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-release-components.html から確認できます。
Hiveの設定ファイルとAWS EMRのconfigのキーの対応
Hiveを叩くためにHiveServerやHiveServer2を使って~みたいな話が出てきた時に、Hive の設定ファイルとして hive-site.xml
の内容が紹介されることがありますが、EMR上でHiveを利用する場合、 hive-site
という Classification
を利用して指定します。
// https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-hive-metastore-external.html [ { "Classification": "hive-site", "Properties": { "javax.jdo.option.ConnectionURL": "jdbc:mysql:\/\/hostname:3306\/hive?createDatabaseIfNotExist=true", "javax.jdo.option.ConnectionDriverName": "org.mariadb.jdbc.Driver", "javax.jdo.option.ConnectionUserName": "username", "javax.jdo.option.ConnectionPassword": "password" } } ]
Hive JDBC Driverの利用について
Clouderaのとか、Apacheのとかあると思いますが、Amazonが用意してるJDBC Driverを使います。 ドキュメントはDLしたzipの中に入っています。。