電通国際情報サービス TechBlog

ISIDが運営する技術ブログ

スマートコントラクト入門

電通国際情報サービス オープンイノベーションラボの比嘉です。

今回のテーマは、スマートコントラクト。スマートコントラクトとはブロックチェーン上にデプロイされるプログラムのことで、今回は、Gethはじめましたの続きになります。 まだ、上記の記事をやってない方は、お手数をおかけしますが先に上記の記事をやってください。GethはEthereumクライアントの中で公式に推奨されているクライアントです。

Gethの再起動

上記記事で、Gethのメインプロセスを終了させた方は、もう一度再起動しましょう。

$ cd private_net
$ geth --networkid 1203 --nodiscover --datadir .

別のターミナルを立ち上げて、メインプロセスにコンソールで接続します。

$ cd private_net
$ geth attach geth.ipc

採掘が止まっている場合は、採掘を開始しましょう。

> eth.mining
false
> miner.start()
null

Solidityのインストール

Ethereumでスマートコントラクトを書くためのプログラミング言語としては、Solidity, Vyper, Fe, lllなどがありますが、よく使われているのはSolidityです。そこで、今回はSolidityをインストールします。 Solidityをインストールするための公式サイトはこちら

macOSの場合

Homebrewを事前にインストールし、次のコマンドを実行しましょう。

$ brew update
$ brew upgrade
$ brew tap ethereum/ethereum
$ brew install solidity
$ brew linkapps solidity

brew updateを実行するときにError: homebrew-core is a shallow clone.のエラーが、起きる場合があります。その場合はメッセージに、書いてあるとおりに、gitコマンドを実行しましょう。 インストールがうまくいっていれば、次のコマンドが成功します。

$ solc --version

Windowsの場合

ダウンロードサイトから、solc-windows.exeを落としてインストールしましょう。

スマートコントラクトのコード

最初のスマートコントラクトとして、数値をスマートコントラクトの状態変数に格納したり、取り出したりするプログラムを書いてみましょう。

NumberRegister.sol

pragma solidity ^0.8.10;

contract NumberRegister {
    uint num;

    function set(uint _num) public {
        num = _num;
    }

    function get() public view returns (uint) {
        return num;
    }
}

Solidityの細かい文法については、今後の記事で取り上げるので、細かいことは気にしなくて大丈夫です。このNumberRegiseter.solをprivate_netのディレクトリに保存しましょう。

solc

SolidityのプログラムをEthereumで実行できるようにするには、solcコンパイルします。コンパイルとは、NumberRegiseter.solのような人間が見て理解しやすいコードをコンピューターが実行できるように変更することです。

もう一つ、ターミナルを立ち上げて、solcを実行しましょう。

$ cd private_net
$ solc --abi --bin NumberRegister.sol

次のような出力が表示されたはずです。

