血と汗となみだを流す

クラウドエンジニアになるための修業の場

Javascriptがわからないので少しずつコード読んで和解していく(cognitoと連携したユーザ登録)

概要

  • サーバーレスウェブアプリケーションの構築をやっていた
  • 「モジュール2 ユーザ管理」通りにやっていたら、あまりにも簡単に認証ページが作成できた
  • が、AWS CognitoとJavascriptがどう動いているか全くわからず・・・
  • そろそろちゃんとJavascriptと向き合わないと行けないなと思い、コードを読んで理解することにした

コード

コード読んだ対象

  • ユーザ登録を行っているregister.htmlで読み込んでるjavascript

長くなってしまったので、先にユーザ登録フローのまとめ

  • register.htmlで登録フォーム表示
    • メールアドレス
    • パスワード
    • パスワード確認
  • submitすると js/cognito-auth.js のhandleRegister()が実行される
  • handleRegister()で以下の処理を実行
    • フォームの値を取得する
    • ユーザ登録処理成功/失敗時の処理を定義
    • ユーザ登録処理(register())を実行
  • register()で以下の処理
    • ユーザの登録データオブジェクトを生成
    • cognito-sdkのAmazonCognitoIdentityクラスを使ってcognitoにユーザを登録する

register.html

  • SignUpページ
  • メールアドレスと、パスワード2回入れる
  • formのデータをsubmitしたときの処理はどこかのJSに書いてあるっぽい
  • JS読み込みは以下の箇所
<script src="js/vendor/jquery-3.1.0.js"></script>
<script src="js/vendor/bootstrap.min.js"></script>
<script src="js/vendor/aws-cognito-sdk.min.js"></script>
<script src="js/vendor/amazon-cognito-identity.min.js"></script>
<script src="js/config.js"></script>
<script src="js/cognito-auth.js"></script>
  • js/vendor/ 配下はおそらくjQuery、bootstrapと、cognitoのSDK用のライブラリ
  • js/config.js はcognitoに接続するためのプールIDやアプリクライアントIDの設定用
  • js/cognito-auth.js が怪しいので見ていく

bootstrap

js/cognito-auth.js が呼ばれるときに実行される処理ってどれ?

  • 関数の最初と最後だけ抜き出してみる
(function scopeWrapper($) {
    ..[省略]..
}(jQuery));
  • functionが()でかこまれてるのは「即時関数」にしている
    • 即時関数: 関数を定義すると同時に実行する
    • つまり、js/cognito-auth.jsが読み込まれると同時に上記関数は実行される
  • 後述の「userPoolオブジェクト生成」「onDocReady()」とかもここで実行されている
  • 引数で「jQuery」が渡されて、引数定義の「$」がjQueryオブジェクトとなる
    • つまり、「function scopeWrapper」内の「$」はjQueryオブジェクト

userPoolオブジェクト生成

  • js/cognito-auth.jsの呼び出し時にオブジェクト生成している
  • インラインでやってることを推測しながらコメントを追加
