エンジニアを目指す日常ブログ

日々勉強したことのメモ。独学ですので間違っていたらコメント等で教えてください。

【Node.js】モジュールの作成方法

はじめに

本記事の目的

Node.jsでWEB-APIサーバを立ち上げたが、一部の処理を別のモジュールとして切り出したい場合がある。自分でモジュールを定義して、処理を呼び出す方法をメモ。

前提

  • Node.jsとnpm(Node.jsのパッケージマネージャ)がインストールされていること。

tomiko0404.hatenablog.com

  • Node.js + Expessを利用してHTTPサーバを立ち上げていること。

前回の記事 tomiko0404.hatenablog.com

module.exportsを利用してモジュール作成

モジュール作成

モジュール用のファイルを作成する。

app.jsの配下にlibフォルダを作成し、その配下にmydouble.jsを作成する。

lib/mydouble.js

module.exports = (num) =>{
    return (num * 2);

}

module.exports

module.exportsに関数を代入することで、モジュールとしてエクスポートできる。

モジュールの呼び出し

app.jsに以下のように記載する。 requireした関数をmydoubleに代入して、mydouble(10)で呼び出している。

app.js

const express = require("express");
const portNumber = 8000;
const app = express();

// ★mydoubleモジュールをrequireする
const mydouble = require("./lib/mydouble.js");

// ★mydoubleを呼び出す
app.get("/", (req, res) => {
    res.status(200).send("My number is " + mydouble(10) + ".");
});


app.listen(portNumber);
console.log(`PortNumber is ${portNumber}`);

結果確認

10×2の20が返却されていることが確認できた。

"結果確認"
結果確認

exportsを利用する場合

exportsを使用して、各プロパティを定義することもできる。

lib/mycalc.js

exports.myadd = (num) => {
    return num + 100;
};

exports.mysubtract = (num) => {
    return num - 100;
};

exports.numbers = {
    a: 1,
    b: 200,
    c: 10000,
};

app.jsでの利用方法

以下のように利用した。

app.js

// ★mycalcモジュールをrequireする
const mycalc = require("./lib/mycalc.js");

// ★mycalc.[プロパティ名]で呼び出す
app.get("/", (req, res) => {
    let data = `mycalc.myadd(10):${mycalc.myadd(10)} `;
    data = data + `mycalc.mysubtract(300):${mycalc.mysubtract(300)} `;
    data = data + `mycalc.numbers.a: ${mycalc.numbers.a}`;
    res.status(200).send(data);
});

参考資料
Node.js 用モジュールの作り方(require でロード可能な Node モジュールを作成する) | まくまくNode.jsノート
exports と module.exports の違い - Qiita

おわりに

Node.jsで自分で定義したモジュールを呼び出す方法がわかった。

Node.js + ejsでフロントエンドを作成する方法メモ

はじめに

本記事の目的

前回、Node.jsを利用してWEB APIサーバを立ち上げた。

流れで、テンプレートエンジンを利用してフロントエンドをNode.jsで実装する方法も学んだので、メモしておく。

以下の講座を参考に実施している。
Node.js + Express で作る Webアプリケーション 実践講座 | Udemy

前提

  • Node.jsとnpm(Node.jsのパッケージマネージャ)がインストールされていること。

tomiko0404.hatenablog.com

  • Node.js + Expessを利用してHTTPサーバを立ち上げていること。

前回の記事 tomiko0404.hatenablog.com

テンプレートエンジンを利用しない場合の書き方

画面サーバとしてNode.jsサーバを利用する場合、ブラウザが理解できるようにHTML形式のデータを返してあげる必要がある。

前回学んだ方法で実装しようとすると以下のようになる。

app.js

const express = require("express");

// ポート番号を変数に設定
const portNumber = 8000;

// app変数にexpress関数を設定する
const app = express();

app.get("/", (req, res) => {
    let data = "<!DOCTYPE html>\r\n";
    data += "<html>\r\n";
    data += "<head>\r\n";
    data += "   <meta charset='UTF-8'>\r\n";
    data += "   <title>startup-ay-sugiura</title>\r\n";
    data += "</head>\r\n";
    data += "<body>\r\n";
    data += "  <h1>Hello World</h1>\r\n";
    data += "  <p>ejsを使わずにHTMLをres.send(data)</p>\r\n";
    data += "</body>\r\n";
    data += "</html>";
    res.status(200).send(data);
});

// リクエストを待ち受ける
app.listen(portNumber);
console.log(`PortNumber is ${portNumber}`);

dataにHTMLを1行ずつ追加していき、最後にres.status(200).send(data)を実行している。

node app.jsを実行し、Postmanで応答を確認すると、HTMLが返却されたことがわかる。

Postmanでの確認結果
Postmanでの確認結果

ブラウザでは以下の表示。

ブラウザで表示
ブラウザで表示

テンプレートエンジン(ejs)を使った作成方法

今回はejsを利用する。

テンプレートエンジンも奥が深そう。

参考文献
anken-hyouban.com

ejsのモジュールをインストール

npmでejsをインストールする。

$ npm install ejs --save

ejsファイルを作成する

app.jsと同じ階層に、viewsフォルダを作成し、その中にindex.ejsを作成する。

後で利用するrenderメソッドでは、パスを指定しないとデフォルトでviewsフォルダ配下を見に行くので、このフォルダ構成にしておくこと。

フォルダ構成
フォルダ構成

app.jsでejsファイルを呼び出す

app.jsは以下のように記載する。

//expressをrequireする
const express = require("express");

// ポート番号を変数に設定
const portNumber = 8000;

// app変数にexpress関数を設定する
const app = express();

// app.setでコンフィグを設定する
app.set("view engine", "ejs");

//sendではなくrenderを使う
app.get("/", (req, res) => {
    res.status(200).render("index.ejs");
});

// リクエストを待ち受ける
app.listen(portNumber);
console.log(`PortNumber is ${portNumber}`);

app.set()

コンフィグを設定するメソッド。

app.set("view engine", エンジン名)

res.render()

http.ServerResponseクラスのメソッド。

res.render(viewファイル(viewsフォルダからの相対パス), locals(引き渡したい値))

