のべラボ.blog

Tech Blog | AWS や サーバーレスやコンテナ などなど

AWS CloudFormation の組込み関数 Ref と Sub について

仕事柄、様々な AWS CloudFormation テンプレートを参照することがありますが、あるテンプレートを見ていた時、ふと、「あれ?ここで使っているは 組込み関数は Subでなくて Refでもいいんじゃない?」と気づくことがありました。

その時の経験から、組込み関数 Ref と Sub についてまとめてみたいと思います。

AWS CloudFormation の組込み関数については、次のドキュメントもあるので、あわせてご参照ください。

組み込み関数リファレンス | AWS CloudFormation ユーザーガイド


まず、次のCloudFormation テンプレートのサンプルをみてみましょう。 これは、Amazon S3 バケットをパラメータで指定した名前で 作成するテンプレートです。

Parameters:
  BucketName1:
    Description: 'Bucket Name #1'
    Type: String
    Default: 'tnobe-sample1-bucket-1'
  BucketName2:
    Description: 'Bucket Name #2'
    Type: String
    Default: 'tnobe-sample1-bucket-2'
Resources:
  MyBucket1:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: !Ref BucketName1   # Ref関数で参照
  MyBucket2:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: !Sub ${BucketName2} # Sub関数で参照

このテンプレートでは、Parameters セクションのパラメータ名を Ref 関数と Sub 関数で参照して、S3のバケット名に指定しています。 Ref 関数では、そのままパラメータ名 (BucketName1) を指定していますが、Sub 関数では、${BucketName2}と、$ { }で囲んでいます。

記述方法は異なりますが、どちらもパラメータの値を参照することができます。


次に、2つ目のサンプルをみてみましょう。

Parameters:
  BucketName1:
    Description: 'Bucket Name #1'
    Type: String
    Default: 'tnobe-sample2-bucket-1'
  BucketName2:
    Description: 'Bucket Name #2'
    Type: String
    Default: 'tnobe-sample2-bucket-2'
Resources:
  MyBucket1:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: !Ref BucketName1
        Tags:
        - Key: Region
          Value: !Ref 'AWS::Region'   # 疑似パラメータをRef関数で参照
  MyBucket2:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: !Sub ${BucketName2}
        Tags:
        - Key: Region
          Value: !Sub ${AWS::Region}  # 疑似パラメータをSub関数で参照

2つ目のテンプレートでは、AWS::Region という疑似パラメータを Ref 関数と Sub 関数で参照して、S3バケットのタグの値を設定しています。

疑似パラメータとは、事前に定義されているパラメータで、例えば AWS::Region であれば、そのテンプレートでCloudFormationスタックを作成するAWSのリージョンのIDが自動的に設定されます。

次のドキュメントに他の疑似パラメータの記載もあるので、参考にしてください。

擬似パラメータ参照 | AWS CloudFormation ユーザーガイド

この2つ目のサンプルでも、Ref 関数では、そのまま疑似パラメータ (AWS::Region) をそのまま指定していますが、Sub 関数では、${AWS::Region}と、$ { }で囲んでいます。

記述方法は異なりますが、疑似パラメータであっても、Ref 関数でも Sub 関数でも値を参照することができます。


では、3つ目のサンプルをみてみましょう。

Parameters:
  BucketId1:
    Description: 'Bucket Id #1'
    Type: String
    Default: '1'
  BucketId2:
    Description: 'Bucket Id #2'
    Type: String
    Default: '2'
Resources:
  MyBucket1:
      Type: AWS::S3::Bucket
      Properties:
        # Ref関数で参照した値を他の文字列と連結したい場合
        BucketName: !Join 
                      - ''
                      - - 'tnobe-sample3-bucket-'
                        - !Ref BucketId1
  MyBucket2:
      Type: AWS::S3::Bucket
      Properties:
        # Sub関数で参照した値を他の文字列と連結したい場合
        BucketName: !Sub 'tnobe-sample3-bucket-${BucketId2}'

3つ目のサンプルでは、文字列 tnobe-sample3-bucket- と、パラメータの値を連結して、バケット名に設定したいという意図があります。

この場合、Ref 関数を使う方法と Sub 関数を使う方法では、記述方法が異なることがわかります。

Ref 関数の場合は、他の文字列と連携つするために、 Join という関数を使っています。

