VSCodeのRemote Development-Containers

アプリケーションの開発をするときに、ローカルで環境で実行しているかのようにリモート環境に接続して、開発をすることができる便利な機能です。 この機能を利用すれば、ローカル環境にインストールされているプログラミング言語のバージョンがランタイムと異なっている場合でも、ローカル環境に影響を与えずにクラウドにデプロイするためにテストをすることができるようになります。

VSCode Remote Development の発表のブログRemote Development with Visual Studio Code

f:id:akubicharm:20191023033829p:plain

Remote Developmentでは、3種類のリモート接続して利用できる環境があります。

ここでは、Remote Development-Containerの利用方法を紹介します

VSCodeへのRemote Development拡張機能のインストール

  • VSCodeの左下の歯車マークをクリックし、プルダウンメニューから[Extensions]をクリックします。 f:id:akubicharm:20191023035348p:plain

  • [Remote Development] と検索キーワードを入力して拡張機能を検索し、[Remote Development]を選択してインストールします。 f:id:akubicharm:20191023035712p:plain

※インストールが完了すると、左下の歯車マークの下に緑色のRemote Developmentのアイコンが表示されます。 f:id:akubicharm:20191023040033p:plain

Remote Development-Containersでの開発

コンテナ環境を利用するために、Dockerデーモンを起動しておきます。

  • 画面左下のRemote Developmentアイコンをクリックしてコマンドパレットを開き、[Remote-Containers: Open Folder in Container...] をクリックします。 f:id:akubicharm:20191023041140p:plain

  • ダイアログで開きたいフォルダを選択します。 f:id:akubicharm:20191023041330p:plain

  • 開発する対象を選択します(ここではAzure Function & Node.js (LTS)を選択)。 f:id:akubicharm:20191023041602p:plain

  • Remote Development-Containers の環境を整備が開始されます。 f:id:akubicharm:20191023041841p:plain ここでやっていることは、開発に利用するDockerコンテナイメージを生成するためのDockerファイルの作成と、そのDockerファイルを使ったコンテナのビルドと実行です。 環境準備が終わると、指定したフォルダーには .devcontainer というディレクトリができています。

  • VSCodeのViewメニューからTerminalを選択します。 f:id:akubicharm:20191023042511p:plain

  • [Dev Containers]は、開発環境のDockerコンテナを実行しているターミナルです。もう一つターミナルを開いてプロンプトを確認するとDockerコンテナに入っていることがわかります。 f:id:akubicharm:20191023045312p:plain

Macのターミナルでも、docker ps コマンドを実行すると開発環境のDockerコンテナが実行されていることが確認できます。 f:id:akubicharm:20191023042900p:plain

Azure App ServiceでKeyVaultからSecretを取得する方法

基本的に https://docs.microsoft.com/ja-jp/azure/key-vault/tutorial-net-create-vault-azure-web-app の記載通りにやれば、権限を与えられたApp ServiceからKeyVaultに保存したSecretを取得することは可能です。

ここでは、各種設定で利用する値は以下の通りとします。

パラメータ名
リソースグループ名 MyGroup
ロケーション Japan East
KeyVault名 MyVault
Secret名 AppSecret
Secret値 MySecret

Azure CLI で実行するときに、コピペで行けるように環境変数にセットしておきます。

export RG_NAME="MyGroup"
export LOCATION="Japan East"
export KV_NAME="MyVault"
export SEC_NAME="AppSecret"
export SEC_VAL="MySecret"
export APP_NAME="MyApp"

リソースグループの作成

az group create --name $RG_NAME --location $LOCATION

KeyVaultの作成

az keyvault create --name $KV_NAME --resource-group $RG_NAME --location $LOCATION

キーコンテナにシークレットを追加

az keyvault secret set --vault-name $KV_NAME --name $SEC_NAME --value $SEC_VAL

値が正しく設定されていることを確認します。

az keyvault secret show --name $SEC_NAME --vault-name $KV_NAME

KeyVaultから値を取得するアプリケーションの実装

ここでは、C# を利用して Azure Function のアプリケーションを作成します。 完全なアプリケーションは https://docs.microsoft.com/ja-jp/azure/key-vault/tutorial-net-create-vault-azure-web-app#open-and-edit-the-solution を参照してください。

  • AzureServiceTokenProvider - トークンをメモリ内にキャッシュし、有効期限の直前に Azure AD から取得します。
  • KeyVaultClient - Key Vaultサービスに対して暗号化キー操作とボールト操作を実行するクライアントクラス

トークンを保持するインスタンスを生成します。

AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();

KeyVaultClientインスタンスを生成します。

KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));

KeyVaultのURLを指定して、シークレットを取得します。 KeyVault名とシークレット名は、自分の環境に合わせて編集します。

var secret = await keyVaultClient.GetSecretAsync("https://<KeyVault名>.vault.azure.net/secrets/<シークレット名>").ConfigureAwait(false);
Message = secret.Value;