(function scopeWrapper($) {
    // サインイン用のページ
    var signinUrl = '/signin.html';

    // config.jsからAWS Cognitoユーザプールの認証情報を取得
    var poolData = {
        UserPoolId: _config.cognito.userPoolId,
        ClientId: _config.cognito.userPoolClientId
    };

    // userPoolオブジェクト定義
    var userPool;

    // ユーザプールID、アプリクライアントID、リージョンがセットされてなかったら、
    // register.html内にある「noCognitoMessage」部分を表示(エラーメッセージ的なやつ)
    if (!(_config.cognito.userPoolId &&
          _config.cognito.userPoolClientId &&
          _config.cognito.region)) {
        $('#noCognitoMessage').show();
        return;
    }

    // 認証情報から、Cognitoユーザプールオブジェクトを生成
    userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
  • 大まかに
    • config.jsの情報からユーザプールオブジェクトを生成

js/cognito-auth.jsのonDocReady()メソッド

  • formのsubmitの挙動に関する定義っぽい箇所があった
    /*
     *  Event Handlers
     */

    $(function onDocReady() {
        $('#signinForm').submit(handleSignin);
        $('#registrationForm').submit(handleRegister);
        $('#verifyForm').submit(handleVerify);
    });
  • submit()メソッド

handleRegister()メソッド

  • submitされると実行される
  • インラインでやってることを推測しながらコメントを追加
    // 画面上のイベントを引数でもらう
    function handleRegister(event) {

        // 「registrationForm」にあったパラメータの値を変数に入れる
        var email = $('#emailInputRegister').val(); // メールアドレス
        var password = $('#passwordInputRegister').val();   // パスワード
        var password2 = $('#password2InputRegister').val(); // パスワード(確認用)

        // 後ろにあるregister()メソッドの引数として、register()が成功したときに実行するfunctionを定義している
        var onSuccess = function registerSuccess(result) {

            // おそらく成功した場合にresultにユーザ情報が入っている
            var cognitoUser = result.user;

            // コンソールにユーザ名を表示
            console.log('user name is ' + cognitoUser.getUsername());

            // 「ユーザ登録成功してメール送ったから確認しろよ、認証コード入っているから、スパムフォルダとか見てね」的な確認メッセージを定義
            var confirmation = ('Registration successful. Please check your email inbox or spam folder for your verification code.');

            // 確認メッセージがあったら(っていうか上で定義しているから絶対あるのでは・・・)、verify.htmlに画面遷移する
            if (confirmation) {
                window.location.href = 'verify.html';
            }
        };

        // 後ろにあるregister()メソッドの引数として、register()が失敗したときに実行するfunctionを定義している
        var onFailure = function registerFailure(err) {

            // エラーを表示
            alert(err);
        };

        // eventの抑制。おそらくsubmitの処理をここで止めている。
        // register()にわたす引数(function)内で画面遷移を行っているから、submitによる画面遷移処理が不要なんじゃないかな?
        event.preventDefault();

        // パスワードとパスワード確認が同一だったら
        if (password === password2) {

            // register()メソッド(おそらくユーザ登録処理)に処理を渡す
            // 引数は
            //   email: 入力されたメールアドレス
            //   password: 入力されたパスワード
            //   onSuccess: 成功時に実行するfunction
            //   onFailure: 失敗時に実行するfunction
            register(email, password, onSuccess, onFailure);
        } else {

            // パスワード一致しなかったらアラート出して終わり(submitは止められているので元の画面のまま)
            alert('Passwords do not match');
        }
    }
  • 大まかに書くと、以下のような感じ
    • フォームの値を取得
    • ユーザ登録処理(register)の成功時に実行するfunctionを定義する
    • ユーザ登録処理(register)の失敗時に実行するfunctionを定義する
    • submitを止める
    • パスワード一致確認して、ユーザ登録処理を実行

register()メソッド

  • インラインでやってることを推測しながらコメントを追加
    /*
     * Cognito User Pool functions
     */

    // 引数4つ受け取る
    //   email: 入力されたメールアドレス
    //   password: 入力されたパスワード
    //   onSuccess: 成功時に実行するfunction
    //   onFailure: 失敗時に実行するfunction
    function register(email, password, onSuccess, onFailure) {

        // メールアドレスデータの連想配列
        var dataEmail = {
            Name: 'email',
            Value: email
        };

        // AmazonCognitoIdentityクラスにメールアドレスデータをセットしたオブジェクトを生成してるっぽい
        // @see https://github.com/aws-amplify/amplify-js/blob/bfa477662591bbd7a92bbb8486778924589e4adb/packages/amazon-cognito-identity-js/es/CognitoUserAttribute.js#L21
        var attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail);

        // userPoolオブジェクト(後述)のsignUpメソッドに以下の引数を渡している
        // メソッド自体はここか? @see https://github.com/aws-amplify/amplify-js/blob/bfa477662591bbd7a92bbb8486778924589e4adb/packages/amazon-cognito-identity-js/es/CognitoUserPool.js#L93
        //   {string} username: 入力されたメールアドレス(email)
        //   {string} password: 入力されたパスワード(password)
        //   {(AttributeArg[])=} userAttributes: 登録するユーザの属性情報配列([attributeEmail])
        //   {(AttributeArg[])=} validationData: バリデーションデータを入れるっぽいが、ここはnull
        //   {nodeCallback<SignUpResult>} callback: コールバック用の関数定義(function signUpCallback)
        userPool.signUp(email, password, [attributeEmail], null,
            function signUpCallback(err, result) {
                if (!err) {
                    // エラーじゃなかったら成功時に実行するfunctionを実行
                    onSuccess(result);
                } else {
                    // エラーだったら成功時に実行するfunctionを実行
                    onFailure(err);
                }
            }
        );
    }
  • 大まかに書くと、以下のような感じ
    • 引数からユーザ情報に登録するデータオブジェクトを作成
    • AmazonCognitoIdentityオブジェクトに登録データとコールバック用の関数を渡す
    • AmazonCognitoIdentityがsignUp処理を実行して、結果によってfunctionを実行
  • cognitoへの登録はAmazonCognitoIdentityがやってくれる模様

本日javascriptと和解できたところ

  • functionを()で囲むと即時関数となって、function定義と同時に実行される
  • bootstrapはCSSフレームワークで、jqueryが必要
  • submit()メソッドで、submitされた時に実行できるfunctionを定義できる
  • Callback関数の形式
    • 成功時/失敗時に実行するfunctionを変数に入れておいて引数で渡す(なるほどcallback)
  • Cognito-SDKのAmazonCognitoIdentityがいろいろやってくれる(がマニュアルが見つからない)

Elasticsearchを触りながら調べたことのメモ

概要

  • Amazon Elasticsearch Serviceを触って気になったところを調べながらoutputする
  • AWS関係なくElasticsearchの仕様に関することも気になったら調べる

Amazon Elasticsearch Service Domainって何?

Amazon Elasticsearch Service ドメインは、Amazon Elasticsearch Service コンソール、CLI、
または API を使用して作成する Elasticsearch クラスターです。

各ドメインは、指定した コンピューティング リソースおよびストレージリソースを備えたクラウド内の Elasticsearch クラスターとなります。

お客様はドメインの作成や削除、インフラストラクチャ属性の定義、アクセスやセキュリティの制御が可能です。
Amazon Elasticsearch Service ドメインは 1 つまたは複数実行できます。
  • つまりこれ
「Elasticsearch Service domain」は、Elasticsearchクラスターの実行に必要なすべてのリソースのコレクションです。

環境構築

  • terraformAmazon Elasticsearch Serviceを構築
  • Elasticsearch触るだけならローカルでコンテナ動かしてもよかったかもしれない
  • 上記つぶやいたら本業の人からコメントもらえた!
    • Javaが動く環境でtgz解凍→bin/elasticsearchで起動できる
    • 軽量で良いらしい・・・!

データ登録・検索

  • RESTで可能
  • 登録
    • /blogs/article/1
      • 「blogs」というインデックスに
      • 「article」というドキュメントを登録する
      • 「1」「2」「3」は、登録された個々のドキュメントのID
curl -H "Content-Type: application/json" -XPUT https://[es domain]/blogs/article/1 -d '
{
    "title": "Title First",
    "content": "I ate a ramen",
    "tags": ["dev", "calory", "Sugar"]
}
'

curl -H "Content-Type: application/json" -XPUT https://[es domain]/blogs/article/2 -d '
{
    "title": "Title Second",
    "content": "I brunk a beer",
    "tags": ["dev", "alcohol", "purintai"]
}
'

curl -H "Content-Type: application/json" -XPUT https://[es domain]/blogs/article/3 -d '
{
    "title": "Title Third",
    "content": "I go to bed",
    "tags": ["off", "sleep", "heeling"]
}
'
  • データ取得
    • 「content」フィールドが「beer」
$ curl -XGET https://[es domain]/_search?q=content:beer
{
    "title": "Title Second",
    "content": "I brunk a beer",
    "tags": ["dev", "alcohol", "purintai"]
}
}]}}
  • インデックス削除
    • 一発でINDEXごと消せるのちょっと怖い