======= NumberRegister.sol:NumberRegister =======
Binary:
608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806360fe47b11461003b5780636d4ce63c14610057575b600080fd5b610055600480360381019061005091906100c3565b610075565b005b61005f61007f565b60405161006c91906100ff565b60405180910390f35b8060008190555050565b60008054905090565b600080fd5b6000819050919050565b6100a08161008d565b81146100ab57600080fd5b50565b6000813590506100bd81610097565b92915050565b6000602082840312156100d9576100d8610088565b5b60006100e7848285016100ae565b91505092915050565b6100f98161008d565b82525050565b600060208201905061011460008301846100f0565b9291505056fea2646970667358221220348a0bef0ed2915311a28c4b28b351b950a27275e260ed0a915108c3b0257d2c64736f6c634300080a0033
Contract JSON ABI
[{"inputs":[],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_num","type":"uint256"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Binaryのところに書いてある6080ではじまり0033で終わる文字列の先頭に0xを付加した上で、シングルクォートでくくり、Gethのコンソールに貼り付けます。BinaryはEVM(Ethereumの仮想マシン)が理解できるバイトコードです。

> bin = '0x608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806360fe47b11461003b5780636d4ce63c14610057575b600080fd5b610055600480360381019061005091906100c3565b610075565b005b61005f61007f565b60405161006c91906100ff565b60405180910390f35b8060008190555050565b60008054905090565b600080fd5b6000819050919050565b6100a08161008d565b81146100ab57600080fd5b50565b6000813590506100bd81610097565b92915050565b6000602082840312156100d9576100d8610088565b5b60006100e7848285016100ae565b91505092915050565b6100f98161008d565b82525050565b600060208201905061011460008301846100f0565b9291505056fea2646970667358221220348a0bef0ed2915311a28c4b28b351b950a27275e260ed0a915108c3b0257d2c64736f6c634300080a0033'

同様にContract JSON ABIもコンソールに貼り付けましょう。ABIはスマートコントラクトの入出力の仕様になります。

> abi = [{"inputs":[],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_num","type":"uint256"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"}]

ここで定義した bin と abi は、この後で使うので覚えておいてください。binはEVM(Ethereumの仮想マシン)が理解できるバイトコード、abiはスマートコントラクトの入出力の仕様です。

スマートコントラクトのデプロイ

先ほどのスマートコントラクトをEthereumネットワークにデプロイしましょう。

> cnt = eth.contract(abi).new({from: eth.accounts[0], data: bin})
Error: authentication needed: password or unlock
    at web3.js:6347:37(47)
    at web3.js:5081:62(37)
    at web3.js:3021:48(134)
    at <eval>:1:28(16)

Error: authentication needed: password or unlockが発生した場合は、アカウントをunlockAcount()しましょう。トランザクションを実行する場合は、アカウントをunlockAccount()する必要があります。このエラーは何度も見ることになるので、どう対応すれば良いか体で覚えましょう。

> personal.unlockAccount(eth.accounts[0])
Unlock account 0x29faad1bb68151278c47df617766bf045c9b2b00
Passphrase: 
true
> cnt = eth.contract(abi).new({from: eth.accounts[0], data: bin})
{
  abi: [{
      inputs: [],
      name: "get",
      outputs: [{...}],
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}],
      name: "set",
      outputs: [],
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: undefined,
  transactionHash: "0x13658235f5bff4afefd57b504a048f5c2bc37241bacfd9ce58177627aa1882b2"
}

cntの中身のaddressがundefinedになっていますね。これは、このスマートコントラクトのデプロイがまだ終わっていないことを表しています。Gethのメインプロセスのログで採掘がきちんと行われていることを確認したら、cnt.addressを確認しましょう。

> cnt.address
"0x102118ad7f8bede0158d2353660f63ea5780f966"

スマートコントラクトに、アクセスするにはABI(スマートコントラクトの入出力の仕様)とaddressが必要です。それでは、NumberRegisterコントラクトを作りましょう。

> cnt2 = eth.contract(abi).at(cnt.address)
{
  abi: [{
      inputs: [],
      name: "get",
      outputs: [{...}],
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}],
      name: "set",
      outputs: [],
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: "0x102118ad7f8bede0158d2353660f63ea5780f966",
  transactionHash: null,
  allEvents: function(),
  get: function(),
  set: function()
}

スマートコントラクトの状態を変更しない場合は、トランザクションなしで実行できます。それでは、NumberRegister.get()メソッドを呼び出してみましょう。 コントラクトオブジェクト.メソッド名.call()で呼びだすことができます。

> cnt2.get.call()
0

スマートコントラクトの状態を変更する場合、コントラクトオブジェクト.メソッド名.sendTransaction()を呼び出します。それでは、NumberRegister.set()を呼び出してみましょう。

> cnt2.set.sendTransaction(1, {from: eth.accounts[0]})
Error: authentication needed: password or unlock
    at web3.js:6347:37(47)
    at web3.js:5081:62(37)
    at web3.js:4137:41(57)
    at <eval>:1:36(10)

エラーが出ていない人は気にしなくて大丈夫です。上記のエラーが出た人は、unlockAccount()を呼び出しましょう。

> personal.unlockAccount(eth.accounts[0])
Unlock account 0x29faad1bb68151278c47df617766bf045c9b2b00
Passphrase: 
true
> txid = cnt2.set.sendTransaction(1, {from: eth.accounts[0]})
"0xf12e076acec31684bade23f3ca12c14396160a86464ce1298bbe10e795824f2e"

Gethのメインプロセスのログで採掘が動いていることを確認し、NumberRegister.get()を呼び出してみましょう。

> cnt2.get.call()
1

cnt2.set.sendTransaction()の第一引数で指定した値が、設定されていることが分かります。

まとめ

スマートコントラクトをコンパイルすると、ABI(入出力の仕様)とバイナリー(EVMが理解できるバイトコード)が出力されます。

バイナリーをEthereumネットワークにデプロイするとaddressが付加されます。

ABIとaddressを使ってコントラクトオブジェクトを作成して、スマートコンタクトにアクセスします。

スマートコントラクトの状態を変更しない場合、コントラクトオブジェクト.メソッド名.call()を呼び出します。

スマートコントラクトの状態を変更する場合、コントラクトオブジェクト.メソッド名.sendTransaction()を呼び出します。

今回はここまで。Gethを止めておきましょう。コンソールはCTL-D。メインプロセスはCTL-Cで止めます。正直、GethのコンソールはNode.jsのモジュールも使えないなど、かなり不便です。次回からは、開発環境としてHardhatを使います。

僕の書いたNFT関連の記事

執筆:@higa、レビュー:@sato.taichiShodoで執筆されました

CodeDeploy によるECS でのBlue/Greenデプロイの話

皆さん、こんにちは。電通国際情報サービスXイノベーション本部ソフトウェアデザインセンターの陳です。

業務でAmazon ECSとCodeDeployを使ってBlue/Greenデプロイを実施してみたのでその方法をご紹介します。
CodeDeployを使ったECSのBlue/Greenデプロイの手順を紹介する記事は少なくありませんが、実際にやってみると意外とハマったことが多かったです。
本記事では、ハマったことや使ってみた感想についてもご紹介したいと思います。

CodeDeployを使ったBlue/Greenデプロイについて

CodeDeployを使ってBlue/Greenデプロイを実現するには、ターゲットグループを2つ用意する必要があります。
ALBのルーティング制御によって、トラフィックを流すターゲットグループを切り替えることで、ダウンタイムなしで環境を切り替えることを実現できます。

図から詳しく説明します。

本番環境はユーザーがアクセス可能な環境で、テスト環境は開発者のみアクセス可能な、動作確認のための環境だと想像してください。
Target Group1とTarget Group2がありますが、初期状態では、本番環境とテスト環境のトラフィックは両方ともTarget Group1に流します。

CodeDeployを利用し、新しいコンテナイメージをデプロイすると、テスト環境のトラフィックの転送先は新しいコンテナーを持つTarget Group2に切り替えます。
本番環境のトラフィックはそのまま古いコンテナーを持つTarget Group1に流すため、デプロイ期間においても本番環境へのアクセスは可能です。

テスト環境での動作確認が完了後、CodeDeployを利用してALBの本番環境へのトラフィック転送を制御できます。本番環境もテスト環境も最新のコンテナーを持つTarget Group2にトラフィックを転送します。トラフィックの転送の切り替えはほとんど時間がかからないため、ダウンタイムほぼ0でデプロイできます。
Blue/Greenデプロイは本番環境とテスト環境の入れ替えのイメージがありますが、CodeDeployの場合はデプロイ完了後、本番環境もテスト環境も同じターゲットグループにトラフィックを転送します。

次のデプロイを実行すると、Target Group1は最新のコンテナーを持つようになリます。
デプロイ実行後、テスト環境のリスナーは自動的にTarget Group1にトラフィックを転送し、本番環境のリスナーはそのままTarget Group2にトラフィックを転送します。
本番環境のトラフィックの転送を制御することで、テスト環境と本番環境は両方ともTarget Group1にトラフィックを転送します。

方法

AWSマネジメントコンソールから以下のリソースを作成しました。

  • VPCなどネットワークインフラ
  • CodeDeployにECSを更新するアクセス許可を付与するIAMロール
  • ALB
  • ECRレポジトリ
  • ECSクラスタ
  • ECSタスク定義
  • ECSサービス
  • Route53を利用する場合は、Aレコードを作成し、ルーティング先をALBにする

リソースの作成、およびBlue/Greenデプロイの実行手順は以下の記事を参考にしました。

今回は本番環境でHTTPSを利用したいため、本番環境のリスナーポートを443、テスト環境のリスナーポートを8443にしました。

手順の自動化

AWS for GitHub Actionsを組み合わせれば、GitHub Actionsワークフローを利用してCodeDeployの実行までの手順を自動化できます。

  1. Dockerfileをbuildし、タグをつけてECRにpushする
    amazon-ecr-login

  2. ECSタスク定義を更新する
    amazon-ecs-render-task-definition

  3. 更新されたタスク定義を使ってCodeDeployのデプロイを実行させる
    amazon-ecs-deploy-task-definition

GitHubにタグをプッシュすることで、既存のECSリソースにCodeDeployを使用したBlue/Greenデプロイができます。ただし、デプロイ後のトラフィック転送先の切り替えなど、CodeDeployに対する操作はAWSマネジメントコンソールから手動で操作する必要があります。

CodeDeployの設定

AWSマネジメントコンソールから、CodeDeployの以下の設定を変更できます。(アプリケーション>デプロイグループを選択>編集)

トラフィックの再ルーティング

トラフィックの再ルーティングとは、ALBで本番トラフィックの転送先のターゲットグループを切り替えることを指します。
デフォルトでは、トラフィックが直ちに置き換え先環境に再ルーティングされるように設定されています。
トラフィックが再ルーティングされる前に、動作確認したい場合は再ルーティングするタイミング、つまり待機する日数、時間、分数を指定できます。動作確認のために再ルーティングを保留できる時間は最短5分、最長時1日間23時間55分まで指定できます。
Lambda関数の検証テストをAppSpecファイルに追加すれば、設定した待機時間内に検証テストが自動的に実行されます。

テスト環境のポートにアクセスすれば動作確認ができます。動作確認が完了後、再ルーティングを実行するために、CodeDeployの「トラフィックの再ルーティング」ボタンを指定した待機時間内に押下する必要があります。(CodeDeployのコンソールでデプロイIDをクリックした後の画面にあります)
待機時間が経過しても、再ルーティングが実行されない場合は、デプロイの状態は失敗になります。

デプロイ設定

デプロイの速度や、デプロイ成功または失敗の条件など、ルールを設定できます。

元のリビジョンの終了

新しいタスクのデプロイが完了後、元のタスクセットを終了するまでの時間を設定できます。デフォルトは1時間です。

設定した時間内に、デプロイしたものに問題があったら、いつでも元のタスクセットにロールバックできます。
再ルーティングの実行後でもロールバックはできます。

終了処理が開始するとロールバックすることはできません。

ハマったこと

CodeDeployのinstallイベントが一向に終わらない

CodeDeployのコンソールでは詳しいログ情報やエラーメッセージが表示されないため、最初は原因がよくわからず困りました。
今回は、Dockerfileに不備があり、起動できない状態のコンテナーをデプロイしようとしているのが原因でした。他の記事を読むと、IAMロールに必要な権限がない場合や、task-definition.jsonにミスがあった場合でもCodeDeoloyのinstallが延々と続くらしいです。
何かの不備があるとCodeDeployでのinstallイベントは一向に終わらなくなります。しかし、Dockerfileやtask-definition.jsonは変更を頻繁に加えるものではないため、デプロイが成功したものを使い続ければこのような問題は発生しないでしょう。

テストトラフィックの動作確認ができない

ECSとCodeDeployを使用してBlue/Greenデプロイを実施すると、設定した待機時間内に、テスト環境のリスナーポートにアクセスし動作確認ができます。しかし、リスナーポートの設定が不適切な場合やWebアプリケーションのURLがハードコードされる場合は、動作確認できないこともあります。

リスナーポートの設定

最初は、本番環境のリスナーポートをHTTPS/443、テスト環境のリスナーポートをHTTP/8080にしましたが、テスト環境のリスナーポートにアクセスできませんでした。
理由としては、検証で使っていた.devドメインではHTTPが使えないからです。他にも、HTTPをHTTPSにリダイレクトする要件があれば、両方ともHTTPSのポートにしたほう望ましいでしょう。

どのドメインからテスト環境にアクセスすべきかがわからなかった

最初は、本番環境と同じドメインでなくALBのドメインを使ってテスト環境にアクセスしてしまいました。
本番環境と異なるドメインからアクセスすると、場合によってログインできなくなったり、APIリクエストを投げられなくなったりすることもあります。
本番環境のドメインhttps://example.comであれば、それと同じドメインのテストポートhttps://example.com:8443からテスト環境にアクセスするのが正解です。

Next.jsを利用する場合のAPI URL問題

Next.jsのgetServerSidePropsを利用し、APIリクエストを送信するには、APIエンドポイントのURLを次のように指定する必要があります。axios.get(https://example.com/api/hello)
https://example.comの部分を環境変数として設定してしまう場合は、異なるポートからアクセスしAPIにリクエストを送信すると、CORSエラーが発生します。
それを回避するために、URLのハードコードをやめて、以下のようにgetServerSidePropsのcontextからホスト名とポート番号を取得しました。
axios.get(https://${ctx.req.headers.host!}/api/hello)
ただし、プロトコルはcontextから取得できないため、httpsを固定するまたは環境変数に入れる必要があります。

使ってみた感想

デプロイの所要時間はとても短い

今回はGitHub Actionsを利用すると、ほとんどのワークフローの処理時間は1秒程度で完結できました。DockerfileのbuildおよびECRへのpushは、相対的に時間かかりましたが、Dockerfileの改善により処理速度の短縮が期待できます。
GitHub Actionsのワークフローが成功した後、CodeDeployでのデプロイ(置き換えタスクセットのデプロイ、テストトラフィックルーティングのセットアップ)は約2、3分間くらいかかります。動作確認を含め、デプロイの全体を数分程度に抑えることができたのですごいと思いました。

本番と同じ環境で動作確認できる

テストトラフィックで動作確認し、問題がなければ本番トラフィックの転送先を切り替えればデプロイが完了しますので、テストトラフィックの転送先のターゲットグループは本番に昇格するみたいなイメージですね。万が一動作確認でバグを見つけても、本番環境に影響せずロールバックができます。

何よりダウンタイム0はすごい

また、トラフィックの再ルーティングはほとんど時間がかからないため、デプロイで発生するダウンタイムは0に近いです。テストトラフィックで動作確認できるため、ユーザーはデプロイ作業に影響されなくシステムを使い続けられます。

まとめ

本記事では、Amazon ECSとCodeDeployを使ってBlue/Greenデプロイメンを実施する方法、ハマったところや使ってみた感想についてご紹介しました。デプロイの時間を短縮し、ダウンタイムなしでデプロイできるので、本当に便利だと思いました。AWSによくまとめてある設定手順がありますので、皆さんご機会がありましたらぜひ使ってみてください。

最後までお読みいただきありがとうございました。

参考にした情報

執筆:@chen.xinying、レビュー:@sato.taichiShodoで執筆されました

NFT入門

電通国際情報サービス オープンイノベーションラボの比嘉です。

今回のテーマはNFT。Non-fungible tokenの略で、日本語だと非代替性トークン。

これと対をなす言葉がFungible token、日本語だと代替性トークン。Bitcoinのような暗号資産は、AさんがもっているトークンとBさんが持っているトークンは区別できません。このようにそれぞれが区別できないトークンを代替性トークンといいます。

NFT(非代替性トークン)はトークンごとにIDをもち、各トークンを区別できます。それでは、プログラマーの視点から、NFTを見ていきましょう。

ERC-721

NFTはERC-721として仕様が決められています。厳密にはERC-721の仕様と異なるNFTも存在しますが、事実上、NFTの仕様といえばERC-721だと思って間違いありません。

ERC-721に準拠したコントラクトは、ERC721とERC165のinterfaceを実装する必要があります。コントラクトとは、Ethereum上にデプロイされるプログラムです。interfaceはJavaのような言語のinterfaceと同じで、実装しなければいけない振る舞いを定義します。

ERC165はERC721を補助するinterfaceです。ERC-721の仕様ではオプションのinterfaceが存在します。ERC165のsupportsInterface()を使って、コントラクトがあるinterfaceを実装しているのか調べることができます。 それでは、ERC721とERC165のinterfaceを見てみましょう。

ERC721

pragma solidity ^0.4.20;

interface ERC721 /* is ERC165 */ {
    event Transfer(address indexed _from,
        address indexed _to,
        uint256 indexed _tokenId);

    event Approval(address indexed _owner,
        address indexed _approved,
        uint256 indexed _tokenId);

    event ApprovalForAll(address indexed _owner,
        address indexed _operator,
        bool _approved);

    function balanceOf(address _owner)
        external view returns (uint256);

    function ownerOf(uint256 _tokenId)
        external view returns (address);

    function safeTransferFrom(address _from,
        address _to,
        uint256 _tokenId,
        bytes data)
        external payable;

    function safeTransferFrom(address _from,
        address _to,
        uint256 _tokenId)
        external payable;

    function transferFrom(address _from,
        address _to,
        uint256 _tokenId)
        external payable;

    function approve(address _approved,
        uint256 _tokenId)
        external payable;

    function setApprovalForAll(address _operator,
        bool _approved)
        external;

    function getApproved(uint256 _tokenId)
        external view returns (address);

    function isApprovedForAll(address _owner,
    address _operator)
        external view returns (bool);
}

ERC-165

interface ERC165 {
    function supportsInterface(bytes4 interfaceID)
        external view returns (bool);
}

仕様上はオプションなんだけど、どのコントラクトも実装している重要なインターフェースが、ERC721Metadataです。それではinterfaceを見てみましょう。

ERC721Metadata

interface ERC721Metadata /* is ERC721 */ {
    function name() external view returns (string _name);

    function symbol() external view returns (string _symbol);

    function tokenURI(uint256 _tokenId) external view returns (string);
}

NFTが発行(mint)されたとき、tokenIdが発行されます。そのtokenIdを使ってtokenURI()を呼びだすとURIが返ってきます。そのURIにアクセスすると次のようなJSONデータが返ってきます。

{
  "name": "NFT Name",
  "description": "NFT Description.",
  "image": "https://example.com/xxx.png"
}

imageが指しているURLにアクセスすると画像を取得できます。整理すると次のようになります。

  • NFTが発行されたときに、tokenIdが発行される
  • NFT(ERC721に準拠したコントラクト)のtokenURI()をtokenIdを引数にして呼びだすと、tokenURIが返ってくる
  • tokenURIにアクセスするとJSONデータが返ってくる。
  • JSONデータのimageに画像のURLが格納されている。

imageに直接Base64でデータを埋め込むこともできます。NFTの正体がだいぶ見えてきたのではないでしょうか。NFTはデジタルデータとJSONデータを通じて、緩くつながっているだけです。

本当に、NFTによってデジタルデータの所有権を証明できるようになったのか

NFTによってデジタルデータの所有権を証明できるようになったという説明をどこかで聞いたことがあるかもしれません。法的な意味での所有権は有体物(物理的に存在するモノ)にのみ発生するものなので、法の専門家は「保有」という言葉を勧めているようです。そこで、次のように書き換えましょう。 NFTによってデジタルデータの保有を証明できるようになった

これは、本当なのでしょうか。 NFTは発行されたときに、購入者のaddressとtokenIdがひもづけされます。そのため、NFT自体の保有は確実に証明できます。しかし、NFTとデジタルデータはJSONデータで緩くつながっているだけなので、NFTだけでデジタルデータを保有していることは証明できません。

それでは、NFTによってデジタルデータの保有を証明できるようになったは間違いなのでしょうか。実はそうとも限りません。

NFTの購入は、OpenSeaのようなプラットフォームを利用することがほとんどでしょう。どのプラットフォームでも購入の際に、利用規約が示されます。この利用規約に書かれていることは、デジタルデータに対する権利として認められています。この権利を持って、NFTによってデジタルデータの保有を証明できるようになったといえる法律の専門家も認めているようです。NFTを購入した時の権利は、プラットフォームの利用規約以外に、パブリックライセンスを使うケースもあるようです。

まとめ

今回は、NFTをプログラマーの視点から眺めてみました。NFTの正体掴めたでしょうか。NFTをプログラマー視点から理解するうえでも、NFTを購入した時にどんな権利を得ているのかということは、どうしても理解しておく必要があります。僕は、法律の専門家ではありませんが、自分のためにNFTの法的な解釈も最小限載せました。僕のNFTの法的な解釈はうのみにせず、専門家の話を聞く/読むことを強くお勧めします。

NFTの法的解釈のおすすめ記事

僕の書いたNFT関連の記事

執筆:@higa、レビュー:@sato.taichiShodoで執筆されました

GAされたAmazon Managed Service for Prometheus + GrafanaでEKSにホストしたマイクロサービスを可視化してみた

メリークリスマス✨ISID 金融ソリューション事業部 市場系イノベーション部の寺山です!
新型コロナ禍の日々ですが、クリスマスイブはちょうど金曜日でしたし、皆さま楽しく過ごせましたかね??
さて、本記事は 電通国際情報サービス Advent Calendar 2021 の最終日のポストとなります。前回は、浦本さんの「フロントエンド依存ライブラリのバージョンアップ戦略」でした。
いやぁ、Advent Calendarに参加するぜ!ってエントリーしてしばらく経ってから、あれ??トリじゃん!?って気づきましたよ。。笑
しかしながらそんなことは気にせず、私が興味を持ったことについて投稿させていただきたいと思います!

はじめに

インフラ・クラウドというエンジニアリング領域を担当している私は、Kubernetes(以下K8s)を以下のように認識しております。

  • インフラストラクチャをソフトウェアでハイレベルに抽象化して制御する強力なテクノロジー
  • コミュニティが活発でありデベロッパーやインフラ管理者を支援するツールが日々進化している

2点目に関連し、コンテナレベルでの監視や可視化をサポートするエコシステムである、PrometheusGrafanaがそれぞれAWSのマネージドサービスとしてGAされました。

GAされてから4カ月ほど経過しますが、EKS+AMP+AMGという記事は以外と私の目に入っておりません。そこで、AMPとAMGを用いてAmazon EKSにホストしたマイクロサービスの可視化をやってみた!というのが、本記事の主旨となります。 K8sに対してはキャッチアップ中というスキルセット&ブログを書くのが初めてということもあり、誤りや至らぬ点もあるかと存じますが、ご指摘等はコメントいただけるとありがたいです(>人<;)

EKSにホストしたマイクロサービスの構成

本題へ入る前に、モニタリング対象のマイクロサービスのインフラ構成をご説明します。

EKSCluster-Mircoservice-Only

コンポーネントは全てAWSのサービスで構成しています。リージョンはアジアパシフィック(東京)です。
マイクロサービスアプリケーションは、バックエンドとして、認証/認可機能、共通機能、これらの機能を用いてビジネスロジックを実装し機能として提供するコンテナーをそれぞれのPod内で実行しています。コンテナーのイメージはAmazon ECR(以下ECR)から取得します。
コンテナランタイムの実行環境はサーバレスコンピューティングサービスであるAWS Fargate(以下Fargate)を利用しています。
ステートフルな情報は永続化層としてプロビジョニングしたAmazon Aurora(以下Aurora)より取得・保管します。
EKSクラスターにデプロイしたAWS Load Balancer Controllerにより、ACM証明書を適用してSSLTLS接続をオフロードするApplication Load Balancer(以下ALB)をプロビジョニングしています。
ALBは、フロントエンド(クライアント)からのREST APIリクエストラフィックビジネスロジックServiceにパスベースでルーティングします。
これらのコンテナー関連リソースを制御するK8sマスターがAWSマネージドとして作成/運用されるAmazon EKS(以下EKS)でクラスターを構成しています。
エンドユーザーはSPAを取得して、REST APIでバックエンドとリソースのやり取りをするというマイクロサービスにおける代表的なアーキテクチャです。SPAはS3に格納し、CloudFrontによりHTTPSで配信します。ただし、オリジンはS3バケットのみであり、バックエンド(ALB)は指定していません。
全体的に、(プライベートサブネットとCloudFrontの構成をサボっているところ以外は)AWSでの典型的なアーキテクチャだと思っています。ちなみに、フロントエンド・バックエンドのアプリケーションを開発したのは私ではありません。ありがとう、チームのみんな〜

コンテナー型マイクロサービスの可視化

PodのログはFluent Bitを利用すれば比較的簡単(Fargate ログ記録参照)にCloudWatch Logsで収集可能となります。
Fluent Bitは一部のメトリクスもログストリームに含めることをサポートしています1
そのため、CloudWatchでメトリクスフィルターを頑張って設定すれば、可視化もできそうです。
ただし、せっかくK8s使用しているのですから、有用(というか人気)なエコシステムは活用したいですよね?!というのが本件のモチベーションとなります。

K8sおよびエコシステムのバージョン

  • EKS:Kubernetes 1.21、eks.3
  • Prometheus:14.11.1
  • Grafana:8.3

AMPのアドオン

AMPユーザーガイドのGetting startedに従って、前述のEKSクラスターにPrometheusをアドオンします。ガイドと違いがある点や特にコメントしたい内容以外は単に作業内容を記述するのみにとどめて説明します。

  • AMP ワークスペースの作成

      $ aws amp create-workspace --alias tech-research-workspace
    
  • Prometheus 用の Namespace と ServieAccount 作成

      $ kubectl create namespace prometheus 
      namespace/prometheus created
    
      $ kubectl create serviceaccount prometheus -n prometheus
      serviceaccount/prometheus created
    
  • サービスロールを作成して Service Account に関連付け

    Set up IAM roles for service accountsで案内されているスクリプトを作成して実行します。
    ガイドのスクリプトではeksctlを利用しており、実際にEKSを構築や運用する際には有用なCLIツールかと思いますが、K8sの理解を深めるためにkubectlで書き直しました。
    と言っても、差分は以下のみなのですが。。。

      eksctl utils associate-iam-oidc-provider --cluster $CLUSTER_NAME --approve
    
    • 私が書き直したスクリプト

      kubectl annotate serviceaccount -n ${SERVICE_ACCOUNT_NAMESPACE} ${SERVICE_ACCOUNT_NAMESPACE} \
      eks.amazonaws.com/role-arn=${SERVICE_ACCOUNT_IAM_AMP_INGEST_ROLE_ARN}
      

    実行します。

    $ ./createIRSA-AMPIngest.sh
    arn:aws:iam::XXXXXXXXXXXX:role/amp-iamproxy-ingest-role
    serviceaccount/prometheus annotated
    
  • EKSノードグループの作成

    ここで、Prometheusのアーキテクチャを確認すると、Prometeheus ServerのTSDBの保存先にストレージが要求されています。
    ※下図はPrometeheus Overview - Architectureより抜粋したものです。

    EKSクラスターはデフォルトでAmazon EBSのStorage Classがデプロイ済みの環境となりますが、私が構築したクラスターはFargateプロファイルのみを作成していたので、EBSをストレージとするPersistent Volumeを利用できません。Amazon EFSのStorage Classを追加してFargate上で実行するか、EC2ノードでEBSを利用するか、なのですが本件では後者としました。

    EC2ノードを利用する場合はEKSクラスターにノードグループを追加します。ノードグループはマネージドノードグループとしました。
    作成方法はAWSユーザーガイドのステップ 4 ノードを作成するManaged nodes – Linuxをご参照ください。

  • Prometheusのインストール

    • Helm チャートリポジトリを追加

      互換性があるということで、AMP用のHelmリポジトリがあるのではなく、コミュニティのリポジトリを追加していますね。マネージドサービスでありながらコミュニティのアップデートを利用できるのは嬉しいですね!

      $ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
      $ helm repo add kube-state-metrics https://kubernetes.github.io/kube-state-metrics
      $ helm repo list
      NAME                    URL
      prometheus-community    https://prometheus-community.github.io/helm-charts
      kube-state-metrics      https://kubernetes.github.io/kube-state-metrics
      
      $ helm repo update
      Hang tight while we grab the latest from your chart repositories...
      ...Successfully got an update from the "kube-state-metrics" chart repository
      ...Successfully got an update from the "prometheus-community" chart repository
      Update Complete. ⎈Happy Helming!⎈
      
    • Helmチャートに渡すパラメーターファイルの作成

      リモート書き込みエンドポイント(remoteWrite)は、AMPコンソールのワークスペースの概要欄や、aws amp describe-workspace --workspace-id <ワークスペースID>より確認可能です。

      amp-ingest-values.yaml

       serviceAccounts:
           server:
               name: "amp-iamproxy-ingest-service-account"
               annotations:
                   eks.amazonaws.com/role-arn: "arn:aws:iam::XXXXXXXXXXXX:role/amp-iamproxy-ingest-role"
       server:
           remoteWrite:
             - url: https://aps-workspaces.ap-northeast-1.amazonaws.com/workspaces/ws-XXXXXXXX-XXXXXXXXXXXXXXXX/api/v1/remote_write
               sigv4:
                   region: ap-northeast-1
                   queue_config:
                       max_samples_per_send: 1000
                       max_shards: 200
                       capacity: 2500
      
    • Prometheus Serverのインストール

      $ helm install tech-research-prometheus-chart prometheus-community/prometheus -n prometheus -f ./amp-ingest-values.yaml 
      NAME: tech-research-prometheus-chart
      LAST DEPLOYED: Tue Dec 14 22:31:55 2021
      NAMESPACE: prometheus
      STATUS: deployed
      REVISION: 1
      TEST SUITE: None
      NOTES:
      The Prometheus server can be accessed via port 80 on the following DNS name from within your cluster:
      tech-research-prometheus-chart-server.prometheus.svc.cluster.local
      #(省略)
      
  • リソースの作成を確認

      $ kubectl get all -n prometheus                                                                                        
      NAME                                                                  READY   STATUS    RESTARTS   AGE
      pod/tech-research-prometheus-chart-alertmanager-646ff55c84-fmzfp      2/2     Running   0          2m19s
      pod/tech-research-prometheus-chart-kube-state-metrics-869b89746zhd5   1/1     Running   0          2m19s
      pod/tech-research-prometheus-chart-node-exporter-pft8p                1/1     Running   0          2m19s
      pod/tech-research-prometheus-chart-pushgateway-6cb64c488f-wrvdx       1/1     Running   0          2m19s
      pod/tech-research-prometheus-chart-server-76f7b57784-k8xj6            2/2     Running   0          2m19s
    
      NAME                                                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
      service/tech-research-prometheus-chart-alertmanager         ClusterIP   192.168.0.150   <none>        80/TCP     2m19s
      service/tech-research-prometheus-chart-kube-state-metrics   ClusterIP   192.168.0.47    <none>        8080/TCP   2m19s
      service/tech-research-prometheus-chart-node-exporter        ClusterIP   None            <none>        9100/TCP   2m19s
      service/tech-research-prometheus-chart-pushgateway          ClusterIP   192.168.0.221   <none>        9091/TCP   2m19s
      service/tech-research-prometheus-chart-server               ClusterIP   192.168.0.244   <none>        80/TCP     2m19s
    
      NAME                                                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
      daemonset.apps/tech-research-prometheus-chart-node-exporter   1         1         1       1            1           <none>          2m19s
    
      NAME                                                                READY   UP-TO-DATE   AVAILABLE   AGE
      deployment.apps/tech-research-prometheus-chart-alertmanager         1/1     1            1           2m20s
      deployment.apps/tech-research-prometheus-chart-kube-state-metrics   1/1     1            1           2m20s
      deployment.apps/tech-research-prometheus-chart-pushgateway          1/1     1            1           2m20s
      deployment.apps/tech-research-prometheus-chart-server               1/1     1            1           2m20s
    
      NAME                                                                           DESIRED   CURRENT   READY   AGE
      replicaset.apps/tech-research-prometheus-chart-alertmanager-646ff55c84         1         1         1       2m20s
      replicaset.apps/tech-research-prometheus-chart-kube-state-metrics-869b8974ff   1         1         1       2m20s
      replicaset.apps/tech-research-prometheus-chart-pushgateway-6cb64c488f          1         1         1       2m20s
      replicaset.apps/tech-research-prometheus-chart-server-76f7b57784               1         1         1       2m20s
    

AMGのアドオン

こちらもAMGGetting startedに従って進めていきましょう!

  • Grafanaワークスペース作成

    Create your first workspaceに従って作成します。
    Grafanaワークスペース・コンソールには、SSOで認証を行いアクセスする必要があるのですが、本件ではSSOの方式にSAMLを選択しました。

    • Amazon Grafana > Workspacesよりワークスペースを作成を押下
    • 名前と説明
    • 認証アクセス
      • Security Assertion Markup Language (SAML)
    • アクセス許可タイプ
      • サービスマネージド
    • IAM アクセス許可アクセス設定
      • 現在のアカウント
      • データソース
        • Amazon Managed Service for Prometheus
    • ワークスペースを作成を押下
    • ステータスがアクティブとなることを確認する

ワークスペースの作成は一旦終了しますが、SAMLの設定を完了させるにあたり、SAML IdPの構築が必要となります。

  • SAML IdPの構築

    本件ではIDaaSであるOktaを利用しました。AWSにて動作確認済みのIdPはConnecting to your identity providerに一覧化されています。こちらに記載のないIdPは、Grafanaに必要なSAMLアサーション属性をマッピングできるかの検証が必要ですね。

    • Oktaコンソール > 管理者より管理者ページにサインインする
      • その際、多要素認証の設定を求められるので、Okta Verifyを利用しました。
    • Directory > Profile Editorと遷移
      • UsersにてOkta用のプロファイルであるUser(default)を選択
      • AttributesのAdd Attributeを押下
      • Add Attribute
        • Display name
          • Role
        • Variable name
          • Role
      • Saveを押下
      • Role属性が追加されていること
    • Directory > Peopleと遷移
      • 自分のアカウントを選択
      • ProfileタブにてAttributesのEditを押下
        • 前述の手順で追加したRole属性にADMINを設定
        • Saveを押下
    • Applictions > Applicationsと遷移
    • Browse App Integration Catalogにて「Amazon Managed Grafana」をSearchして選択
    • アプリケーションの詳細画面にてAddを押下
    • General Settings
      • デフォルトのままでDoneを押下
      • Amazon Managed GrafanaアプリケーションのSing Onタブに遷移
      • SettingsにおいてEditを押下
      • ユーザーのアサイ
        • Amazon Managed GrafanaアプリケーションのAssignmentsタブに遷移
        • AssignプルダウンメニューよりAssign to Peopleを選択
        • 作成済みのアカウント(今回は私のOktaアカウント)をAssign
        • Doneを押下
  • AMGSAML設定

    OktaをIdPとしたSAML認証に必要な設定を行います。

    • Amazon Grafana > Workspaces > 作成したワークスペースを選択
    • 認証タブのSecurity Assertion Markup Language (SAML)セットアップを完了にするを押下
    • Security Assertion Markup Language (SAML)
    • GrafanaワークスペースSAML設定が有効となることを確認する
  • Grafana workspace consoleにアクセスする

    SSOが設定できたかの動作確認も兼ねて、GrafaraのUI(ワークスペース・コンソール)にアクセスします。

    • Amazon Grafana > Workspacesより作成したワークスペースを選択し、Grafana ワークスペース URLに表示されているリンクを開く
    • Sign in with SAMLを押下

      AMG-SAML-SignIn

    • Oktaと未認証状態の場合は、Oktaにサインインする

      AMG-Okta-SignIn

    • Grafanaワークスペース・コンソールが表示されることを確認する。

      AMG-WorkspaceConsole

可視化

Grafana上でのメトリクスの可視化が行える状態になったので、実際にダッシュボードを作成してみます。

  • AMPのデータソースを追加

    • Grafana ワークスペースコンソール> 左部メニューのAWSアイコン > AWS Data Sourcesを選択
    • AWS Data Sources
      • Data sourcesタブ
      • Service
        • Amazon Managed Service for Prometheus
      • Regions
        • Asia Pacific (Tokyo)
      • AMPのワークスペースを選択してAdd data source
    • Provisioned data sourcesにAMPのワークスペースが追加されていることを確認する。
  • ダッシュボードの追加

    Grafana.comに公開されているダッシュボードをインポートして、EKSクラスターの可視化を行います。

無事、EKSクラスターとPodのメトリクスを可視化することができました!

  • CPU使用率

    AMG-Dashboard-CPU-Usages

  • メモリ使用率

    AMG-Dashboard-Memory-Usages

まとめと今後の展望

「やってみた」感想は以下のとおりです。

  • K8sはキャッチアップ中、PrometheusとGrafanaを触るのが初めての私でも、クラスターやPodのメトリクス収集と可視化を行うことができました。
  • Contributorの貢献、情報量の多さというOSSのメリットと、それをAWSがマネージドサービスとしてナレッジの集約・導入ハードルを下げて提供しているというメリットの両方を体感しました。
    • これはEKSにも当てはまると考えております。

今後の展望としては以下を検討しております。

  • 各エコシステムのアーキテクチャや仕様、制約の理解
  • ダッシュボードのカスタマイズやCloudWatchとの棲み分け整理
  • 監視・可視化という運用機能ならなおさらFargateで実行したい

特に3点目は、調査できたら改めて記事にしたいと思っております!
(実はFargateでトライして、苦戦したのでEC2で妥協したのはナイショ♡)

おまけ:VSCodeKubernetes拡張機能

毎日VSCodeのお世話になっております。VSCodeを使い始める前の日々には戻れないです。
ご存じの方も多いかと思いますが、VSCodeにはMicrosoft社製のKubernetes 拡張機能があります。
この拡張機能YAMLスキーママニフェストの入力補助を行う目的で導入していたのですが、左部パネルのK8sアイコンより、色々できることに気づきました。
K8sクラスターやNamespaceの切り替え、各リソースの情報の取得もできます。
便利〜!という蛇足でした。

最後までご覧いただきありがとうございました。
この記事がお一人でも多く方の参考になる、または、弊社に少しでも興味も持った方がいらっしゃいましたら幸甚です。 それでは、良いお年を〜!

参考文献

執筆:寺山 輝 (@terayama.akira)、レビュー:@sato.taichiShodoで執筆されました

フロントエンド依存ライブラリのバージョンアップ戦略

こんにちは、ISID デジタルビジネス推進室の浦本です。好きな食べ物は生八ツ橋です。
本記事は 電通国際情報サービス Advent Calendar 2021 の24日目の記事です。

はじめに

皆さんは、npmでインストールした依存パッケージを定期的に更新されていますか?

「面倒だから更新していない。。。」
「フロントエンドはそのままでも大丈夫でしょ?」

と思って放置されている方もいらっしゃるかもしれません。

しかーし!!

更新せずに放置していると、古い依存パッケージの脆弱性を突かれてしまったり、アプリのコード体系が古くなり開発に支障が出たりします。

そこで本日は、面倒になりがちな依存パッケージのバージョン更新を円滑に行うための戦略を書きたいと思います。

【用語について】 本記事では、依存パッケージを利用する開発プロジェクトを単に「アプリ」と呼称します。

戦略

以下より詳細をご説明します。

dependencies と devDependencies の違いを意識する

お悩み:「色々とパッケージを追加したけれど、どれが重要か分からなくなってきた。」

package.json内の dependencies にはプロダクション・コードに影響する依存パッケージ名を列挙し、 devDependencies にはプロダクション・コードに影響しない依存パッケージ名(ビルドツールなど)を列挙します。

【例】

{
  "name": "my-app",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "hogehoge": "^2.1.0",
    "fugafuga": "^3.4.2"
  },
  "devDependencies": {
    "piyopiyo": "^6.7.0"
  }
}

依存パッケージ名を両者に振り分けておくことで、更新作業の際に、どのパッケージがより重要であるか容易に把握できます。 また、脆弱性情報の有無を確認するための npm audit コマンドでは --production オプションを指定することで dependencies のみを調査対象とすることもできます。

【振り分け方法】
npm install <パッケージ名> コマンドにて依存パッケージを追加する際に、下記のオプションで指定します。

## dependenciesに追加 (オプション指定不要)
$ npm intall hogehoge

## devDependenciesに追加 (--devまたは-Dオプションを付与)
$ npm install --dev hogehoge

既に依存パッケージを追加済みである場合は、package.jsonを手動で編集して対象パッケージ名の行を移動した後に、引数なしの npm install コマンドを実行すれば大丈夫です。

更新サイクルをチーム内で明確に決める

お悩み:「依存パッケージ、最後に更新したのはいつだろう(遠い目)。」

フロントエンドの依存パッケージは非常に速いペースで機能拡張されていきますので、定期的に更新するという意識を持たないと、ついつい利用バージョンが古いままになってしまいます。

そこで下記のように、いつ(どのような頻度で)更新を行うかを明確化することが大切です。

  1. 臨時のセキュリティ更新
    • 週に1回など短い間隔で依存パッケージの脆弱性の有無をチェックし、脆弱性があればピンポイントで更新する。これによりアプリをセキュアに保つ。
    • npm audit --production コマンドにて dependencies の依存パッケージに対し既知の脆弱性がないかチェックし、影響度に応じてパッケージを更新する。または、 GitHub Dependabot などの自動チェックサービスを用いる。
  2. 定期的な一括更新
    • 3カ月に1回など具体的な頻度を決めて、依存パッケージを可能な範囲で全て更新する。これによりコードの陳腐化を防ぐ。
    • npm outdated コマンドにて新しいバージョンの存在チェックを一括で行い、影響調査・更新を実施する。

動作に影響を与える可能性が高い依存パッケージを把握する

お悩み:「package.json内の記載順にパッケージ更新可否を調査し始めたが、何だか効率が悪い。」

以下に属する依存パッケージは芋づる式で他のパッケージの動作に影響を与えるため、優先的に更新の検討を行う事をオススメします。

  • TypeScript
    • 最近はTypeScriptの型定義を提供するライブラリが多くありますが、型定義よりもTypeScriptのバージョンの方が古いとコンパイルエラーになる場合があるため、真っ先に更新可否を調査したいところです。
  • webpackなどのモジュール・バンドラ、およびプラグイン
    • 例えばwebpackの場合、基本的に複数のloader系プラグインを導入して使うことになるため、webpackとプラグイン間のバージョン相性が悪いとビルドに失敗します。当然、各loader系プラグインの作者はバラバラなので、最適なバージョンの組み合わせは自分で探る必要が出てきます。まさにパズルであり、場合によっては更新を断念する事もあります。こちらも優先的に調査したいところです。
  • VueやReactなどのフレームワーク、およびプラグイン
    • こちらは説明不要ですね!フレームワークの更新内容はアプリの実装コード全体に影響してしまうので、早めに調査しましょう。

まとめると、以下の優先順位で影響を調査していけば、手戻りを防ぐことが出来ます。

  1. npm audit --production コマンドにて脆弱性が表示されたパッケージ
  2. 本節で触れた、動作に影響を与える可能性が高い依存パッケージ
  3. 残りの dependencies
  4. 残りの devDependencies

【Tips】
プラグイン系パッケージが想定している基幹パッケージ(例えば wepack-hogehoge-plugin の作者が想定している webpack)のバージョンを知りたいときは、GitHubリポジトリのリリースノートの確認に加えて、対象パッケージ直下にあるpackage.json内の devDependenciespeerDependencies に書いてある基幹パッケージのバージョンをチェックしましょう。

peerDependencies の方は馴染みがないかもしれませんが、ここには、プラグイン側がアプリの dependencies または devDependencies に要求する基幹パッケージのバージョンが記載されています。 ただし、緩い範囲(例えばメジャーバージョンの指定のみ)でバージョン指定されていることもあるので、あくまで指標として捉えてください。

ビルド結果の差分を確認する

お悩み:「従来まで取得できていた値がundefinedになっちゃった!」

TypeScriptなどのトランスパイラや、webpackなどのモジュール・バンドラのバージョンを更新すると、生成されるJavaScriptコードに差分が出ることがあります。 それが僅かな差分であっても、アプリの一部が機能しなくなる可能性があります。

生成されたコードの差分を確認するためには、以下の手順を踏んでください。

  1. 旧環境と新環境において、モジュール・バンドラのコード圧縮をOFFにしてそれぞれビルドを行う。
    • ※圧縮したままだと比較が困難であるため
  2. JavaScriptコードの差分をdiffツールで確認する。明らかに影響がなければここで終了。
  3. 影響が有りそうな差分を発見した場合、その周辺のキーワードを元に、TypeScriptやwebpackのGitHubソースコードを確認し、コードを生成している箇所を突き止める。その上で差分の意味を理解し、自分のアプリに影響があるかを判断する。

なお、開発環境のNode.jsをメジャーバージョンアップしたときも、念のため、同様の手順で確認しておいた方が良いでしょう。

バージョン選定の理由や注意点を表にまとめる

お悩み:「何らかの理由でこのバージョンに固定したんだけど、思い出せない。」

依存パッケージの定期的な一括更新作業を行うとき、前回の実施時から日が空いてしまうと、前回採用したバージョンの選定理由を忘れてしまう事があります。 それを防ぐために、バージョン選定の理由や注意点を表にまとめておきましょう。未来の自分・自チームへの助けになります。

下表に例を示します。

No. 分類 パッケージ名 バージョン 選定理由や注意点
1 dependencies hogehoge 2.1.0 動作確認済みであるv2系の最新版を利用。v3系はアイコンの見た目が変わるので利用不可。
2 dependencies fugafuga 3.4.2 IE11向けのpolyfillなのでバージョンアップ不要。IE11のサポートを切ったら消す。
...
70 devDependencies piyopiyo 6.7.0 極力最新版を利用するが、あくまでTypeScriptのバージョンに依存。

このような情報さえまとめておけば、更新作業担当者が変わっても差し支えないため、柔軟な作業アサインも可能となります。

コマンド一発で実行可能な単体テストを用意しておく

お悩み:「影響範囲の確認が終わらないよ~!」

依存パッケージの更新時は、アプリの動作に影響がない事を確認する必要があります。

このテスト作業の負荷を少しでも減らすために、フロントエンドの各種実装コードに対して、普段からコマンド一発で実行可能な単体テストを書いておく事が非常に重要です。

最近ではVueやReactなどの普及によりUIコンポーネントを主眼に置いた開発が浸透してきているため、コードの部品化が促進され、比較的テストが作りやすい状況にあると言えます。

ご利用のフレームワークで推奨されているテストライブラリを用い、UIコンポーネントやクラスの単体テストを実装しておきましょう。何千というテストケースが一気に通る様を眺めるのは爽快ですよ!

【テスト実装方法の参考リンク】

おわりに

いかがでしたでしょうか。 本記事の内容が、少しでも読者の方のお役に立つことができたなら幸いです。

最後に戦略図を再掲します。

電通国際情報サービス Advent Calendar 2021 の他の記事もぜひ、お楽しみください。

執筆:@uramoto.kazuhiro、レビュー:@sato.taichiShodoで執筆されました

データクラウド”Snowflake” のおはなし

本記事は、電通国際情報サービス Advent Calendar 2021の23日目の記事です。
担当は、エンタープライズIT事業部 データマネジメントコンサルティング部 宮城です。

データはDX推進における要であり、データを司る「環境」の重要性というのは昨今ますます高まってきています。
先日、ISIDは、データクラウド"Snowflake"の販売代理店契約を締結しました。
本日は、この”Snowflake”について特に私が感銘を受けている特徴を2つ紹介します。

特徴その①:独自のアーキテクチャ<ストレージとコンピュート>

一般的なコンピューターを構成する重要な要素はCPUとメモリとストレージです。"Snowflake"では、そのうちCPUとメモリだけを分離したものをコンピュートという概念で扱います。
ストレージは1つ。利用用途ごとに、さまざまなスペックのコンピュートを立てることができます。
各コンピュートはお互い影響せず、独立したパフォーマンスを実現できます。
このコンピュートを「ウェアハウス」と呼びます。ウェアハウスのスペックは「サイズ」と呼ばれ、XS⇒S⇒M⇒L⇒・・・とTシャツのサイズと同じように表現されます。
たとえば、下記のようなウェアハウスの使い方ができます。

  • データ加工専用ウェアハウス:
      大量のデータを処理するため、大きいサイズのウェアハウスを1台
  • BI参照専用ウェアハウス:
      複数のユーザーが同時にアクセスするため、小~中程度のウェアハウスを複数台

この「ウェアハウス」について、ポイントを2つご紹介します。

完全時間課金

大きいサイズのウェアハウスは高速なぶん高価なわけですが、上記の使い方でデータ連携が1時間内に終われば、データ連携用のウェアハウスは1時間分しか課金されません。データ連携処理が必要とする処理性能に合わせて、全体の性能を上げる必要はないのです。利用用途単位で処理性能を決めれば良いのです。用途によって求められる性能は違いますので、このような考え方は非常に効率的といえます。

ウェアハウスの運用が容易

たとえば、新しい部門がDWHを新たに使いたいと言い出したとします。このとき、その部門用に新たにウェアハウスを作成して提供してあげるだけです。既存のユーザーが使っているウェハアウスには、パフォーマンスを含めてなんの影響を与えません。
また、運用の中でウェアハウスのサイズや数を変えたい場合、Web画面から簡単に操作できるのも魅力的です。

ウェアハウスの追加

特徴その②:「データ・シェアリング」機能

特徴①のアーキテクチャの派生ともいえるのが、「データ・シェアリング」の機能です。
自社のアカウントのストレージにあるデータを、別アカウントに共有できます。共有した側を「データ・プロバイダー」、データを共有される側を「データ・コンシューマー」と呼びます。
このとき、ストレージは「データ・プロバイダー」が管理し、ウェアハウスは「データ・コンシューマー」が管理します。データの”保持”とデータの”利用”を、分離して考えることができます。

こちらも、ポイントを2つご紹介します。

データ連携処理が不要

たとえば、自社のデータを他社や他組織に共有しようとした場合、従来であれば、共有用のデータを出力する⇒そのデータを取り込んでもらうという処理フローを作ることになります。
データの構造が変わったり、共有したいデータが増えたりするたび、また追加で開発をしなければならないという保守性の問題が発生します。データに障害が発生した場合のリカバリも大変ですね。
また、ガバナンスの観点からも、データをばらまきたくないという考えもあります。
データ連携処理を作らなくてもデータを共有できるわけなので、このような課題がクリアになる、というわけです。

データ共有で広がる世界

自社で保有しているデータに加えて、他組織や外部のデータを利用することで分析の幅が広がります。これは共有される側のメリットです。
一方、共有する側にもメリットがあります。たとえば、製品メーカーが各工場・各製品の販売・在庫・生産などのデータをSnowflakeに一元管理し、販売代理店各社にデータ共有するというストーリーが考えられます。販売代理店は提供された情報をもとに高精度な販売見込データを立てることができ、販売見込販売機会の拡大や見込の精度向上に繋がります。販売代理店のパフォーマンスが向上することで、結果として製品メーカー側にもメリットが生まれます。
データを共有したり共有されたりすることにより、さらに可能性が拡がっていく。その考えを実現するのが、"Snowflake"の「データ・シェアリング」です。 データ・シェアリング

まとめ

本記事は、データクラウド"Snowflake"の特徴についてご紹介しました。
さらに詳しく知りたい方は、30日無料トライアルで"Snowflake"を体験してみてください。

電通国際情報サービス Advent Calendar 2021も残りわずかです。引き続きお楽しみください。

執筆:@miyagi.reiko、レビュー:@sato.taichiShodoで執筆されました

部門横断型セキュリティレビューの20年を振り返ってみます

これは電通国際情報サービス アドベントカレンダーの22日目の記事です。 こんにちは。電通国際情報サービス(ISID) Xイノベーション本部の富田です。 本記事はISIDで20年継続している全社的な施策のセキュリティレビューをご紹介し、その活動を振り返ってみたいと思います。

背景

現在のシステム開発を取り巻くセキュリティ概況は、顧客情報の漏えい、機密情報の窃取、ランサムウェアによる脅迫など被害報告が後を絶たず、攻撃は高度化・巧妙化していると言えます。そのため、セキュリティ確保の要求は日々高まっています。そのような状況の中、システム開発に目を向けると、開発チームが脅威とその対策方法を個別に調査するのには限界があると考えています。そこで必要になるのがセキュリティ専門チームによる調査・検証で得た知見の蓄積と展開です。

知見の展開では、全社的に進めることが欠かせません。ISIDではセキュリティ専門チームによる部門横断のセキュリティレビューを行っています。

セキュリティレビューの開始は、1990年代にさかのぼります。

  • 1998年に、当時はチャレンジングだったJava技術を適用したインターネットバンキング構築を行いました。その経験から、早期からWebアプリケーションのセキュリティに関心を持っていました。

  • 2001年頃にWebならではの新たな脅威が発生します。クロスサイトスクリプティング等の新たな脅威が現れました。これを機に、2001年に組織的な対応を検討し、セキュリティレビューのプロセスを策定しました。そして、2002年にISIDのセキュリティレビューが開始されました。

  • 2008年には、要件定義/設計時のセキュリティレビューに加え、構築システムのアプリケーション部分(及びインフラの一部)のセキュリティチェックを目的に、脆弱性検査(静的検査と動的検査)を開始しました。

その後、継続して改善と強化を行っています。

ISIDのセキュリティレビューについて

セキュリティレビューの目的、受託開発やISIDの製品/サービス開発のプロジェクトにおけるセキュリティリスクを低減することです。レビューは、プロジェクトのフェーズに応じて段階的に実施し、設計面のセキュリティにおいて一般的な脆弱性検査より踏み込んだレビューによりセキュリティを確保します。

  1. 提案時のセキュリティレビュー

    • RFP、要求仕様書、提案書を元にヒアリング形式でリスクの洗い出しを行います。
  2. 設計時のセキュリティレビュー

    • 非機能要件定義書/基本設計書の内容を元に、チェックシートを使って対策のレビューを行います。
  3. 脆弱性検査(静的検査、動的検査)

    • 構築システムのアプリケーション部分およびインフラの一部に対して、検査ツールを使用して脆弱性検査を行います。

レビュー体制は、セキュリティ分野の有識者で構成された10名ほどの専門チームです。具体的には、セキュリティ専門グループのメンバーだけでなく、開発技術とクラウドアーキテクチャの専門グループのメンバーも参画しています。

この20年で変わっているものは

2008年に脆弱性検査が追加され、その時点でレビュープロセスとしては概ねできあがっていますが、その後はプロセスに従って形式的にレビューを実施してきたのでしょうか?

そうではありません。

それは、レビューの題材が変わるからです。以下の要素が変化し、絡み合ってきます。

その他の変化には、セキュリティレビューで使用するチェックシートがあります。 設計時のセキュリティレビューに利用するセキュリティ対策チェックシートも変わっていきます。例えば、以下のような分野別のチェックシートを新規に作成してきました。

  • 2010年 クラウド環境シートを作成
  • 2011年 モバイルアプリシートを作成
  • 2016年 認証と認可プロトコルのシートを作成
  • 2018年 IoTシステムのシートを作成

これらは、プロジェクトでの適用可能性が出てきたタイミングで作成しています。 その他にも、セキュリティ対策チェックシート本体を含めたチェックシートを定期的(半期に1回程度)に見直しています。

これらのチェックシートは、セキュリティ専門チームの調査・検証の成果をもとに、新しい脅威への対策やセキュリティ対策のベストプラクティスなどをタイムリーに反映(育てているイメージ)したものです。特長としては、何のための対策かが分かるようにしている点です。

大事にしてきたポリシー

セキュリティレビューを進めるときに大事にしてきたことは、当事者意識を持って、「問題の指摘と対応案をセットで伝える」ということです。プロジェクトの開発チームとは別の第三者的なチームとしてセキュリティレビューを行いますが、最終的なゴールは同じです。良いシステムを作り、顧客の要求にこたえることです。

今後について

セキュリティ確保の要求が強まっている状況において、最新の脅威やクラウドサービスの進化などに追随すべく、セキュリティ専門チームによるより広く深い知見の蓄積と展開が必要だと考えています。ISIDでは、従来のやり方にとらわれない、開発手法などのトレンドに応じたセキュリティレビューの仕組みを作っていってくための体制強化を行っています。

執筆:@tomita、レビュー:@sato.taichiShodoで執筆されました