アプリケーションをAzureにデプロイします。

KeyVaultのポリシーを設定

アプリケーションがKeyVaultからSecretを取得できるようにします。

デプロイしたアプリケーションのアプリケーションIDを生成します。

az webapp identity assign --name $APP_NAME --resource-group $RG_NAME

コマンドの実行結果として、アプリケーションID(principalId)が出力されます。

{
  "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "type": "SystemAssigned",
  "userAssignedIdentities": null
}

アプリケーションにKeyVaultへのアクセス(get, list)を許可します。

export SP_ID=<コマンドで出力された principalId>

az keyvault set-policy --name $KV_NAME --object-id $SP_ID --secret-permissions get list

アプリケーションを実行すると、KeyVaultからSecretが取得できます。

Azure IoT Central でX509のデバイス認証

Azure IoT Central

Azure Iot Centralは、Azure で提供されている IoT を実現するためのSaaS (Software as a Service) プラットフォームです。デバイスさえあれば、テレメトリデータを蓄積、可視化、また、閾値を超えたらメールを送信するなどのアクションを簡単に設定することができます。 しかも、5デバイスまでならば無料で利用できるというプライスモデルで、何ができるかな?と迷っている方もお手軽に始められるところがすごい!

IoT Central は、Azure IoT Hub Device Provisioning Service を利用して、デバイスの認証と管理を行なっています。

f:id:akubicharm:20190508173711p:plain
https://docs.microsoft.com/ja-jp/azure/iot-dps/about-iot-dps

IoT Central にルート証明書、中間証明書を登録し、デバイスにはリーフ証明書とデバイスのプライベートキーとなる証明書を配置することによって、X.509 認証が利用可能になります。

Azure IoT Central のデプロイ

まずは、Azure IoT Central をデプロイします。ボタンを数回クリックするだけで5分くらいで自分専用のIoTの環境が出来上がります。

1. https://apps.azureiotcentral.com/ にアクセスします
2. "新しいアプリケーション" をクリックします

f:id:akubicharm:20190506162516p:plain:w300

3. アプリケーションの作成画面で、アプリケーション作成の情報を入力し"作成"ボタンをクリックします
名称
支払いプランの選択 評価版
アプリケーションテンプレートを選択する サンプルDevkits
Configure your application - アプリケーション名 適当な名称
Configure your appilcation - URL 一意になるFQDN

f:id:akubicharm:20190506163048p:plain:w600

デプロイが終わると、こんなダッシュボードが見えるようになります。既存のテンプレートではシミュレーションデバイスがすでに登録された状態になっています。

f:id:akubicharm:20190506163727p:plain:w600

Azure IoT Central の証明書の作成と登録

証明書の作成スクリプトが提供されているので、そのスクリプトを利用して証明書を作成していきます。

https://github.com/Azure/azure-iot-sdk-c/blob/master/tools/CACertificates/CACertificateOverview.md に記載の手順に沿って、証明書を作成します。

以下は、Bash での作成手順ですので、Power Shell を利用する場合は上記サイトを参照してください。

1. Azure IoT SDKをダウンロードします
方法1: ZIP 形式でダウンロードする場合

(1) https://github.com/Azure/azure-iot-sdk-c にブラウザでアクセスします

(2) 画面右上の"Clone or Download"のプルダウンメニューをクリックし、"Download ZIP" をクリックします

f:id:akubicharm:20190508120713p:plain:w600

(3) ダウンロードしたファイルを展開します

方法2: git clone する場合
git clone https://github.com/Azure/azure-iot-sdk-c
2. 証明証作成の環境を準備します

作業用ディレクトリを作成し、移動します。

mkdir work
cd work

azure-iot-sdk-c/tools/CACertificates/ から *.cnf, *.shファイルをコピーし、シェルスクリプトchmod コマンドで実行可能にします。