$ curl -XDELETE https://[es domain]/blogs

mappingとは

  • RDBでいうテーブル定義
  • データの型によって自動でmappingしてくれる
  • 検索の要件によっては、自動でmappingしないで手動でやる
  • INDEXに既にデータが入っている場合、mappingの変更はできない
  • 変更したい場合はaliasを使って、既存のmappingから新しいmapping定義に移行させる方法を取る

  • mapping取得

curl -XGET https://[es domain]/blogs/_mapping
{
    "blogs": {
        "mappings": {
            "article": {
                "properties": {
                    "content": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword",
                                "ignore_above": 256
                            }
                        }
                    },
                    "tags": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword",
                                "ignore_above": 256
                            }
                        }
                    },
                    "title": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword",
                                "ignore_above": 256
                            }
                        }
                    }
                }
            }
        }
    }
}

indexオプション

  • 指定なしの場合は analyzed が適用(解析する)
  • not_analyzed の場合、解析しない

analyzerオプション

わかったこと

  • Amazon Elasticsearch Serviceの「domain」はElasticsearchクラスターの実行に必要なすべてのリソースのコレクション
  • 登録/検索がRESTで簡単にできるの素晴らしい
  • 自動でmappingしてくれる
  • フィールドの形態素解析とかやってくれるのとても便利
  • 以下2つから、マスターデータは別途持っておいたほうが良さそう
    • Elasticsearchのmapping変更はできない。aliasを使って新しいmappingに移行する
    • curl -XDELETE でINDEXごと消える。