index.ejsにHTMLを記載する

以下のように普通のHTMLを記載してみる。

views/index.ejs

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>サンプルay-s</title>
    </head>
    <body>
        <h1>Hello world</h1>
        <p>ejsでrenderする</p>
    </body>

</html>

問題なくHTMLが返却された。

HTMLが返却された
HTMLが返却された

ejsに外から値を渡すパターンの作成方法

app.jsへの記載

render関数を利用している部分を書き換え、以下のようにする。

//expressをrequireする
const express = require("express");

// ポート番号を変数に設定
const portNumber = 8000;

// app変数にexpress関数を設定する
const app = express();

// app.setでコンフィグを設定する
app.set("view engine", "ejs");

//★renderメソッドにオブジェクトを渡す
app.get("/", (req, res) => {
    res.status(200).render("index.ejs",{title: "ejsに外から変数を渡すパターン"});
});

// リクエストを待ち受ける
app.listen(portNumber);
console.log(`PortNumber is ${portNumber}`);

ejsの文法

出力タグ (エスケープ有り)

<%=%>でくくると、変数の値をそのまま出力する。 ただし<などはエスケープされる。

<%= title %>

出力タグ(エスケープ無し)

<%-%>でくくると、変数の値をそのまま出力する。エスケープもされない。

<%- title %>

ejsへの変数の渡し方

res.renderメソッドの第二引数で、オブジェクト形式として引き渡すことができる。

ejsの記載

ejsに<h2>タイトル:<%= title %></h2>を追加。

views/index.ejs

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>サンプルay-s</title>
    </head>
    <body>
        <h1>Hello world</h1>
        <h2>タイトル:<%= title %></h2>
        <p>ejsでrenderする</p>
    </body>

</html>

結果確認

変数で渡した値もHTMLに含まれて返却された。

変数で渡した値もHTMLに含まれて返却された。
変数で渡した値もHTMLに含まれて返却された。

ejs内でJavaScriptを記載するパターンの作成方法

ejsの文法

スクリプト <% %>

<%%>でくくるとJavaScript扱いとなる。

<% 処理 %>

app.jsの記述

title項目だけでなくtextsフィールド(配列)もejsに引き渡す。

app.js(app.get文だけ記載)

app.get("/", (req, res) => {
    res.status(200).render("index.ejs", {
        title: "ejsに外から変数を渡すパターン",
        texts: [{ text: "テキスト1" }, { text: "テキスト2" }, { text: "テキスト3!" }],
    });
});

ejsの記述

ejs中で、受け取ったtextsフィールドをfor文で繰り返し呼び出し、<li>要素に入れる。 ここで、<li></li>は、スクリプトタグ<% %>で囲ってはいけないため、複数のタグを記載する必要がある。

views/index.ejs

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>サンプルay-s</title>
    </head>
    <body>
        <h1>Hello world</h1>
        <h2>タイトル:<%= title %></h2>
        <ul>
            <% for (let data of texts) { %>
                <li><%= data.text %></li>
            <% } %>
        </ul>
        <p>ejsでrenderする</p>
    </body>
</html>

結果確認

結果の確認。for文が実行されて3要素返却された。

for文が実行されて3要素返却された
for文が実行されて3要素返却された

ブラウザでも表示された。

ブラウザ表示
ブラウザ表示

【補足】その他のejs文法

終了タグについて

通常の終了タグは %>だが、 -%>とすると改行を削除して出力される。

<%エスケープについて

<%という値を返却したいときは、<%%と記載することでエスケープできる。

【参考】ejs以外のテンプレートエンジンの例

ejs以外にも以下のようなテンプレートエンジンがある。

  • pug (jade)
  • hjs
  • hbs

pugはExpressのデフォルトテンプレートエンジンとのこと。 また、昔はjadeと呼ばれていたが、呼び方が変わったらしい。

これらを使いたい場合は(例:hjsを利用)、先ほどのejsを利用した記載から、以下の変更が必要になる。

  • index.ejs というファイル名を index.hjs に変更する
  • app.setの中身を書き換える
app.set("view engine", "hjs");
  • res.renderを書き換える
res.status(200).render("index.hjs",{title: "hjsを利用するパターン"});

おわりに

テンプレートエンジンを利用して、HTMLを返却する方法をメモした。

HTTPリクエストツールPostmanの利用/インストール時のエラー対応

はじめに

Node.jsの勉強をしていたところ、HTTPリクエストをPOSTメソッドで投げたい場面が出てきたため、Postmanを利用することにした。手順のメモ。

【参考】GETでHTTPリクエストを投げる方法

ブラウザを立ち上げて、IPアドレスまたはURLを入力する。

GETでHTTPリクエスト
GETでHTTPリクエス

Postmanを利用してPOSTのリクエストを投げる

デスクトップ版のインストール

ブラウザ版は使いこなせなかったので、デスクトップ版をインストールする。

www.postman.com

ダウンロードしてきた.exeファイルをダブルクリックする。 待っていると自動でインストールが終わる。(待つだけなので少し不安になる)

アプリ起動が上手くいかない場合

一度目に実施した際はインストール後のアプリがうまく起動しなかった。

Postman Agent をダブルクリックしても何も表示されないし、タスクマネージャーにも表示されなかった。

上記のサイトからインストールし直したところ、うまくいった。

また、ショートカットが2種類作成されたが、起動時は「Postman」のショートカットを選ぶ必要がある模様。

ショートカット
ショートカット

アップデート

アップデートはひとまず「Dismiss」を選択。

サインイン

「Create your account or sign in later?」 という選択肢もあるので「Skip and go to the app」をクリックする。

HTTPリクエストを選択

右上の「New」→「HTTP Request」をクリックする。

HTTPリクエストを選択
HTTPリクエストを選択

お試しリクエストを投げる

試しにGETリクエストを投げてみる。 お試し用のAPIを提供してくれている、JSON PLACE HOLDERのサイトを利用。

今回はhttps://jsonplaceholder.typicode.com/usersのURLを利用する。

JSON Place Holder jsonplaceholder.typicode.com