cp [ダウンロードしたディレクトリ]/azure-iot-sdk-c/tools/CACertificates/*.cnf .
cp [ダウンロードしたディレクトリ]/azure-iot-sdk-c/tools/CACertificates/*.sh .
chmod 700 certGen.sh
3. ルート証明書を作成します
./certGen.sh create_root_and_intermediate

たくさん新しいディレクトリやファイルが作成されていますが、ここから利用していくのは certs/ ディレクトリと private/ ディレクトリにあるファイルです。

4. IoT Centralへルート証明書を登録します

(1) IoT ポータル画面のメニューで"管理→デバイス接続"をクリックします

(2) 管理画面の資格情報エリアで"証明書(X.509)"タブを選択し、フォルダーアイコンのボタンをクリックします

f:id:akubicharm:20190508121215p:plain:w600

(3) ファイル選択ダイアログでルート証明書のファイル certs/azure-iot-test-only.root.ca.cert.pem を選択します

(4) 証明書の確認のために、歯車のボタンをクリックします

f:id:akubicharm:20190508131314p:plain:w600

(5) 証明書の確認ダイアログでリロード(丸い矢印)ボタンをクリックして、確認コードを生成します

f:id:akubicharm:20190508132612p:plain:w600

(6) コピーボタンをクリックして、確認コードをコピーします

f:id:akubicharm:20190508132730p:plain:w600

(7) 中間証明書を作成します

./certGen.sh create_verification_certificate [コピーした確認コード]

(8) 証明書の確認ダイアログに戻って"確認"ボタンをクリックし、ファイル選択ダイアログでcerts/verification-code.cert.pem を選択します

f:id:akubicharm:20190508132922p:plain:w600

(9) 証明書の確認ダイアログの上部に「確認済み」と表示されたことを確認して "Close" ボタンをクリックします

f:id:akubicharm:20190508132955p:plain:w600

バイス登録の準備

以降では、IoT Central用のサンプルプログラム(Python)を利用しますので、IoT Central 用の Python ライブラリが必要です。

1. デバイス用の証明書を作成します
./certGen.sh create_device_certificate mydevice
cd ./certs && cat new-device.cert.pem azure-iot-test-only.intermediate.cert.pem azure-iot-test-only.root.ca.cert.pem > new-device-full-chain.cert.pem

以下のファイルが新たに作成されています。

  • certs/new-device-full-chain.cert.pem
  • private/new-device.key.pem

スクリプト内に証明書ファイルのプレフィックスが固定で new-device と指定されていますので、ファイル名を可変にしたい場合はスクリプトを書き換えてください。

2. 証明書をデバイスにコピーします

次の2つのファイルをデバイス/usr/local/share/ca-certificates ディレクトリにコピーします。

  • certs/new-device-full-chain.cert.pem
  • private/new-device.key.pem
3. デバイスへのパッケージのインストール(Ubuntuの場合)
sudo apt -y update
sudo apt -y install python-pip
4. IoT Central の python ライブラリをインストールします
pip install iotc
5. クライアントプログラムをダウンロードします

github で公開されているサンプルプログラムをダウンロードします。

wget https://raw.githubusercontent.com/Azure/iot-central-firmware/master/RaspberryPi/app.py
6. X.509 認証ができるようにプログラムを編集します

編集前

    8 deviceId = "DEVICE_ID"
    9 scopeId = "SCOPE_ID"
   10 deviceKey = "PRIMARY/SECONDARY device KEY"
   11
   12 iotc = iotc.Device(scopeId, deviceKey, deviceId, IOTConnectType.IOTC_CONNECT_SYMM_KEY)
  • deviceId : IoT Central に登録される時に利用されるデバイスID

  • scopeId : Device Provisioning Service の識別ID。IoT Central のポータルのメニューで"管理→デバイス接続"をクリックして確認できます。 f:id:akubicharm:20190508135555p:plain

  • deviceKey : デバイスに接続するためのキー情報。ここでは、X.509認証に利用する keyfile と certfile のファイルのパスを指定するように変更します。

編集後

     8 deviceId = "dev01"
     9 scopeId = "0ne00057EA0"
    10 deviceKey = {
    11      "keyfile": "/usr/local/share/ca-certificates/private/new-device.key.pem",
    12     "certfile": "/usr/local/share/ca-certificates/certs/new-device-full-chain.cert.pem"
    13 }
    14 
    15 iotc = iotc.Device(scopeId, deviceKey, deviceId, IOTConnectType.IOTC_CONNECT_X509_CERT)

バイスからAzure IoT Centralへの接続

バイスをIoT Cenrtralに登録する方法は2つあります。

  • IoT Centralのポータルで事前登録
  • バイスがアクセスした時に自動登録

方法1: IoT Cenrtralのポータルで事前登録

1. デバイスエクスプローラーでデバイスを登録します

(1) IoT Centralのポータルの左Paneのメニューで "デバイスエクスプローラー" をクリックします

(2) エクスプローラーのテンプレート一覧で "Raspberr Pi (1.0.0)" をクリックします

(3) 右Pane上部の "+" プルダウンメニューの "実際" をクリックします

f:id:akubicharm:20190508140325p:plain

(4)新しいデバイスの作成画面でパラメータを入力し、"作成" をクリックします

f:id:akubicharm:20190508140453p:plain

2. サンプルプログラムを実行します
python app.py

以下のようなログが出力されれば接続成功です。

(1557297237.393921, '- iotc :: connect :: ')
(1557297239.495437, u'- iotc :: _loopAssign :: https://global.azure-devices-provisioning.net/0ne00058A7C/registrations/dev02/operations/4.99da589eb420cb29.8b56c569-372e-4507-ac92-3aba25128ddf?api-version=2018-11-01')
(1557297240.164666, u'- iotc :: _mqttConnect :: iotc-d1c9a56c-8bb6-4db4-9ff5-99c16448cb13.azure-devices.net')
(1557297240.166233, ' - iotc :: _mqttconnect :: created mqtt client. connecting..')
(1557297241.019479, 'mqtt-log : Sending CONNECT (u1, p0, wr0, wq0, wf0, c1, k120) client_id=dev02')
(1557297241.35323, 'mqtt-log : Received CONNACK (0, 0)')
(1557297241.353464, '- iotc :: _onConnect :: rc = 0')
(1557297241.353711, ' - iotc :: _mqttconnect :: on_connect must be fired. Connected ? True')

>>> 中 略  <<<
(1557297242.355496, "mqtt-log : Sending PUBLISH (d0, q0, r0, m6), '$iothub/twin/GET/?$rid=0', ... (1 bytes)")
(1557297242.355664, '- iotc :: MAKE_CALLBACK :: ConnectionStatus')
- [onconnect] => status:0
(1557297242.355846, '- iotc :: _onPublish :: None')
(1557297242.355868, '- iotc :: MAKE_CALLBACK :: MessageSent')
    - [onmessagesent] =>  
(1557297242.53629, u"mqtt-log : Received PUBLISH (d0, q0, r0, m0), '$iothub/twin/res/200/?$rid=0', ...  (276 bytes)")
(1557297242.536373, '- iotc :: _onMessage :: topic($iothub/twin/res/200/?$rid=0) payload({\r\n  "desired": {\r\n    "setCurrent": {\r\n      "value": 0\r\n    },\r\n    "setVoltage": {\r\n      "value": 0\r\n    },\r\n    "fanSpeed": {\r\n      "value": 0\r\n    },\r\n    "activateIR": {\r\n      "value": false\r\n    },\r\n    "$version": 1\r\n  },\r\n  "reported": {\r\n    "$version": 1\r\n  }\r\n})')

方法2: デバイスがアクセスした時に自動登録

1. サンプルプログラムを実行します
python app.py

以下のようなログが出力されて、サンプルプログラムが終了します。

(1557297143.836877, '- iotc :: connect :: ')
(1557297145.821161, u'- iotc :: _loopAssign :: https://global.azure-devices-provisioning.net/0ne00058A7C/registrations/dev02/operations/4.99da589eb420cb29.60660343-17b9-44c0-b940-baba1c034dbb?api-version=2018-11-01')
(1557297149.346818, u'- iotc :: _loopAssign :: https://global.azure-devices-provisioning.net/0ne00058A7C/registrations/dev02/operations/4.99da589eb420cb29.60660343-17b9-44c0-b940-baba1c034dbb?api-version=2018-11-01')
(1557297149.856327, "ERROR : (_mqttConnect) DPS L => {u'status': u'failed', u'registrationState': {u'status': u'failed', u'registrationId': u'dev02', u'lastUpdatedDateTimeUtc': u'2019-05-08T06:32:26.1041395Z', u'errorMessage': u'Custom allocation failed with status code: 401', u'createdDateTimeUtc': u'2019-05-08T06:32:25.9595725Z', u'errorCode': 400209, u'etag': u'IjAwMDA2OTFmLTAwMDAtMDEwMC0wMDAwLTVjZDI3N2ZhMDAwMCI='}, u'operationId': u'4.99da589eb420cb29.60660343-17b9-44c0-b940-baba1c034dbb'}")
2. IoT Centralのポータルでデバイスを確認します

(1) IoT Centralのポータルの左Paneで "デバイスエクスプローラー" をクリックします

(2) エクスプローラで "関連付けが解除されているデバイス" をクリックします

(3) デバイスチェックボックスをチェックして、右上の "関連付け" ボタンをクリックします

f:id:akubicharm:20190508144508p:plain

(4) デバイスを関連づけるダイアログでテンプレートを選択し、"関連付け" をクリックします f:id:akubicharm:20190508144618p:plain

3. 再度、サンプルプログラムを実行します
python app.py

参考

Azure Stream Analytics のクエリのTips 〜 JSON の配列を扱う方法〜

Azure Stream Analyticsとは

Azure Stream Analyticsは、SQL 風のシンプルな言語を使用して、IoT または非 IoT の複数のデータ ストリームに対する超並列のリアルタイム分析を簡単に開発および実行できます。(Stream Analytics - リアルタイム データ分析 | Microsoft Azure から引用)

f:id:akubicharm:20180927182425p:plain

データ分析のためのクエリ

IoTのデバイスなどから収集したデータを分析するクエリは SQL のように記述できるので、SQLを書いたことがある人ならはブスに理解できます。また、入力データのフォーマットにはJSON、 Avro、CSVを想定しているので、それらを簡単に処理するための組み込み関数などがいくつか用意されています。

今回は、入れ子要素の扱い方とJSON の配列データを扱う方法を紹介します。

入れ子要素の扱い

Stream Analytics のクエリでは、JSON入れ子データは「.」連結で簡単に取得することができます。 例えば、下記のようなデータが IoT Hub からStream Analyticsに送られてくる場合

{"id": "001",  "person":  {"name": "taro", "age": 20}}

person の入れ子要素のname、ageを取得するためのクエリは以下のようになります。

SELECT
  id
, person.name
, person.age
INTO
  [blob]
FROM
  [iothub]

配列要素の扱い

JSON の要素が配列の場合は、組み込み関数を利用して配列要素を取り出して、フラットなデータとして扱うためにGetArrayElements 関数とAPPLY句を利用します。

GetArrayElements関数

文法

GetArrayElements (配列要素のキー)

GetArrayElements関数で配列要素のキーを指定することで、配列要素を一行のデータとして扱うことができるようになります。 GetArrayElements関数で配列要素を取得すると、配列のインデックス(ArrayIndex)と配列の要素(ArrayValue)として値を取得することができます。

APPLY句

文法

FROM (入力ソースまたは入力ソースのエリアス)
{CROSS |OUTER} APPLY (配列要素)AS (配列要素のエリアス)

配列要素には GetArrayElements(配列要素のキー)を指定します。 配列要素の値を参照する場合には、SELECT句で(配列要素のエリアス).(要素名)と指定します。

APPLYには、CROSS APPLYとOUTER APPLYがあります。

  • CROSS APPLY : SQLの INNER JOINと同じでデータがある場合のみ取得可能です。
  • OUTER APPLY : SQLのOUTER JOINと同じでデータがない場合はNULL値が返ります。

以下のような入れ子の配列データを扱う方法を見ていきましょう。

[
{
 "id": "001",
 "data": [
    {"sub": 1001, "name": "alpha001"},
    {"sub": 2001, "name": "bravo001"},
    {"sub": 3001, "name": "charly001"}
  ]
},
{
 "id": "002",
 "data":[
    {"sub": 2, "name": "bravo"}
  ]
},
{
 "id": "003",
 "dummy": [
    {"sub": 3, "name": "charly"}
  ]
}
]

INNER JOIN風な使い方

配列の要素をINNER JOINして利用する場合には、CROSS APPLY句を利用します。下記のサンプルでは、

8行目で、GetArrayElements関数で入力となるJSONからdata要素を配列として取得し、arrayElementというエリアスで参照できるようにしています。そして、id と取得したdata要素をJOINしています。

3行目では、配列要素として取得したdata要素の配列インデックスを取得しています。id=001のデータはdata要素配列は3なので、0, 1, 2 というインデックスが取得されます。

4-5行目では、配列要素として取得したdata要素の値を取得しています。

f:id:akubicharm:20180927202906p:plain

1:    SELECT  
2:        event.id,
3:        arrayElement.ArrayIndex, 
4:        arrayElement.ArrayValue.sub,
5:        arrayElement.ArrayValue.name
6:    into [blob] 
7:    FROM [iothubsim] as event 
8:    CROSS APPLY GetArrayElements(event.data) AS arrayElement

クエリの結果は、以下のようになります。

ID ARRAYINDEX SUB NAME
"001" 0 1001 "alpha001"
"001" 1 2001 "bravo001"
"001" 2 3001 "charly001"
"002" 0 2 "bravo"

OUTER JOIN 風な使い方

配列の要素をINNER JOINして利用する場合には、OUTER APPLY句を利用します。下記のサンプルでは、

8行目で、GetArrayElements関数で入力となるJSONからdata要素を配列として取得し、arrayElementというエリアスで参照できるようにしています。そして、id と取得したdata要素をOUTER JOINしています。

f:id:akubicharm:20180927203302p:plain

1:    SELECT  
2:        event.id,
3:        arrayElement.ArrayIndex, 
4:        arrayElement.ArrayValue.sub,
5:        arrayElement.ArrayValue.name
6:    into [blob] 
7:    FROM [iothubsim] as event 
8:    OUTER APPLY GetArrayElements(event.data) AS arrayElement

クエリの結果は、以下のようになります。

ID ARRAYINDEX SUB NAME
"001" 0 1001 "alpha001"
"001" 1 2001 "bravo001"
"001" 2 3001 "charly001"
"002" 0 2 "bravo"
"003" null null null

おわりに

SQLのように記述できる Stream Analytics のクエリの組み込み関数を上手く使えば、欲しいデータを簡単に取得することができます。 今回紹介した関数以外にも、配列を扱うための関数には GetArrayElementGetArrayLengthもありますので用途にあわせて使ってみてください。

OpenShift on Azureのデプロイ

Azure での OpenShift の前提条件 | Microsoft Docs の記載の手順にしたがってデプロイする方法を説明します。

OpenShift のデプロイ用の ARM のテンプレートは、cloud provider 設定ができるようになったりしているので Azure 側での事前準備が必要になりましたが、いくつかのコマンドを実行すれば良いだけなの案外簡単です。

OpenShift をデプロイするにあたって、事前準備でAzure CLI を利用します。リソースグループ名やロケーションなどを環境変数に設定しておけば、以降の手順を実行する際に各自好きな名称を設定しても、コピペで作業を進めていけるので、まず、各自で可変になりそうな値は環境数に設定します。

パラメータ名 説明
KVRG keyvaultrg Key Vault用のリソースグループ名
LOCATION eastus リージョン
KVNAME keyvault Key Vault名
SECNAME keysecret Secret名
OCPRG openshift OpenShiftをデプロイするリソースグループ名
OPENSHIFTSP openshiftsp+乱数OpenShift用のサービスプリンリプル サービスプリンリプルは、一位の名前である必要があるのでここでは乱数を付与するようにしていますが、任意の自分のアカウント名などをつけても良いです。

Bash を使っている場合は、次のコマンドを実行します。

export KVRG=keyvaultrg
export LOCATION=eastus
export KVNAME=keyvault
export SECNAME=keysecret
export OCPRG=openshift
export OPENSHIFTSP=openshiftsp$RANDOM

OpenShift をデプロイするための準備

1. CLI を使って azure portal にログイン

az login

2. OpenShiftをデプロイするリソースグループを作成

az group create --name $OCPRG --location $LOCATION

3. Key Vault を保持するリソースグループを作成(OpenShiftをデプロイするリソースグループとは別にする)

az group create --name $KVRG --location $LOCATION

4. Key Vault を作成

az keyvault create --resource-group $KVRG --name $KVNAME \
       --enabled-for-template-deployment true \
       --location $LOCATION

5. SSH キーの生成

ssh-keygen -f ~/.ssh/openshift_rsa -t rsa -N ''

6. Azure Key VaultにSSH秘密鍵を登録

az keyvault secret set --vault-name $KVNAME --name $SECNAME --file ~/.ssh/openshift_rsa

7. サービスプリンリパルの生成

az ad sp create-for-rbac --name $OPENSHIFTSP \
          --role Contributor --password "@dmin9999" \
          --scopes $(az group show --name $OCPRG --query id)

ここで The request did not have a provided subscription. All requests must have an associated subscription Id. というエラーが発生した場合は、--scopes で subscription が正しく取得できていません。その場合は、az group show --name $OCPRG --query id を実行し、そこで出力された値を--scopes のパラメータに利用してください。

az group show --name $OCPRG --query id
"/subscriptions/<数字がいっぱい>/resourceGroups/openshift"   ← 出力される文字列
az ad sp create-for-rbac --name openshiftspkeomizo --role Contributor --password "@dmin9999" --scopes "/subscriptions/<数字がいっぱい>/resourceGroups/openshift"

コマンドが成功すると、次のような文字列が出力されるのでメモ帳などにコピーしておく。

{
  "appId":  "9999999-9999-9999-9999-999999999999"",
  "displayName": "openshiftsp1234",
  "name": "http://openshiftsp1234",
  "password": "@dmin9999",
  "tenant": "9999999-9999-9999-9999-999999999999"
}

MarketplaceからOpenShiftをデプロイ

1. Azure PortalでOpenShiftのリソースグループを選択

f:id:akubicharm:20180905143647p:plain

2. リソース追加ボタンをクリック

f:id:akubicharm:20180905143853p:plain

3. 検索文字列に「OpenShift」を指定してテンプレートを選択

f:id:akubicharm:20180905144136p:plain

4. 下までスクロールして「Create」をクリックしてウィザードを開始

f:id:akubicharm:20180905144313p:plain

5. ウィザードのパラメータを入力

1. Basics

f:id:akubicharm:20180905145345p:plain

パラメータ名 説明
VM Admin User Name clusteradmin デフォルト値のまま変更なし
SSH Public Key for VM Admin User VMssh で接続する時の公開鍵
Subscription 適用するサブスクリプション 仮想サーバを9台デプロイできるだけの余裕があること!!!
Resource Group Use existingを選択。リソースグループ名は$OCPRGに設定した名称 空っぽのリソースグループであること
Location $LOCATIONに設定したリージョン
2. Infrastructure Settings

f:id:akubicharm:20180905145744p:plain

パラメータ名 説明
OCP Cluster Name Prefix ocpcluster デフォルト値のまま変更なし
Master Node Size 3 x Standard D4s V3 メモリ、CPUの要件に合わせて適宜変更。台数は奇数。
Infrastructure Node Size 3 x Standard ES2s v3 メモリ、CPUの要件に合わせて適宜変更
Number of Application Nodes 2 必要な台数に合わせて適宜変更
Application Node Size 2 x Standard D2s v3 メモリ、CPUの要件に合わせて適宜変更
Bastion Host Size 1 x Standard DS2 v2 デフォルト値のまま変更なし
Custom IP subnet No 変更なし
Key Vault Resource Group Name keyvaultrg 事前準備の手順4で指定した Key Vaultのリソースグループ名。$KVRG
Key Vault Name keyvault 事前準備の手順4で指定した Key Vault名。$KVNAME
Secret Name keysecret 事前準備の手順6で指定したsecret名。$SECNAME
3. OpenShift Container Platform Settings

f:id:akubicharm:20180905151311p:plain

パラメータ名 説明
OpenShift Admin User Password @dmin123 任意の文字列
Confirm OpenShift Admin User Password @dmin123
Red Hat SubscriptionManager User Name Red Hat Customer Portalに登録しているメールアドレス
Red Hat Subscription Manager User Password Red Hat Customer Portalに登録しているパスワード
Red Hat Subscription Manager OpenShift Pool ID Red Hatから割り当てられているサブスクリプションのPool ID
Configure Azure Cloud Provider Yes デフォルト値のまま変更なし
Azure AD Service Principal Client ID GUID 事前準備の手順7のサービスプリンシプルの作成で出力された AppID
Azure AD Service Principal Client ID Secret 事前準備の手順7:サービスプリンシプルの作成時に指定したパスワード
4. Additional Settings

f:id:akubicharm:20180905151845p:plain

パラメータ名 説明
Configure Cluster Logging No デフォルト値のまま変更なし。ロギングの設定はインストール後でもできます
Configure Metrics for the Cluster No デフォルト値のまま変更なし。メトリクスの設定はインストール後でもできます
Default Router Subdomein nipio デフォルト値のまま変更なし
5. Summary

バリデーションがパスしたら、「OK」ボタンをクリックします。 f:id:akubicharm:20180905152614p:plain

6. Buy

内容を確認して「Create」ボタンをクリックします。 f:id:akubicharm:20180905152736p:plain

6.完成を気長に待つ

1時間くらいはかかるので、気長に待ちましょう。

OpenShift にログイン

1. Master サーバのパブリックIPアドレスを選択

Azure PortalでOpenShiftのリソースグループを選択し、「master」から始まる Public IP address を選択します。 f:id:akubicharm:20180905153417p:plain

2. MasterサーバのDNS名を確認

詳細画面のDNS Nameをコピーします。

f:id:akubicharm:20180905153726p:plain

3.ブラウザでアクセス

コピーしたDNS Nameを利用してOpenShiftの管理コンソールにログインします。 管理コンソールは8443ポートではなく、443ポートで動作しています。

https://masterdnsxxxxxxxxxx.eastus.cloudapp.azure.com

4. clusteradmin でログイン

f:id:akubicharm:20180905154404p:plain

パラメータ名 説明
Username clusteradmin
Password OpenShiftデプロイのウィザード3: OpenShift Container Platform Settingsで指定したパスワード

5. コンソールの確認

この画面が表示されれば OK です。パチパチパチー。

f:id:akubicharm:20180905154749p:plain

ユーザ管理

マーケットプレイスからデプロイした場合は、ユーザ認証がhtpasswd形式になっています。ユーザを追加する場合は、masterサーバに配置されている/etc/origin/master/htpasswdファイルにユーザのエントリを追加します。

Azure AD を使って認証する方法は、 openshift-playground/AzureADAuthorization.md at master · akubicharm/openshift-playground · GitHub を参照してください。

備忘録:Windowsで管理者特権でコマンドを実行する方法

ドメインユーザではなくローカルの管理者としてコマンドプロンプトを起動すれば、管理者特権が必要なコマンドや.exeを実行できる。

powershell start-process cmd -verb runas

これで、ダイアログが表示されるので、ローカルの管理者ユーザとパスワードを入力

ユーザ:[ホスト名]¥Administrator

備忘録:OpenShift 3.7 を All in One でインストール

いつもAzureを使っているので、AWSも使ってみようと OpenShift の All in One の環境をデプロイした時のメモ。

AWSインスタンスへの設定

  • publicの固定IPを付与するために Elastic IPを設定
  • 管理コンソール(8443)、Web App(80, 443)のInbound accessを許可するためにSecurity Groupを設定

OpenShift のインストール

必要なパッケージのインストール

subscription-manager で登録した後は、必要なパッケージのインストール

subscription-manager repos --disable="*"
subscription-manager repos \
    --enable="rhel-7-server-rpms" \
    --enable="rhel-7-server-extras-rpms" \
    --enable="rhel-7-server-ose-3.7-rpms" \
    --enable="rhel-7-fast-datapath-rpms"


yum -y install wget git net-tools bind-utils iptables-services bridge-utils bash-completion kexec-tools sos psacct
yum -y update
yum -y install atomic-openshift-utils
yum -y install atomic-openshift-excluder atomic-openshift-docker-excluder
atomic-openshift-excluder unexclude


yum -y install docker


sed -i '/OPTIONS=.*/c\OPTIONS="--selinux-enabled --insecure-registry 172.30.0.0/16"' /etc/sysconfig/docker