あとがき

  • まだまだ奥が深そうだが、一旦概要はつかめたのでここまで
  • 次はAPI Gateway + LambdaからElasticsearch Serviceにアクセスしてみる

t2.micro(EBS:マグネティック)からm5.large(EBS:SSD)にインスタンスタイプをあげたメモ

概要

  • 以下 条件 の移行をやってみた作業メモ

条件

  • インスタンスタイプをt2.microからm5.largeに変更
  • EBSをマグネティックからSSDに変更
  • EBSのボリュームサイズを10GiB→12GiBに増やす

準備

準備1(EC2建てる)

  • t2.microでEC2を建てる
    • ルートデバイス
      • /dev/xvda
      • 8GB
    • ブロックデバイス
      • /dev/xvda
      • /dev/sdb
      • 10GB
    • VPCとかSubnetは今回触りたいところじゃないのでdefault
    • SSHするためにPublic IP付与

準備2(ブロックデバイスパーティション分割)

  • EC2にssh接続
$ ssh -i [秘密鍵] ec2-user@[PublicIP]
$ sudo cfdisk /dev/sdb
                                                                                      cfdisk (util-linux 2.23.2)

                                                                                  ディスクドライブ: /dev/sdb
                                                                              サイズ: 10737418240 バイト. 10.7 GB
                                                             ヘッド: 255   トラック当たりのセクタ: 63   シリンダ: 1305

         名前                          フラグ                       パーティションタイプ      FSタイプ                                [ラベル]                            サイズ (MB)
 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
                                                                     基本/論理                空き領域                                                                     10737.42                  *

            [ヘルプ ]     [新規作成]    [  表示  ]    [  終了  ]    [  単位  ]    [書き込み]


                                                               空きパーティションから新しくパーティションを作成
  • 選択項目
    • [新規作成]
    • [基本領域]
    • [書き込み]
  • ブロックデバイスを一覧表示
$ lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda    202:0    0   8G  0 disk
└─xvda1 202:1    0   8G  0 part /
xvdb    202:16   0  10G  0 disk
└─xvdb1 202:17   0  10G  0 part
  • ext3でフォーマット(なぜext3かは◯◯上の理由)
$ sudo mkfs -t ext3 /dev/sdb1
mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 2621432 4k blocks and 655360 inodes
Filesystem UUID: d46d0ff2-5c03-45d6-ae8d-319e5ba3a945
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

準備3(ブロックデバイスをマウントする)

$ sudo mkdir /data
$ lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda    202:0    0   8G  0 disk
└─xvda1 202:1    0   8G  0 part /
xvdb    202:16   0  10G  0 disk
└─xvdb1 202:17   0  10G  0 part
  • fstab修正
$ sudo vim /etc/fstab

(追加)
/dev/xvdb1  /data       ext3    defaults        0   0
  • マウント
$ sudo mount -a
  • 確認
