落とし穴に立て札を立てるが如く

ハマりどころの解決が少しでも早くなることを願って書いていきます

【小ネタ】Azure PipelineのMicrosoft-hostedなOSがubuntuのagentsでazcopyコマンドを使うときはazcopyのバージョンに気をつけるんよー

f:id:nam_yu_sql:20210226085724j:plain この記事はcloud config tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

タイトルが長いですね。
あと何も知らない人には何を言ってるかわからないですね。
ここにたどり着いた方は多分下の方に書いてるエラー文とかで検索に引っかかった方かと思います。
今回はそういった方向けのお話になります。

結論から

Azure PipelineのMicrosoft-hostedなagentを使ってazcopyのv7にはなくてv10には含まれるコマンドを使おうとした場合、azcopyコマンドのエイリアスazcopy10 でないとThe syntax of the command is incorrect. Unrecognized command or argument 'copy' といったエラーが発生します。
エラーの意味合いとしては「azcopyにcopyと続くコマンドはないよ~」というものです。
この例ではMicrosoft-hostedなUbuntu OSのagentで azcopy copy とコマンドを打ったのですが、その際に使われたazcopyのバージョンはv7で、それには azcopy copy のコマンドが含まれていなかったことが原因です。
azcopyのv10で追加されたコマンドである azcopy copy を使用しようとした場合、 `azcopy10 copy' で書き始めることでこの問題は解決できます。

もうちょっと詳しい話

これだけだと味気ないのでもう少し結論の話に肉付けします。
Microsoft-hostedのagentとは何かということとそれに最初からインストールされているソフトウェアのお話、あとその中のazcopyコマンドのお話です。

Microsoft-hostedなagentとは

Azure pipelineではパイプラインで処理を実行するためにAgentと呼ばれる、Azure上でホストされたVMを使用します。
このVMは、自分で設定したVMを使用する(Self-hosted agent)他、Microsoftによってあらかじめ設定されたVM(Microsoft-hosted agent)を使用することもできます。
Self-hosted agentにおいては、Pipelineでビルドを行う際に必要なソフトウェアをユーザーが決めてインストールすることになります。
この作業は手間でもあるのですが、代わりにインストールするソフトウェアやハードウェア性能をより細かく設定できるという利点でもあります。
これによって、例えばアプリビルド時にライセンスが必要なUnityを設定したGPUマシマシのハイエンドなVMを用意してUnityアプリを高速でデプロイするなんてこともできます。
一方で、Microsoft-hosted agentではビルドに使うことがある多くのソフトウェアのインストールや準備を既に行っているVMが利用できます。
これによって、特にインストールなどをしなくてもaz clidotnet コマンド等を使用することができ、ビルドやデプロイのためにソフトウェアのインストールの手間をかけずに済みます。
逆に最初からインストールされていないソフトウェアを使用する場合は、agentのVMはパイプラインの処理ごとに変更が初期化されるため、毎回インストールの処理をしなければなりません。
Microsoft-hosted agentsの中でもさらにWindows Server OSを利用したものやUbuntuMac OSをインストールしたVMを使用することができます。
これによって、ビルドに使用したいマシンのOSについてある程度選択することもできます。
一般的には最初から使用できるようになっていて、かつ最初から十分に設定が行われているMicrosoft-hostedなagentを使用することになるかと思います。

Microsoft-hostedなagentにインストールされているソフトウェアの話

Microsoft-hostedなagentには初めからビルドに使うソフトウェアが色々インストールされているため特にパイプライン内でソフトウェアのインストールをせずにaz clidotnetコマンドなどを使用できるというお話をしましたが、実際にどのようなソフトウェアがインストールされているかはこちらのドキュメントに纏められています。
それぞれのOSのLinkから、そのOSのagentにインストールされているソフトウェアの一覧を見ることができます。
例えば、基本的に全部のOSにaz clidotnetコマンドがインストールされているほか、Go、npm、gitなども全部のOSでインストールされています。
面白いものではRも使えるようです。
あと、UbuntuWindows Server限定ですがDockerコマンドも利用できます。
よくやるのはGithubにコードをマージされたらDockerコマンドでコンテナ化してazコマンドでACRにデプロイとかですね。

ただしUbuntuのazcopyには注意

今回の記事の主題として注目してほしいのがこの中のUbuntuのagentにインストールされているazcopyの欄です。
Ubuntu OSのagentにはAzCopyのバージョン10.8と7.3がインストールされているのですが(2021年2月現在)、エイリアスがそれぞれ azcopy10azcopy になっています。
azcopy10 とコマンドを打つとazcopyのバージョン10.8が使用され、 azcopy とコマンドを打つとバージョン7.3が使用されます。
一方で他のOSのエージェントだとどれもazcopyのバージョン10.8のみ利用可能で、azcopyとコマンドを打つとバージョン10.8のazcopyが実行されます。
Ubuntuのagentでのみ、 azcopy のコマンドを打つとバージョン7.3のものが使用され、azocopyコマンドは認識されるもののバージョン10で追加されたコマンドが見つからず使用できないということが起きます。
気をつけましょう。

おわりに

最近行っていたパイプライン周りの作業でこのような問題に引っかかってエラーシュートに時間がかかったので「こんなおとがあるよー」という共有でした。
同じ問題で詰まった方の助けになれば幸いです。

参考

Azure DevOps PipelineのPowerShellで各種変数の取得方法チートシート

f:id:nam_yu_sql:20210225083359j:plain
この記事はcloud.config tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

みなさーん、パイプライン、組んでますか?
組んでたらどうというわけでもないのですが、最近パイプライン組み盛りのなむゆです。
Azure DevOps Pipelineではパイプラインを実行するためにyamlファイルを書きますが、そこでは様々な方法で設定した変数を利用できます。
特にpowershellでは設定した変数をフル活用して各種処理を行ったりするのですが、その設定した変数を使うときに毎回シグナルを忘れて調べる羽目になっていたのでチートシートを作った共有です。
PowerShell以外のタスクにおいても引数の取得はできますが、所によって取得のシグナルが異なっていたりするので、一番よく使う例、あと他のタスクでもたいてい同様になる例としてpowershellでのシグナルをまとめています。

各種変数の取得方法チートシート

変数の取得元 変数使用時のシグナル
パラメータ ${{ parameters.パラメータ名 }}
variableで定義した変数 $(変数名) または ${{ variables.変数名 }}
variable groupから取得する変数 $(変数名)

それぞれの変数と使いどころ

パラメータ(Runtime parameters)

パラメータはドキュメントでは「Runtime parameters」とも呼ばれ、パイプラインの実行ごとに引数として渡してやるのが特徴です。
それにより、パイプラインの実行ごとに値を切り替えることができるのでパイプラインの実行ごとに別の値を設定してやることが可能です。
yaml内では、一番上の階層にそれぞれ変数の名前、表示名、型、オプションでデフォルト値を設定して指定します。
例:

parameters:  
  - name: "sampleParam"  
    type: string  
    displayName: "SampleParameter"  

使用時は、 $ と波かっこ二つで囲い、 parameters.の後に変数名を入れて使います。
例:
${{ parameters.sampleParam }}

variable

variableは、yaml内で設定できる一般的な固定値です。
主に同じ固定値を何度も使いまわすときに使っています。
固定値の値が変更になった時の修正範囲を少なくできます。
ドキュメントにあるように、root、stage、jobのスコープに対して変数を設定することもでき、全体に対して設定すると変数名が被るような場合にも適用範囲を分けて実行することができます。
また、もし変数名が被った場合は、rootよりstage、stageよりjobの変数の値が優先されます。
スコープが狭いものほど優先して適用されるあたりcssと若干似ている用にも感じますね。
例(rootに設定する場合):

variables:  
  - name: SAMPLE_VARIABLE_VALUE  
    value: sample variable value  

使用時は、 $ とかっこで変数名を囲むか $ と波かっこで囲んでvariables.の形で書く方法が一般的です。
違いは変数の値が処理されるタイミングのようです。
テンプレートを使用しているか、conditionを使用しているかといった場合によって使い分けます。

variable group

variable groupは使用する変数の値をあらかじめ設定して保持しておく仕組みです。
これを使用することでparameter程ではないけれども使用する値が時々変更されるような場合や、yamlファイルの中には直接書き込みたくないシークレットの値を扱うことができます。
個別の値の設定の方法はドキュメントにあるので今回は省略します。
以下はパイプラインyamlでの使用例です。
variableと同様にvariablesに書きますが、- group として設定してやる必要があります。
例:

variables:  
  - group: SAMPLE_VARIABLE_GROUP  

これで、 SAMPLE_VARIABLE_GROUP のvariable groupから値が読み出されるようになりました。
個別のvariableの名前を宣言する必要はなく、これでこのvariable groupの中の変数が読み出せるようになります。
以下の例では、 SAMPLE_VARIABLE_GROUPのvariable group内にSAMPLE_VARIABLE_GROUP_VALUE という名前の変数が設定されていると仮定した例です。
例:
$(SAMPLE_VARIABLE_GROUP_VALUE)

なお、variable groupの値についてはpowershell内では $() の書き方のみ使用できるようです。

おわりに

今回はazure pipelineで設定する変数のpowershell上での取得方法のチートシートを共有しました。
パイプラインを作成する際にはたいてい何かしら変数を使って処理を出し分けたい要件があると思いますが、その際に役に立てば幸いです。

参考

久々に機械学習に触りたくなって。Azure Machine Learningで回帰モデルを作る・後編

f:id:nam_yu_sql:20210216084031j:plain

この記事はcloud.config tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

続きまして

この記事は前回の「久々に機械学習に触りたくなって。Azure Machine Learningで回帰モデルを作る・前編」から引き続いての後編になります。
今回は前回作った「データ投入」「前処理」の部分に続き、「モデルトレーニング」の部分を作っていきます。

モデルのトレーニングを行う

まずは回帰モデルをトレーニングする部分のパイプラインを作成します。
「Normalize Data」の下に続けて画像のようにモジュールを探してきて配置します。配置したら、矢印をつなぎ合わせます。
f:id:nam_yu_sql:20210216084147p:plain
モジュールの配置と接続ができたら、それぞれの設定を行っていきます。
まずは「Split Data」の設定を開きます。
「Fraction of rows~」とある部分を0.7、Random seedはLearnと合わせて123にします。
「Fraction of rows~」は、下に伸びているパイプの左側に送るデータと右側に送るデータを分ける割合になります。
回帰モデルを作るのにあたって、モデルをトレーニングするのに使うデータとそのデータの評価をするのに使うデータを分けるために設定しています。
「Random seed」は、その割合でランダムに振り分けるときに使うシード値です。
f:id:nam_yu_sql:20210216084316p:plain
続いて、「Train model」を設定します。
ここでは回帰モデルで予測する対象の値を決めます。
今回の分析では、車の各種情報から自動車の価格を予測しようとしているので、「列の編集」ボタンから、予測の対象である価格を選択しておきます。
f:id:nam_yu_sql:20210216084330p:plain
これでパイプラインの設定は完了です。
前回と同様にデザイナー画面上部の「送信」ボタンを押してモデルのパイプラインを実行します。
今回は、前回正規化まで行った実験があるので、それを選択します。
これによって、処理を途中まで行った結果を用いてそれ以降の処理を行うことができます。
「送信」ボタンを押して処理を実行します。
f:id:nam_yu_sql:20210216084408p:plain
しばらくして処理がすべて完了したら結果を見てみましょう。
「Score Model」の「出力とログ」タブを開き、「Scored dataset」から視覚化のアイコンをクリックします。
f:id:nam_yu_sql:20210216084419p:plain
すると、このようなモデルのスコア付の結果が出力しています。
特に注目したいのが、「price」と「Scored Labels」の列です。
price はその車の実際の価格で、その隣のScored Labelsは今回トレーニングした回帰モデルを使って予測された価格です。
実際の価格より高かったり安かったりしますが、ある程度近い値が産出されているように見えるかと思います。
f:id:nam_yu_sql:20210216084430p:plain

おわりに

今回は久々にAzure Machine Learningを利用して機械学習の実装を試してみました。
個人的には以前に書籍を読みながらいろいろ試したり学生時代からっきしだった数学にまた取り組んでみたりして打ち込んだ当時の情熱が思い起こされて何かしら懐かしい気分になりました。
Azure Machine Learningというサービスとしては触るたびに見た目が変わっていて、当時感じた技術やサービスの進歩の速さを今回も感じられました。
また定期的に触っていこうかと思います。

参考

久々に機械学習に触りたくなって。Azure Machine Learningで回帰モデルを作る・前編

f:id:nam_yu_sql:20210215085837j:plain この記事はcloud.config tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

最近、再び機械学習熱が出てきたなむゆです。
AzureにはAzure Machine Learningという機械学習をローコードで行うサービスがあります。
これで久々に遊んでみようと思ったのですが、いつも頼りにしている Microsoft Learningのハンズオンを試していて日本語翻訳周りでかなり混乱した部分があったので、そのあたりを補完しながらリソース作成→回帰モデル生成までの流れをまとめてみたいと思います。
ただ、纏めていたら分量と画像の量が多くなってきたので、今回は内容を前後編に分け、前半ではサンプルデータの正規化まで行います。

下準備

まずはAzure ポータルから「Azure Machine Learning」のサービスを検索し、リソースを作成します。
リソースの名前とリージョン名だけ妥当な名前を入力し、作成を行います。
f:id:nam_yu_sql:20210215084824p:plain
リソースが作成されたら、作成したAzure Machine Learningのリソースに移動し、「スタジオの起動」のボタンをクリックします。
すると、別タブでAzure Machine Learningの操作を行うスタジオのページが開きます。
Azure Machine Learningの機械学習関連のタスクは主にここで行われます。
f:id:nam_yu_sql:20210215084845p:plain
次は機械学習モデルのトレーニングに必要な「コンピューティングクラスター」を作成します。
Machine learningスタジオのホーム画面の左下の方にある「コンピューティング」ボタンを押します。
f:id:nam_yu_sql:20210215084856p:plain
コンピューティングのページのタブを「コンピューティングクラスター」に切り替えます。
ここには作成したのコンピューティングクラスターの一覧が表示されますが現状は存在しないので「新規」ボタンから新規作成を行います。
f:id:nam_yu_sql:20210215084908p:plain
設定内容としてははLearnで解説されているとおり仮想マシンに「Standard_D11_v2」を選択したいのですが、初期状態では仮想マシンの選択肢にそのオプションが表示されていません。
なので、「仮想マシンのサイズ」の欄の「全てのオプションから選択」のラジオボタンを選択状態にしてそのオプションを表示させ、選択しておきます。
設定したら「次へ」ボタンを押します。
f:id:nam_yu_sql:20210215084917p:plain
続いてクラスターのコンピューティング名などを設定します。
ここもLearnに合わせて最大ノード数を2に設定します。
コンピューティング名は覚えられるもので設定しましょう。自分の場合は「namuyutest」としています。
設定できれば「作成」ボタンを押してクラスターの作成を開始します。
f:id:nam_yu_sql:20210215084934p:plain
これで必要な下準備は完了です。続いて実際にモデルを作成していきましょう。

データの前処理を行う

今回はオーソドックスに回帰モデルを作っていくのですが、一般的に機械学習を行う時の流れとして「データを取ってくる」→「データの前処理を行う」→「モデルのトレーニングを行う」という手順を踏みます。
この処理をそれぞれ一つの塊として、モデル作成の手順を一続きにしてつなぎ合わせたものを「パイプライン」と呼びます。
Azure Machine Learningで機械学習を行う方法の一つとして、そのパイプラインを「デザイナー」という機能を使って行うものがあり、今回はそれを利用します。

まずはホーム画面から、再び左の法のアイコン一覧のうち今度は上の方の「デザイナー」のボタンをクリックします。
すると、これまでデザインしたパイプラインの一覧の画面に移るのですが今回はまだパイプラインを作成していないので上の方のプラスボタンを押して新規作成します。
f:id:nam_yu_sql:20210215084955p:plain
デザイナーの画面にやってきました。
ここでまず行うのは、Learningと合わせてパイプラインの名称を変えることです。
現在のパイプラインの名称をクリックすると名前を変更できるので、「Auto Price Training」に置き換えておきます。適当にどこか別のところをクリックすると自動でセーブされます。
f:id:nam_yu_sql:20210215085007p:plain
次に、その名前の横の歯車ボタンから、パイプラインの設定画面に入ります。
ここで、このパイプラインがモデルのトレーニングに使用するコンピューティング先(コンピューティングクラスター)を選択します。
f:id:nam_yu_sql:20210215085017p:plain
先程作成したコンピューティングクラスターを選択して確認ボタンを押します。
ちなみにその確認ボタンはモーダルの中の画面外の下の方にあるのでスクロールして探してください。
間の空白は一体。
f:id:nam_yu_sql:20210215085029p:plain
設定を終えたら、パイプラインのデザインを行っていきます。
まずは、「データを取ってくる」の部分を作ります。デザイン画面右上の本棚のようなボタンを押し、出てくる検索窓に「automobile」あたりの文字を入力し、「Automobile price data (Raw)」を探します。
これが今回使用するサンプルデータです。
見つけられたら、これをデザイン画面内にドラッグアンドドロップします。
f:id:nam_yu_sql:20210215085159p:plain
次はこのデータに前処理をかける部分を作成していきます。
再び本棚のアイコンをクリックし、今度は「Select Columns in Dataset」をドラッグアンドドロップします。
これはこのモジュールにやってきたデータから必要な列だけを選択する部分になります。
f:id:nam_yu_sql:20210215085216p:plain
ドラッグアンドドロップ出来たら、これまで持ってきたモジュールをつなぎ合わせます。「Automobile price data (Raw)」の下の〇から「Select Columns in Dataset」の上の〇までドラッグします。
これによって、生のデータから列を選択することができるようになります。
f:id:nam_yu_sql:20210215085225p:plain
次はその列選択の設定を行います。
列選択のモジュールをクリックし、右に出てくる設定画面から「列の編集」をクリックします。
f:id:nam_yu_sql:20210215085236p:plain
すると、このモジュールにやってくるデータの中のどの列を使用するかを選べます。
ここでは「名前別」のラジオボタンをクリックし、使用する列を選択します。
今回は「normalized-losses」以外の列を全部使用するので、列を全部追加した後で「normalized-losses」だけを削除する形で設定しました。
設定ができたら、「保存」ボタンをクリックして閉じます。
f:id:nam_yu_sql:20210215085255p:plain
次は、「Clean Missing Data」と「Normalize Data」のモジュールを同じく本棚のメニューから探して持ってきて、画像のようにつなぎ合わせます。
これらは、それぞれデータの入っていない列のあるデータの削除を行ったり、データの正規化(それぞれのデータの値が取る値の範囲を扱い範囲に収まるよう変形する)を行ったりするのに使います。
f:id:nam_yu_sql:20210215085305p:plain
これらの設定を行っていきましょう。
まずは「Clean Missing Data」の設定から始めます。
ここでは、特定の列に足りないデータがある際の動作を設定するのですが、まずは「列の選択」をクリックして足りないデータがあるかチェックする列を指定します。
今回は「bore」「stroke」「horseposer」の3つを設定して保存します。
f:id:nam_yu_sql:20210215085331p:plain
続いて、設定画面の下の方の「Cleaning mode」から、先程選択した列の値が存在しなかった場合の振る舞いを設定します。
今回は、それらの値が存在しなかった場合はそのデータがある行を丸々サンプルから排除することにするため、「Romove entire row」を選択します。
f:id:nam_yu_sql:20210215085341p:plain
次に「Normalize Data」をクリックしてデータの正規化の設定を行います。
今回は、正規化の処理を行う列を選択するため、再び「列の選択」をクリックして設定モーダルを開きます。
ここでは、以下の画像に示している列の名前をルールに追加しておきます。
これによって、追加した名前の列のデータに対して正規化を書けることができます。設定できたら保存ボタンを押して戻ります。
f:id:nam_yu_sql:20210215085350p:plain
ここまででサンプルデータの前処理のパイプラインを組むことができたので、これを実行してみましょう。
デザイナー画面上部の「送信」ボタンを押し、パイプライン実行のセットアップのモーダルを呼び出します。
新しい実行を行うので、「新規作成」のラジオボタンを選択し、新しい実験名として「mslearn-auto-training」を入力します。
設定ができたら下部の「送信」ボタンを押してこのパイプラインの処理をコンピューティングクラスターに送信します。
これで実験が始まるのでしばらく待ちましょう。
f:id:nam_yu_sql:20210215085401p:plain
実験が進むと各モジュールの横に「完了」と表示され、全部のモジュールの処理が完了すればパイプライン全体の処理が完了となります。

処理の完了したモジュールは、その処理の終了時点での出力を確認することができます。
例えば、「Normalize Data」の出力を確認してみます。
Normalize Dataのモジュールを開き、「出力とログ」のタブを開きます。
上の方の「データ出力」の欄の「Transformed dataset」の棒グラフのアイコンをクリックすると出力されたデータが確認できます。
f:id:nam_yu_sql:20210215085432p:plain
ここで各種データの値と、列ごとに集計された棒グラフが確認できます。
棒グラフからはデータの全体的な分布を把握することもできます。
この図とパイプラインの視点になる生データのモジュールの出力を見比べると前処理として削除されたデータや列があったり、正規化されてデータの値が大体-1から1の間に変換されている列があることが分かるはずです。
f:id:nam_yu_sql:20210215085445p:plain

おわりに

今回はAzure Machine Learningのデザイナーを使用して機械学習のパイプラインをデータの正規化をするところまで作成しました。
Learnを見ながらやると途中で表示内容が違っていて詰まることが多かったので、その部分が補完できているとうれしいです。
続きはまた完成し次第リンクを張ろうと思います。

参考

Azure Active DirectoryのアカウントでSQL Databaseにログインしようの会

f:id:nam_yu_sql:20210212090906j:plain
この記事はcloud.config tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

DP-300の資格試験に完全勝利したなむゆです。
この資格はAzureのRDBサービス周りの各種機能について習熟していることを示す資格で、その試験勉強中に触った機能で面白かったものをピックアップしてみようということで一席打ちます。
ということで今回はSQL DatabaseにAzure Active Directoryのアカウントでログインできるようにしてみます。

Azure Active DirectoryのアカウントでSQL Databaseにログインできるようにする

まずはいつものようにSQL Databaseのリソースを作成します。
f:id:nam_yu_sql:20210212090937p:plain
リソースを作成したら忘れずに現在のIPからのアクセスを「サーバーファイアウォールの設定」から行っておきましょう。

設定できたら、次はSQL DatabaseのActive Directory管理者を設定します。
このユーザーはAzure Active Directoryに登録されているユーザーの中で最初にSQL Databaseにログインできるようにするユーザーで、そのユーザーを用いて他のActive Directoryに登録されたユーザーをSQL Databaseにログインできるようにできます。
f:id:nam_yu_sql:20210212091148p:plain
SQL Databaseのリソースの中の「Active Directory管理者」を選択します。
出てきた表示の上部に「管理者の追加」があるので、そこをクリックします。
f:id:nam_yu_sql:20210212091151p:plain
そうすると、現在使用しているActive Directoryのユーザーの一覧があるので、今回はあらかじめ作成しておいた「testtest」という名前のユーザーを登録しておきます。
このユーザーを選択し、「選択」ボタンをクリックして戻ります。
最後に「保存」をクリックして保存します。

これによって最初のActive DirectoryのユーザーがこのSQL Databaseにログインできるようになりました。
このユーザー情報でSQL Databaseにログインできることを確認しましょう。
ここからの作業はSSMS(SQL Server Management Studio)を使用しますのでまだインストールしていない場合はインストールしておきます。

SSMSを開き、データベースに接続します。ログイン時に「認証」の欄を「Azure Active Directory - パスワード」を選択します。
その下に先程追加したActive Directoryユーザーのユーザー名とパスワードを入力します。
ユーザー名はユーザープリンシパル名が全文必要なので、プロファイルのページから全文コピーしてきましょう。
f:id:nam_yu_sql:20210212091154p:plain
これでActive Directory管理者のユーザーでログインできたはずです。
次は、このユーザーを用いて他のAzure Active Directory上のユーザーを追加していきましょう。
接続したデータベースを右クリックして「新しいクエリ」を選択し、クエリエディタを呼び出します。
f:id:nam_yu_sql:20210212091144p:plain
そこに、以下のクエリを打ちこんで実行します。
{ユーザープリンシパル名}は実際に存在するユーザーのユーザープリンシパル名を置き換えて実行してください。

CREATE USER [{ユーザープリンシパル名}] FROM EXTERNAL PROVIDER  
GO  

これでもう一つのActive Directory上のユーザーがSQL Databaseに追加されました。
SSMSをもう一つ開き、そのユーザーのユーザー名とパスワードでログインしてみましょう。
ログインできるようになっているはずです。

このようにして、Azure SQL DatabaseにAzure Active Directory上のユーザーを用いてログインできるようにできます。
ただ、この状態だとActive Directory管理者が追加したユーザーは個別のデータベースには接続できず、何の権限も与えられていない状態なので個別に権限を与えてやる費用があります。

おわりに

今回はAzure SQL DatabaseにAzure Active Directoryのアカウントを用いてログインしてみました。
これができることによって、アプリケーションの開発者がSQL Databaseに対して毎回フル権限のある管理者アカウントでログインすることで事故を起こす可能性を減らし、また、それぞれのDBのユーザーの登録情報(例えばパスワード変えたりActive Directoryから削除したり)といった変更をActive Directoryへの変更だけで済ませることができます。
Azure SQL Databaseの利用者の権限について制約がある場合に検討することが多いトピックのように思うので、頭の隅に留めておくと役立つかと思います。

参考

動かしながら学んだKubernetes Istioのメモ

f:id:nam_yu_sql:20210208065704j:plain この記事はcloud.config tech blogにマルチポストしています。

tech-blog.cloud-config.jp

はじめに

最近ずっとkubernetesの勉強しているなむゆです。
特にここ4週間くらいはIstioについて重点的に動かしたり資料を読んだりしていたのでその時に学んだ基礎的な点を記事にまとめておきたいと思います。

istioとは

Istioとは、高機能なオープンソースのサービスメッシュです。
Kubernetesのようなプラットフォームにインストールして使用され、内部にサービスメッシュを展開します。
現在はKubernetesのほかに、HashiCorpによってつくられたサービスディスカバリのConsul、または個別の仮想に対応しています。

サービスメッシュとは

「高機能なサービスメッシュ」と書きましたが、ではそのサービスメッシュとは何かというと、マイクロサービスアーキテクチャのようなサービスを複数展開し、相互に連携して全体の機能を実現しているときにそれらのサービス間のネットワークを仲介する機能です。
例えば、サービス間で通信したいとなった際に通信相手のサービスの名前解決を行ったり、それらの通信に失敗したときのリトライ機能などを基本的な機能として持ちます。
これにより、マイクロサービスアーキテクチャにおいて課題になりがちであった、サービス間の通信の障害や通信が増えることによる性能劣化といった問題を解決し、マイクロサービスアーキテクチャを実現しやすくしてくれます。
実際にどんな実装が行われていてどんな機能が実現されているかはサービスメッシュによって差があります。

これがあると何がうれしいの?

Istioはそんなサービスメッシュを実装しているもののうちの一つです。
これがなくてもkubernetesにおいてリクエストやkubernetes内のネットワークを構築することはできなくはないのですが、サービスメッシュを使うとその仕組みをより高機能に、より簡単に実装できます。
例えば、クラスター内の通信について、リトライ処理を追加したりA/Bテストを行う時に使うような割合でトラフィックを分割する仕組み、リクエストのタイムアウトの時間などを設定できます。
それらの通信についてメトリクスやログを取ることもでき、kialiやgrafana等の可視化ツールと連携してネットワークの監視を行うこともできます。
これらの機能をいくつかの設定を行うだけで実現できるのがサービスメッシュの強みになります。

アーキテクチャ

詳しい個別の情報についてはドキュメントをどうぞ。
ドキュメントが英語なのと個別に見ていくとキリがないので分かりやすい粒度でまとめてみます。
Istioのサービスメッシュは大きく分けるとData Planeという部分とControl Planeという部分に分かれます。
これらはオブジェクトとして物理的にわかれているものではなく概念的な分類なのですが、それぞれでIstio内で担う役割が違います。

Data Plane

まずData Planeなのですが、こちらは外部からやってきたものやサービスの間で交わされる通信を実際に行う役割を担います。
具体的には、Envoyと呼ばれるリソースがあり、これがkubernetes内に立てられるサービスごとにペアとなるように作られます。
このペアのように作られる様子をサイドカーと呼んだりします。バイクに対するサイドカーのように、サービスごとに横付けされるように作られるためです。
で、これが何をするものなのかと言うと、例えるなら家ごとに置かれた郵便受けやポストのようなものになります。
具体的には、他のサービスやkubernetes外部と送受信を行うプロキシになります。
外部からやってきた通信はまずEnvoyに届き、プロキシが横付けしたサービスにその内容を伝えます。
また、外部に対する通信もサービスからEnvoyに送り、そこから他のサービスやkubernetes外部に内容が送られます。
年賀状も家に届くときはまず郵便受けに届いてそこから取り出しますし、送るときは送り先に直接届けるのではなくポストに投函しますよね。
Envoyもそのような役割を果たし、ネットワーク関連の言葉で言うとプロキシの役割を果たします。そしてそれはサービス毎にサイドカーとして作られ横付けされたサービスに対するプロキシになるわけです。
また、Envoyを通して通信を行うことで通信時のトラフィックの統計情報を収集する役割もあります。

Control Plane

Control Planeは、そんなData Planeを制御する役割を持ちます。
代表的な例としてはどんなurlのリクエストがやって来たらどこのサービスにそのリクエストを送り届けるかといったルーティングVirtual Serviceを用いて行うというものがあります。
これによってkubernetes外部からやってきたリクエストをどのサービスに渡すかを制御します。
他にも、kubernetes内のサービス間での通信を制御し、通信時にルールを設定することでセキュリティの機能を実装することもできます。
これらの機能は、細かく分けるとさらにPilot(Istioの通信制御等のルールをEnvoyに伝えたりその他便利機能)、Citadel(証明書周り)、Galley(Istioに対して行う設定受けつけ)といった部分に分かれますが、今は全部まとめてIstiodというものにまとめられているようです。
なので、IstiodはEnvoyの制御を行うControl Planeの役割を大体になっているようなイメージになります。

ざっくりした動作の流れ

ここまでIstioの個別の部分の説明してきましたが、それだけだとそれを使ってどのような流れの処理になるのかイメージしづらいので、外部からリクエストがやってきてそれに対してレスポンスを行うまでの流れをざっくりと解説してみます。

全体の図としてはこのようになります。マイクロサービスアーキテクチャを採用しているのでサービスは複数あり、それぞれにEnvoyがサイドカーとして横付けされています。
この中で、EnvoyはData Planeに属しています。
この図の中で、黄色い付箋はそれぞれ一個のpodになります。
f:id:nam_yu_sql:20210208070035p:plain
kubernetesにリクエストがやってきました!
まずはこれをIngress Gatewayが受け取ります。
Ingress Gatewaykubernetes外部からやってくるリクエストの窓口で、ここからVirtualServiceのようなオブジェクトで設定したルールに応じて各種内部のサービスにリクエストを送り届けます。
f:id:nam_yu_sql:20210208065855p:plain
というわけで今回はサービスAにリクエストを送りたいのでサービスAにサイドカーとして横付けされたEnvoyにリクエストが届きました。
f:id:nam_yu_sql:20210208070048p:plain
EnvoyはそれをサービスAに渡します。
f:id:nam_yu_sql:20210208070057p:plain
今回の処理ではサービスBでの処理も行わなければならないため、サービスBに対しても通信を行います。
その際にも、まずはEnvoyと通信し、そこからサービスBへ通信を行います。
f:id:nam_yu_sql:20210208070107p:plain
サービスBでも同様に、まずEnvoyが通信を受け取り、それをサービス本体に渡します。
こうしてサービスAとサービスBの通信が実現します。
f:id:nam_yu_sql:20210208070120p:plain
サービスBでの処理が終わればまたEnvoyを通して処理結果をサービスAに返し・・・
サービスAはegress gatewayを経由してリクエスト元のkubernetesクラスター外にレスポンスを返します。
f:id:nam_yu_sql:20210208070336p:plain
これがIstioを用いてkubernetes内で通信を行う一連の流れになります。
実際にはさらにDBなどkubernetes外部のリソースと通信するために何度もegress gatewayを用いて通信を行ったりもします。

あれ、Control Planeは?

・・・本当はさらにControl Planeもこれらの処理に一枚噛んでいます。
同時に説明すると一つの動作の説明が増えるので章を分けました。
先程の例でのControl Planeの役割を説明します。

例えば、Ingress gatewayにやっていたリクエストをどのサービスに渡すかのルーティングの制御をControl Planeが行います。
VirtualServiceに設定したルーティングのルールに従い、ingress gatewayで受け取ったリクエストをどのサービスに渡すかを決め、Envoyに対してリクエストを送らせるようにします。
f:id:nam_yu_sql:20210208070416p:plain
また、サービスAとサービスBの間の通信において認証、認可の機能が必要になった場合のそれらの仕組みもControl Planeで実装します。
f:id:nam_yu_sql:20210208070427p:plain
他に、DestinationRuleやVirtualServiceを操作してサービスのバージョンアップを行う際のBlue/Greenデプロイやサーキットブレイカーなどを実装したりもします。
f:id:nam_yu_sql:20210208070447p:plain
こうした形でControl PlaneはData Planeを裏から制御する振舞いをしています。

インストール方法

それでは実際の使い方を説明していきます。
環境としてはWindows 10 HomeのOSのPCにDocker DesktopのKubernetes機能で立てたシングルノードのkubernetesを使用します。
導入方法はこちらでまとめているので、まだ導入していない場合はこちらを参考にどうぞ。

導入されたらば、次に進みます。

まずはPC上にIstioctlをダウンロードしてきます。

こちらのサイトの「istioctl-(バージョン)-win.zip」をダウンロードしてきて解凍します。
解凍したらば、分かりやすい場所に移動してそのディレクトリにPathを通します。

Pathを通してistioctlが使用できる状態になれば、インストールする対象のクラスターを現在使用しているコンテキストに指定します。

例えばDocker Desktopで立てたkubernetesにインストールする場合はPowerShell等で下記のようなコマンドを実行します。

kubectl config use-context docker-desktop  

コンテキストを切り替えたら、下記のコマンドで現在のコンテキストで接続するクラスターにistioをインストールします。

istioctl install --set profile=default -y  

「profile=○○」という部分によって、インストールされる内容が変わります。defaultのほかにdemominimal等があり、それぞれのセットアップの内容はこちらに解説があります。

weatherforecastアプリをデプロイしてみる

ここからはIstio公式サイトのGetting Startedをベースに、.net coreアプリをkubernetes上にデプロイして動かしてみます。
Getting Startedではサンプルのアプリケーションとしてbookinfoアプリを動かしてみていますが、今回は普段触れることの多いので.net coreアプリも同様にデプロイできることを示すため以前のブログで作成したweatherforecastのアプリをデプロイしてみます。
そのため、アプリケーションを作成する部分については上記のブログを参考にしながら作成していることが前提となります。
手順2まで済ませたら、こちらの手順に合流しても大丈夫です。
docker buildする際にはあとでタグが分かりやすくするために以下のコマンドでビルドします。

docker build -t weather-forecast:weather-forecast .  

コンテナが作成できたら、アプリケーションをデプロイしてIstioを用いてルーティングを行うためのマニフェストファイルを作成していきます。
以下の3つのyamlコードをコピーして同じディレクトリのファイルに保存してください。

apiVersion: v1  
kind: Namespace  
metadata:  
  name: weather-forecast  
  labels:  
    istio-injection: enabled  
apiVersion: networking.istio.io/v1alpha3  
kind: Gateway  
metadata:  
  name: weather-forecast  
  namespace: weather-forecast  
spec:  
  selector:  
    istio: ingressgateway # use istio default controller  
  servers:  
    - port:  
        number: 80  
        name: http  
        protocol: HTTP  
      hosts:  
        - "*"  
---  
apiVersion: networking.istio.io/v1alpha3  
kind: VirtualService  
metadata:  
  name: weather-forecast  
  namespace: weather-forecast  
spec:  
  hosts:  
    - "*"  
  gateways:  
    - weather-forecast  
  http:  
    - match:  
        - uri:  
            exact: /weatherforecast  
      route:  
        - destination:  
            host: weather-forecast.weather-forecast.svc.cluster.local  
            port:  
              number: 80  
  
apiVersion: v1  
kind: Service  
metadata:  
  name: weather-forecast  
  namespace: weather-forecast  
  labels:  
    app: weather-forecast  
    service: weather-forecast  
spec:  
  ports:  
    - port: 80  
      name: http  
  selector:  
    app: weather-forecast  
---  
apiVersion: apps/v1  
kind: Deployment  
metadata:  
  name: weather-forecast-v1  
  namespace: weather-forecast  
  labels:  
    app: weather-forecast  
    version: v1  
spec:  
  replicas: 1  
  selector:  
    matchLabels:  
      app: weather-forecast  
      version: v1  
  template:  
    metadata:  
      labels:  
        app: weather-forecast  
        version: v1  
    spec:  
      containers:  
        - name: weather-forecast  
          image: weather-forecast:weather-forecast  
          imagePullPolicy: IfNotPresent  
          ports:  
            - containerPort: 80  

yamlファイルを作成できたら、PowerShellを開きます。
上記の3ファイルを置いてあるディレクトリまで移動しておいてください。

移動出来たら、そのディレクトリにある3つのマニフェストファイルをkubernetesに適用します。

kubectl apply -f .  

これで作成したマニフェストファイルが適用され、指定したオブジェクトが生成されます。
一番重要なアプリケーションのPodが動作しているかどうかは以下のコマンドで確認できます。

kubectl get pods -n weather-forecast  

STATUSの欄がRunningになっていればデプロイに成功しています!

デプロイに成功したら、このAPIを叩いてみましょう。
ブラウザを開き、URLの入力欄にlocalhost:80/weatherforecastと入力してアクセスできます。
Json型のレスポンスが返ってくれば成功です!

このURLにアクセスすると、Gatewayで指定したとおり、80番ポートからkubernetesにリクエストが入ります。
それからIngressGatewayにおいてVirtualServiceに設定したとおりに/weatherforecastのパスにやってきたリクエストはweather-forecast.weather-forecast.svc.cluster.localのhostに送られます。
このhostはこちらで解説されているように、{サービス名}.{namespace名}.svc.cluster.localのルールに従って名前解決されるので、weather-foreastのnamespaceのweather-forecastサービスにリクエストが流れます。
weather-forecastのnamespaceのweather-forecastサービスにはDeploymentのオブジェクトで指定したとおりWeatherForecastのアプリのPodが結び付けられているので、めでたくリクエストはWeatherForecastのアプリケーションにたどり着きます。

このようにして、Istioを使用して通信のルーティングを行うことができます。

おわりに

今回はIstioの基本的な点を説明しながら、実際に動かせるアプリケーションを立てる方法を説明しました。
以前のkubernetesの学習環境の導入方法アプリのコンテナのビルドの方法と合わせることで、アプリケーション開発~kubernetes上でサービスを利用可能にするするまでの一連の作業が順を追って理解できると思うので、Istioだけでなくkubernetes出のアプリの開発、運用の基本的な方法を知りたいという方はこれらの過去記事もご覧ください。

参考

暗号化しろーーー!!!!(もうされてる!)SQL Serverのデータを暗号化して保護するTDEを設定する

f:id:nam_yu_sql:20210203093007j:plain この記事はcloud.config tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

こんにちは、相変わらずDP-300受験のためあれこれ調べたり試したりしているなむゆです。
今回もその学習中に見つけたAzure Sql Databaseのセキュリティ系の機能で一席打ちたいと思います。

TDE(透過的なデータ暗号化)とは

TDEとはTransparent Data Encryptionの略で、データベースのデータを暗号化して保護する機能です。
例えば、データベースにINSERT文でデータを挿入するときに、ディスクに書き込みしようとしたタイミングでそのデータを暗号化して保存します。一方で、そのデータを取り出そうとしたときはメモリに読みだされるタイミングで暗号化を解除します。
暗号化と暗号化の解除には暗号化キーと呼ばれるものが必要で、特に自前のサーバーにあるSQL ServerにTDEを設定するときには暗号化キーを作成し、それをSQL Serverの暗号化キーとして設定してやる必要があります。
ちなみに、SQL Databaseでは2017年以降この機能がデフォルトで設定されており、新しくリソースを作る際にTDEを設定するために新しく何かを追加で設定する必要はありません。
f:id:nam_yu_sql:20210203093035p:plain
しかし、例えばもしデータベースの暗号化に自前の鍵を使いたーい!となった場合にはそのような設定を加えることもできます。
次のパートではその方法を見ていきます。

Key Vaultにキーを保存してそのキーを使用してTDEを設定する

こちらに用意しましたのは前回の記事で作成したSQL Databaseです。
こちらには前回の記事で作成したユーザー情報的なデータが格納されています。
f:id:nam_yu_sql:20210203093115p:plain
まずは先にKey Vaultを作成しておきます。
今回は「tdetestnamuyu」あたりの名前でどうでしょうか。
f:id:nam_yu_sql:20210203093128p:plain
それでは、Azure Key Vaultから鍵を取得してTDEを設定するために、まずは SQL Serverのメニューの「Transparent Data Encryption」を開きます。
そして、設定を「顧客が管理するキー」に変更します。
f:id:nam_yu_sql:20210203093140p:plain
するとその下に使用するキーを選択する部分が出てくるので、「キーの変更」をクリックします。
f:id:nam_yu_sql:20210203093151p:plain
ここではキーを保存するKey Vaultを設定します。キーコンテナーのドロップダウンから先程作成したKey Vaultを選択しましょう。
f:id:nam_yu_sql:20210203093200p:plain
するとKey Vaultに保存されている度のキーを使用するか確認されますが今回はまだキーがないので「新規作成」をクリックし、名前を設定して新規作成します。

新規作成したら、作成されたキーのバージョンを設定し、「選択」をクリックして戻ります。
そして最後に、「保存」ボタンをクリックしてTDEの設定を確定すると、それ以降Key Vaultから暗号化キーを取得して暗号化、暗号化解除を行うようになります。
f:id:nam_yu_sql:20210203093208p:plain
と言っても特にそれで何が変わったか実感することはほとんどないですが・・・

ちょっと悪いことしよう

先程の説明で、暗号化キーはデータを挿入するとき、読み出しを行うときに使用されると解説しました。
では、その暗号化キーを削除するといったいどうなってしまうのでしょうか?
試してみましょう。
f:id:nam_yu_sql:20210203093513p:plain
あっあっ大事な鍵がー!
f:id:nam_yu_sql:20210203093523p:plain
ということでさっくり暗号化キーを消し飛ばしました。
さて、TDEの暗号化や複合化で使う暗号化キーを削除すると、SQL Databaseはいったいどうなってしまうのでしょうか(棒)
f:id:nam_yu_sql:20210203093533p:plain
クエリエディタを開いてログインしようとすると、このようなエラーが出ました。
KeyVaultからキーが読み出せなくなったので、SQL Databaseにログインすらできなくなりました。
当然ながらこの状態ではデータの書き込みも読み出しもできません。
f:id:nam_yu_sql:20210203093544p:plain
SQL Databaseの概要画面でも、キーが取得できなくなったことに対する怒りのメッセージが出ています。
f:id:nam_yu_sql:20210203093557p:plain
こうなると、キーをKeyVaultの機能を用いて復元するか別所に用意したKeyVaultに保管しておいた同じキーを再設定しない限りデータは復元できません。
KeyVaultに時前の鍵を用意してそれを用いてTDEを設定する際は、誤ってそのリソースを削除したりキーを削除したりしてしまわないようにリソースにロックをかけたりKeyVaultの設定でキーを論理削除できるようにしておきましょう。
復元の手段は多重に確保しておく必要があります。

おわりに

今回はSQL Database(SQL Serverも)のデータベースの保護機能のであるTDE(透過的なデータ暗号化)について共有しました。
データベースの保護機能としてSQL Databaseにおいてはデフォルトで設定されている部分ですが、要件次第でカスタマイズも可能です。
ただ、その場合はくれぐれも鍵をなくさないように・・・というのがポイントかと思います。
こんな機能もあるのかと心に泊めていただけると幸いです。

参考