systemctl enable docker
systemctl start docker

インベントリファイル

Docker用のストレージを作らなかったり、リソースが少なめだったりするので事前チェックをすり抜けるためのパラメータ openshift_disable_check=memory_availability,disk_availability,docker_storage  を設定

!!!本当は、ちゃんとシステム要件を満たすリソースを割りあてないとダメです!!!

[OSEv3:children]
masters
nodes
etcd

# Set variables common for all OSEv3 hosts
[OSEv3:vars]
# SSH user, this user should allow ssh based auth without requiring a password
ansible_ssh_user=ec2-user

# If ansible_ssh_user is not root, ansible_become must be set to true
ansible_become=true

openshift_deployment_type=openshift-enterprise

openshift_disable_check=memory_availability,disk_availability,docker_storage

openshift_master_default_subdomain=000.000.000.000.nip.io

# uncomment the following to enable htpasswd authentication; defaults to DenyAllPasswordIdentityProvider
openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider', 'filename': '/etc/origin/master/htpasswd'}]

# host group for masters
[masters]
ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com

# host group for etcd
[etcd]
ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com

# host group for nodes, includes region info
[nodes]
ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com openshift_schedulable=true openshift_node_labels="{'region': 'infra', 'zone': 'default'}" openshift_public_hostname=ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com openshift_hostname=ip-172-31-000-000.ap-northeast-1.compute.internal