「SEND」を押すとちゃんとリクエストが返ってきた。

リクエスト画面
リクエスト画面

自分で立ち上げたNode.jsサーバにリクエストを投げる

以下のようにgetメソッドのみ受け付けるサーバを立ち上げた。

app.js

var express = require("express");
var app = express();

app.get("/", (req, res) => {
    res.status(200).send("Hello World.");
}); 
app.listen(8000);

GETリクエストを投げる

GETリクエストを投げると、値が正常に返却された。

GETの場合
GETの場合

POSTリクエストを投げると、404エラーが返却された。

POSTの場合
POSTの場合

おわりに

Postmanを利用してHTTPリクエストを投げられるようになった。

PowerShellを管理者権限で実行できているか確認するコマンドメモ

はじめに

今回の記事の目的

PowerShellを管理者権限で実行できているのか確認するコマンドのメモ。

確認方法

以下のコマンドを実行し、

$ ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
True

なら管理者権限で実行できている。

参考文献: techexpert.tips

PowerShellの管理者権限での実行方法

PowerShell起動時に、右クリック→管理者権限で実行を選択する。

PowerShellの管理者権限での実行方法
PowerShellの管理者権限での実行方法

背景

以下の記事でも書いたように、npm installyarn installしようとすると、symblic linkの作成不可エラーが発生することがある。

An unexpected error occurred: "EPROTO: protocol error, symlink '../../../mime/cli.js' -> '/home/vagrant/workspace/backend-practice/front_react_back_node/node_modules/send/node_modules/.bin/mime'".

tomiko0404.hatenablog.com

PowerShell上にvagrantを立ち上げている場合、Powershellを管理者権限で実行しないと このエラーが発生する。

VS Codeのターミナルでの確認

VSCodeのターミナルを利用していたのだが、管理者権限でのPowerShell実行ができていないことが分かった。 VSCode自体を管理者権限で起動しても、状況は変わらず。

VSCodeは管理者権限でPowerShellを実行できていなかった
VSCodeは管理者権限でPowerShellを実行できていなかった

おわりに

PowerShellを管理者権限で実行できているか確認することができた。 標準のターミナルが見にくいので、VSCodeでできると良かったのだが…。現状はPowerShellを右クリックして起動するしかなさそう。

時間ができたら他のやり方も調べてみたい。

CodePipelineを利用してECS Fargateでブルーグリーンデプロイメントする

はじめに

今回の記事の目的

CodePipelineを利用してECS Fargateでブルーグリーンデプロイメント(Blue-Green Deployment)する。

まず、ビルド、デプロイについて単体で理解し、それらの設定をCodePipelineに組み込んでいった。かなり苦労したので、エラーの内容も合わせて紹介する。

順々にやっていったことで20000字の超大作になってしまったが、チュートリアルの通りにやるだけだとなかなか理解できないので、本記事の流れで理解していくのがおすすめ。

主に参考にしたチュートリアル
https://pages.awscloud.com/rs/112-TZM-766/images/AWS_CICD_ECS_Handson.pdf

前提条件

以下の記事で作成したFargateを利用する。 ALB経由でインターネットからアクセス可能なコンテナを立ち上げた。 tomiko0404.hatenablog.com

また、コードコミットとの連携は以下の記事の通り完了している。 tomiko0404.hatenablog.com

【参考】CodePipelineを使用せずイメージだけ作り直した場合の動作確認

dockerイメージをECRにプッシュ

アプリを変更し、dockerイメージをビルドし直したら、ECRにpushする。 ECR上でもlatestが最新となった。

この状態でALBにHTTP接続してみてもアプリは変更前(旧バージョン)の状態であった。

Webアプリは旧バージョン
Webアプリは旧バージョン

最終的に用意する必要があるファイル

元々作っていたプロジェクトフォルダ直下に、以下3ファイルを追加する必要がある。詳細は実施内容の中で記述する。

  • buildspec.yml
  • appspec.yml
  • taskdef.json

これらのファイルはCodeCommit上のリポジトリに存在しないと意味が無いので注意。 作成したり修正したりするたびに、pushする必要がある。

buildspec.yml

buildspec.ymlとは、CodeBuildがビルド時に実行する処理を記載するファイル。

チュートリアルを通してCodeBuildを理解する #reinvent | DevelopersIO

appspec.yml

appspec.ymlとは、CodeDeployを使ってデプロイする際の条件を記載したもの。

taskdef.json

taskdef.jsonとは、「タスク定義」を記載したもの。

CodeBuildとCodeDeployの理解

CodePipelineは、ソースコードのコミット→ビルド→デプロイの3ステップを自動で行ってくれるものである。

そもそもビルド、デプロイの概念を理解したいため、ビルド(Code Build)、デプロイ(Code Deploy)のステップをそれぞれ手動実行で利用してみる。

CodeBuildを利用してみる(手動)

IAMポリシー作成

「CodeBuildが」「ECRに」アクセスするためのIAMポリシーを作成する。

公式サイト( CodeBuild のDocker サンプル - AWS CodeBuild ) からのコピペで実施しようとしたがうまくいかなかった(ECRログインで権限エラー)ので、とりあえずフルアクセス権限にした。

フルアクセス権限作成

IAMのマネジメントコンソール→「ロールを作成」→「AWSサービス」→「CodeBuild」

ユースケースの選択
ユースケースの選択

Administrator Accessのポリシーをアタッチする。

Administrator Accessのポリシーをアタッチ
Administrator Accessのポリシーをアタッチ

最終的に以下のようになっていた。CodeBuildでIAMロールを設定すると自動で必要なポリシーもつくと思われる。

最終的なIAMロール
最終的なIAMロール

【参考】公式サイトの内容

公式サイトでは、ポリシーに以下JSONを追加するようにとのことだった。うまくいかなかった原因は不明。

{
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:CompleteLayerUpload",
        "ecr:GetAuthorizationToken",
        "ecr:InitiateLayerUpload",
        "ecr:PutImage",
        "ecr:UploadLayerPart"
      ],
      "Resource": "*",
      "Effect": "Allow"
    },

buildspec.yml 作成