一方、Sub 関数の場合は、文字列の中に、${BucketId2} が埋め込ている形で記述します。

この場合だと、Ref関数 + Join 関数の記述より、Sub 関数の方がシンプルに記述できますね。


まとめ

  • AWS CloudFormation の組込み関数 Ref と Sub では、単一の値を参照するという面では、どちらも同じように使用できます。
  • AWS CloudFormation のドキュメントにも記載はありますが、もともと Ref 関数は、パラメータやテンプレートのリソースの論理IDを参照する用途で使用します。 また、Ref 関数であれば、${ } で囲む必要がないので、単一の値を参照するだけであれば、Ref 関数の使用が適切でしょう。
  • ただし、文字列を連結したい場合は、Sub 関数の方がシンプルに記述できるということは、覚えておいた方が良さそうですね!

Amazon Linux 2 に microk8s をインストールする方法

先日、Amazon Linux 2 に minikube をインストールする方法という記事を書きましたが、今回は microk8s をインストールする方法をまとめていきます。

インストール手順は、 Canonical 社の microk8s の Getting Start のページに記載されていますが、まず推奨される環境を用意します。

Getting Startのページでは次のような環境が推奨されています。

  • 最低 20G のディスク空き容量
  • 最低 4G のメモリ

そのため、EC2 インスタンスインスタンスタイプは t3.medium を選択して、EBS のストレージ容量も 余裕をもって 30GB に設定することにしました。 t3.medium は、AWSの無料利用枠ではないためご注意ください。

また、EC2インスタンスに接続した後のシェルを bash にしておきましょう。 そのため、もし Systems Manager の Session Manager で接続した場合は、次の例のコマンドを実行して、シェルをbash にして、かつホームディレクトリに移動しておくとよいでしょう。

sudo su - ssm-user

インスタンスに接続したら、さっそく microk8s をインストールしたいところですが、Amazon Linux 2 の場合は、まずは snapd をインストールする必要があります。

snapdのリポジトリをダウンロードします。

cd /etc/yum.repos.d/
sudo wget https://people.canonical.com/~mvo/snapd/amazon-linux2/snapd-amzn2.repo

次に /etc/yum.conf を開きます。

sudo vi /etc/yum.conf

そして、一番最後に下記を追記して保存します。

exclude=snapd-*.el7 snap-*.el7

これで、snapd をインストールできるようになります。

cd
sudo yum install -y snapd
sudo systemctl enable --now snapd.socket

snapd のインストールが完了したら、いよいよ microk8s をインストールします。

sudo snap install microk8s --classic --channel=1.24

注意: 実行後、次のようなエラーが表示された場合は、1,2分待ってから再度実行して下さい。

error: too early for operation, device not yet seeded or device model not acknowledged

インストールが完了すると、次のようなメッセージが表示されます。

microk8s (1.24/stable) v1.24.0 from Canonical  installed

次に、OSユーザーを microk8sグループ に追加するなどの処理を行います。

sudo usermod -a -G microk8s $USER
sudo chown -f -R $USER ~/.kube

設定を反映させるため、新たにセッションを開始します。

sudo su - $USER

microk8sのステータスを確認しておきましょう。

microk8s status --wait-ready

これで、microk8s を使用する準備が整いました。 ただ、microk8s では、Kubernetes を操作するのに microk8s kubectl を使うため、次のような alias を設定しておくことにします。

alias kubectl='microk8s kubectl'

では、シンプルな Deployment を作成して確認みましょう。

kubectl create deployment nginx --image=nginx
kubectl get pods
kubectl get deploy

microk8s を問題なくインストールできていれば、Pod のステータスは Running になっているはずです。

bash を使う、snapd のインストールが必要、という点に注意すれば、minikube よりもシンプルに使えそうだというのが個人的な感想です!


モダンなJavaScriptのお勉強:テンプレート文字列編

今回は、テンプレート文字列を試してみます。

ES2015から、テンプレート文字列を使用して、文字列を構成できるようになっています。

例えば文字列を連結する場合、従来は次のような方法で行っていました。

const firstName = "のべ";
const lastName = "てつお";
const address = "京都";
const  printFormat="氏名: " +  firstName + " " +  lastName + "\n" + "住所: " + address;
console.log(printFormat);

結果:

氏名: のべ てつお
住所: 京都 

テンプレート文字列を使うと、次のように記述できます。