PV を NFS で提供

NFS サーバの設定

パッケージのインストール

yum -y install nfs-utils

NFS の設定

mkdir -p /var/export/pvs/pv{1..10}
chown -R nfsnobody:nfsnobody /var/export/pvs
chmod -R 2770 /var/export/pvs

for volume in pv{1..10} ; do
echo Creating export for volume $volume;
echo "/var/export/pvs/${volume} *(rw,sync,root_squash)" >> /etc/exports; done;

systemctl enable rpcbind nfs-server
systemctl start rpcbind nfs-server nfs-lock nfs-idmap
systemctl stop firewalld
systemctl disable firewalld

setsebool -P virt_use_nfs=true;

で、動作確認

ssh [クライアントIPアドレス]
mkdir /tmp/test
mount -v [NFSサーバ名]:/var/export/pvs/pv1 /tmp/test

umount /tmp/test
exit

詳細はこの辺を参照。 Using NFS - Configuring Persistent Storage | Installation and Configuration | OpenShift Container Platform 3.7

PV の作成

PV の定義作成

export volsize=1Gi

for volume in pv{1..10} ; do cat << EOF > ${volume}.yaml
{
"apiVersion": "v1", "kind": "PersistentVolume", "metadata": {
"name": "${volume}" },
"spec": { "capacity": {
"storage": "${volsize}" },
"accessModes": [ "ReadWriteOnce" ], "nfs": {
"path": "/var/export/pvs/${volume}",
"server": "$NFS_SERVER" },
"persistentVolumeReclaimPolicy": "Recycle" }
}
EOF
echo "Created def file for ${volume}"; done;

