MakerelでLamdaのColdStartを監視する、をLamdaでやる
この記事はMackerelアドベントカレンダー7日目の記事です。 こんにちは、MackerelアンバサダーのKuchitamaです。 昨日の記事は、 ore-publicさんの運用中に止めたり上げたりするプロセスをMackerelで監視するでした。
本来、「Makerelでエンジニアの退職後も定期バッチをヘルシーに保つTips(仮)」という記事を書く予定でしたが、12/23(月)の MackerelDay#2 のアンバサダーLTで話すことになったので、予定を変更してお送りしております。 元々の内容にご興味あったかたは是非会場にいらしてください。
AWS Lamdaのモニタリング
さて本題。 AWS Lamdaの監視については、 Mackarelでは AWSインテグレーションで実現できます。
ただ、実運用において重要なメトリクスがありません。 そう、 cold start に関するログです。
cold startの発生率や発生した際の処理時間は、様々な条件で変化します。 そのため、AWS Lambdaを利用する人は様々な方法で、cold startを回避する、もしくは発生時の処理時間を短く抑えています。 この点では非常に多くの施策があるのですが、いざ自分で試すとなると、そういった施策の必要性、緊急性、効果の有無やその大小を計測する必要があります。
そこで、Makerel上でcold startのメトリクスを見れるようにしました。
今回の成果物はGitHubに公開しています。
https://github.com/Kuchitama/mackerel-cloudwatch-logs-metric
cold startの情報はどこにあるか
そもそも、cold startの情報はどこから確認できるのか。 AWS上で確認する方法は2つあります。
X-Ray
X-RayはAWS上のリクエストをトレースするサービスです。
X-Rayで cold start が発生するリクエストを確認すると、下図のように Initialization という項目が表示されます。 この Initialization が、先の図にある Partial cold start に要した時間を指しています。逆にcold startが起こらない場合、Initializationの項目は表示されません。
ただし、 X-Ray でこの情報を確認するには、sampling設定を調整して、 cold startが発生したリクエストがサンプリングされている必要があります。 監視という点では、X-Rayは不向きだと言えるでしょう。
CloudWatch Logs
もう一つ、cold startの情報が出力される場所があります。そう、Lambdaの実行ログです。
この実行ログがどこに保存されるかというと、 AWS CloudWatch Logsに保存されています。
そして、 CloudWatch Logsは Insights という機能で、 ログに対してクエリを発行し、パース、フィルター、集計が可能です。
クエリの発行と結果の取得はAPIが提供されているので、プログラムに落とし込むのも容易です。
https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_Operations.html
- StartQuery
- GetQueryResult
今回は、この機能を使って cold start発生時に Partial cold start にかかる平均時間を取得し、 Mackerelに送信します。
どこでメトリクスを取得するか
severlessアーキテクチャを採用しているのに、監視のためにサーバを用意するのも憚られます。 監視プログラムの実行はLambdaに載せてしまうことにしましょう。 幸い、Lambdaからメトリック送信をされている方はすでにいらっしゃいました。
こちらを参考にしつつ、 mkr のバイナリはDockerから取得することにしました。 リポジトリ内の prepare.sh を実行すると、Linux用の mkrバイナリがリポジトリ内に作成されます。
処理の流れ
Lamda function で実行する一連の処理は全て handler.js
にまとめています。
CloudWatchLogs Insight に投げたクエリは非同期に実行されるので、startQuery と getQueryResult の関数を分けています。 queue内で、startQueryで取得した queryId を DynamoDB に保存し、dequeue で読み込み getQueryResultで結果を取得、その結果をMakerelに送信しています。 あらかじめ、Makerelの AWSインテグレーションで、Lamdaの基本的な監視はできているので、今回は同じサービスに対してサービスメトリックとして投稿しています。
Mackrelで見てみると
AWSインテグレーションで取得した 平均処理時間と 今回作成した initialDurationのグラフを並べてみます。 initialDurationの集計が5分おきに実行されるので、スパイクの発生時間に少し誤差がありますが、2つのグラフを並べて同じ画面で見れるので問題発生時の調査が格段にしやすくなりました。
また、Monitorsで閾値を設定することで、サービスの改修を続けるうちにパフォーマンスが悪化してしまうということも検知できるようになりました。
まとめ
ということで、 Lamdaを使ってLamdaの監視を実現、特に重要となる cold startのメトリクスをMakerel上で監視できるようになりました。
注意点として、 Lambda, DynamoDB, CloudWatchLogs Insightの料金は従量課金となっています。コストに関してはAWSのドキュメントを確認していただきたいですが、監視の間隔や計測するログデータの量のバランスをとって調整してください。
以上、Makerelアドベントカレンダー7日目の記事でした。 明日は、YujiSoftwareさんが何かツールを作って紹介してくださるようです。
また最後になりましたが、今回の内容について、元となるLamda上でのメトリクス投稿について記事を紹介してくださった a-know さん、そもそも記事を残してくださった kmiya_bbm さん、本当にありがとうございました。 あと、記事書いてる間ほったらかしてる息子よ、ごめんね。
Mackerelアンバサダーになりました
昨日、株式会社はてな様からオファーを頂き、Mackerelアンバサダーに就任しました。
Mackerelアンバサダーになりました!長らく愛用してはいたけど、アンバサダーに選んでもらえると思ってなかった。マジで嬉しい!! #mackerelio pic.twitter.com/71L4fk5B5b
— 口玉(I am Scala Ninja) (@Kuchitama) February 20, 2019
いい機会なので、私とMackerelの関わりを振り返ってみようと思います。
使い始め
どうやら、2014年10月1日から使い始めたみたいです。フリュー在籍中で、ソーシャルゲーム開発をしてた時期ですね。 このときは完全に遊び半分で個人で試し始めました。
ただ、メトリクスの登録自体は超簡単に出来た。グラフ見やすいしMackerel便利便利
— 口玉(I am Scala Ninja) (@Kuchitama) October 1, 2014
ずいぶん古い…
そして、その日のうちに独自プラグイン作り始めてる???
ScalaでMackerelにカスタムメトリクス登録するプログラム書けたけど、memoryのグラフみたいに表示できない…tackedの設定がうまく効いてない?それとも設定が間違ってる?experimentalだし仕方ないんだろうか? http://t.co/g0EeWDuIHA
— 口玉(I am Scala Ninja) (@Kuchitama) October 1, 2014
したら、当時はてなCTOだった id:stanaka さんにサポートしていただきました。
@Kuchitama 説明が分かりにくくてすみません。コードを見せていただけるとなにか分かるかもしれません。mackerel-agent-pluginsではstackするプラグインも用意できています。 https://t.co/qt4LQe4qfy
— Shinji Tanaka (@stanaka) October 2, 2014
これで、僕は完全にMackerel推しになりました。だって、こんなサポートされたら好きになってまうやろ。 このとき作ったプラグインはScala製でJVMのメトリクスを取得するものでした。 Scalaの練習のつもりで、作ったのですがJVMの起動のオーバーヘッドが大きくて使い勝手はよくありませんでした。 というか、同様の機能を持ったGo製プラグインが公式にありますしね。
業務導入
シェアウィズ転職直後に入ったプロジェクトでMackerel導入を決めました。 当時、大阪の長堀橋にあったオフィスまで、わざわざ東京からはてなの担当者に説明に来ていただきました。 このときは、サーバ台数もそれほどなかったので、無料枠です。(ここまでしてもらっておきながら…)
あれ? Mackerelのインストールって ansible galaxyに載ってないのか?
— 口玉(I am Scala Ninja) (@Kuchitama) October 26, 2015
このとき、MackerelのAnsible RoleにPR送ってますね。
微力ながら、Mackerelに貢献できました。
その後も、 id:a-know さんが新機能の説明兼ユーザインタビューで、オフィスまで来ていただくなど、相変わらず手厚いサポートを続けていただきました。
しかも、この時もらったグラスは、はじめての子育てに大きく貢献してくれました。
いつも使ってる子ども用のマグカップじゃ、お茶飲まないのにMackerelグラスならグビグビ pic.twitter.com/x7sW6iJsGw
— 口玉(I am Scala Ninja) (@Kuchitama) May 19, 2017
が、割られてしまいました。。。
愛用してたMackerelグラスが割れてしまった…MeはShockhttps://t.co/JsafApoEJN
— 口玉(I am Scala Ninja) (@Kuchitama) November 6, 2017
その後、別の受託開発をしていたプロジェクトで、監視にMackerelを導入しました。 こっちは、ちゃんと(お客さんが)お金を払っての導入で、やっぱりサーバ台数少ないんですが、Mackerelに微力ながら貢献できました。 多分、今もサーバ台数増やしつつ利用は続いていると思います。
そして今
キャッシュビーに移ってからも、引き続きMackerelを(無料プランで)利用しています。
あと、家の Raspberry Pi & Nature Remo と連携させて、室内の気温監視もしています。そういえば、このメトリクス設定する時トラブって、 id:daiksy さんが助けてくれました。多謝
昨日、休日にもかかわらずMackerelの挙動がおかしいと、ディレクターに直接聞いた上、別のメンバーの方まで調べてくれたものの、原因は俺のブラウザに入ってたAdBlockだった。ごめんなさい、ごめんなさい。そして、ちゃんとさっき俺の部屋が30℃超えたって通知来ました。
— 口玉(I am Scala Ninja) (@Kuchitama) September 16, 2018
振り返ってみれば、なんだかんだと、Mackerelとは長い付き合いですね。 本当に微々たることしかできませんが、アンバサダー業がんばります。
Terraform と AWS のちょっとした知見 - Terraformでインフラ構築#2
Terraformを使って、AWSを管理しているプロジェクトでちょっとした作業を行った際の個人的な知見の備忘録。 割としょうもない内容だけど、運用続けていくうえで抑えておきたいのでメモを残す。
Terraformのバージョンは最新に追従できていなくて、 v0.9.11
を使用。
EC2のインスタンスタイプ変更時はEBSはそのまま残る
EC2をスケールアップした際の挙動。 インスタンスがstopされ、インスタンスタイプが指定のものに変更されて、再起動される。 この時、EBSは変更されないので、EBSに保存されていたデータはそのまま引き継がれる。
ここにある作業内容をそのままTerraformがやっている。 https://recipe.kc-cloud.jp/archives/1348
tfファイルの変更内容
resource "aws_instance" "example" { #... - instance_type = "t2.micro" + app_ec2_instance_type = "t2.small" #... }
Elastic IPの設定
EIPを設定する際に、 下記のように aws_eip
だけ設定していると、EC2インスタンスのインスタンスタイプ変更時に再起動された際に EIPがアタッチされなかった。
aws_eip_association
の設定が必要
resource "aws_eip" "example" { instance_id = "i-XXXXXXXX" vpc = true }
tfファイルの変更内容
resource "aws_eip" "example" { - instance_id = "i-XXXXXXXX" vpc = true } + + resource "aws_eip_association" "example" { + instance_id = "i-XXXXXXXX" + allocation_id = "${aws_eip.example.id}" + }
RDSインスタンスタイプ変更時には apply_immediately
を trueにする
これを設定しておかないと、インスタンスタイプが変更されずにやきもきすることになる。というか、やきもきした。 Terraformというか、RDSの知見。
tfファイルの変更内容
resource "aws_db_instance" "example" { # ... - apply_immediately = "false" + apply_immediately = "true" # ... }
RDSインスタンスタイプ変更時にはストレージは変更されない
これはEC2と同様。 当たり前といえば当たり前だが、ちゃんと把握しておかないと作業するときドキドキするので、メモしておく
tfファイルの変更内容
resource "aws_db_instance" "example" { # ... - instance_class = "db.t2.micro" + instance_class = "db.m4.small" # ... }
RDSインスタンスタイプ変更時にエンドポイントは変更されない
これも当たり前だけど、一応メモ。 RDSのエンドポイントは、EC2と違ってIPに依存しないので、再起動が発生しても影響を受けない。
Infrastructure as Code ―クラウドにおけるサーバ管理の原則とプラクティス
- 作者: Kief Morris,宮下剛輔,長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/03/18
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
大阪でReactもくもく会に行ってきた
ちょっと時間が経ってしまったけど、 5/19に大阪で非公開のReactもくもく会というイベントが開かれて、参加してきたのでログを残す。
参加した経緯
最近、業務でそろそろReactをプロダクトに採用する機運が高まってきた。 そんなタイミングで、ちょうど知り合いから、Reactもくもく会やるけど参加しないかと声が掛かった。 Reactやってないけど、ReactNativeは触ってるので、普段からReact周りのキャッチアップはしててTwitterやFBに流してたので、それ見てこえかけてもらえたらしい。
得られた学び
とにかく、めちゃくちゃ学びが多かった。 実務でReactやってる人たちが集まる会だったので、公開可能ラインが判断つかないので、大丈夫そうなところだけ挙げると↓な感じ。
- reflux良さそう
- Airbnbのスタイルガイドはちゃんと読もう github.com
- eslintにも追加しよう github.com
- package.jsonの書き方とか、ちょっとした、でも役に立つテクニックを教えてもらえた
やったこと
業務での採用に向けて、Rails5.1でReactする。 でもnodeのバージョンが古くてはまってて、ほとんど進まなかった…
思ったこと
- WebViewアプリでReactしてる人がいたけど、Reactのコードのところ完全にReactNativeでも通用する感じだった
- ReactNativeが安定するまでは、React+OnsenUI+WebViewとかReact+OnsenUI+(Cordva|Monaca) で良さそう
- Reactファミリーの Learn once, Write Anywhere は本物
- ひょっとして、僕は会の趣旨に会わないくらい初心者かも知れない
共有したこと
- ReactNativeのプロダクト運用のつらみ
- ReactNativeのバージョンアップペースが早い
- マイグレーションつらい
- BreakingChangeが普通にある
今後について
来月も開催予定です。 このもくもく会の趣旨は、 1. 参加者同士のノウハウの交換にフォーカスしたい 2. そのため完全な初心者をフィルタリングするためにしばらくクローズドなイベントとして開催 3. でも、参加者が増えるのは歓迎 といったところです。
プロダクトでReact使うぐらいのノウハウを持ってて、他の人の知見知りたければお声がけください。
ぼくはterraformだけ触ろうと思った - terraform でインフラ構築#1
先日のホッテントリにこんな記事が…
丁度この記事見る直前ぐらいにterraformを仕事で使って、全く同じ気持ちを抱きました。 terraformでもCloudFormationでも、CLIでクラウドインフラ構築とかやってた人は触ったら抜け出せなくなると思います。 ただ、terraformはAWSに限定されないです。強い。
なぜterraform
terraformは安心のHashiCorp製のオーケストレーションツールです。 terraformを使うことで、インフラの Infrastructure as Code が実現できます。
というかインフラに限らず、かなり幅広く XXX as Codeできますね。 社内IT担当者とか結構嬉しいんじゃないでしょうか GitHubのリポジトリやチームメンバーの管理もできるみたいです(なんでもありやな)
改めて言うまでもないかも知れませんが、メリットを挙げるとこんな感じだと思います。
- 設定がバージョン管理できるので、属人性を無くせる
- 設定反映の自動化により手作業によるオペレーションミスが減らせる
- DryRunで実行前に挙動をチェックできるのでオペレーションミスが減らせる
terraformのインストール
Go製なので、↓から、自分のマシン用の実行ファイル落としてきてパス通ったフォルダに置くだけ、ぽん
Download Terraform - Terraform by HashiCorp
簡単ですね
動かしてみる
DryRunして、実際に立ち上げて、そして落とすという一連の操作をやってみます。
1. 設定ファイルを作成
とりあえず、デモとして AWS に Amazon Linux のインスタンスを立ち上げる設定を書きます。
とりあえずのステップワンなので1ファイルに全部書いちゃいます。
適当なディレクトリを作ってその中に、下記のgistの ec2.tf
ファイルを置きます。
$ mkdir terraform $ cd terraform $ vim ec2.tf
ちなみに、インスタンスタイプが t2.micro
でなく t1.micro
になっているのは、とりあえず最小構成としてEC2インスタンスだけを立ち上げたかったからです。
t2.micro
は VPC必須になっていますが、この設定ファイルでは VPCについての設定を書いていないため、EC2インスタンスを立ち上げることができません。
2. DryRunでチェック
設定が書けたら、 plan
で確認します。
$ terraform plan
3. 実際に立ち上げる
問題なさそうなので、インスタンスを立ち上げましょう。 apply
を実行します。
$ terraform apply
マネジメントコンソールを確認すると、インスタンスができてました。
4. 立ち上げたインスタンスを停止する
さて、とりあえず動作確認は充分ですし、お金がもったいないので、いらないインスタンスには退場してもらいましょう。
destroy
を実行します。
$ terraform destroy
ターミネートできました。
こんな感じで、 plan
apply
destory
で、AWSが簡単に操作できるのが terraform です。
もうシェル芸でAWS構築する必要がなくなりました。
Docker上のRedashのバックアップとリストア手順
昨日の書いたエントリがホッテントリ入りしてて、喜ばしい限りです。
悲しい思いをしましたが、いく分か取り戻せた気がします。
今日は、昨日の反省を活かして、トラブルがあっても大丈夫なようにRedashのPostgresデータのバックアップとリストアの手順をまとめます。
ちゃんとリストアの手順までまとめておかないとね!!
でないと、実況Youtubeをするはめになる… (実際昨日は @kiy0taka さんと、 @irof さんに実況しないのって煽られてました)
例によってDocker上で運用している前提です。 AWSとかGCP上で運用しているなら、こちらのドキュメントに従えば多分大丈夫だと思います。
バックアップ手順
ホストOSのシェルで、下記のコマンドを実行すれば、バックアップファイルが手に入ります。
$ cid=`docker ps | grep redash_postgres | awk '{print $1}'` $ docker exec ${cid} /bin/bash -c 'pg_dump -U postgres postgres | gzip > /usr/local/redash_backup.gz' $ docker cp ${cid}:/usr/local/redash_backup.gz redash_backup.gz
たまたま、ホストマシンとして使ってる Mac mini にJenkinsがインストール済みだったので、Jenkinsで定期的に実行できるように、↓の Pipeline Scriptを用意しました。(実際には、更に外部ストレージにコピーしています)
リストア手順
何かあった時に Youtubeで中継することの無いよう、リストアの手順まできっちり用意します。
基本的に、昨日のエントリにあるとおり、Volume名をしていている前提で進めます。
Volume名を指定せずに運用している場合は、 docker-compose down
して、 up
して、データの流しこみを行えば問題ないと思います。
手順は下記の通り
- RedashのDockerコンテナを停止する
- PostgresのVolumeにつながったコンテナを起動
- テーブル削除&テーブル再作成
- バックアップデータの流し込み
- Redashを起動して動作確認
1. RedashのDockerコンテナを停止する
コンテナが稼働中であれば、一旦止めてしまいます
$ docker-compose -f docker-compose.production.yml donw --remove-orphans
2. PostgresのVolumeにつながったコンテナを起動
$ docker run -d -v redash_postgres_data:/var/lib/postgresql/data -p 5432:5432 postgres:9.3 # Docker のcontainer id を確認 $ cid=`docker ps | grep postgres | awk '{print $1}'` $ echo ${cid} ecd9564a3315
3. テーブル削除&テーブル再作成
# コンテナの IPアドレスを取得 $ dbip=`docker inspect {コンテナID} | jq .[].NetworkSettings.IPAddress` $ echo ${dbip} 172.17.0.2 $ psql -h ${dbip} -U postgres template1 psql (9.5.6) Type "help" for help. template1=# DROP DATABASE IF EXISTS postgres; DROP DATABASE template1=# CREATE DATABASE postgres; CREATE DATABASE template1=# \q
4. バックアップデータの流し込み
docker cp
でホストマシン上にあるバックアップファイルを、コンテナにコピーして、流し込みます。
$ docker cp redash_backup.gz {コンテナID}:/usr/local/redash_backup.gz $ docker exec -t {コンテナID} /bin/bash -c 'zcat /usr/local/redash_backup.gz | psql -U postgres -d postgres'
5. Redashを起動して動作確認
$ docker-compose -f docker-compose.production.yml up -d
補足
バックアップ用のスクリプトは、基本的に、JenkinsのJobとして、定期実行する前提で書いたので、 Docker Compose は使っていません。
Redashのディレクトリから手動で実行するのであれば、 docker ps
より docker-compose ps
を使ったほうがいいかも知れません。
PostgresのVolumeに名前をつけていない場合で、マウント中のVolumeを知りたいときは、 docker inspect
が使えます。
情報量が多いので、jq
を使って、絞り込みました。
docker inspect | jq -r .[].Mounts[].Name
読む予定の本
- 作者: 末安泰三
- 出版社/メーカー: ソーテック社
- 発売日: 2016/12/20
- メディア: Kindle版
- この商品を含むブログを見る
- 作者: Adrian Mouat,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/08/17
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
Docker上のRedashのデータをなくしてから復旧するまでの全記録
会社で、Redashを運用してるんですが、そのRedashがぶっ飛んで、もうだめだーと思ったものの、なんとか復旧出来たので、忘れないうちにやったことをまとめておきます。
結論から言うと、 ちゃんとDocker, Docker Composeの運用ノウハウ勉強してから、Redash立てようなって話です。
長いので先にまとめ
- RedashをDockerで運用してた
docker-compose down
したら、データが全て消えた- Volumeを指定してなかったのが原因
- Volumeディレクトリから発掘して事なきを得た
- RedashをDockerで運用するなら
volumes
は指定しような
経緯
会社で、Mac mini に Docker for Mac を入れて、 Redash運用してます。 コイツでプロダクションデータの可視化なんかもやってて、非エンジニアの人に色々見せるのに重宝してました。
で、何が起こったのかというと↓な感じ
Redash v1.0.1 が2日前にリリースされてた!! https://t.co/hAF94yaFSB
— 口玉(I am Scala Ninja) (@Kuchitama) 2017年4月4日
めでたい!!!!
やべぇ!!!調子に乗って、適当にredash updateしようとしたら、うごかなくなったああああ!!!!!!
— 口玉(I am Scala Ninja) (@Kuchitama) 2017年4月4日
(>'A`)>ウワァァ!!Redashがぁぁぁ。
— 口玉(I am Scala Ninja) (@Kuchitama) 2017年4月4日
docker-composeで運用するの、ただでさえノウハウないしリスクでしかなかった…
昨日ぶっとんだredash、 @kiy0taka さんの情報提供によりなんとか復旧出来た!!マジ感謝!!!
— 口玉(I am Scala Ninja) (@Kuchitama) 2017年4月5日
ついでに、redashのバージョンも 1.0.1に上がったので言うことなし
— 口玉(I am Scala Ninja) (@Kuchitama) 2017年4月5日
何やらかしたの?
元々、 Redash のバージョンが v1.0.0-rc.2 でした。 つい先日、v1がリリースされたので、喜び勇んで、運用しているRedashのバージョンをあげようとしました。
Redashのドキュメントを見ながら実行しようとしたんですが、どうもドキュメントは、AWSとかGCPとかで運用してるの前提に記載されてるらしい。
なら、立ち上がってるDocker Container を一度落として、Redashのリポジトリをpullすれば、アップグレードできるんじゃないかって思ったんです。
そして、 docker-compose down --remove-orphans
を実行しました。してしまいました。
で、改めて docker-compose -d -f docker-compose.production.yml up
を実行して、ブラウザで Redashを開いたところ、 Internal Server Error の文字が…
PostgreSQL のデータを確かめるために、↓を実行すると…
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 960b42350d18 redash/nginx:latest "nginx -g 'daemon ..." 56 minutes ago Up 56 minutes 443/tcp, 0.0.0.0:8090->80/tcp redash_nginx_1 e853151fdff4 redash_server "/app/bin/docker-e..." 56 minutes ago Up 56 minutes 0.0.0.0:5000->5000/tcp redash_server_1 fabcbe1076ac postgres:9.3 "docker-entrypoint..." 56 minutes ago Up 56 minutes 5432/tcp redash_postgres_1 50874f74a6fe redis:2.8 "docker-entrypoint..." 56 minutes ago Up 56 minutes 6379/tcp redash_redis_1 0d6d983060b4 redash_worker "/app/bin/docker-e..." 56 minutes ago Up 56 minutes 5000/tcp redash_worker_1 $ docker exec -it fabcbe1076ac /bin/bash root@fabcbe1076ac:/# psql -U postgres psql (9.3.16) Type "help" for help. postgres=# \dt No relations found.
な、何もない!!!!!
@kiy0taka さんの天啓
というわけで、失意にくれて、某slackチャンネルで嘆いていると、 @kiy0taka さんが色々とアドバイスをくれました
kiy0taka [9:37 AM] Data Volumeごと消えちゃったの? kuchitama [9:44 AM] docker立ち上げ直した時に、上書きされたっぽいすね… kiy0taka [9:45 AM] なんと… kuchitama [9:46 AM] docker-compose down がまずかったのかな… kiy0taka [9:48 AM] あーもしかしてvolumeに名前つけてなかった? kuchitama [9:51 AM] これをそのまま動かしてましたね〜 マジメに compose 勉強するか https://github.com/getredash/redash/blob/master/docker-compose.production.yml kiy0taka [9:52 AM] お、まだデータあるかも [9:56] postgresのvolumeが指定されてないから `docker volume ls` したどれかに残ってるかもしれない
復旧するためにやったこと
- Volumeの確認
- PostgreSQLで使ってたVolumeの特定
- Volumeからpg_dumpを取得
- Volume名を指定してVolume作成
- 旧Volumeからデータコピー
Volumeの確認
まずは、今残っているVolumeの確認
$ docker volume list DRIVER VOLUME NAME local 03caf1bf6ea2a81c3c11e699fb994f7f6eecf17ce34a424442d6d52bc461d006 local 066d7758d45f3e3bf53e7a8e6b000a43a0ecbdfd515402118b069b1f587d3f42 local 1cd40529441b334487a45cb46766f020229d78c3ac7f49618bb727898b34e561 local 241c844e7745b0478fe084c8c289e656c7843b9538e2e1789d37e971c5700a2a local 2626cc49fae0425de3814f341b6b0f2d4c039bb8163c8a600100752eeda61d65 local 2d9eca5a4c13a533f7afb47ecffd20726c31dbffd4ab8604b538ceecc32c6401 local 4a80807c699663692c4e20039874851efc3ea1ea1836a40bbab8b7eca062fa7d local 6f1efb9cf644d645d34e4905bf762248b4d3405fdcda8f645214d07d4d12cb27 local 70850d1355368612e3908ec7033ed805ae8f292673597c7b2bdc0bcc7616e14a local 72669aa7e81aef5880e9d9323baadf479d8feeb12a811f6cc8f723533b8d184d local 748cdf747fc8ff16cf5030de1d8dc96ca4af46896988717a310cad31bee98163 local 7aad2bd160a5780b02768da17e30541e68a5ebcf23fbf74319e4e8d157ceb575 local 7c55dc6918b3620f859b8dae54c5dc4cbaa774da77e0bf1505274aa068a53202 local 9817cf6340ec933949f5d021417a885d2ef33544f849053566b6d9f13ad4c07d local 98336ea63f91ec5cf7c19e267daed350167f8040c148b701b0f79027e76e8418 local c1612d3c38d3dd45ae7c17675d751316f418cdbde734650fd2340a90e2e8f739 local c6130e1ce308011c2419bdfb525ea943cc26ff10b00bf958f65e97056be93837 local c8525c0edd65e51b87cee226a213940d9430867d8222f373eaccfcb2f5310041 local dd70b3531d7f6a722a140c1b875cf730d81e5486a93e6e3c674ad436d7457357 local df15a22599482c15b845d3c6fb3e3272b3d0626dee546f55f82ee5a5990f0845 local e0b8c01f409cc73b7c1d040dde080d062b35c46e13b09063078a05e5958f5a5f local f2533120680c4d5377579e25054a3b235a9a8f140474470b41aab5e9220c6056
この中のどれかに、Redashのpostgresデータが残っているはず!
ということで、Volumeのディレクトリを見てみようとホストの /var/lib/docker/volumes
を見ようとしますが、
/var/lib/docker ディレクトリがない!!!
というのも、 Docker for Mac は Apple の Hypervisor 上で動作しています。つまり、仮想マシンにDockerコンテナがいるわけです。 そのため、 /var/lib/docker はホストマシン上には存在していません。
screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
で、Hipervisor上の仮想マシンにアクセスできました。
キヨタカ兄さんマジありがとう!!!
/ # cd /var/lib/docker/volumes/ /var/lib/docker/volumes # ls 03caf1bf6ea2a81c3c11e699fb994f7f6eecf17ce34a424442d6d52bc461d006 066d7758d45f3e3bf53e7a8e6b000a43a0ecbdfd515402118b069b1f587d3f42 1cd40529441b334487a45cb46766f020229d78c3ac7f49618bb727898b34e561 241c844e7745b0478fe084c8c289e656c7843b9538e2e1789d37e971c5700a2a 2626cc49fae0425de3814f341b6b0f2d4c039bb8163c8a600100752eeda61d65 2d9eca5a4c13a533f7afb47ecffd20726c31dbffd4ab8604b538ceecc32c6401 4a80807c699663692c4e20039874851efc3ea1ea1836a40bbab8b7eca062fa7d 6f1efb9cf644d645d34e4905bf762248b4d3405fdcda8f645214d07d4d12cb27 70850d1355368612e3908ec7033ed805ae8f292673597c7b2bdc0bcc7616e14a 72669aa7e81aef5880e9d9323baadf479d8feeb12a811f6cc8f723533b8d184d 748cdf747fc8ff16cf5030de1d8dc96ca4af46896988717a310cad31bee98163 7aad2bd160a5780b02768da17e30541e68a5ebcf23fbf74319e4e8d157ceb575 7c55dc6918b3620f859b8dae54c5dc4cbaa774da77e0bf1505274aa068a53202 9817cf6340ec933949f5d021417a885d2ef33544f849053566b6d9f13ad4c07d 98336ea63f91ec5cf7c19e267daed350167f8040c148b701b0f79027e76e8418 c1612d3c38d3dd45ae7c17675d751316f418cdbde734650fd2340a90e2e8f739 c6130e1ce308011c2419bdfb525ea943cc26ff10b00bf958f65e97056be93837 c8525c0edd65e51b87cee226a213940d9430867d8222f373eaccfcb2f5310041 dd70b3531d7f6a722a140c1b875cf730d81e5486a93e6e3c674ad436d7457357 df15a22599482c15b845d3c6fb3e3272b3d0626dee546f55f82ee5a5990f0845 e0b8c01f409cc73b7c1d040dde080d062b35c46e13b09063078a05e5958f5a5f f2533120680c4d5377579e25054a3b235a9a8f140474470b41aab5e9220c6056 metadata.db
postgreで使ってたVolumeの特定
この中から、Postgresコンテナ で利用してたVolumeを特定します
/var/lib/docker/volumes # find . | grep pg_clog ./241c844e7745b0478fe084c8c289e656c7843b9538e2e1789d37e971c5700a2a/_data/pg_clog ./241c844e7745b0478fe084c8c289e656c7843b9538e2e1789d37e971c5700a2a/_data/pg_clog/0000 ./7aad2bd160a5780b02768da17e30541e68a5ebcf23fbf74319e4e8d157ceb575/_data/pg_clog ./7aad2bd160a5780b02768da17e30541e68a5ebcf23fbf74319e4e8d157ceb575/_data/pg_clog/0000 ./2626cc49fae0425de3814f341b6b0f2d4c039bb8163c8a600100752eeda61d65/_data/pg_clog ./2626cc49fae0425de3814f341b6b0f2d4c039bb8163c8a600100752eeda61d65/_data/pg_clog/0000 ./7c55dc6918b3620f859b8dae54c5dc4cbaa774da77e0bf1505274aa068a53202/_data/pg_clog ./7c55dc6918b3620f859b8dae54c5dc4cbaa774da77e0bf1505274aa068a53202/_data/pg_clog/0000 ./e0b8c01f409cc73b7c1d040dde080d062b35c46e13b09063078a05e5958f5a5f/_data/pg_clog ./e0b8c01f409cc73b7c1d040dde080d062b35c46e13b09063078a05e5958f5a5f/_data/pg_clog/0000 ./c8525c0edd65e51b87cee226a213940d9430867d8222f373eaccfcb2f5310041/_data/pg_clog ./c8525c0edd65e51b87cee226a213940d9430867d8222f373eaccfcb2f5310041/_data/pg_clog/0000 ./98336ea63f91ec5cf7c19e267daed350167f8040c148b701b0f79027e76e8418/_data/pg_clog ./98336ea63f91ec5cf7c19e267daed350167f8040c148b701b0f79027e76e8418/_data/pg_clog/0000 ./1cd40529441b334487a45cb46766f020229d78c3ac7f49618bb727898b34e561/_data/pg_clog ./1cd40529441b334487a45cb46766f020229d78c3ac7f49618bb727898b34e561/_data/pg_clog/0000
候補は8件に絞られました。
そこから、どれが運用してたRedashのPostgresのボリュームなのかを特定するために↓で1つずつ調べて回ります。 1つずつVolumeをバインドした Postgres のコンテナを立ち上げて、DBの中身を確認していく地道な作業です
$ docker run -d -v {絞り込んだvolumeのID}:/var/lib/postgresql/data -p 5432:5432 postgres:9.3 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 295afcefc16c postgres:9.3 "docker-entrypoint..." 11 seconds ago Up 6 seconds 0.0.0.0:5432->5432/tcp objective_feynman $ docker exec -it {↑のコンテナID} /bin/bash # psql -U postgres postgres=# \dt postgres=# select * from users; postgres=# \q # exit $ docker kill {↑のコンテナID}
この繰り返しで、Redashのデータが入っていたVolumeが特定できました。
Volumeからpg_dumpを取得
データが入っていたVolumeが特定できたので、今後なにが起こってもいいようにまずはデータをバックアップしておきます。
DBのデータを確認したのと同じ要領で、Postgresのコンテナを立ち上げて、pg_dumpを実行して、docker cp
でファイルをホストマシンに保存しました。
$ docker run -d -v {絞り込んだvolumeのID}:/var/lib/postgresql/data -p 5432:5432 postgres:9.3 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 295afcefc16c postgres:9.3 "docker-entrypoint..." 11 seconds ago Up 6 seconds 0.0.0.0:5432->5432/tcp objective_feynman $ docker exec -it {↑のコンテナID} /bin/bash # pg_dump -U postgres postgres | gzip > /usr/local/redash_backup.gz # exit $ docker cp 295afcefc16c:/usr/local/redash_backup.gz ~/Desktop
Volume名を指定してVolume作成
まずは、2度とVolumeが変わってしまわないように、Volume名を指定します。 ここでも、 @kiy0taka さんのアドバイスが
このgistにあるように、 postgres
の volumes
と一番下にあるトップレベルの volumes
を指定しました。
この辺の設定は↓に記載が有ります。
そんでもって、一旦 docker-compose up
して、 down
します。
これで、名前のついたVolumeが作られます。
$docker-compose -f docker-compose.production.yml up -d Creating network "redash_default" with the default driver Creating volume "redash_postgres_data" with default driver Creating redash_worker_1 Creating redash_redis_1 Creating redash_postgres_1 Creating redash_server_1 Creating redash_nginx_1 $ docker volume list DRIVER VOLUME NAME # ...中略... local redash_postgres_data
これで、何度 docker-compose up
しても、同じVolumeが RedashのPostgresコンテナにバインドされます。
旧Volumeからデータコピー
新しい redash_postgres_data
Volumeを常に利用するようになったので、このVolumeを元のVolumeで上書きしました。
まず、コンテナを落として、Hipervisor上でファイルを上書きしてしまいます。
$ docker-compose down --remove-orphans Stopping redash_server_1 ... done Stopping redash_redis_1 ... done Stopping redash_postgres_1 ... done Stopping redash_worker_1 ... done Removing orphan container "redash_nginx_1" Removing redash_server_1 ... done Removing redash_redis_1 ... done Removing redash_postgres_1 ... done Removing redash_worker_1 ... done Removing network redash_default $ screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty / # cd /var/lib/docker/volumes/ /var/lib/docker/volumes cp -R 7aad2bd160a5780b02768da17e30541e68a5ebcf23fbf74319e4e8d157ceb575/_data/ redash_postgres_data/ (Ctrl+a):kill
これで、docker-compose up
して、ブラウザでRedashを開いてみると、ちゃんと表示されました。
た、助かったぁぁぁ
composeをちゃんと身に着けたいので
この辺読んでみよう(目次にcomposeの項目がある)
- 作者: 末安泰三
- 出版社/メーカー: ソーテック社
- 発売日: 2016/12/20
- メディア: Kindle版
- この商品を含むブログを見る
- 作者: Adrian Mouat,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/08/17
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
最後に
ほんとに @kiy0taka さんありがとうございました
人って温かい。。。
そういえば、 @kiy0taka 兄さんには、社会人なりたてのころにもこんなこと教えてもらったりしてたなぁ
追加
バックアップとリストアの手順をまとめました