あけましておめでとうございます。エンジニアリンググループの松原@ma2geです。 私はこちらの記事にもあるマルデバチームのチームリーダーをしていますが、採用チームとしても働いております。 今回は採用チームで取り組んでいるエンジニアの成長や OSS 活動を推進する仕組みの一部として、 チラッとこのブログにも出てきた「エンジニア実績システム」を導入してみた話です。
続きを読むエムスリーのグローバル戦略と今回のニューヨークオフィス出張について(まとめ)
エムスリーエンジニアリンググループ(以下、エンジニアリングG)の山崎です。 VPoEとして2018年締めくくりのテックブログを書きたいと思います。
はじめに
2018年はエムスリーエンジニアリンググループにとって多くのチャレンジをした1年でした。 まずはエンジニアリングGの頼もしい仲間達に感謝の気持ちを伝えたいと思います。 本当にお疲れ様でした。
さて、2018年の多数のチャレンジの中から、本日はエムスリーのグローバル戦略と今回のニューヨークオフィス出張についてまとめたいと思います。
その前に告知
2019/01/17(木) 19:00 〜 21:30 に「M3 Tech Meetup #6 〜US出張報告会〜」と題して、今回ニューヨークオフィス出張を行った矢崎、冨岡、笹川よりUS出張での経験を共有する報告会を実施します。 海外での生活事情や仕事、コミュニケーションの限界などライブ感そのままに今回の出張についてご報告いたします。 後日イベントページを公開しますので、ご興味のある方は是非、下記のconnpassよりエンジニアリングGをフォローください。
続きを読むルーターを風呂場の天井裏に置きたくないので VLAN を使ってみた
エムスリー エンジニアの 矢崎 (id:Saiya) です。
集合住宅では天井高などの都合で 浴室天井裏にルーターが置かれる ケースが少なくないと思うのですが、VLAN を使うことで自由な場所にルーター等を配置できるようにしてみました。その状態で一年ほど運用した限り個人的には満足な結果であったため、自分のための備忘録も兼ねて記事にしてみました。
浴室天井裏とルーター
集合住宅の場合、光ファイバーが個別の部屋に引かれていることは稀*1であり、光ファイバーは建物全体で共有し、そこから LAN ケーブルなどとして各部屋へ分配されることが多いです*2。その場合、ユニットバスの天井と部屋全体の天井の間に隙間があるために、浴室の天井裏に配線や支給品のルーター*3が配置されることが少なくありません。
しかし、筆者は自前のルーター機材を色々試して遊ぶといった趣味があるのですが、浴室天井裏に自前の機材を配置することは好んでおりません:
- 脚立などがないと安全にアクセスできず、作業効率が悪い
- 排熱面であまり有利な場所ではない
- インジケーターランプの点灯状態などが常日頃から見えないのが悲しい
- (中古で買ったりしているとはいえ)高価な機材を水場の上に置くのが好みではない *4
とはいえどもインターネットにつながる回線が浴室天井裏までしか引かれていないのが現実なので、どうにかして部屋(ルーター設置場所)にインターネット回線を伸ばす必要があります。
実現した回線構成
※ 正確には他にも機材がありますが本筋に関係ない部分は省略
上記のように、天井裏にはスイッチを配置し、ルーター本体は部屋の中に配置しました。インターネットへ至る LAN 回線はスイッチを経由してルーターまで延長し、ルーターからのイントラネット回線(家庭内の通信回線)もスイッチを経由して各部屋に接続しています。
しかしここで問題なのは、天井裏から各部屋への物理的な LAN ケーブルは 1 本しかないという点です。図からも読み取れる通り、天井裏とルーターの間には 2 つの経路が必要になります。こういった記事 や こういった記事 にあるように LAN ケーブルを自力で敷設する方もおられますが、筆者は物件の都合と物理層の工作スキルの都合で、物理的にケーブルを引かない選択肢を模索しました。
では物理的に 1 つの LAN ケーブルに 2 つの異なる LAN を通すにはどうすればよいのでしょうか?
*1:ちなみに筆者が一つ前に住んでいた物件は個別の部屋のしかもちょうどよい場所に光ファイバーが引かれている貴重な物件でした。しかし転居先では電柱との位置関係も悪く、ファイバーを引けませんでした。
*3:VDSL の場合は終端装置も
*4:実際はユニットバスの水密性は高いので大丈夫だと思うのですが
M3 Tech Meetup #5 ~年の瀬前のLT大会~を開催しました
こんにちは、エムスリー エンジニアリンググループの大和です。
いよいよ年の瀬も近づいてまいりましたが、12/6 (木) に弊社オフィスにて「M3 Tech Meetup #5 ~年の瀬前のLT大会~」を開催しましたのでご報告いたします。
参加されたエンジニアの皆様におかれましては、当日は弊社までお越しいただきありがとうございました。
発表内容
当日は、以下に紹介するタイトルで弊社エンジニアが登壇しました。
続きを読むAuto Scaling に対応した EC2 監視アラーム設定ツール
こんにちは、エムスリー 兼 QLife エンジニアの園田です。
昨日、小ネタで投稿した Auto-Scaling 配下の EC2 の CloudWatch Alarm 設定ツールを SAM の OSS として公開したので、その説明のポストとなります。
昨日の小ネタ記事はこちらです。
(小ネタ) AutoScaling で増減した EC2 インスタンスに動的に CloudWatch Alarm を設定 - エムスリーテックブログ
なぜ実装したか
エムスリーグループの QLife では、オンプレのインフラ環境を2018年の9月に AWS へ完全移行しました。
移行後の環境は ZABBIX 3 や Mackerel の監視が導入されていますが、新規サービスなどで AWS アカウントや VPC を追加した場合に、監視設定業務が ZABBIX のノウハウに依存し、属人化してしまいます。Mackerel などの外部サービスの場合、ホスト課金も増えてしまいます。
また、ZABBIX は Auto-Scaling に弱く、ホスト自動登録を行うためには(ノウハウ自体はありふれているが)標準機能にないハックが必要となります。
他の監視の仕組み( Prometheus など)も検討しましたが、どうせ監視システムの運用コストがかかるなら内製してしまえ!とカッとなって実装した次第であります。
また、運用監視の要件として、ホストごとの監視を必須とする場合(官公庁とかだとよくある)にもマッチするかと思われます。
ツール概要
S3 に監視定義用の JSON または YAML ファイルを置いて、Launch Template や Launch Configration のタグにそのファイルへの参照を設定します。 Auto-Scaling のインスタンス起動イベントを CloudWatch Event Rule で検知して Lambda を実行し、タグの値に紐付いた監視定義をインスタンスに対して適用(CloudWatch Alarm を作成)します。 インスタンス削除時も同様に、タグから定義を参照して当該アラームを削除します。
説明だけだと意味不明だと思いますので、実際の監視設定手順を書きます。
監視定義 適用手順
1. リポジトリを clone
git clone https://github.com/QLife-Inc/ec2-auto-metric-alarms.git
cd ec2-auto-metric-alarms/
2. 監視定義ファイルを格納するバケットを作成
こちらは既存のバケットでも構いません。
aws s3api create-bucket \ --bucket "your_bucket_name" \ --acl private
3. 監視定義ファイルをアップロード
リポジトリの sample-definitions にサンプルがあるので、それを利用します。YAML を利用する場合は --content-type text/yaml
を指定します。
aws s3api put-object \ --bucket "your_bucket_name" \ --key "your_prefix/cpu-util" \ --body "sample-definitions/cpu-util.yml" \ --content-type "text/yaml"
4. 監視を設定するインスタンスにタグを付与
AutoScalingGroup で利用する Launch Template や Launch Configuration の設定で EC2 インスタンスに付与するタグを追加します。 また、すでに起動済みのインスタンスに対して監視を適用する場合はインスタンスにも直接タグを付与する必要があります。 Auto-Scaling を介さずに動作確認を行う場合もインスタンスにタグを直接付与してください。
デフォルトのキーは AlarmDefinitionName
です。この値に、先ほど S3 にアップロードしたオブジェクトのキー(ファイル名)を設定することで、インスタンスと監視定義を紐づけます。
5. 通知先の SNS トピックを作成
緊急通知用と通常通知用の2つのトピックを作成します。トピック名はなんでも構いません。
aws sns create-topic --name "system-emergency-notification" aws sns create-topic --name "system-notification"
トピックが作成できたら、適当なメールアドレスをサブスクリプションとして登録しておきます。
6. ツール(SAM)をデプロイ
sam
コマンドがインストールされていない場合はインストールしてください。
pip install --user --upgrade aws-sam-cli # brew install aws-sam-cli
ソースをパッケージングします。sam package
コマンドを実行すると、指定した S3 バケットに SAM のソースアーカイブがアップロードされます。このアップロードされたアーカイブから CloudFormation により Lambda 関数が作成されます。また、 template.yaml
が CloudFormation テンプレートとしてコンパイルされます。
sam package --template-file "template.yaml" \ --output-template-file "cloudformation.yml" \ --s3-bucket "your_source_bucket" --s3-prefix "sam-sources"
sam deploy
コマンドを実行します。このコマンドで、 package
コマンドによって生成された cloudformation.yml
から CloudFormation の Stack が作成されます。
コマンド実行時に CloudFormation のパラメータを渡す必要があります。 template.yaml
の Parameters
ディレクティブで Default
が設定されているパラメータ以外は必須になります。
sam deploy --capabilities CAPABILITY_NAMED_IAM \ --stack-name "your_stack_name" \ --template-file "cloudformation.yml" \ --parameter-overrides \ DefinitionBucketName="your_bucket_name" \ DefinitionObjectPrefix="your_prefix/" \ FunctionName="ec2-auto-metric-alarms" \ EmergencyTopicArn=${5.で作成した緊急通知先トピックのARN} \ OrdinaryTopicArn=${5.で作成した通常通知先トピックのARN}
7. ツール実行
SAM のデプロイが成功すると Lambda 関数が作成されているはずですので、Lambda のコンソールから直接実行してみます。
このツールの挙動として、Auto-Scaling 以外のイベントデータを受け取った場合、現在起動中の監視定義タグが設定されているすべてのインスタンス
に対して監視定義を更新するため、テストイベントデータは空の JSON で問題ありません。
作成された Lambda 関数の画面から、「テストイベントの設定」を開いて、空のイベントデータを設定します。
作成したテストイベントを選択して「テスト」ボタンを押して正常終了すれば、4. でタグを設定したインスタンスに対する CloudWatch Alarm が生成されていることが確認できます。
以上が簡単な監視定義の適用手順となります。
監視定義ファイルの解説
README にもモデルのスキーマについて説明がありますが、より詳しい説明を書きます。
このツールで利用する監視定義ファイルに記載する監視定義は CloudWatch の PutMetricAlarm API のリクエストモデルを拡張したモデルで、 JSON または YAML で定義します。
先ほどの手順でサンプルとして利用した cpu-util
の監視定義ファイルは以下のようになっています。
--- _cpu_util: &cpu_util namespace: AWS/EC2 dimensions: - name: InstanceId value: <%= instance.id %> metric_name: CPUUtilization statistic: Average threshold: 90 unit: Percent comparison_operator: GreaterThanThreshold period: 300 treat_missing_data: ignore name: cpu-util description: EC2 の CPU 監視テンプレート alarm_definitions: - <<: *cpu_util alarm_id: notice-cpu-util notification_type: ordinary alarm_name: ec2-<%= instance.id %>-notice-cpu-util alarm_description: <%= instance.name %> CPU使用率が 10 分間 90 % を超えていたら通知 evaluation_periods: 2 datapoints_to_alarm: 2 - <<: *cpu_util alarm_id: emergency-cpu-util notification_type: emergency alarm_name: ec2-<%= instance.id %>-emergency-cpu-util alarm_description: <%= instance.name %> CPU使用率が 30 分間 90 % を超えていたら通知 evaluation_periods: 6 datapoints_to_alarm: 6
よく見ると、 <%= instance.id %>
などが登場して、 ERB
のテンプレートになっていることがわかります。
この instance
は Aws::EC2::Instance
のラッパーインスタンスで、 Lambda 実行時に埋め込まれるため、同じ監視定義でも AlarmName
が重複することなく、複数の EC2 インスタンスの監視定義を作成できるようにしています(CloudWatch Alarm は Region と AlarmName で一意になる)。
監視定義の再利用
EC2 の監視といっても、そのインスタンスの用途によって監視内容は様々です。 例えば全ての EC2 で監視するメトリクス、ElasticBeanstalk のインスタンスで監視するメトリクス、ECS Cluster のインスタンスで監視するメトリクスなど、同じ EC2 というサービスでも異なるメトリクスに対する複数の監視定義が必要になることが多々あります。 それらについて、共通の監視定義を毎回実装するのは運用上避けたいので、他の監視定義をincludeすることで定義の継承を可能としています。
例えば、前述の CPU 監視とは別に、EC2 ステータスチェックの監視テンプレートがあるとします。
--- name: ec2-status description: EC2 の ステータス 監視テンプレート alarm_definitions: - alarm_id: notice-status-check notification_type: ordinary alarm_name: ec2-<%= instance.id %>-notice-status-check alarm_description: <%= instance.name %> ステータスチェックが失敗したら通知 namespace: AWS/EC2 dimensions: - name: InstanceId value: <%= instance.id %> metric_name: StatusCheckFailed statistic: Maximum threshold: 1 comparison_operator: GreaterThanThreshold period: 300 evaluation_periods: 1 datapoints_to_alarm: 1 treat_missing_data: ignore
CPU 監視とステータス監視はすべての EC2 インスタンスで利用したい、というユースケースの場合、以下のようにアップロード済みの監視定義を継承することができます。
--- name: ec2-default description: EC2 の共通監視テンプレート include_definitions: [ cpu-util, ec2-status ]
ステージング環境など、緊急通知を送信したくないインスタンスに対しては以下のように緊急通知だけを除外した定義を利用できます。
--- name: ec2-default-without-emergency description: EC2 の共通監視テンプレート(緊急通知除外) include_definitions: [ ec2-default ] ignore_alarm_ids: [ emergency-cpu-util ]
このように監視要件に合わせた監視定義の ERB
テンプレートを監視対象となるサーバロールごとに実装して、 S3 にアップロードしてタグで参照してあげれば OK です。
エンジニア募集!!
QLife では共にチーム一丸となってより良いものづくりにこだわれる仲間を募集中です! 小さいサービスが多いので新しい AWS のサービスの利用にも非常に積極的に取り組んでいます! カジュアル面談も行っていますので、興味がある方は entry@qlife.co.jp に「カジュアル面談希望」とメールをください!
エムスリーでもエンジニアを随時募集しています!共に医療 × テクノロジーの未来を切り拓いてくれる仲間を募集中です! AWS 以外にも GCP や Firebase などのクラウドも活用しています!興味がある方はカジュアル面談やTechtalkにおこしください!!
(小ネタ) AutoScaling で増減した EC2 インスタンスに動的に CloudWatch Alarm を設定
こんにちは、エムスリーエンジニアの園田です。
AWS の AutoScaling で増減する EC2 インスタンスに対して CloudWatch Alarm を動的に設定したくなることありますよね?
AutoScalingGroup のメトリクスで AutoScalingGroup 内の平均 CPU 利用率などを監視することはできますが、
個々のインスタンスそれぞれに対してアラームを設定することは(今のところ)できません。
正確には、設定したとしても AutoScaling で新しく起動したインスタンスには設定されませんし、
スケールインで削除されたからといって自動でアラームの設定が削除されることもありません。
そこで、 CloudWatch Event Rule と Lambda を使って増減するインスタンスに対して動的にアラームを設定するのを試してみました。(何番煎じかわかりませんが・・・)
なお、この記事は エムスリーアドベントカレンダー ではないです。
監視シナリオ
今回は、以下のシナリオを例として実装してみます。
EC2 インスタンスのCPU使用率が 10 分間 80 % を超えていたら、SNSトピックに通知する。
イベントデータの JSON 確認
Lambda を実装する上で、CloudWatch Event からどういったイベントデータを受け取れるのかを確認しなければいけません。
イベントデータの JSON を確認するために、マネジメントコンソールで CloudWatch > イベント > ルール の ルールの作成
ボタンをポチります。ルールの作成画面で以下のように設定すると、サンプルイベントデータが表示されるので、コピっておきます。
表示されたサンプルイベントデータは以下の通りです。
{ "version": "0", "id": "3e3c153a-8339-4e30-8c35-687ebef853fe", "detail-type": "EC2 Instance Launch Successful", "source": "aws.autoscaling", "account": "123456789012", "time": "2015-11-11T21:31:47Z", "region": "us-east-1", "resources": [ "arn:aws:autoscaling:us-east-1:123456789012:autoScalingGroup:eb56d16b-bbf0-401d-b893-d5978ed4a025:autoScalingGroupName/sampleLuanchSucASG", "arn:aws:ec2:us-east-1:123456789012:instance/i-b188560f" ], "detail": { "StatusCode": "InProgress", "AutoScalingGroupName": "sampleLuanchSucASG", "ActivityId": "9cabb81f-42de-417d-8aa7-ce16bf026590", "Details": { "Availability Zone": "us-east-1b", "Subnet ID": "subnet-95bfcebe" }, "RequestId": "9cabb81f-42de-417d-8aa7-ce16bf026590", "EndTime": "2015-11-11T21:31:47.208Z", "EC2InstanceId": "i-b188560f", "StartTime": "2015-11-11T21:31:13.671Z", "Cause": "At 2015-11-11T21:31:10Z a user request created an AutoScalingGroup changing the desired capacity from 0 to 1. At 2015-11-11T21:31:11Z an instance was started in response to a difference between desired and actual capacity, increasing the capacity from 0 to 1." } }
今回利用するのは、起動したのか削除されたのかを判別するための $.detail-type
と、インスタンスを特定するための $.detail.EC2InstanceId
だけです。
Lambda 関数の実装
これを参考に、Lambda を実装してみます。せっかくなので、最近使えるようになった Ruby で実装しました。
追加ライブラリを利用していないため、パッケージのアップロードは不要です。
require 'json' require 'aws-sdk' # 通知先の SNS トピックは Lambda の環境変数に設定しておく TOPIC_ARN = ENV['TOPIC_ARN'] # 実際にプロダクション利用する場合はイベントデータから受け取ったリージョンを指定してください EC2 = Aws::EC2::Resource.new CW = Aws::CloudWatch::Resource.new # サンプルイベントデータを参考に、eventから必要な値を取得して処理する def lambda_handler(event:, context:) instance_id = event['detail']['EC2InstanceId'] case event['detail-type'] # スケールアウトして新しくインスタンスが起動した場合 when 'EC2 Instance Launch Successful' on_launched(instance_id) # スケールインしてインスタンスが削除された場合 when 'EC2 Instance Terminate Successful' on_terminated(instance_id) end end def on_launched(instance_id) instance = EC2.instance(instance_id) return unless instance.exists? return if CW.alarm("ec2-#{instance.id}-cpu-util-notification").exists? # CloudWatch Alarm を作成 CW.client.put_metric_alarm({ alarm_name: "ec2-#{instance.id}-cpu-util-notification", alarm_description: "CPU使用率が 10 分間 80 % を超えていたら通知", # EC2 namespace: 'AWS/EC2', # インスタンスを指定 dimensions: [ { name: "InstanceId", value: instance.id } ], # CPU 使用率の平均 metric_name: 'CPUUtilization', statistic: "Average", # > 80 % threshold: 80, unit: 'Percent', comparison_operator: "GreaterThanThreshold", # 10 分間 (5 分 * 2 回) のうち 2 回 period: 300, evaluation_periods: 2, datapoints_to_alarm: 2, # データなしは無視 treat_missing_data: "ignore", # 閾値を超えたら警告通知 alarm_actions: [ TOPIC_ARN ], # 元に戻ったことも通知 ok_actions: [ TOPIC_ARN ], }) end # インスタンスが削除されたらアラームも削除 def on_terminated(instance_id) alarm = CW.alarm("ec2-#{instance_id}-cpu-util-notification") alarm.delete if alarm.exists? end
Lambda の実行ロールには以下の権限をつけておきます。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "ec2:DescribeInstances", "cloudwatch:PutMetricAlarm", "cloudwatch:DeleteAlarms", "cloudwatch:DescribeAlarms" ], "Resource": "*" } ] }
サンプルイベントデータをテストイベントに設定して、インスタンスIDだけ実在するIDに変更して Lambda をテスト実行してみると、CloudWatch Alarm が作成されます。
aws cloudwatch describe-alarms --alarm-name-prefix ec2-
{ "MetricAlarms": [ { "AlarmName": "ec2-i-xxxxxxxxxxxxxxxx-cpu-util-notification", "AlarmArn": "arn:aws:cloudwatch:ap-northeast-1:999999999999:alarm:ec2-i-xxxxxxxxxxxxxxxx-cpu-util-notification", "AlarmDescription": "CPU使用率が 10 分間 80 % を超えていたら通知", "AlarmConfigurationUpdatedTimestamp": "2018-12-07T08:19:33.703Z", "ActionsEnabled": true, "OKActions": [ "arn:aws:sns:ap-northeast-1:999999999999:system-notification" ], "AlarmActions": [ "arn:aws:sns:ap-northeast-1:999999999999:system-notification" ], "InsufficientDataActions": [], "StateValue": "OK", "StateReason": "Threshold Crossed: 2 out of the last 2 datapoints [0.0 (07/12/18 08:14:00), 0.0 (07/12/18 08:09:00)] were not greater than the threshold (80.0) (minimum 2 datapoints for ALARM -> OK transition).", "StateReasonData": "{\"version\":\"1.0\",\"queryDate\":\"2018-12-07T08:19:34.301+0000\",\"startDate\":\"2018-12-07T08:09:00.000+0000\",\"unit\":\"Percent\",\"statistic\":\"Average\",\"period\":300,\"recentDatapoints\":[0.0,0.0],\"threshold\":80.0}", "StateUpdatedTimestamp": "2018-12-07T08:19:34.311Z", "MetricName": "CPUUtilization", "Namespace": "AWS/EC2", "Statistic": "Average", "Dimensions": [ { "Name": "InstanceId", "Value": "i-xxxxxxxxxxxxxxxx" } ], "Period": 300, "Unit": "Percent", "EvaluationPeriods": 2, "DatapointsToAlarm": 2, "Threshold": 80.0, "ComparisonOperator": "GreaterThanThreshold", "TreatMissingData": "ignore" } ] }
テストデータの detail-type
を EC2 Instance Terminate Successful
に変更して実行すれば、アラームが削除されることも確認できます。
CloudWatch Event Rule の作成
Lambda 関数ができたら、先ほど作りかけた CloudWatch Event Rule を作成します。
イベントタイプに EC2 Instance Launch Successful
と EC2 Instance Terminate Successful
を指定しています。
まとめ
CloudWatch Event Rule と Lambda の組み合わせで AutoScalingGroup で増減するインスタンスに動的にアラームを設定できました。今回は CPU使用率でしたが、 CloudWatch Agent と組み合わせればメモリやディスクの監視通知も可能ですし、ECS タスクでも同様のことができると思います。
2018/12/27 追記
この仕組みを利用した SAM (Serverless Application Model) を OSS として公開しました。 公開した SAM については後日またこのテックブログにポストしたいと思います。
エンジニア募集!!
エムスリーでは、共に医療 × テクノロジーの未来を切り拓いてくれる仲間を募集中です! AWS 以外にも GCP や Firebase などのクラウドも活用しています!興味がある方はカジュアル面談やTechtalkにおこしください!!