$ df -h
ファイルシス   サイズ  使用  残り 使用% マウント位置
devtmpfs         483M   68K  483M    1% /dev
tmpfs            493M     0  493M    0% /dev/shm
/dev/xvda1       7.8G  1.1G  6.7G   14% /
/dev/xvdb1       9.8G   23M  9.2G    1% /data
$ lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda    202:0    0   8G  0 disk
└─xvda1 202:1    0   8G  0 part /
xvdb    202:16   0  10G  0 disk
└─xvdb1 202:17   0  10G  0 part /data

変更作業

参考

EBSの変更

  • [EC2]-[ボリューム]-[アクション]-[ボリュームの変更]
    • マグネティック → SSD
    • 10Gib → 12GiB

インスタンスタイプ変更

ディスクリサイズ

  • disk確認(m5はNVMeだった)
$ df -h
ファイルシス   サイズ  使用  残り 使用% マウント位置
devtmpfs         3.8G   56K  3.8G    1% /dev
tmpfs            3.8G     0  3.8G    0% /dev/shm
/dev/nvme0n1p1   7.8G  1.1G  6.7G   14% /
$ lsblk
NAME          MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme0n1       259:2    0   8G  0 disk
├─nvme0n1p1   259:3    0   8G  0 part /
└─nvme0n1p128 259:4    0   1M  0 part
nvme1n1       259:0    0  12G  0 disk
└─nvme1n1p1   259:1    0  10G  0 part
$ sudo growpart /dev/nvme1n1 1
/usr/bin/growpart: 行 170: シリンダ数*255、63*: 構文エラー: オペランドが予期されます (エラーのあるトークンは "シリンダ数*255、63*")
$ locale
LANG=ja_JP.UTF-8
LC_CTYPE=ja_JP.UTF-8
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=
$ export LANG="en_US.UTF-8"
$ sudo growpart /dev/nvme1n1 1
CHANGED: partition=1 start=63 old: size=20971457 end=20971520 new: size=25157727,end=25157790
$ lsblk
NAME          MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme0n1       259:2    0   8G  0 disk
├─nvme0n1p1   259:3    0   8G  0 part /
└─nvme0n1p128 259:4    0   1M  0 part
nvme1n1       259:0    0  12G  0 disk
└─nvme1n1p1   259:6    0  12G  0 part
$ sudo resize2fs /dev/nvme1n1p1
resize2fs 1.42.12 (29-Aug-2014)
open: No such device or address while opening /dev/nvme1n1p1
  • 一旦再起動
- sudo reboot
  • 再実施:拡張デバイス名変更(エラー)