PVの作成

 for f in *.yaml; do oc create -f $f; done

 トラブルシューティング

Service Catalog がデプロイされない問題

Bug 1523625 – service catalog deployment fails

こんな感じで、kube-service-catalog プロジェクトの controller-manager がちゃんとデプロイされていない場合。

$ oc get po --all-namespaces
NAMESPACE                           NAME                                      READY     STATUS             RESTARTS   AGE
kube-service-catalog                controller-manager-8r8vt                  0/1       CrashLoopBackOff   19         1d

まずは、 oc logs controller-manager-8r8vt --previous で、ログを確認して証明書のエラーが発生している場合は、証明書を置き換えてあげる必要があります。

エラーの例

F1206 08:45:28.713230       1 controller_manager.go:198] error running controllers: failed to get supported resources from server: unable to retrieve the complete list of server APIs: servicecatalog.k8s.io/v1beta1: an error on the server ("Error: 'x509: certificate signed by unknown authority (possibly because of \"crypto/rsa: verification error\" while trying to verify candidate authority certificate \"service-catalog-signer\")'\nTrying to reach: 'https://172.30.72.245:443/apis/servicecatalog.k8s.io/v1beta1' ") has prevented the request from succeeding 

以下の手順で証明書を書き換えます。

cat /etc/origin/service-catalog/ca.crt | base64
=>結果をコピーして、1行にまとめておく

oc edit apiservice/v1beta1.servicecatalog.k8s.io
=>ca_bundleフィールドを置き換える

追記

2018-03-23

docker-1.12.x をインストールしているにもかかわらず、docker-1.13 のリポジトリが見えているというエラーが発生する場合は、openshift_disable_checkパラメータにpackage_versionを指定する。

openshift_disable_check=memory_availability,disk_availability,docker_storage,package_version