プロジェクトフォルダ直下(Dockerfileと同じ場所)に作成した。 公式サイト(CodeBuild のDocker サンプル - AWS CodeBuild)からのコピペ。

これを見ると、実行しているコマンドは手動でECRにプッシュしていた時と同じことをしているとわかる。(一部環境変数になっているが、後で設定する。)

version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...          
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG      
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG

CodeBuildプロジェクトを作成する

マネジメントコンソールの「CodeBuild」→ 「ビルドプロジェクトを作成する」。

公式サイト:
ビルドプロジェクトの作成 (コンソール) - AWS CodeBuild
に従って実施。

  • 環境イメージは「マネージド型イメージ」。
  • オペレーティングシステムは「Ubuntu」、ランタイムは「Standard」、イメージは「aws/codebuild/standard:4.0」、イメージのバージョンは最新のものとした。(公式サイト( CodeBuild のDocker サンプル - AWS CodeBuild ) より)
  • 特権付与(Privileged)にチェックする
  • ソースの設定
    • プロバイダはCodeCommit
    • リポジトリは自分で作成したCodeCommitのリポジトリ
    • リファレンスタイプはブランチ。ブランチは「master」とした。
  • ビルドバッジは無効にした。
  • サービスロールは、先ほど作成した「ECRにアクセスできるロール(adminをつけたロール)」を設定する。
  • ビルド仕様は「buildspecファイルを使用する」を選択。オプションのBuildspec名は記載不要。デフォルトでbuildspec.ymlを利用するようになっているため。
  • アーティファクトは「なし」とした。
  • 環境変数の設定。buildspecファイルに記載した環境変数を、ECRに手動でpushするときのコマンドと見比べながら以下のように設定。
パラメータ
AWS_DEFAULT_REGION ap-northeast-1
AWS_ACCOUNT_ID [AWSアカウント(数字12桁)]
IMAGE_TAG latest
IMAGE_REPO_NAME ay-s-react-practice-6(ECRのリポジトリ名)

参考:CodeBuildプロジェクト作成画面
参考:CodeBuildプロジェクト作成画面

ビルドの実行

「ビルドを開始」で手動ビルド(=CodeCommitからECRへのpush)を実施する。 何とか成功。

失敗するときはビルドプロジェクトに設定したIAMロールに、ECRへのアクセス権限があるか要確認。

成功
成功

ECR上に新たなイメージがビルドされていることを確認した。 ECR上に新たなイメージがビルドされていることを確認した。

これでビルドは完了。

CodeDeployを利用してみる(手動)

以下記事で作成したサービスを、CodeDeployを使ってデプロイする。
ECS(Fargate)でコンテナを起動その2(ALBを利用したルーティング&CodeDeployの下準備) - エンジニアを目指す日常ブログ

前提として必要な設定

前回の記事で完了しているが、事前に必要な設定として以下のようなものがある。

  • Fargateサービスの作成時にALBが設定されていること。
  • CodeDeploy用のIAMロールが作成されていること。
  • Fargateサービスの作成時に、デプロイ方法をBlue/Greenデプロイメントと設定していること。
  • Fargateサービスの作成時に、「CodeDeploy のサービスロール」にCodeDeploy用IAMロールを設定していること。

公式サイト「CodeDeploy のBlue/Greenデプロイメントを実行する」以降の手順を実施する。

AWS CodeDeploy による AWS Fargate と Amazon ECS でのBlue/Greenデプロイメントの実装 | Amazon Web Services ブログ

タスク定義の新バージョンを作成する

タスク定義から、現行バージョンのタスク定義にチェックを入れ「新しいリビジョンの作成」をクリック。Nameタグのみ、値を少し変えて作成完了する。

タスク定義の新バージョンを作成
タスク定義の新バージョンを作成

サービスの更新を手動で実行

ECSコンソールの「サービス」→立ち上げているサービスにチェック→「更新」ボタンをクリック。

サービスの更新
サービスの更新

サービスの設定画面
  • リビジョンは2(latest)に変更する。

サービスの設定画面
サービスの設定画面

  • デプロイメントの設定は変更なし。 デプロイメントの設定は変更なし

  • ネットワークの設定も変更なし。 ネットワークの設定も変更なし

  • オートスケーリングも設定なしのまま。

  • サービスの更新を実行する。

デプロイ開始

CodeDeployによるBlue/Greenデプロイメントが開始した。

サービスの更新完了
サービスの更新完了

デプロイに失敗した・・・・・・・

デプロイ失敗
デプロイ失敗

失敗したので、ロールバックしてくれている模様。つまり、今リリースしている資材には影響を与えていない。

ロールバック
ロールバック

デプロイ失敗のログ確認

CodeDeployのコンソール画面にはログが出てこなかったが、ECSコンソール画面の「サービス」→「ログ」のタブからログを確認することができた。

また、「タスク」タブで「Stopped」を選ぶと、起動しようとして停止を繰り返すタスクがたくさん存在していることがわかる。停止を繰り返して60分たったので、デプロイがタイムアウトし、失敗となった。

デプロイ失敗の原因

Dockerfileの中身にミスがあった。CodeBuildの失敗時に色々試していた時に、コンテナのWORKDIRを変更してしまっていた。その結果/appフォルダ内にあるpackage.jsonが見つからずエラーとなっていた。

FROM node:14.15.4-slim

RUN apt-get update && apt-get install -y locales \
    && locale-gen en_US.UTF-8 \
    && localedef -i en_US -f UTF-8 en_US.UTF-8 \
    && echo "export LC_ALL=en_US.UTF-8" >> ~/.bashrc \
    && ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

COPY ./app /app
WORKDIR /app
RUN npm install
ENV PORT 80
CMD ["npm", "start" ] 

WORKDIR / ←←これが原因だったため、削除

RUN apt-get install -y \
    wget \
    curl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

Dockerfileを修正し、CodeCommitにpush→CodeBuildを手動実行→サービスの更新を再実行した。

サイトを参考にした。
CodeDeployを使用したデプロイがタイムアウトとなり失敗する - あとらすの備忘録

デプロイに成功

デプロイに成功した。このまま1時間待機して問題が無ければ元のタスクが終了する。