const firstName = "のべ";
const lastName = "てつお";
const address = "京都";
const  printFormat= `氏名: ${firstName} ${lastName} \n住所: ${address}`;
console.log(printFormat);

結果:

氏名: のべ てつお 
住所: 京都

同じ結果にできましたね。 テンプレート文字列では、 ` つまりバッククォートで文字列を囲みますが、その中の ${ } で囲んだ部分には JavaScript の変数や処理結果を埋め込むことができます。

上の例の ${firstName} では、firsrName 変数を埋め込んでいるのでその値が出力できます。

たくさんの + 演算子を使って連結するよりもシンプルで、可読性も向上できそうですね。

${ } で囲んだ部分には JavaScriptの処理も書けるので、試しに次のようなコードを実行してみましたが、期待通り 1100円と出力できました。

function getTaxRate() {
    return 0.1;
}

const productPrice = 1000;
const  priceFormat= `税込み価格 ${productPrice + (productPrice * getTaxRate())} 円`;
console.log(priceFormat);

結果:

税込み価格 1100 円

まとめ

  • テンプレート文字列を使うことで、+ 演算子を用いた文字列の連結によりもシンプルで読みやすいコードを記述できます。
  • テンプレート文字列は、` (バッククォート)で囲みます。この中で、${ }で囲まれた部分には JavaScriptを記述し、変数や動的な値を出力できます。

Amazon Linux 2 に minikube をインストールする方法

この記事に記載されている方法は、minikube 1.26 以降のバージョンでは適用できませんのでご注意ください。 詳細は、下記の v1.26.0 のリリース情報をご参照ください。

Releases · kubernetes/minikube · GitHub


こちら minikube start の内容を参考に実施しました。 minikube start の記載だけでは不十分な箇所があったので、迷わずインストールできるよう手順をこの記事に書いていきます。

まずは、AWS で EC2 インスタンスを作成します。

この時、minikube start に記載されている次の要件を満たすため、インスタンスタイプは t3.small で EBSボリュームの容量も 20 GB 以上にしておきます。(このスペックは AWS の 無料枠 ではありませんのでご注意ください。)

  • 2 CPUs or more
  • 2GB of free memory
  • 20GB of free disk space

インスタンスが作成されたら、接続します。 私は Session Manager で接続しましたが、ssh を使って ec2-user で接続してもかまいません。

接続後、次の手順を実施していきます。

Docker をインストールする

sudo yum update -y
sudo amazon-linux-extras install -y docker
sudo systemctl enable docker
sudo systemctl start docker

OSユーザーをdockerグループに追加

次の例では OSユーザーを ssm-user にしています。

sudo gpasswd -a ssm-user docker

この後、いったんログアウトして、もう一度ログインします。

minikube のインストール

いよいよ minikube をインストールします。 conntrack のインストールも必要です。

curl -LO https://github.com/kubernetes/minikube/releases/download/v1.25.2/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
sudo yum install -y conntrack

minikubeの起動

インストールが終了したら、起動します。 次の例では --vm-driver=none で起動しています。

minikube start --vm-driver=none

kubectl の設定

次の例では、minikube の handbook の kubectl の内容を参考に、シンボリックリンクを使って kubectl を使うようにしています。

sudo ln -s $(which minikube) /usr/local/bin/kubectl

kubectl を試してみます。

kubectl get all

結果の例:

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   2m

これで、完了です。 一度手順が確立できれば、簡単に、いつでもすぐに再構築できますね。


モダンなJavaScriptのお勉強:分割代入編

今回は、分割代入 についてまとめます。

代入とは、変数への値を設定することです。 例えば、JavaScript で次のようなオブジェクトがあるとします。

const customer = {
    id:       1,
   name:  "のべ",
   email:  "xxx@nobelabo.net"
};

この customer オブジェクトから name と email プロパティを取り出して変数に格納したいとします。 分割代入を使わない場合は、次のようになります。

let name = customer.name;
let email  = customer.email;
console.log(name);
console.log(email);  

結果:

のべ
xxx@nobelabo.net

2つの変数を別々に用意して、それぞれ、オブジェクト名.プロパティ名 を指定して代入していますが 分割代入を使うと、もっとシンプルに変数に値を代入できます。 では、分割代入を使って同じことをやってみましょう。