$ sudo resize2fs /dev/nvme1n1p1
resize2fs 1.42.12 (29-Aug-2014)
Please run 'e2fsck -f /dev/nvme1n1p1' first.
$ sudo e2fsck -f /dev/nvme1n1p1
e2fsck 1.42.12 (29-Aug-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/nvme1n1p1: 11/655360 files (0.0% non-contiguous), 79696/2621432 blocks
  • 再実施2回目:拡張デバイス名変更(エラー)
$ sudo resize2fs /dev/nvme1n1p1
resize2fs 1.42.12 (29-Aug-2014)
Resizing the filesystem on /dev/nvme1n1p1 to 3144715 (4k) blocks.
The filesystem on /dev/nvme1n1p1 is now 3144715 (4k) blocks long.
  • fstab修正
$ sudo vim /etc/fstab

(変更)
/dev/xvdb1  /data       ext3    defaults        0   0
↓
/dev/nvme1n1p1  /data       ext3    defaults        0   0
  • mount
$ sudo mount -a
  • 確認
$ df -h
ファイルシス   サイズ  使用  残り 使用% マウント位置
devtmpfs         3.8G   56K  3.8G    1% /dev
tmpfs            3.8G     0  3.8G    0% /dev/shm
/dev/nvme0n1p1   7.8G  1.1G  6.7G   14% /
/dev/nvme1n1p1    12G   26M   12G    1% /data

要検証箇所

  • growpartしたあと、resize2fsしたらなぜかデバイスが認識されなかった・・・(rebootで認識された)
open: No such device or address while opening /dev/nvme1n1p1

ACMで管理しているSSL証明書が、CloudFrontに反映されない場合の対応

状況

  • CloudFrontでSSLを使用している
  • SSL証明書ACM(AWS Certificate Manager)で管理している
  • ACMSSL証明書の再インポートを行ったが、CloudFrontで配信しているコンテンツの証明書が更新されない

原因

対応

  • 今回はDistributionの値を何も変更せずに「Yes! EDIT」ボタンを押す
  • Distributionのステータスが「in Progress」→「Deployed」になる
  • 証明書が反映される

おにぎりを綺麗な三角形で作る知見を頂いたのでまとめ

概要

  • おにぎりがうまく握れなかった。
  • 握り方がわからない旨をツイートしたらいろいろな知見を頂けた。
  • 頂いた知見をまとめました

元ツイート

頂いた知見

  • 手のひらの中で三角形をイメージする
    • エガちゃんが喋ってるときの手がいい角度かも
  • 力を入れすぎずに何度か角度を変える
  • 片方の手で山を作る
  • 思ったより鋭角
    • 丸いのも好き
  • 諦めてまんまるにする
  • 【コツ】おにぎりを三角形に握れない人が勘違いしている3つのこと!
  • 数作って練習(俺はできるで)
  • 東北はまんまるとか平たい丸が多い
  • 三角にするための治具を作る(買う)
  • 手早くキュッと、外はしっかり中はふっくら(居酒屋で学ぶ)

(追加)めぐみさんから頂いた知見

  • お茶碗にご飯を入れてゆらす
  • ラップにのせる
  • 四方向から包む(利き手によるが)
  • 右手を半円にし、左手を人差し指中指薬指と手のひらで山を作る
  • くるくる回しながら軽く握ってゆく

勝手にまとめると

  • おにぎりは三角以外でもOK
    • まるや、平たいまる、俵型など
  • 三角をイメージする際に、
    • 左手は固定して支える役目(土台的な)
    • 右手で三角(鋭角)。エガちゃんの手
  • 練習しろ
  • 道具(おにぎり用の三角形の型)で冪等性を担保する

Elasticsearch Serviceへcurlでデータを登録しようとしたらエラー

環境

  • AWSのElasticsearch Service
  • バージョン: 6.3

発生したエラー

  • 実行したコマンド
curl -XPUT https://[ES_ENDPOINT]/blog/article/1 -d '
{
    "title": "test title 001",
    "content": "test content 001",
    "tags": ["aws", "infra"]
}
'
  • 発生したエラー
{"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406}%

原因

In earlier releases of Elasticsearch, the content-type was optional, and if it was missing or not recognised, then the server would sniff the content and make an educated guess regarding the content-type. 
That will no longer happen in Elasticsearch 6.0 - every incoming request needs to have the correct content-type for the body it contains.

正しいコマンド

  • Content-Type を指定する
curl -H "Content-Type: application/json" -XPUT https://[ES_ENDPOINT]/blog/article/1 -d '
{
    "title": "test title 001",
    "content": "test content 001",
    "tags": ["aws", "infra"]
}
'
  • 成功した際の戻り値
{"_index":"blog","_type":"article","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1}%

Amazon RDSのリードレプリカ台数について(MySQL)

Amazon RDS Read Replicaとは?

この記事の対象

リードレプリカを作れる台数

  • 1つのmasterから作れるリードレプリカは5台がMAX
  • AWSサポートに問い合わせることにより上限緩和できる「リードレプリカの上限数」とは異なる
    • AWSサポートで上限緩和できるのは「トータルのリードレプリカ数」
    • (ex)
      • master A のリードレプリカ x 4
      • master B のリードレプリカ ← トータル5台なので1台しかレプリカを作れない
        • 緩和後、2台以上作れる
        • が、 1つのmasterから作れるリードレプリカは5台 は緩和されない

リードレプリカのリードレプリカ

  • MySQL5.6以降のバージョンなら、リードレプリカをソースにリードレプリカを作成できる
    • ソースのDBインスタンスMySQLが5.6以上であること
    • 自動バックアップを有効であること
  • リードレプリカのリードレプリカの・・・・は4つ以上作ることはできない
    • (ex)
      • master - ReadReplica1(OK) - ReadReplica2(OK) - ReadReplica3(OK) - ReadReplica4(NG)
  • MySQL および MariaDB リードレプリカ