デプロイステータス
デプロイステータス

手動で「元のタスクセットを終了」することもできた。

元のタスクセット終了後
元のタスクセット終了後

タスクの起動状況を見ると以下のように遷移。一時的に2つのタスクが起動し、デプロイ終了すると1つになる。

タスクの起動状況
タスクの起動状況

ALBにアクセスすると、修正版のWebアプリが表示された。Deploy画面のStep2まで完了した時点で、ALBの向き先は新バージョンのタスクに変更されていた(新バージョンのアプリを閲覧できた)。

修正版のWebアプリ
修正版のWebアプリ

CodePipelineを使った自動デプロイ(この記事の本番)

本構成のCodePipelineの役割

  • CodeCommit上のソースコードの変更を検知して、パイプラインを開始してくれる。
  • パイプラインが開始すると、CodeBuildでdockerイメージ化&ECRへのイメージプッシュを実施(そのようにbuildspec.ymlを記載している)してくれる。
  • 続いて、パイプラインでCodeDeployを動かしてFargateのサービスを更新してくれる。

パイプラインの作成

パイプラインを作成する。AWSマネジメントコンソールの「CodePipeline」→「新規のパイプラインを作成する」。

サービスロール

  • サービスロールは新規作成する。
    CodePipeline:パイプラインの設定
    CodePipeline:パイプラインの設定

ソースプロバイダ

  • ソースプロバイダーは「CodeCommit」
  • プロジェクトのリポジトリとブランチ名を設定する。
    CodePipeline:ソースステージの設定
    CodePipeline:ソースステージの設定

ビルドステージ

  • ビルドステージを追加する。
  • プロバイダは「AWS CodeBuild」を選択する。
  • プロジェクト名は先ほど作ったBuildプロジェクトを指定した。
    CodePipeline:ビルドステージの追加
    CodePipeline:ビルドステージの追加

デプロイステージ

  • デプロイステージを追加する。
  • デプロイプロバイダーは「Amazon ECS(ブルー/グリーン)」を選択。
  • AWS CodeDeployアプリケーション名を選択する。アプリケーションとは、CodeDeployでのデプロイの設定をまとめたもの。
    ※【利用中のECSサービスの頭に「AppECS-[クラスタ名]」が追記されたアプリケーション名】が選べるようになっていた。これは先ほど手動でデプロイしたときに作成されたもの。
  • AWS CodeDeployデプロイグループを選択する。デプロイグループとは、デプロイする単位をグループ化したもの。
    ※【利用中のECSサービスの頭に「DgpECS-[クラスタ名]」が追記されたデプロイグループ名】が選べるようになっていた。これも先ほど手動でデプロイしたときに作成されたもの。以下のような内容が設定されていた。

デプロイグループに設定されている内容
デプロイグループに設定されている内容

CodePipeline:デプロイステージの追加
CodePipeline:デプロイステージの追加

ひとまずパイプラインの作成を完了した。

デプロイステージの編集

taskdef.jsonファイルを作成する

先ほど(タスク定義の新バージョンを作成する)で作成したタスク定義をJSON形式でコピーしてきて、プロジェクトフォルダ直下に新規作成したtaskdef.jsonファイルに貼り付けた。