let  { name,  email }  = customer;
console.log(name);
console.log(email);  

結果:

のべ
xxx@nobelabo.net

いかがでしょう?

変数宣言で、{ } で囲って複数の変数を指定しています。 これらの変数に、customer のプロパティ名と一致している値が代入されています。 この例では { name, email } という順で指定していますが、{ email, name } のように順番が変わっても大丈夫です。 少しシンプルにできましたね。

次に、変数名を代入元のオブジェクトのプロパティ名と違うものにする方法をみてみましょう。

let  { name: customerName,  email: customerEmail }  = customer;
console.log(customerName);
console.log(customerEmail);  

結果:

のべ
xxx@nobelabo.net

変数宣言時に、{プロパティ名: 任意の変数名 } とすることで実現できますね!

この分割代入ですが、オブジェクトだけでなく配列でも使用できます。 配列の場合は、変数を [ ] で囲みます。

const  colors = ["Red", "Blue", "Yello"];
let  [  red,  blue ]  = colors;
console.log(red);
console.log(blue);  

結果:

Red
Blue

ただし配列の分割代入の場合、配列の要素順にしか値を代入できません。 例えば、次のようなコードにすると、blue 変数には 文字列 "Red" が、red 変数には 文字列 "Blue" が代入されますのでご注意ください。

const  colors = ["Red", "Blue", "Yello"];
let  [  blue,  red ]  = colors;
console.log(red);
console.log(blue);  

結果:

Blue
Red

まとめ

  • オブジェクトの分割代入では、{ } 内でオブジェクトのプロパティ名を指定すれば、順序に関わらず代入できることがわかりました。
    • プロパティ名と同じ変数名にすることも、任意の変数名にすることもできましたね。
  • 配列の分割代入では、{ } 内で任意の変数名を指定して代入できますが、あくまで配列の要素順で代入されることに注意しましょう!

モダンなJavaScriptのお勉強:変数宣言編

これまでは、普通に var を使って変数宣言していましたが、ECMAScript 2015 で追加された letconst を使って、その違いを確認してみます。

var の場合

例えば、次のような宣言をしてみます。

var message = "Hello";

この変数 message は、値の変更がでます。変数だから当然と言えば当然かもですが。

message = "Hi";
console.log(message);

結果

Hi

また、同じ変数名で再度宣言することもできます。

var message = "ハロー";
console.log(message);

結果

ハロー

let の場合

letの場合は、値の変更は可能ですが、同じ変数名での再宣言は不可になります。

まず let で宣言します。

let message = "Hello";

その後、値を変更します。次のコードは正常に実行できます。

message = "Hi";
console.log(message);

結果

Hi

ただし、次のように再宣言するコードはSyntaxErrorになり、実行できません。

let message = "ハロー"; // SyntaxError
console.log(message);

const の場合

constは、値の変更も、同じ変数名での再宣言も不可になります。

いわゆる 定数 の扱いですね。

const で宣言してみます。

const message = "Hello";
console.log(message);

その後、値を変更します。次のコードはSyntax Errorにはなりませんが、実行時にエラーになります。

message = "Hi";
console.log(message);

発生したエラーは、TypeError: Assignment to constant variable でした。

また、let と同じく次のように再宣言するコードはSyntaxErrorになり、実行できません。

const message = "ハロー"; // SyntaxError
console.log(message);

const は、値の変更が不可という事がわかりましたが、1つ注意点があります。

値が不可なのは、文字列 ( String ) や 数値 ( Number) や 真偽 ( Boolean) などのプリミティブ型であり、オブジェクトのプロパティや配列の要素は変更できます。

オブジェクトのプロパティの例をみてみましょう。

次のコードは const でオブジェクトを宣言していますが、そのプロパティは変更可能です。

const member1 = {
     id: 1,
     name: "Neco",
     address: "Tokyo"
};
member1.address = "Osaka";
console.log(member1);

結果

{ id: 1, name: 'Neco', address: 'Osaka' }

配列の要素の例もみてみましょう。このコードでも const で宣言した配列の要素を変更しています。

const mode = ["PLAY", "STOP"]
mode.push("PAUSE");
console.log(mode);

結果

[ 'PLAY', 'STOP', 'PAUSE' ]

まとめ

var と違い、letconst は同じ変数名での再宣言は不可であることがわかりました。

