AWS ElasticSearch Service の手動スナップショットを取得する
掲題の対応を実施したので、内容をメモしておきます。
AWSはElastic Search Serivceを使えば、Elastic Searchを簡単に起動でき、Kibanaも入っている状態でスタートできるのですが、 データの手動バックアップアップ、リストアに関してはひと手間かかります。
手順
以下の公式の手順を実施するだけで終わりなのですが、やや行間を埋める必要があったので、そこを埋めつつ記載します。
上記を見ると、自動スナップショットはよろしく取ってくれるようですが、手動スナップショットはいくつかの手順を踏む必要があると書いています。 自分は、Elastic Searchドメインを削除する前に、事前にバックアップを取得しておく必要があり、手動バックアップを行いました。
前提条件
なにやら実施する前にいくつかの前提条件があるそうですが、まとめると..
- Elastic Searchのスナップショット格納先のS3バケットを作成する必要がある。(Glacierはだめ)
- ElasticSearch Service に S3にデータを保存できるロールを作成し、付与する必要がある。
- (IAMに慣れていないと分かりづらいかもですが)、ElasticSearch Serviceがこのロールを扱える(引き受けられる)ように IAMロールに
Principal
を設定する必要がある。 - ロールの付与はElasticSearch Serviceのアクセスポリシーの設定から行う。
- (IAMに慣れていないと分かりづらいかもですが)、ElasticSearch Serviceがこのロールを扱える(引き受けられる)ように IAMロールに
Principal の設定は以下のIAMロール画面の 信頼関係
タブから設定できます。
設定したprincipal は以下のとおりです。(公式のそのまま)
{ "Version": "2012-10-17", "Statement": [{ "Sid": "", "Effect": "Allow", "Principal": { "Service": "es.amazonaws.com" }, "Action": "sts:AssumeRole" }] }
このロールに、ポリシーを追加してやります。今回は面倒なのでインラインポリシーで追加しました。 S3バケット名を、バックアップ用に作成したバケット名に変更してやります。
{ "Version": "2012-10-17", "Statement": [{ "Action": [ "s3:ListBucket" ], "Effect": "Allow", "Resource": [ "arn:aws:s3:::s3-es-backup" ] }, { "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Effect": "Allow", "Resource": [ "arn:aws:s3:::s3-es-backup/*" ] } ] }
さらに、次にElastic Search Serviceのアクセスポリシーを修正して、先程作成したロールの付与と、スナップショット作成のために HttpsPut
を許可してやります。こちらはElasticSearch Serviceの画面から 修正します。
こちらは公式のものをコピペすると何故かエラーになり、 "Principal" を追加してやると変更できました。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "iam:PassRole", "Resource": "arn:aws:iam::xxxxxxx:role/ESTheSnapshotRole" }, { "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "es:ESHttpPut" ], "Resource": "arn:aws:es:ap-northeast-1:xxxxx:domain/es-target-domain/*" } ] }
スナップショットリポジトリの登録
通常であれば PUT elasticsearch-domain-endpoint/_snapshot/my-snapshot-repo-name
でスナップショットリポジトリを登録できるのですが、AWSの ElasticSearch ServiceはCurlでは対応できず、Pythonなどのライブラリを使用する必要があるようです。これもサンプルを指示通りに修正し、実行します。
import boto3 import requests from requests_aws4auth import AWS4Auth host = 'https://xxxxxxxx.ap-northeast-1.es.amazonaws.com/' # include https:// and trailing / region = 'ap-northeast-1' # e.g. us-west-1 service = 'es' credentials = boto3.Session().get_credentials() awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token) # Register repository path = '_snapshot/es-snapshot-repo-name' # the Elasticsearch API endpoint url = host + path payload = { "type": "s3", "settings": { "bucket": "s3-es-backup", "region": "ap-northeast-1", # for all other regions "role_arn": "arn:aws:iam::xxxxxxx:role/ESTheSnapshotRole" } } headers = {"Content-Type": "application/json"} r = requests.put(url, auth=awsauth, json=payload, headers=headers) print(r.status_code) print(r.text)
上記を実行して {acknowledgement: true}
が返ってきたので、作成できたようです。
スナップショット取得
スナップショット取得は上記に続き以下を実行します。
path = '_snapshot/es-snapshot-repo-name/last-snapshot' url = host + path r = requests.put(url, auth=awsauth)
これを実行した後、 GET /_snapshot/es-snapshot-repo-name/_all
でスナップショット作成状態を確認し、
SUCCESS
担っていることを確認し、S3にも出力されていることを確認しました。
リストア
リストアに関しては、長くなってきたので、割愛します..
所感
いつも雰囲気でIAMを使用して理解していないせいもあり、少し予想より時間がかかってしまいました。 Elastic Search Serviceはとても簡単に利用開始できるのですが、こいう言った細かい運用は少し複雑な印象を受けます。このあたりももっとさくっとできればいいのですが...
WordpressのカスタムフィールドをREST API経由で更新する
掲題の対応方法をメモっておきます。 PHPは全然得意ではないのですが、Word Pressが世の中で流行っている以上、 なかなか逃げられず、調査したので、その内容を残しておきます。
課題
カスタムフィールド (今回は Smart Custom Fieldプラグインを使用)を REST API経由で投稿(Create)したい
調査内容
記事投稿なので、エンドポイントは /wp/v2/posts
で良さそうです。
アクセストークン周りの認証の方法は以下の記事を参考にさせていただきました。ここでは割愛します。
これで通常のTitleやらContentは投稿できました。問題はカスタムフィールドです。
いろいろ調査すると、どうやら register_rest_field
という関数を使用すると、既存のREST APIを拡張できるようです。
こいつをfunctions.php内で呼んでやります。
add_action( 'rest_api_init', function() { register_rest_field( 'post', // post type 'post_meta', // rest-apiに追加するキー array( 'get_callback' => function( $object, $field_name, $request ) { ... }, 'update_callback' => function( $value, $post, $field_name) { ... }, 'schema' => null, ) ); });
という風にかいてやれば、既存のpostエンドポイントを拡張し、post_meta情報を受け付けるようになるようです。 値の取得、更新はget_callback, update_callbackに処理を記述してやれば良さそうです。
細かい処理は説明すると煩雑になるので、実際にうごいたサンプルを備忘がてら載せておきます。
'get_callback' => function( $object, $field_name, $request ) { // 出力したいカスタムフィールドのキーをここで定義 $meta_fields = array( 'field1', 'field2' ); $meta = array(); foreach ( $meta_fields as $field ) { $meta[ $field ] = get_post_meta( $object[ 'id' ], $field, false ); } return $meta; }, 'update_callback' => function( $value, $post, $field_name) { if (!$value) {return;} foreach($value as $key => $data){ if(is_array($data)){ foreach($data as $record){ add_post_meta($post->ID, $key, $record); } }else{ add_post_meta($post->ID, $key, $data); } } }
update_callbackはエラー判定などかなり端折っていますが、Smart Custom Fieldは繰り返し設定ができるので、 その場合配列が渡させるので処理を分けています。
所感
自分だけかもしれませんが、WordpressはREST APIのリファレンスはどうも分かりづらい気がしていて、 なかなかこういった情報が探しづらいなと言う印象を受けました。 あんまりREST API経由で カスタムフィールドを更新したいという要件自体レアかもしれないですが、残しておきました。
jsonwebtokenでAuth0で発行されたJWTを検証する
掲題の対応でWebで調べてもすぐに出なかったのでメモしておきます。
Auth0とFirebaseを連携させたいときに、まずCloud Functionで Auth0で発行されたJWTの検証を 行おうと思ったのですが、その手順と調べた内容です。
Auth0公式に方法がざっくり書いています。
大きく3つ方法があり、
- ASP.NET Coreのようなミドルウェアを使う。
- jwt.ioが提供しているライブラリを使う。
- nodeを使うなら jsonwebtoken というライブラリでいいよ
- 自前で検証処理を実装する。
とのことです。 今回はCloud Function上で検証がしたいので、node-jsonwebtoken のライブラリを使用することにします。
これを見ると、 ここ に
jwt.verify(token, secretOrPublicKey ...)
という関数が用意されているので、これを使用すれば良さそうです。
tokenが 検証したいJWT, secretOrPublicKeyは シークレットもしくは公開鍵を入れるようです。
今回JWTの生成アルゴリズムがRSA256だったので、公開鍵を入れる必要がありそうです。
この公開鍵は、Auth0 は JWKs という形式で配っているそうです。
↑を読むと、 https://YOUR_DOMAIN/.well-known/jwks.json
にGETするとJWKsが返ってくるようです。
しかしこれはそのままでは公開鍵としては使えないようです。
適当にggるとどうやらjwkから公開鍵を生成してやらないと行けないようです。 jwk-to-pemというライブラリがあったので、そちらを使います。
const jsonwebtoken = require('jsonwebtoken') const jwkToPem = require('jwk-to-pem'); const pem = jwkToPem(jwk) // jwk は auth0からGETしたjwksの1つ const result = jsonwebtoken.verify(jwt, pem)
みたいな感じで無事検証できました。
追記
このメモを書いた後で見つけたのですが、 "jwks-rsa" というライブラリもあって、こちらを使ったほうが楽だったかもです。
所感
公式ではサラッと書いていましたが、 jwksがどこにあるのや、そこから公開鍵を生成しないといけないなど、 基本が分かっていなかったので、少々手間取りました。 似たような問題でつまづくケースがあるかもなので、残しておきました。
FireStoreの定期バックアップを実施したメモ
Firebaseを使用している新規Webサービスで、いい加減バックアップを取っておかないとまずいよね、ということがあり、バックアップを取ってみたんですが、その内容のメモになります。
前提
- FirebaseのBlazeプラン以上でないと実行できません。
手順
以下の2つの公式の説明を見れば終わりなのですが、以下手順と所感です。
始めてみたとき、あれ、2つの方法があるのかなと思いましたが、よくよく見ると、1つ目の記事はgcloud コマンドラインツールで import / export する方法で、 2つ目の記事は exportを cloud function で定期実行する方法、ということになります。なので定期的なバックアップ取得〜リストアのテストまでやるには、上記の両方の記事を参照する必要があります。
定期的なバックアップ取得(Export)
ここでは詳細は手順を書いても公式と同じになってしまうので、ざっくり概要のみ書くと、
- cloud functionを作成してデプロイする(Blazeプランじゃないとデプロイ時にエラーになる)
- GCPから新しいバックアップ保存用のバケットをCloud Storageに作成する。(Firebaseコンソール画面からは見えない)
gcloud
,gsutil
コマンドで エクスポートして保存できる権限を付与する。(gcloud
コマンドがインストールされてない場合インストールする。後のリストアでも使用する)- GCPのCloud Scheduler から、作成した定期バックアップを手動で起動して、 Cloud Storageに保存されることを確認する。
と行った感じです。普段の開発でFirebaseのみ使用している場合、GCPのツール入れたり管理画面に入ったりで、多少戸惑いがあるかもしれません(私はありました)
そして公式には明示的な記載は見つからなかったのですが、エクスポートされたデータはJSONのようにきれいなデータとして出力されません。なのでバックアップが正常に行われているかどうかは、リストアして確認する必要がありそうです。
リストア(import)
インポートは gcloud
コマンドを使用してExportしたバケットとバックアップ時のPrefixを指定すればOKです。
ただ、リストア時には以下のような注意事項がありました。
データをインポートすると、データベースの現在のインデックス定義を使用して必要なインデックスが更新されます。エクスポートにインデックスの定義は含まれません。
インポートでは、新しいドキュメント ID が割り当てられません。インポートでは、エクスポート時に取得された ID を使用します。ドキュメントをインポートするときに、ドキュメントの ID が予約され、ID の競合が防止されます。同じ ID のドキュメントがすでに存在する場合、インポートを行うと既存のドキュメントが上書きされます。
データベース内のドキュメントがインポートの影響を受けない場合、そのドキュメントはインポート後もデータベースに維持されます。
特定のコレクションのみのリストアに関して
特定のコレクション グループのインポートがサポートされるのは、特定のコレクション グループをエクスポートした場合のみです。すべてのドキュメントのエクスポートから特定のコレクションをインポートすることはできません。
要するに、フルバックアップで取った場合は、全戻ししかできないようです。 また単純にドキュメントのIDで上書きなので、完全にバックアップ時の状態にそのまま戻るわけでは無さそうで、そうするには事前にコレクションの削除などが必要そうでした。
所感
FirebaseはかんたんなWebサービスならこれ一つでいい感じに開発が進められるのですが、FireStoreがMySQLなどのよくあるRDBとクセが違うのである程度慣れが必要なのですが、さらに運用面でも馴染んでおく必用がありそうです。小さなサービスならとりあえずRDBのダンプ取っておけばなんとかなりましたが、バックアップやリストアの検証してたら初回は時間がかかってしまいました。
こういった運用の準備や検証とかもいれると、いくらFirebaseがさくっと作れると言っても、初回は慣れている技術スタックのほうがやはり早いです。
一度設定して理解してしまえばそんなに難しいことはなく、次回同じことをやる際にはすんなり行けるとは思うので、本当にサクッと作りたいときにサクッと作るには、日頃からこういった細かいテストや検証を経て慣れ親しんでおく必要がありそうです。
Kubernetes for Macから ECRのイメージを取得する方法
Kubernetes for Mac (正確にはDocker for Mac上で動いているKubernetes) でテストするときには、ローカルでDockerイメージ作ってそれを使用することが多いのですが、 ローカルのkubeから直接ECRに登録されている Private Dockerイメージを読みたいことがあったので調べました。 ググったらすぐ出てくる方法なんですが、一応メモっておきます。
手順
前提として、 awscliやcredentialの設定はできてるとします。
ログインできるかの確認
$ $(aws ecr get-login --region ${AWS_REGION} --no-include-email)
まずはdocker loginが動くか確かめます。
AWS_REGISONは適宜指定します。東京の場合は ap-northeast-1
ですね。
次に docker-registryのsecretを作成します。
$ ecr_login="$(aws ecr get-login --no-include-email --region $AWS_REGION)" $ kubectl create secret docker-registry ecr \ --docker-username=`echo $ecr_login | awk '{print $4}'` \ --docker-password=`echo $ecr_login | awk '{print $6}'` \ --docker-server=`echo $ecr_login | awk '{print $7}'`
次にPrivate Registryのイメージを読み込むyamlに、以下のように imagePullSecrets
を指定してやります。
あとはこのyamlファイルを applyすればOKです.
参考
- 作者:山田 明憲
- 発売日: 2018/08/25
- メディア: Kindle版