タスク定義(JSON)
タスク定義(JSON

その後、

 "image": "イメージのタグ名",

となっている部分を

 "image": "<IMAGE1_NAME>",

と書き換える。

appspec.ymlファイルを作成する

プロジェクトフォルダ直下にappspec.ymlを作成し、公式ドキュメントに従い、以下の通り記載する。

公式ドキュメント:
チュートリアル: Amazon ECR ソースと、ECS と CodeDeploy 間のデプロイを含むパイプラインを作成する - AWS CodePipeline

コンテナ名は、taskdef.jsonで定義したタスクの中で作成しているコンテナ名である必要がある。 appspec.yml

version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: "ay-s-ReactPrc6-forALB-vpc16-container"
          ContainerPort: 80

デプロイステージのアーティファクトを設定する

アーティファクトとは、CodePipeline上で前のステージから次のステージに引き渡すもの。(例:SorceからBuildeへ)

デプロイステージのアクションを編集する。

pipelineの「編集」→「ステージを編集する」→「Deploy」の編集ボタンをクリックする。

  • 入力アーティファクトを「Source Artifact」と「Build Artifact」とする。
  • Amazon ECS タスク定義を「SourceArtifact」の「taskdef.json」とする。
  • AWS CodeDeploy App Spec ファイルを「SourceArtifact」の「appspec.yml」とする。
  • 入力アーティファクトを持つイメージの詳細を「Build Artifact」とする。
  • タスク定義のプレースホルダー文字を「IMAGE1_NAME」とする。

デプロイアクションの編集
デプロイアクションの編集

imageDetail.jsonを作成する

イメージファイルのURLを指定するためのimageDetail.jsonを作成する。 imageDetail.jsonは、ビルドステージで自動作成させるため、buildspec.ymlにファイル作成のための処理を追記する。

※今回はBlue/Green デプロイのためimageDetail.jsonだが、ローリングデプロイの場合は imagedefinitions.jsonとなり、フォーマットも異なるので注意。(原因②artifactのファイル名も参照)

まず、buildspec.ymlのpost_build:の処理の中に以下を追記。

      - printf '{"ImageURI":"%s"}' $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG > imageDetail.json

イメージURLをimageDetail.jsonに書き込んでいる。

また、ファイル末尾に以下を追記。

artifacts:
    files: imageDetail.json

全文は以下となる。
buildspec.yml

version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...          
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG      
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
      - echo Writing image definitions file....
      - printf '{"ImageURI":"%s"}' $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG > imageDetail.json

artifacts:
    files: imageDetail.json

Build後、ArtifactファイルはS3に保存されているため、ダウンロード可能。

ビルドの実行履歴
ビルドの実行履歴

中身は以下のように記載されている。

imageDetail.json

{"ImageURI":"XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/ay-s-react-practice-6:latest"}

※XXXXXXXはアカウントID

設定ファイルをコードコミットにpush

appspec.ymlbuildspec.ymltaskdef.jsonを下記の通り配置できたので、コードコミットにpushする。

設定ファイルの配置
設定ファイルの配置

$ git add .
$ git commit -m "設定ファイルを作成"
$ git push origin_codecommit master

コードコミットの設定:
tomiko0404.hatenablog.com

動作確認

ソースコードを変更して、CodeCommitにプッシュ。

※実際は、下記のとおり問題にぶつかり続けたので、各種設定ファイルの変更→コミットをかなりの回数実施しています。

$ git add .
$ git commit -m "ソースコードを変更"
$ git push origin_codecommit master

やっとできた!

コードパイプライン実行画面
コードパイプライン実行画面

Deployが進行中になっているのは、1時間の切り戻し待機中(Blue/Greenデプロイ)のため。

置き換えタスクセットがトラフィックを処理していればOK。

デプロイ詳細
デプロイ詳細

ブラウザから確認

ALBのDNS名にアクセスすると、変更が反映されていた。

ブラウザから確認
ブラウザから確認

DNS名の確認方法:
ECS(Fargate)でコンテナを起動その2(ALBを利用したルーティング&CodeDeployの下準備) - エンジニアを目指す日常ブログ

エラー対処のご紹介

ハマったエラーの紹介。
※ここまでの章は、ハマったエラー原因は解消した状態での結果を載せている。

エラー#1:BuildArtifactへのアクセス拒否

デプロイステージで以下のエラーが発生。

You are missing permissions to access input artifact: BuildArtifact.

原因と解決策

buildspec.yml内でBuildステージのアーティファクトを作成できていなかったことが問題。imageDetail.jsonを作成するの手順を実施することで解消。

エラー#2 BuildArtifactの読み込み時にエラー

なんとかBuildArtifactを作れたが、以下エラーが連発。

Exception while trying to read the image artifact file from: BuildArtifact.

原因①イメージ名の環境変数間違い

環境変数$IMAGE_REPO_NAMEと自分でCodeBuild上で設定していたが、チュートリアルに沿って$REPOSITORY_URIにしてしまっていた。

原因②artifactのファイル名

imagedefinition.jsonではなく、imageDetail.jsonでないとだめ。

  • ECS標準デプロイの場合:imagedefinitions.json
  • Blue/Greenデプロイの場合:imageDetail.json

原因③artifactファイルの中身のパラメータ名違い

チュートリアルがECS標準デプロイ前提だったので、中身の書き方もそのまま間違えていた。

imagedefinitions.jsonの場合(誤)

[
  {
    "name": "sample-app",
    "imageUri": "11111EXAMPLE.dkr.ecr.us-west-2.amazonaws.com/ecs-repo:latest"
  }
]

imageDetail.jsonの場合(正)

{
"ImageURI": "ACCOUNTID.dkr.ecr.us-west-2.amazonaws.com/dk-image-repo@sha256:example3"
}

artifactファイルの書き方
イメージ定義ファイルのリファレンス - AWS CodePipeline

エラー#3:コンテナ名まちがい

デプロイステージで以下のエラーが発生。

The ECS service cannot be updated due to an unexpected error: The container ay-s-ReactPrc6-forALB-vpc16-container-codepipeline does not exist in the task definition. (Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException; Request ID: XXXXXXXX; Proxy: null). Check your ECS service status.

原因と解決策

appspec.ymlファイルの中でContainerName:を設定する際、勝手に名前を付けてしまっていた。エラーが出たため、タスク定義の中で設定されているコンテナ名に修正した。

エラー#4

デプロイを開始したが、その後タスクが起動と停止を繰り返す現象。

以下の状態で止まり、60分でタイムアウトする。

デプロイ失敗
デプロイ失敗

さらに、今回はログが出る前にタスクがStopしている模様。

サービスのログ
サービスのログ

ただし、タスクのステータス画面に怪しげな文言が出ていたので確認。

タスクのステータス画面
タスクのステータス画面

STOPPED (CannotPullContainerError: inspect image has been retried 1 time(s): failed to resolve ref "docker.io/library/ay-s-react-practice-6:latest": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: ...)

原因と解決策

ECSのタスク定義画面から、コンテナの設定を見てみると、「イメージ」にちゃんとしたURLが入っていない。

ECSのタスク定義確認
ECSのタスク定義確認

imageDetail.jsonの中身が

{"ImageURI":"ay-s-react-practice-6:latest"}

となっており、"imageUri"がURIになっていないことが原因と思われた。

そこで、imageDetail.jsonを作っているbuildspec.ymlを修正した。

誤:元の記載)
- printf '{"ImageURI":"%s"}' $IMAGE_REPO_NAME:$IMAGE_TAG > imageDetail.json

正:修正後)
  - printf '{"ImageURI":"%s"}' $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG > imageDetail.json

おわりに

土日をつぶして2週間かかったが、CodePipelineでソースコードをデプロイすることができた。

その他参考資料

docs.aws.amazon.com qiita.com

Lambda+API GatewayからDynamoDBにアクセスする方法

はじめに

今回の記事の目的

Lambda関数を作成し、DynamoDBにアクセスする。 Lambda関数を呼び出すためにAPI Gatewayを利用する。

IAMロールを作成する

「DynamoDBにアクセスする権限」を「Lambdaに」与える。

  • IAMコンソールの「ロール」画面から「ロールの作成」。
  • ユースケースの選択で「Lambda」を選択。
  • Attach アクセス権限ポリシーで以下を選ぶ。
    • AWSLambdaBasicExecutionRole
    • AmazonDynamoDBFullAccess

以下の通り作成した。

IAMロール作成の確認画面
IAMロール作成の確認画面

API Gateway

Lambdaプロキシ統合

Lambdaプロキシ統合という仕組みを利用する。 HTTPSで受信したデータをLambda関数に自動的に渡したり、Lambda関数から戻ってきたデータを整形してHTTPSで戻す仕組み。

Lambda関数の定義

def lambda_handler(event , context)

  • eventは、呼び出し元の情報。例えばAPI Gatewayだったら、ブラウザから送信された値を持つ。
  • contextは、実行環境(Lambdaコンテナの環境)に関する情報。割り当てられたメモリなど。