再宣言は、コードが混乱する元になりがちなので、基本的に letconst での変数宣言が良さそうです。

また、letconst の使い分けは、変数として扱うか、定数として扱いかで考えればいいですね。

AWS Certified Database - Specialty (DBS-C01) のお勉強:RDSのまとめ

AWS Certified Database - Specialty (DBS-C01) 試験を受ける予定。勉強したことのまとめを書いていきます。なお、私個人のメモなので、基礎から体系的に整理しているわけではないのは、ご容赦ください!

 

今回は、RDSについてのメモです。

RDS

AWSのリレーショナル・データベースのマネージドサービス。マネージドサービスなので、下記はAWSの管理となり、ユーザーはデータベースを使用するアプリケーションの最適化に注力できるというメリットがある。

  • データベース用のインフラ(サーバーやストレージ)のプロビジョニング
  • データベースのインストール
  • データベースの冗長化を容易に行える機能の提供
  • データベースのスケーラビリティを高める機能の提供
  • データベースのバックアップ、リストアを容易に行える機能の提供
  • データベースのメンテナンスを容易に行える機能の提供

RDSで利用できるデータベースのエンジン

RDSの可用性

  • マルチAZ構成
    • プライマリで使用するデータベースと、プライマリで障害発生時に切り替えるスタンバイのデータベースを異なるAZに作成し、プライマリからスタンバイへデータを同期的にレプリケーションする構成。
  • リードレプリカ
    • リードレプリカ(読み込み専用データベース)を作成し、通常時は読み込みで使用するが、障害発生時にプライマリに昇格させる

RDSのスケーラビリティ

  • インスタンスクラス(EC2でいうインスタンスタイプ)を変更してスケールアップ
  • ストレージ容量の拡張
    • 手動または自動で拡張可能。
    • ただし、ストレージ容量の縮小は不可
  • リードレプリカ(読み込み専用データベース)
    • 0~5個作成可能
    • 他のリージョンでも作成可能
    • リードレプリカは自動バックアップが有効でないと作成できない。
    • プライマリのデータベース停止時は、リードレプリカを削除する必要あり。

RDSのバックアップ/リストア

  • 自動バックアップ
    • バックアップウィンドウでスケジューリングして日次でスナップショットを取得
    • トランザクション・ログは5分毎に取得
    • 保持日数 0~35まで指定可能。デフォルト7
    • AWS内部管理のS3に格納される
    • バックアップウィンドウで指定した期間で実施
    • マルチAZ構成の場合、スタンバイ側に対して実施される
  • 手動でスナップショット取得
    • 保持日数 指定ないので、自動では削除されない
  • 取得したスナップショットのコピーや共有
    • 他のリージョンへコピー可能
    • ただし、パラメータグループやセキュリティグループはコピーされない
    • 他のアカウントと共有可能
    • 任意のS3バケットへのエクスポートが可能

RDSのメンテナンス

  • パッチ適用やデータベースのバージョン更新
  • メンテナンスウィンドウでスケジューリング(週次、30分の枠)
  • マネジメントコンソールから[今すぐ適用]または[次のメンテナンスウィンドウで適用]を選択できる。
  • 重要でないメンテナンスは、放置することで無期延期扱いできる
  • 重要なメンテナンスは、無期延期できない
  • マルチAZ構成の場合、まずスタンバイ側で適用、スタンバイ側をプライマリに昇格させた後に、元プライマリ側に適用する
  • データベースの静的パラメータ変更は、「メンテナンス」ではないので、メンテナンス・ウィンドウで自動適用できない。手動での再起動が必要になるケースもある。

RDSのセキュリティ

  • VPCのセキュリティグループでネットワークアクセスの制御
  • データ保管時の暗号化
    • データベース作成時の設定可能
    • 既存データベースを暗号化する場合は、スナップショットを取得、そのスナップショットを暗号化を指定してコピー、そのスナップショットからリストアする
  • データ転送時の暗号化
    • AWSより証明書取得
    • アプリで接続時にSSL/TLS指定
  • データベース認証・認可
    • データベース側の機能で設定
  • 監査ログ
    • 各データベースの機能で取得し、CloudWatch Logsへ転送可能

RDSのパフォーマンス

  • EBS最適化を設定しても、インスタンスタイプの帯域幅が狭ければ、十分なI/O性能を発揮することはできない。
/* -----codeの行番号----- */