Lambda関数の戻り値

Lambda関数からの戻り値は、API GatewayのLambdaプロキシ統合の場合決まっている。

{
    'statusCode':'200',
    'headers':{
        'content-type':コンテンツタイプ
    },
    'body' : 本文データ
}

Lambda関数とAPI Gatewayを作成する

  • マネジメントコンソールから「Lambda」を選択
  • 「関数」→「関数の作成」

設計図の選択

  • 今回は「設計図から作成」を選択する。
    AWSがもともと作っているサンプルをもとに作成する。

設計図からLambda関数を作成
設計図からLambda関数を作成

  • 今回は「microservice-http-endpoint-python」を選ぶ。
    Node.jsで作りたい場合は「microservice-http-endpoint」を選ぶ。

基本設定

以下の通り基本設定をした。IAMロールは先ほど作ったものを選択する。

基本設定
基本設定

API Gatewayの設定

以下の通りAPIの設定をした。

セキュリティは

  • オープン
  • JWT オーソライザーを作成

から選択する。今回は公開APIとするためオープンを選択した。

JWTオーソライザーについては割愛。
JWT オーソライザーを使用した HTTP API へのアクセスの制御 - Amazon API Gateway

API Gatewayの設定
API Gatewayの設定

Lambda関数のコード

今回pythonを利用して記載する。

boto3のインポート

AWSサービスを使うためのpythonモジュールboto3をインポートして、DynamoDBを利用する。

import json
import boto3

dynamodb = boto3.resource('dynamodb')

lambda関数の定義

lambda関数を定義する。

def lambda_handler(event, context):

※これ以下のコードはすべてlambda_handlerの中身なので、インデントを下げて記載する。

DynamoDBのテーブルから値を取得する。

    keijitable = dynamodb.Table("ay-s-keijiban") # テーブルを変数に入れる
    response = keijitable.scan() # テーブルの全データを取得するメソッド。あまり大きいと全部読み取れないので注意。

HTMLの作成

返却したいHTMLを作成する。

    html = "<html>・・・・・</html>"

注意:""の中で"を使いたい場合はエスケープする必要がある。(例:<meta charset=\"UTF-8\">

HTMLを作成する中で、取得したデータを利用する。

    for data in sorted(response["Items"], reverse=True, key=lambda d: d["postat"]):
        ・・・・
        ・・・・
for文の構文
for 変数名 in オブジェクト :
sortedの構文

sorted()は、ソートした新たなリストを生成するメソッド。

sorted( 元のリスト, 引数)

引数reverseは、Trueとすると降順にソートする。

また、引数keyは、

key=lambda x: x[1]

とすることで、1番目の要素をキーとしてソートできる。

key=lambda x: x["postat"]

postat項目を要素としてソートできる。

sortedの資料
[解決!Python]リスト(配列)をソートしたり、逆順にしたりするには(sort/reverseメソッド、sorted/reversed関数):解決!Python - @IT

返却項目作成

最後に返却するJSONを作成する。

    return {
        'statusCode':'200',
        'headers':{
            'content-type':'text/html'
        },
        'body' : html
    }
pythonのポイント
  • Java等では{ }で囲むが、pythonではインデントを用いてコードブロックを表現する。

以下の講座を参考にした。コードはコピペできないので重要要素だけメモ。
AWS Lambdaを活用したサーバレス実践 -第3回- - Schoo(スクー)

Lambda関数をテストする

「Test」→「Configure test event」を選択。

イベントテンプレートは「apigateway-aws-proxy」を選択。

要求電文は特に変更しない。

テストの作成
テストの作成

エラー発生 #1

以下のエラーが発生した。

[ERROR] JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 39, in lambda_handler
    payload = event['queryStringParameters'] if operation == 'GET' else json.loads(event['body'])
  File "/var/lang/lib/python3.7/json/__init__.py", line 348, in loads
    return _default_decoder.decode(s)
  File "/var/lang/lib/python3.7/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/var/lang/lib/python3.7/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None

原因は、デプロイをする前にテストしていたことである模様。

設計図にもともと記載があったコードを実行してしまっていたようだった。

エラー発生 #2

デプロイしてからテストしたところ、以下のエラーが発生。

START RequestId: XXXXXXXXXXXX Version: $LATEST
[ERROR] KeyError: 'items'
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 14, in lambda_handler
    for data in sorted(response["items"], reverse=True, key=lambda d: d["postat"]):
END RequestId: XXXXXXXXXXXX
REPORT RequestId: XXXXXXXXXXXX  Duration: 72.25 ms  Billed Duration: 73 ms  Memory Size: 512 MB Max Memory Used: 69 MB  Init Duration: 372.27 ms

原因は、以下のコードの Itemsitemsになっていたタイプミスだった。

for data in sorted(response["Items"], reverse=True, key=lambda d: d["postat"]):

Lambda関数のコードに書いているファイル名はlambda_function.pyとなる。

CloudWatch logs

テスト実行結果からCloudWatch logsに遷移して、以下のようにログを見ることができる。

CloudWatch
CloudWatch

テスト成功

諸々修正してテストが成功した。

テスト成功
テスト成功

APIを打鍵してみる

API Gatewayのエンドポイントを確認して、打鍵してみる。

エンドポイントの確認
エンドポイントの確認

確認結果

APIをブラウザから打鍵できた。

ブラウザから打鍵した結果
ブラウザから打鍵した結果

おわりに

Lambda+API Gatewayを利用してAPIを作成する方法がわかった。 また、pythonからDynamoDBにアクセスする方法がわかった。

関連記事

前回までの記事

DynamoDBでテーブルを作成して、データを追加する。

tomiko0404.hatenablog.com

AWS DynamoDBにデータベースを作成し、データを入力する方法メモ

はじめに

今回の記事の目的

AWS上にDynamoDBを作成し、レコード(アイテム)を追加する。 アイテムの追加は、マネジメントコンソールからの実施と、AWS CLIを用いた2つの方法で実施してみる。

DynamoDBとは

DBモデル

  • AWSが提供するフルマネージド型のNo SQL データベース。
  • キーバリュー型のDBである。
  • 日付や時刻の型がない。
  • レコード(アイテム)ごとに項目が異なっていても良い。
  • Writeは結果整合性モデル(2つのAZに書き込みが終わったら完了扱い)
  • Readは結果整合性モデルだが、オプションで強い整合性モデルも利用できる。

NW、性能

  • 高可用性(3か所のAZ)
  • プロビジョンドスループットといって、事前に必要なキャパシティを設定できる。テーブルごととCRUDごとに設定できる。(例:Read 100、Write 1000)
  • VPCに属さない。
  • ストレージの上限がない。
  • 大量に発生する行動データなどに使われることが多い。

作成するテーブル

以下レイアウトでテーブルを作成する。

属性名 説明 プライマリキー
id Number 投稿のID
name String 投稿者名
message String 投稿したメッセージ
postat String 投稿した日時

テーブルの中身は、以下のAWS Lambda講座で例として利用されていたものと基本的に同じ。
AWS Lambdaを活用したサーバレス実践 -第2回- - Schoo(スクー)

テーブルを作成する

AWSマネジメントコンソールから「DynamoDB」を検索し、「テーブルの作成」。

テーブル名設定

現在の AWS アカウントとリージョンで一意である必要がある。

キーの設定

テーブルのキーを設定する。キーにはいくつか種類がある。

パーティションキー

ソートキー

  • テーブル作成時に、パーティションキーのほかに1つの属性データを選び、ソートキーにすることができる。
  • パーティションキーと合わせて、データを一意に特定する。
  • 同じパーティションキーを持つアイテムのグループでは、アイテムはソートキーを使ってソートされて管理されている。

ローカルセカンダリーインデックス(Local Secondary Index:LSI

  • ソートキー以外で絞込検索を行うインデックス。
  • ソートキーを設定していないテーブルには利用できない。
  • パーティションキーとソートキーが複合キーになっているテーブルで、パーティションキーとまた別の属性で検索したいとき、その別の属性をLSIにすることで、パーティションキー+LSIという検索ができる。

グローバルセカンダリーインデックス(Global Secondary Index:GSI)

  • LSIの強力版で、ハッシュキーをまたいで自由に検索できる。
  • 内部的には別テーブルを作っているため(?)、スループットやストレージ容量が追加で必要になる。(LSIも同じ)

イメージがわかりやすい参考資料
DynamoDBのキー・インデックスについてまとめてみた - Qiita

【参考】テーブル作成画面

DynamoDB作成
DynamoDB作成

アイテムを作成する

マネジメントコンソールで作成

マネジメントコンソールからアイテムを作成できる。

dynamoDBに項目を作成
dynamoDBに項目を作成

値を入力する。

項目の値入力
項目の値入力

AWS CLIで作成

AWS CLIの初期設定

以下の記事「AWS CLIの基本設定」を参照。
tomiko0404.hatenablog.com

アイテムの作成コマンド

put-itemメソッドを使う。

構文は以下。

$ put-item
    --table-name <value>
    --item <value>
    [--expected <value>]
    [--return-values <value>]
    [--return-consumed-capacity <value>]
    [--return-item-collection-metrics <value>]
    [--conditional-operator <value>]
    [--condition-expression <value>]
    [--expression-attribute-names <value>]
    [--expression-attribute-values <value>]
    [--cli-input-json | --cli-input-yaml]
    [--generate-cli-skeleton <value>]

公式リファレンス
put-item — AWS CLI 2.2.44 Command Reference

itemオプションに設定するデータ形式

itemオプションに実際の値を入れていくが、以下のような形で、通常のJSONを設定してもデータ投入できない。

# NG{
  "id": 2,
  "name": "CLI子2丁目",
  "message": "AWSCLIからput-item。JSONの中に改行の\\を入れると良くないらしい。",
  "postat": "2021-10-09 4:00"
}

DynamoDB特有のJSON構文で記載する必要がある。

# OK{
  "id": { "N": "2" },
  "name": { "S": "CLI子2丁目" },
  "message": {
    "S": "AWSCLIからput-item。JSONの中に改行の\\を入れると良くないらしい。"
  },
  "postat": { "S": "2021-10-09 4:00" }
}

このJSONの構文としては、

"項目名" : { "データ型" : "実際の値"} 

となる。データ型は、

  • N :数値
  • S :文字列
  • B :バイナリ
  • SS :文字列配列
  • NS :数字配列

など。

データ型が「数値」であっても、JSON上は""で囲む点に注意。

詳細は公式ドキュメント参照。
put-item — AWS CLI 2.2.44 Command Reference
各データ型の説明:
命名ルールおよびデータ型 - Amazon DynamoDB

最終的にコマンドラインで実行するのは以下のコマンド。

$ aws dynamodb put-item \
    --table-name ay-s-keijiban \
    --item '{     
            "id": { "N": "2" }, 
            "name": { "S": "CLI子2丁目" }, 
            "message": { "S": "AWSCLIからput-item。JSONの中に改行の\\を入れると良くないらしい。" }, 
            "postat": { "S": "2021-10-09 4:00" } 
            }' \
    --return-consumed-capacity TOTAL

\ はコマンド中での改行を意味する(Linux一般)。
注意:JSON中に\を記載するとうまくいかない。
公式ドキュメントだとJson中にも\を書いているようなのだが。

また、--return-consumed-capacity TOTAL

消費された書き込み容量単位の総数を返します。

とのこと。コマンドの応答として以下が返却された。

{
    "ConsumedCapacity": {
        "TableName": "ay-s-keijiban",
        "CapacityUnits": 1.0
    }
}

アイテムを追加した結果

GUICLIの2つの方法でアイテムを追加することができた。

ちなみに、マネジメントコンソールで作成したデータは、その後の手順で同じidとなるデータを上書きしてしまい、消えてしまっている。

アイテムを追加した結果
アイテムを追加した結果

おわりに

DynamoDBのテーブルを作成し、アイテムを追加することができた。

関連記事

つづき

作成したDynamoDBにAPIでアクセスする

tomiko0404.hatenablog.com