Posts filed under ‘Microsoft Azure’

Azure Spring Cloud の環境構築方法のご紹介

本ブログエントリは、Microsoft Azure Advent Calendar の 20日目の内容です。
昨日は @mstakaha1113 さんによる 「AzureでIoT系のサービスをサラッと(?)使ってみよう」でした。
明日は @hoisjp さんです。

Pivotal と Microsoft は 2019/10/8 オースティンで開催された SpringOne Platform 2019 Azure Spring Cloud というサービスを発表しました。


(SpringOne 2019 における Azure Spring Cloud の発表内容)

Azure Spring Cloud の特徴


Azure Spring Cloud は Microsoft と Pivotal が共同開発した Spring Cloud アプリケーションの開発・運用に特化した環境で、これを利用した場合、アプリケーションの運用・管理コストを大幅に軽減してくれます。

実際の実行環境は Azure Kubernets Service (AKS) ですが、Kubernetes 環境を全く意識することなく、本来必要となる複雑な管理操作を完全に隠蔽しています。実際 Kubernetes コマンドを直接実行する事はできません。その為、おそらく多くの方が Kubernetes 上で動作している事に気づかないかもしれません。

筆者は Kubernetes による Java アプリケーションの開発・運用も経験をしていますが、Kubernetes 上での開発・運用に比べて、特にインフラ面の管理コストが大幅に削減できると考えています。
通常 Kubernetes 上で Java アプリケーションを動作させるためには、コンテナを強く意識したビルド・プロセス、リリース・プロセスが必要です (コンテナのビルド、コンテナレジストリへの Push、YAML の生成、k8s への適用など)。

# Build the Source Code
$ mvn clean package

# Build the Container Image
$ docker build -t $DOCKER_IMAGE:$VERSION . -f Dockerfile
$ docker tag $DOCKER_IMAGE:$VERSION $DOCKER_REPOSITORY/$DOCKER_IMAGE:$VERSION

# Push the image to Container Registry
$ docker push $DOCKER_REPOSITORY/$DOCKER_IMAGE:$VERSION

# Create and Modify the  Deployment YAML file

# Apply to the Kubernetes
kubectl apply --record -f deployment.yaml

上記以外にも、Kuberenes 自身のメンテナンスやパッチ適用、クラスタ自身の運用管理を行わなければなりません。

しかし、Azure Spring Cloud を利用すると Pivotal Build Service という機能を完全統合しているため、アプリケーション開発者は、ソースコードの開発により集中できるようになります。具体的には開発者はソースコードの開発に集中し、コンテナのビルドや YAML ファイルの生成は不要で、コマンドを2、3回実行するだけで簡単にアプリケーションをデプロイできるようになります。デプロイに関しても最初から Blue-Green デプロイの機能を持つため、最新のビルドは Staging 環境にデプロイし、動作確認したのち、本番環境と切り替えるといった操作も容易に実現できます。
さらに、既存の Azure の Managed Service (現時点では Cosmos DB, MySQL, Redis) とのサービス・バインディングの機能も持つ為、JDBC などの接続情報を容易に作成することもできとても便利です。

上記以外にも多くの機能を持つ Azure Spring Cloud ですが、筆者は比較的小規模〜中規模のマイクロサービス提供をしたい場合、今後有用な選択肢になると考えています。



実際の操作イメージを掴む為、下記のデモ動画をご覧ください。

下記動画のデモ内容


  1. デモアプリケーションのご紹介 (PetStore)
  2. Azure DataBase for MySQL の動作確認
  3. Visual Studio Code を利用した Spring Boot アプリの実装のご紹介
  4. ソースコードのビルド
  5. Azure Spring Cloud アプリの作成
  6. Azure Spring Cloud アプリから Managed MySQL へのバインド
  7. CPU, Memory, インスタンスなどのスケール機能のご紹介
  8. Spring Boot アプリケーションを Azure Spring Cloud アプリへデプロイ
  9. Log Analytics による、アプリケーション・ログの確認
  10. アプリケーションの動作確認
  11. 分散トレーシング機能のご紹介 (Application Insights を利用)
  12. ブルー・グリーン・デプロイ機能の検証
      ソースコード修正→ビルド→ステージング環境へのデプロイ
  13. ステージング・アプリと本番アプリの切り替え
  14. GitHub Actions を利用した CI/CD の構築


(GUI で Azure Spring Cloud と MySQL を接続する環境構築方法)

※ ご注意:本デモ動画は筆者のプレゼン時に操作時の待ち時間を短縮するため、操作待ちの箇所をカット(編集)しています。実際には、本デモ動画よりも所用時間が長くなることをご理解ください。

NeXTSTEP :Azure Spring Cloud 構築の事前準備 (CLI 版)

以降のエントリーでは、上記 GUI (動画ビデオ) で環境構築した内容と、ほぼ同等の内容を CLI (コマンドライン)だけで構築する方法について紹介します。

CLI で環境構築する場合は別途、Log AnalyticsApplication Insights の連携などを自ら行う必要がある為、まずはこれらを作成するところから始めます。

1. Azure へのログインと Spring Cloud 用エクステンションの追加


まず、Azure CLI を利用するために az login コマンドでログインをしましょう。そして次に、Azure Spring Cloud を操作するために、az extension コマンドでエクステンションを追加してください。

$  az login
$  az extension add --name spring-cloud

2. 環境変数の設定


次に、各種リソースの名前などを可変で変更しやすくするため、さらに入力ミスを極力減らす目的で、下記の環境変数を設定してください。

$  export RESOURCE_GROUP=Spring-Cloud-Services
$  export SPRING_CLOUD_SVC_NAME=spring-cloud-services-jp
$  export LOCATION=southeastasia
$  export APP_INSIGHTS_NAME=spring-clouds-appinsights
$  export MYSQL_NAME=mysql4springcloud
$  export MYSQL_USERNAME=terada
$  export MYSQL_PASSWORD=whelp90-OCRs
$  export MYSQL_DB_NAME=petstoredb
$  export SPRING_CLOUD_APP_NAME=petstore-app
$  export SPRING_CLOUD_APP_NEW_VERSION_NAME=petstore-app-new-version

上記の環境変数名のそれぞれの意味を下記に記載します。適宜ご自身の環境に応じて上記の環境変数の値は変更してください。

環境変数名 説明
RESOURCE_GROUP リソースグループ名
SPRING_CLOUD_SVC_NAME Azure Spring Cloud のサービス名
LOCATION リソースを配置するリージョンの場所
APP_INSIGHTS_NAME Application Insights の名前
MYSQL_NAME MySQL の名前
MYSQL_USERNAME MySQL のログイン・ユーザ名
MYSQL_PAAWORD MySQL のユーザ・パスワード
MYSQL_DB_NAME MySQL のデータベース名
SPRING_CLOUD_APP_NAME Azure Spring Cloud のデプロイするアプリケーション名
CLOUD_APP_NEW_VERSION_NAME Azure Spring Cloud のステージング環境に配備するアプリケーション名

3. Azure リソースグループの作成


それでは早速、Azure Spring Cloud をインストールするリソース・グループを作成します。下記のコマンドを実行してください。

$  az group create \
     --location $LOCATION \
     --name $RESOURCE_GROUP

4. Application Insights のインストール


リソース・グループを作成した後、Application Insights をインストールしてください。Application Insights をインストールする事で、Azure Spring Cloud から分散トレーシング機能を利用できるようになります。

$ az resource create \
     --resource-group $RESOURCE_GROUP \
     --resource-type "Microsoft.Insights/components" \
     --name $APP_INSIGHTS_NAME \
     --location $LOCATION \
     --properties '{"Application_Type":"web"}'

上記コマンドを実行した結果が、JSON 形式で出力されます。出力結果の中に、下記のような InstrumentationKey が表示されます。
後の設定で利用するため、この値をコピーして保存しておいてください。

    "InstrumentationKey": "d25f6639-****-****-****-f1b******b41",

5. Log Analytics Workspace のインストール

次に、Log Analytics Workspace をインストールします。下記の defaultValue の値をご自身の環境にあわせて修正して deploy_logworkspacetemplate.json というファイル名で保存してください。

{
"$schema": "https://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
    "workspaceName": {
        "type": "String",
 		"defaultValue": "workspace-name(適宜名前を修正してください)", 
 		"metadata": {
          "description": "Specifies the name of the workspace."
        }
    },
    "location": {
        "type": "String",
 		"allowedValues": [
 		  "eastus",
                  "southeastasia",
 		  "westus"
 		],
 		"defaultValue": "southeastasia",
 		"metadata": {
 		  "description": "Specifies the location in which to create the workspace."
 		}
    },
    "sku": {
        "type": "String",
 		"allowedValues": [
          "Standalone",
          "PerNode",
 	      "PerGB2018"
        ],
 		"defaultValue": "PerGB2018",
         "metadata": {
        "description": "Specifies the service tier of the workspace: Standalone, PerNode, Per-GB"
 	}
      }
},
"resources": [
    {
        "type": "Microsoft.OperationalInsights/workspaces",
        "name": "[parameters('workspaceName')]",
        "apiVersion": "2015-11-01-preview",
        "location": "[parameters('location')]",
        "properties": {
            "sku": {
                "Name": "[parameters('sku')]"
            },
            "features": {
                "searchVersion": 1
            }
        }
      }
   ]
}

上記の JSON を deploy_logworkspacetemplate.json ファイルに保存したのち、下記のコマンドを実行し Log Analytics の Workspace を作成してください。

$ az group deployment create \
     --resource-group $RESOURCE_GROUP \
     --name spring-cloud-log-analytics-workspace \
     --template-file deploy_logworkspacetemplate.json

6. Azure Database for MySQL のインストールと検証用 DB の作成

最後の準備事項として、下記のコマンドを実行して Azure Database for MySQL をインストールします。

※ ご注意:今回の MySQL の作成方法は検証目的で作成しています。本番環境用ではないためご注意ください。

$ az mysql server create \
     -l $LOCATION \
     -g $RESOURCE_GROUP \
     -n $MYSQL_NAME \
     -u $MYSQL_USERNAME \
     -p $MYSQL_PASSWORD \
     --sku-name GP_Gen5_2

MySQL を作成した直後は Firewall の設定により全てのクライアントからのリクエストを受け付けられなくなっています。そこで Firewall の設定を行い MySQL に接続できるようにします。ここでは、Azure 内の IP アドレス (0.0.0.0) からだけ MySQL に接続をできるようにしています。

※ ご注意:本来は個別に接続可能な IP アドレスを設定してください。

$ az mysql server firewall-rule create \
     -g $RESOURCE_GROUP \
     -s $MYSQL_NAME \
     -n allowfrominternal \
     --start-ip-address 0.0.0.0 \
     --end-ip-address 0.0.0.0

上記の設定で、Azure 内のネットワークからは MySQL に接続できるようになります。たとえばコマンドの実行環境が Cloud Shell などを利用している場合、これで接続ができるようになるかと想定します。

一方、MySQL への接続が外部のネットワークからの場合、0.0.0.0 の部分を変更し個別に接続可能な IP アドレスを指定してください。管理ポータルを利用すると簡単にクライアントの IP アドレスを入手し登録する事もできます。MySQL の「Connection Security」より「Add ClientIP」というボタンを押下するとご自身の IP アドレスが自動的に取得できます。「Save」ボタンを押下してご自身のパソコンなどからアクセスできるように設定してください。


Firewall 設定が完了すると、mysql コマンドを利用して MySQL に接続ができるようになります。下記のコマンドでは日本語入力に対応する設定や、データベースの作成、さらにはテーブル作成やデータをインサートを行なっています。 ( catalog.sql は後述する git clone で入手できます)

$ mysql -u $MYSQL_USERNAME@$MYSQL_NAME \
     -h $MYSQL_NAME.mysql.database.azure.com -p

mysql> show databases;
mysql> show variables like "char%";
mysql> set character_set_database=utf8mb4;
mysql> set character_set_server=utf8mb4;
mysql> create database petstoredb default character set utf8mb4;
mysql> use petstoredb;
mysql> source ./catalog.sql
mysql> select * from item;

CLI 版:Azure Spring Cloud の環境構築

7. Azure Spring Cloud の構築

上記の準備を完了することで、Azure Spring Cloud を便利に利用できるための環境が整いました。そこで、ここから実際に Azure Spring Cloud のサービスを作っていきます。リソース・グループ内に Azure Spring Cloud のサービスを作成してください。

$ az spring-cloud create \
     -n $SPRING_CLOUD_SVC_NAME \
     -g $RESOURCE_GROUP

8.Azure Spring Cloud と Log Analytics の連携

Azure Spring Cloud のサービスを作成したのち、Log Analytics WorkSpace と連携するための設定を行ってください。
大変残念ながら、この連携の設定は現時点で Azure 管理ポータルからしかできません。
管理ポータルから Azure Spring Cloud を選択し、「Monitoring」→「Diagnostics settings」を選択してください。

次に「+ Add diagnostic setting」を押下し「Name」に適切な名前を入力してください。

次に「Send to Log Analytics」にチェックし「Subscription」と「Log Analytics workspace」から、準備段階で作成したワークスペース名を選択してください。log, metrics の全項目にチェックし「Save」ボタンを押下してください。

以上で、デプロイしたアプリケーションのログなどが Log Analytics 経由で参照できるようになります。

9. Azure Spring Cloud 上に新規アプリの作成

Azure Spring Cloud のサービスを作成したので、次にサービス内に Spring Boot/Spring Cloud のマイクロサービス・アプリケーションをデプロイします。

$ az spring-cloud app create \
     -n $SPRING_CLOUD_APP_NAME \
     -s $SPRING_CLOUD_SVC_NAME \
     -g $RESOURCE_GROUP

10. MySQL へのバインドを作成

次に、Azure Spring Cloud から MySQL を利用できるようにバインド設定を行います。GUI からバインドを作成する際は、GUI からサブスクリプションを選択しその中に含まれる MySQL を選択することで容易にバインド情報を作成できますが、CLI からバインドを行うためにはまず MySQL の ID を取得しなければなりません。そこで、MySQL の ID を取得するために、下記のコマンドを実行して取得してください。ここで、「“id”: “/subscriptions/***」 ではじまる行の内 「/databases/petstoredb」 より前の部分を MySQL の リソース ID (–resource-id) として利用します。

$ az mysql db show \
     --name $MYSQL_DB_NAME \
     -g $RESOURCE_GROUP \
     --server-name $MYSQL_NAME
{
  "charset": "utf8mb4",
  "collation": "utf8mb4_general_ci",
  "id": "/subscriptions/********-****-****-****-************/resourceGroups/Spring-Cloud-Env/providers/Microsoft.DBforMySQL/servers/mysql4springcloud/databases/petstoredb",
  "name": "petstoredb",
  "resourceGroup": "Spring-Cloud-Env",
  "type": "Microsoft.DBforMySQL/servers/databases"
}

取得した リソース ID を指定して MySQL のバインドを作成してください。

$ az spring-cloud app binding mysql add \
     --app $SPRING_CLOUD_APP_NAME \
     --resource-id "/subscriptions/********-****-****-****-************/resourceGroups/Spring-Cloud-Env/providers/Microsoft.DBforMySQL/servers/mysql4springcloud" \
     --database-name $MYSQL_DB_NAME \
     --name "mysql-binding"  \
     -s $SPRING_CLOUD_SVC_NAME \
     -g $RESOURCE_GROUP \
     --username $MYSQL_USERNAME@$MYSQL_NAME \
     --key $MYSQL_PASSWORD

バインドが完了すると Azure Portal 上では下記のような内容を確認できます。

11. サンプル・ソースコードの入手

次に、GitHub よりサンプルのソースコードやデータ、設定ファイルなどを入手してください。

$ git clone https://github.com/yoshioterada/Azure-Spring-Cloud-with-MySQL-Sample

ディレクトリ構成は下記のようになっています。

├── catalog.sql (MySQL に挿入するデータ)
├── deploy_logworkspacetemplate.json (Log Analytics Workspace を作成するためのJSON)
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── yoshio3
    │   │           └── demo
    │   │               ├── CatItemRepository.java (Repository クラス)
    │   │               ├── DemoApplication.java  (Main クラス)
    │   │               ├── Item.java   (JPA Entity クラス)
    │   │               └── PetItemController.java (REST API 実装クラス)
    │   └── resources
    │       ├── AI-Agent.xml
    │       ├── application.properties
    │       ├── log4j2.xml
    │       ├── static
    │       │   ├── css
    │       │   │   ├── new-design.css  (新デザイン)
    │       │   │   └── old-design.css  (旧デザイン)
    │       │   └── images
    │       └── templates
    │           └── index.html   ( Web ページ ThymeLeaf )
    └── test
        └── java
            └── com
                └── yoshio3
                    └── demo
                        └── DemoApplicationTests.java

12. ソースコードのビルドとアプリのデプロイ

入手したソースコードを mvn コマンドでビルドしてください。ビルドが完了すると target ディレクトリ配下に demo-0.0.1-SNAPSHOT.jar ができます。

$ mvn clean package -DskipTests
$ ls target/
classes
demo-0.0.1-SNAPSHOT.jar
demo-0.0.1-SNAPSHOT.jar.original
generated-sources
generated-test-sources
maven-archiver
maven-status
test-classes

ビルドの成果物である demo-0.0.1-SNAPSHOT.jar を Azure Spring Cloud のアプリに対してデプロイします。

この時、事前準備で作成した Application Insights の InstrumentationKey を環境変数 (–env “azure.application-insights.instrumentation-key=) に設定します。これにより Java で実装した Application Insights を動作できます。デプロイには少し時間がかかりますので、しばらくお待ちください。

$ az spring-cloud app deploy \
     -n $SPRING_CLOUD_APP_NAME \
     -s $SPRING_CLOUD_SVC_NAME \
     -g $RESOURCE_GROUP \
     --instance-count 2 --memory 2 \
     --runtime-version Java_8  \
     --env "azure.application-insights.instrumentation-key=********-****-****-****-************" \
     --jar-path ./target/demo-0.0.1-SNAPSHOT.jar --version 1 

13. 外部から接続可能な Public URL を作成

デプロイ時に Public URL の公開オプションを指定せずにデプロイすると下記のように 「Test Endpoint」しか作成されません。

GUI からは「Assign domain」のボタンを押下するだけで容易に Public URL を付加する事ができますが、CLI では下記のコマンドを実行することで Public からアクセス可能な URL を作成できます。

$ az spring-cloud app update \
     -n $SPRING_CLOUD_APP_NAME  \
     -s $SPRING_CLOUD_SVC_NAME  \
     -g $RESOURCE_GROUP \
     --is-public true

作成された URL を確認するために、下記のコマンドを実行してください。”url” の行に URL が表示されます。

$ az spring-cloud app show \
     -n $SPRING_CLOUD_APP_NAME  \
     -s $SPRING_CLOUD_SVC_NAME  \
     -g $RESOURCE_GROUP

    ........ (中略)

    "url": "https://spring-cloud-services-******-********-***.azuremicroservices.io"
  },
  "resourceGroup": "Spring-Cloud-Env",
  "type": "Microsoft.AppPlatform/Spring/apps"
}

14. 動作確認

上記の URL に対して curl コマンド、もしくは Web ブラウザを利用してアクセスしてみてください。

$ curl https://spring-cloud-services-******-********-***.azuremicroservices.io/cats

15. 新バージョンをステージングへデプロイ

上記で一通りアプリケーションのデプロイはできるようになりましたが、さらにアプリケーションを更新して、Blue-Green デプロイの機能も試してみましょう。
アプリケーションの一部を更新して新バージョンを作成します。
ここではわかりやすくするため、デザインを変更してみましょう。index.html を開き、CSS を “old-design.css” から “new-design.css” に修正して、さらに <H1>Hello Java<H1> の行も追加します。

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Springboot</title>
    <meta charset="utf-8" />
    <link th:href="@{/css/new-design.css}" rel="stylesheet" type="text/css"></link>
</head>
<body>
<H1>Hello Java</H1>

編集が終わったのち、新しいバージョンを作るために再度 mvn コマンドでソースコードをビルドします。

$ mvn clean package -DskipTests

今回は、アプリケーションを Staging 環境にデプロイするため、下記のコマンドを実行します。–name で新規バージョンにつける名前を指定します。

(ご注意:上記で実行した az spring-cloud app deploy コマンドとは違います)

$ az spring-cloud app deployment create \
     -s $SPRING_CLOUD_SVC_NAME \
     -g $RESOURCE_GROUP \
     --name $SPRING_CLOUD_APP_NEW_VERSION_NAME \
     --version 2 \
     --app $SPRING_CLOUD_APP_NAME \
     --jar-path target/demo-0.0.1-SNAPSHOT.jar

16. 本番とステージングのアプリの入れ替え

上記で、Staging 環境に新しいバージョンがデプロイされましたが、新バージョンを本番環境に適用するためには、旧バージョンから新バージョンにリクエストの振り先を変える必要があります。そこで、振り先を新バージョンに変更するために下記のコマンドを実行してください。

$ az spring-cloud app set-deployment \
     --deployment $SPRING_CLOUD_APP_NEW_VERSION_NAME \
     --name $SPRING_CLOUD_APP_NAME \
     -s $SPRING_CLOUD_SVC_NAME \
     -g $RESOURCE_GROUP

このようにして簡単にバージョンの切り替えも可能です。

17. GitHub Actions による CI/CD

さらに、下記にのような GitHub Actions のワークフローを作成(.github/workflows/main.yaml)することで、GitHub に対してソースコードを Push する度に、ソースコードのビルドからデプロイまでを自動化することもできます。

このワークフローを作成する上で注意したポイントは、Staging にすでにアプリケーションがデプロイされている場合、上書きできずエラーになるため、一旦既存のデプロイ済みのアプリケーションを削除して追加しています。また、ソースコードリビジョンとデプロイ名を一致させるために、環境変数に Git のリビジョン番号などを代入し、それを名前に付加するようにしています。

name: Build and deploy on Azure Spring Cloud

on: [push]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8
    - name: Get Year Month Day 
      run: echo ::set-env name=DATE::$(date '+%Y%m%d-%H%M%S')
    - name: Get the Git Revision Number
      run: echo ::set-env name=GIT_SHORT_VERSION::$(git rev-parse --short HEAD)
    - name: Build with Maven
      run: mvn package -DskipTests -Pcloud
    - name: Login to Azure Spring Cloud
      uses: azure/actions/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}
    - name: Install Azure Spring Cloud extension
      run: az extension add -y --source https://azureclitemp.blob.core.windows.net/spring-cloud/spring_cloud-0.1.0-py2.py3-none-any.whl
    - name: Get Un Active Service Name 
      run: echo ::set-env name=UNACTIVE_SERVICE::$(az spring-cloud app deployment list -g Spring-Cloud-Services -s spring-cloud-services-jp --app petstore-app  -o json |  jq -c '.[]| [.name, .properties.active]' | grep false | awk -F'["]' '{print $2}')
    - name: Delete UnActive Service 
      run: az spring-cloud app deployment delete -n ${{env.UNACTIVE_SERVICE}} -g Spring-Cloud-Services -s spring-cloud-services-jp --app petstore-app
    - name: Deploy to Azure Spring Cloud
      run: az spring-cloud app deployment create -g Spring-Cloud-Services -s spring-cloud-services-jp --name green-${{env.DATE}}-${{env.GIT_SHORT_VERSION}} --version ${{env.DATE}}-${{env.GIT_SHORT_VERSION}} --app petstore-app --jar-path target/demo-0.0.1-SNAPSHOT.jar

以上、で GUI でデモした内容とほぼ同等の内容を CLI だけで実施しましたが、自動化設定を行う際には本内容が必要になる場合もあるかと想定します。本エントリを少しでもお役に立てていただければ誠に幸いです。

その他の参考情報

Azure Spring Cloud は 2019 年 10 月に発表されたばかりのサービスで、現時点ではまだ Preview 版になります。しかしながら現状でも便利な機能が含まれるため、ぜひ多くの皆様にお試しいただければ誠に幸いです。また、本紙の都合上取り上げなかった機能に関しても下記のようなドキュメントから参照していただく事ができます。

Azure Spring Cloud
Azure Spring Cloud のドキュメント
その他 Spring on Azure に関する情報
Azure Spring Cloud のご紹介

また、Microsoft MVP である@setoazusaさんも、12/19 に「Azure Spring CloudでBlue-Green Deploy」というエントリーを投稿してくださっているようです。こちらも合わせてご覧ください。

さいごに

Azure Spring Cloud の正式リリース(GA) は来年 2020 年の Q2 あたりを予定しています。ご興味のある方はぜひ、お早めにお試しいただきぜひ使用感に関してフィードバックをいただければ誠に幸いです。
より多くのフィードバックをいただき改善していくことでさらに良くなってまいりますので、ぜひ多くの皆様お試しください。
ご協力のほどどうぞよろしくお願いします。

2019年12月20日 at 12:22 AM コメントを残す

Kubernetes の導入時に考えるべきこと

Azure にシステム導入・移行するお客様に日頃ご支援をさせていただいているのですが、多くのお客様やエンジニアの皆様から、たびたび似たようなご質問を頂くので、その内容をここに紹介したいと思います。(実際、今日もとあるお客様で下記のご相談を頂いたので)

ご質問:

お客様からたびたび頂くご質問の例

  • このシステムを Kubernetes (AKS) 上で構築するのは正しいですか?
  • とあるコンサルから Kubernetes を導入しないと会社の未来はないと言われたのですが、本当ですか?
  • 今、Azure Web App for Container か AKS (Kubernetes) の何れかの選択で悩んでいるのですが、どちらが良いですか?
  • 今、このような Kubernetes(AKS) のシステム構成を考えているのですが、正しいですか?

質問の背景:

これらのご質問は、メッセージは異なるのですが基本的には同じ質問です。結局どのような場合に kubernetes (AKS) を活用するのが効果的なのかが理解出来ていないため出てくる質問です。

個人的には当たり前になっていたので、この手の内容はまとめなくても良いかな?と思っていたのですが、度々、お問い合わせを頂くので多くの方がお悩みなのかな?と思ったのと、今日ミーティングに同席された方から、ぜひまとめて欲しいとのご要望を承ったので書くことにしました。

ご質問いただいた際の私の対応:

このようなご質問をいただく際、私からは必ず、質問者に対して下記の2つを問い合わせます。

  1. そのシステムは変更の激しいシステムですか?例えば今後サービスの追加は多いですか?もしくは修正が多いですか?
  2. コンテナ化するサービスは大量の CPU やメモリのリソースを消費しますか?

Kubernetes を選択するか否か:

A. Kubernetes が適する場合

上記の質問に対する答えに対し、1 が「はい」、2 が「いいえ」 の条件を共に満たす場合は Kubernetes の導入が適するかと思います。(前提:アジャイル、DevOps などが出来る環境が整っている会社の場合)

1: はい (変更が激しい)
2: いいえ (大量の CPU/メモリは消費しない)

B. Kubernetes が適さない場合:

一方で、上記の質問に対する答えに対し、1 が「いいえ」、2 が「はい」の条件のどちらか片方でも条件を満たす場合は、Kubernetes の導入は適さないと思います。

1: いいえ (変更は激しくない)
2: はい (大量の CPU,メモリを消費する)

理由:

システムは変更の激しいシステムか否か

まず、1 の質問の背景はマイクロサービス化をしたいと考えるお客様に対しても同様の質問をするのですが、「変更」には2つの観点があります。一つは、「既存のサービスに対し頻繁な更新・バージョン・アップ」、そしてもう一つは「新機能の追加が多くある」です。

「既存のサービスに対し頻繁な更新・バージョン・アップ」が必要な場合、一早いサービスの入れ替えが必要になります。それを実現するためには、アジャイルでの開発を実践し、DevOps でビルドやリリースのパイプラインを自動化していきます。そして、古いバージョンから新しいバージョンに安全に入れ替えるために、ローリング・アップデートやブルー・グリーン・デプロイ、カナリー・デプロイなどの手法を用いて入れ替えていく必要があります。
その際、システム構築スピードであったり、構築やサービス入れ替えの容易性が重要になってきます。デプロイ先として IaaS を選ぶ場合、VM の構築には時間が掛かります。そして上記のようなローリング・アップグレードやブルー・グリーン・デプロイ、カナリー・デプロイなどの手法を取り入れるためには、ご自身でこれらを実現するための環境を整える必要があり多大な労力を伴います。
こうした手間や労力を軽減してくれるのが PaaS (Azure では Azure Web App)であったり Kubernetes(AKS) になります。

この時点では、まだ選択肢として PaaS, Kubernetes 何れもありうる状況ですが、次に考えるのがもう一つの「新機能の追加が多くある」か否かです。デプロイするサービス数が増えて来たり、サービス間の連携などが増えてくると、PaaS では管理が煩雑になる場合があります。その場合、Kubernetes クラスター内でまとめて管理をする方がサービス間の管理やサービス全体の運用管理が楽になったり見通しが楽になったりします。
具体的なサービスの追加数は、個々のシステムや企業における運用・管理ポリシーによって異なるので本来ならば明示は避けたい所ですが、追加するサービス数が 5-10 程度ならば、迷わず PaaS をお勧めします。
しかし、サービス数が、20を超えるようならば Kubernetes の導入をお勧めします。
もちろん、 5-10 程度でも Kubernetes をご利用いただいても良いかと思いますが、導入するサービス数に対して、運用・管理、さらに学習コストの方が高くつくのではないかと想定します。

CPU やメモリのリソースを消費するか否か

また、2 の稼働させるサービスは「大量の CPU やメモリのリソースを消費しますか?」についてですが、こちらも選択する際の重要な要素と考えています。

Kubernetes 上で稼働する Pod (コンテナを束ねた物) が実際にはどこで動いているのかを考えて頂くと納得していただけるのですが、Pod(コンテナ) は、実際には、Kubernetes クラスタのノード上で動いています。ノードは実際には 1VM になります。例えば Kubernetes クラスタを 3 ノード (3 VM) で構成し、各ノードの VMに CPU 4 コア、16GB の VM を割り当てた場合を考えます。

この場合、3ノード全体で利用できる CPU やメモリーのリソースは下記の通りです。

CPU: 4 Core * 3 node = 12 Core(1200m)
Memory: 16 Gb * 3 node = 48 GB

自身が提供するサービスは、上記の 12 Core, 48 GB を超えてスケール・アウト(増やす)事は出来ません。実際には、Kubernetes を動作させるために必要な管理用の Pod(kube-system内のpod)で利用する CPU や Memory のリソースも含まれるため、上記の MAX 分までを自身のサービスを利用することも出来ません。

極端な例でわかりやすく説明すると、仮に自身が提供するサービスが 1 Pod (コンテナ) あたり CPU 1Core 分を消費するようなアプリケーションの場合、1ノードあたり 2 〜 3 Pod、トータルで 6 〜 10 pod 位しか作れないのです。また、1 Pod (コンテナ) あたり 2 GB 位メモリを消費するようなアプリの場合は、約 20 pod 位しか作れないことになります。
もし、CPU や メモリーを大量に消費するようなサービスを提供したい場合は、わざわざ Node の CPU やメモリを共有する Kubernetes 環境で提供するよりも、IaaS 環境で 1 VM に1サービスをデプロイして提供した方が、Kubernetes のオーバヘッドもなく、パフォーマンスも発揮するかと想定します。

つまり、Kubernetes で提供するサービスは、簡単にスケール・アウトしやすいサービスのデプロイには向いていますが、パフォーマンスを上げるためにスケール・アップが必要なサービスには向かないと考えています。
その場合、IaaS でも PaaS でも Serverless でも違う選択肢を考えた方が良いかと思います。

さいごに

Kubernetes は決して銀の弾丸ではないため、どうぞ適材・適所で稼働に向くサービスを稼働させるようにしてください。

2019年7月20日 at 1:51 AM

JAPAN CONTAINERDAYS v18.12 での発表について

先日 JAPAN CONTAINERDAYS v18.12 に参加し 「40 Topic of Kubernetes in 40 Minutes」 という内容で 40 個の Kubernetes に関するトピックを 40 分でご紹介する内容を発表させていただきました。

1-16 のトピックについては当日はデモをしながら説明をしたのですが、参加してくださった方のお一人が具体的に私がどのようなデモをしたのかをまとめてくださっていました。(誠にありがとうございます。)

Topic 1-16 のまとめ記事はコチラ。
Container Days × kubernetes(k8s) × 「40 topic of kubernetes in 40 minutes」メモ

今回の私の発表内容には賛否両論があるかと思いますが、この内容は、2018 年 12 月の現時点で、私が私のお客様に対してお伝えする、Kubernetes(k8s) を本番環境に対して適用する際の注意ポイントをまとめた内容です。

まず、私の立ち位置を簡単にご紹介しますと、私は k8s の製品営業でも k8s の担当エンジニアでもございません。k8s の良さを理解しつつ、正しい所で正しく使っていただきたいと思っているエンジニアです。もし、提供するサービスが k8s にあっていなければ、違う方法を選択したほうが良いですよと私のお客様には言っています。そして、それによって扱うエンジニアが幸せになり、企業もより良いサービスを素早く提供していただきたいと考えています。

余談ですが、実話としてあるお客様から以前こんなご相談を受けました。

相談者:「寺田さん、御社では無い方からこのような事を言われまして」
某営業さん:「このシステムを将来的にコンテナ化し k8s を導入しないと駄目だ!将来がなくなる」
相談者:「えっ?えっ?」
相談者:「寺田さん、本当なんですか?」
寺田:「どのようなシステムなんですか?」
相談者:「こんなシステムで、今はこのような開発人員構成です」
寺田:「それなら、無理にしなくていいです」

最初に話を伺った際に、マジかこの営業?お客様を地獄の底に連れて行きたいのか?と思ったくらいでした。

k8s は確かに素晴らしいので、上手く使いこなせばとても大きな効果を得られます。しかし、扱い方を間違えると効果が得られないばかりでなく、余計管理コストは高くつき大変な思いをすることにもなるでしょう。

今回のイベント会場の懇親会会場でも別の方から、下記のようなご質問をいただきました。
「エンドのお客様がコンテナ化や k8s 化に期待しており、会社としてやらなければならないのだが、上司から今までと作り方もやり方は変えられない。」
寺田:「いえ、それコンテナ化してもメリット無いですよ!」

このようなやりとりは、今の日本に少なからずあると思うのです。k8s を導入したらそれだけで幸せになれると思っているのでしょうか?

まず、その場合に私が最初にお伺いするのは下記のような内容です。

「サービスは今後どのように成長して行きますか?」
「もっというならば、新機能の追加は今後数多くありますか?」
「作ったサービスの改良やバージョンアップは頻繁にありますか?」

共に YES ならば k8s を検討し始めても良いですし、そうでなければ違う道を模索して良いと思います。

実は、このセッションは私の、k8s を扱うまでの三部作シリーズの3本目のコンテンツになります。

1. 今後の開発ビジョン


2. Java on Kuberenetes on Azure

3. 40 Topic of Kuberenetes in 40 Minutes

1 に関しては、Kubernetesは銀の弾丸ではない――エンジニアが生き残るために必要な技術とは【デブサミ2018 関西】に発表内容がまとめられていますので、こちらをご参考にいただければと思います。k8s を扱うその前に、心構えであるとかバックグラウンドを説明したのがこちらです。

ポイントは、「どのような時に、そして何のために k8s を使うのか?」を考える事がとても重要だと言う事です。

実際に k8s を扱うにしても、出来る事は数多くあります、その際、この機能は必要?別のほうが簡単じゃない?管理が楽になるんじゃ無い?と思うならば、率先して違う手段も考えるのも良いと思います。いや、それでも k8s のここが便利だから使って、いち早くサービスを提供・展開したいと思って初めて、k8s を扱う土俵に立てるのだと思います。

こうした背景を踏まえて、三部作の3つ目として作成したのが今回のコンテンツでした。特に 26-33 の項目は、おそらく今まで誰も表立って触れてこなかった内容だと思いますので、あえてこの場を借りて発表しました。

時間の関係上、セッション中でも詳しい点をお伝えできなかった所もあるので、ここで真意も含めて共有したいと思いますが、長くなるので別エントリに分けます。

本エントリの続きはこちら
第2弾:Kubernetes を本番環境に適用するための Tips

2018年12月6日 at 1:36 PM 1件のコメント

Azure Functions for Java Preview Release

この度、San Francisco で開催された JavaOne 2017 で、Microsoft は Azure Functions の Java 版を Preview 版として公開しました。本エントリーでは、ちょとだけ試してみましたので、その内容をご紹介します。

Mac OS/X の環境で Azure Functions を動作させるためには下記の環境が必要です。環境が整っていない場合、インストール・実行が正しくできない場合があります。必要な環境にご注意ください。

Azure Functions のローカル実行環境のインストール
Local Execution Environment Install

$ sudo npm i -g azure-functions-core-tools@core --unsafe-perm
Password:

> azure-functions-core-tools@2.0.1-beta.18 uninstall /Users/tyoshio2002/.nodebrew/node/v8.6.0/lib/node_modules/azure-functions-core-tools
> node lib/uninstall.js

deleting /Users/tyoshio2002/.azurefunctions/bin
/Users/tyoshio2002/.nodebrew/node/v8.6.0/bin/func -> /Users/tyoshio2002/.nodebrew/node/v8.6.0/lib/node_modules/azure-functions-core-tools/lib/main.js
/Users/tyoshio2002/.nodebrew/node/v8.6.0/bin/azfun -> /Users/tyoshio2002/.nodebrew/node/v8.6.0/lib/node_modules/azure-functions-core-tools/lib/main.js
/Users/tyoshio2002/.nodebrew/node/v8.6.0/bin/azurefunctions -> /Users/tyoshio2002/.nodebrew/node/v8.6.0/lib/node_modules/azure-functions-core-tools/lib/main.js

> azure-functions-core-tools@2.0.1-beta.18 postinstall /Users/tyoshio2002/.nodebrew/node/v8.6.0/lib/node_modules/azure-functions-core-tools
> node lib/install.js

+ azure-functions-core-tools@2.0.1-beta.18
updated 1 package in 112.93s

次に、Maven コマンドで Azure Functions のプロジェクトを作成します。

$ mvn archetype:generate -DgroupId=com.yoshio3  -DinteractiveMode=false  -DartifactId=AzureFunctionTest
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] >>> maven-archetype-plugin:2.4:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO] 
[INFO] <<< maven-archetype-plugin:2.4:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO] 
[INFO] 
[INFO] --- maven-archetype-plugin:2.4:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: basedir, Value: /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test2
[INFO] Parameter: package, Value: com.yoshio3
[INFO] Parameter: groupId, Value: com.yoshio3
[INFO] Parameter: artifactId, Value: AzureFunctionTest
[INFO] Parameter: packageName, Value: com.yoshio3
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test2/AzureFunctionTest
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.258 s
[INFO] Finished at: 2017-10-28T13:24:07+09:00
[INFO] Final Memory: 15M/223M
[INFO] ------------------------------------------------------------------------

プロンプト無しで Maven プロジェクトを作成したい場合の実行例:

mvn archetype:generate -DinteractiveMode=false -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DgroupId=com.yoshio3 -DartifactId=Java-Azure-Functions -Dversion=1.0-SNAPSHOT -Dpackage=com.yoshio3 -DappName=Java-Azure-Functions -DappRegion=westus2

デフォルトで Hello World のコードが生成されます。

package yoshio3.com;

import com.microsoft.azure.serverless.functions.annotation.*;
import com.microsoft.azure.serverless.functions.ExecutionContext;
import java.util.logging.Level;

/**
 * Hello function with HTTP Trigger.
 */
public class Function {
    @FunctionName("hello")
    public String hello(@HttpTrigger(name = "req", methods = {"get", "post"}, authLevel = AuthorizationLevel.ANONYMOUS) String req,
                        ExecutionContext context) {
        return String.format("Hello, %s!", req);
    }

このサンプル・コードをビルドします。

$ mvn clean package
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building Azure Java Functions 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ azure-functions-test ---
[INFO] Deleting /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target
[INFO] 
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ azure-functions-test ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ azure-functions-test ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ azure-functions-test ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ azure-functions-test ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ azure-functions-test ---
[INFO] Surefire report directory: /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
Running yoshio3.com.FunctionTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.117 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ azure-functions-test ---
[INFO] Building jar: /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions-test-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- azure-functions-maven-plugin:0.1.4:package (package-functions) @ azure-functions-test ---
AI: INFO 06-10-2017 12:00, 1: Configuration file has been successfully found as resource
AI: INFO 06-10-2017 12:00, 1: Configuration file has been successfully found as resource
[INFO] 
[INFO] Step 1 of 6: Searching for Azure Function entry points
[INFO] Reflections took 101 ms to scan 1 urls, producing 1 keys and 2 values 
[INFO] 2 Azure Function entry point(s) found.
[INFO] 
[INFO] Step 2 of 6: Generating Azure Function configurations
[INFO] Generation done.
[INFO] 
[INFO] Step 3 of 6: Validating generated configurations
[INFO] Validation done.
[INFO] 
[INFO] Step 4 of 6: Saving empty host.json
[INFO] Successfully saved to /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions/function-test-java/host.json
[INFO] 
[INFO] Step 5 of 6: Saving configurations to function.json
[INFO] Starting processing function: Timer
[INFO] Successfully saved to /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions/function-test-java/Timer/function.json
[INFO] Starting processing function: hello
[INFO] Successfully saved to /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions/function-test-java/hello/function.json
[INFO] 
[INFO] Step 6 of 6: Copying JARs to staging directory /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions/function-test-java
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource to /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions/function-test-java
[INFO] Copied successfully.
[INFO] Successfully built Azure Functions.
[INFO] 
[INFO] --- maven-resources-plugin:3.0.2:copy-resources (copy-resources) @ azure-functions-test ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 33.243 s
[INFO] Finished at: 2017-10-06T12:01:07-07:00
[INFO] Final Memory: 39M/564M
[INFO] ------------------------------------------------------------------------

ローカルで実行します。

$ mvn azure-functions:run
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building Azure Java Functions 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- azure-functions-maven-plugin:0.1.4:run (default-cli) @ azure-functions-test ---
AI: INFO 06-10-2017 09:13, 1: Configuration file has been successfully found as resource
AI: INFO 06-10-2017 09:14, 1: Configuration file has been successfully found as resource
[INFO] Azure Functions stage directory found at: /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions/function-test-java
[INFO] Azure Functions Core Tools found.
[INFO] Starting running Azure Functions...

                  %%%%%%
                 %%%%%%
            @   %%%%%%    @
          @@   %%%%%%      @@
       @@@    %%%%%%%%%%%    @@@
     @@      %%%%%%%%%%        @@
       @@         %%%%       @@
         @@      %%%       @@
           @@    %%      @@
                %%
                %

[2017/10/06 16:14:30] Reading host configuration file '/Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions/function-test-java/host.json'
[2017/10/06 16:14:31] Host configuration file read:
[2017/10/06 16:14:31] {
[2017/10/06 16:14:31] }
[2017/10/06 16:14:31] 
info: Worker.Java.c26685f3-cbd5-4bff-bbea-d3e9e00d08ed[0]
      Start Process: /Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/bin/java  -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 "/Users/tyoshio2002/.azurefunctions/bin/workers/Java/azure-functions-java-worker.jar" --host 127.0.0.1 --port 56034 --workerId c26685f3-cbd5-4bff-bbea-d3e9e00d08ed --requestId 4270cbeb-361f-422a-872a-c0ec946199c5
[2017/10/06 16:14:32] Generating 1 job function(s)
info: Worker.Java.c26685f3-cbd5-4bff-bbea-d3e9e00d08ed[0]
      Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
[2017/10/06 16:14:32] Starting Host (HostId=yoshionomacbookpro-1392184404, Version=2.0.11308.0, ProcessId=65522, Debug=False, Attempt=0)
Listening on http://localhost:7071/
Hit CTRL-C to exit...

Http Functions:

	hello: http://localhost:7071/api/hello

info: Worker.Java.c26685f3-cbd5-4bff-bbea-d3e9e00d08ed[0]
      Listening for transport dt_socket at address: 5005
info: Worker.Java.c26685f3-cbd5-4bff-bbea-d3e9e00d08ed[0]
      Microsoft Azure Functions Java Runtime [build 1.1-SNAPSHOT]
[2017/10/06 16:14:32] Found the following functions:
[2017/10/06 16:14:32] Host.Functions.hello
[2017/10/06 16:14:32] 
[2017/10/06 16:14:32] Job host started
info: Worker.Java.c26685f3-cbd5-4bff-bbea-d3e9e00d08ed[0]
      [INFO] {com.microsoft.azure.webjobs.script.handler.MessageHandler.handle}: message generated by "class com.microsoft.azure.webjobs.script.rpc.messages.StartStream$Builder"
info: Worker.Java.c26685f3-cbd5-4bff-bbea-d3e9e00d08ed[0]
      Worker initialized
info: Worker.Java.c26685f3-cbd5-4bff-bbea-d3e9e00d08ed[0]
      94978bb8-3f21-47c7-961d-5d9caecc0136 - "/Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions/function-test-java/azure-functions-test-1.0-SNAPSHOT.jar"::"yoshio3.com.Function.hello" loaded
[2017/10/06 16:16:27] Function started (Id=a529fffb-fd7b-43d4-bd53-3283808f68ce)
[2017/10/06 16:16:27] Executing 'Functions.hello' (Reason='This function was programmatically called via the host APIs.', Id=a529fffb-fd7b-43d4-bd53-3283808f68ce)
[2017/10/06 16:16:27] Function "94978bb8-3f21-47c7-961d-5d9caecc0136" executed
[2017/10/06 16:16:27] Function completed (Success, Id=a529fffb-fd7b-43d4-bd53-3283808f68ce, Duration=444ms)
[2017/10/06 16:16:27] Executed 'Functions.hello' (Succeeded, Id=a529fffb-fd7b-43d4-bd53-3283808f68ce)

起動が完了したら、curl コマンドなどでアクセスしてみてください。

$ curl http://localhost:7071/api/hello -d "Java World"
Hello, Java World!

上記は、簡単な Hello World ですが他のトリガーを利用する場合は、下記のように local.settings.json ファイルに、AzureWebJobsStorage のアクセスキーを入力する必要があります。どうご注意ください。

local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=fileup;AccountKey=*******;EndpointSuffix=core.windows.net",
    "AzureWebJobsDashboard": ""
  }
}

たとえば、タイマーをトリガーに何らかの処理をしたい場合、下記のようなコードを書きます。

    @FunctionName("Timer")
    public String functionHandler(@TimerTrigger(name = "timerInfo", schedule = "*/30 * * * * *") String timerInfo, final ExecutionContext executionContext) {
        executionContext.getLogger().log(Level.INFO, "Timer trigger input: {0}", timerInfo);
        return "From timer: \"" + timerInfo + "\"";
    } 

ローカルで検証が終わったので、Microsoft Azure へデプロイします。

$ mvn azure-functions:deploy
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building Azure Java Functions 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- azure-functions-maven-plugin:0.1.4:deploy (default-cli) @ azure-functions-test ---
AI: INFO 06-10-2017 12:31, 1: Configuration file has been successfully found as resource
AI: INFO 06-10-2017 12:31, 1: Configuration file has been successfully found as resource
[INFO] Starting deploying to Function App function-test-java...
[INFO] Authenticate with Azure CLI 2.0
[INFO] --> POST https://login.microsoftonline.com/********-****-****-****-**********/oauth2/token
[INFO] 1178-byte body:
client_id=04b07795*******
[INFO] --> END POST
[INFO] <-- 200 OK https://login.microsoftonline.com/72f988bf-86f1-41af-91ab-2d7cd011db47/oauth2/token (833 ms, 2907-byte body)
[INFO] Cache-Control: no-cache, no-store
[INFO] Content-Length: 2907
[INFO] Content-Type: application/json; charset=utf-8
[INFO] Date: Fri, 06 Oct 2017 19:31:31 GMT
[INFO] Expires: -1
[INFO] P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
[INFO] Pragma: no-cache
[INFO] Server: Microsoft-IIS/8.5
[INFO] Set-Cookie: esctx=AQABAAAAAAABlDrqfEFlSaui6xnRjX5E6ugjSSC5bAEQSJ1V_VvTv2HB9o-5-******;; domain=.login.microsoftonline.com; path=/; secure; HttpOnly, x-ms-gateway-slice=004; path=/; secure; HttpOnly, stsservicecookie=ests; path=/; secure; HttpOnly
[INFO] Strict-Transport-Security: max-age=31536000; includeSubDomains
[INFO] X-Content-Type-Options: nosniff
[INFO] x-ms-request-id: 4813f784-046f-414e-8d9e-29a4e43e3c00
[INFO] X-Powered-By: ASP.NET
[INFO] 2907-byte body:
{"token_type":"Bearer","scope":"user_impersonation","expires_in":"3599","ext_expires_in":"0","expires_on":"1507321891","not_before":"1507317991","resource":"https://management.core.windows.net/","access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkhIQnlLVS0wRHFBcU1aaDZaRlBkMlZXYU90ZyIsImtpZCI6IkhIQnlLVS*********
[INFO] <-- END HTTP
[INFO] Target Function App does not exist. Creating a new Function App ...
[INFO] Successfully created Function App function-test-java
[INFO] 
[INFO] Step 1 of 4: Creating ZIP package...
[INFO] Successfully saved ZIP package at /Users/tyoshio2002/NetBeansProjects/Azure-Function-Test1/azure-functions-test/target/azure-functions/function-test-java.zip
[INFO] 
[INFO] Step 2 of 4: Uploading ZIP package to Azure Storage...
[INFO] Successfully uploaded ZIP package to https://d0a43c4e4c4a435d9f25.blob.core.windows.net/java-functions-deployment-packages/function-test-java.20171006123210784.zip
[INFO] 
[INFO] Step 3 of 4: Deploying Function App with package...
[INFO] Azure Resource Manager read/write per hour limit reached. Will retry in: 5 seconds
[INFO] Successfully deployed Function App with package.
[INFO] 
[INFO] Step 4 of 4: Deleting deployment package from Azure Storage...
[INFO] Successfully deleted deployment package function-test-java.20171006123210784.zip
[INFO] Successfully deployed Function App at https://function-test-java.azurewebsites.net
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:01 min
[INFO] Finished at: 2017-10-06T12:33:00-07:00
[INFO] Final Memory: 42M/488M
[INFO] ------------------------------------------------------------------------

デプロイが完了したのち、Azure の Portal 画面を確認して正しくデプロイされている事、そしてアクセスするための URL を確認します。

Azure にデプロイした URL へアクセスしてみます。

$ curl https://function-test-java.azurewebsites.net/api/hello -d "Java World"
Hello, Java World!

ローカルで実行したのと同様に、正しく実行する事ができました。
より詳細な情報は、Azure Functions Java developer guide
に記載されています。

ぜひ、みなさまお試しください!!

2017年10月7日 at 4:46 AM

皆んな大好き Excel !! Excel REST API Java サンプルアプリケーション

2016 年 8 月初旬 Office 365 の Excel REST API が正式にリリースしました。
アナウンス:「Announcing the general availability of the Microsoft Excel API to expand the power of Office 365

上記により、Graph API と呼ばれる REST API を使用して、Office 365 の OneDrive に存在する Excel ファイルを操作できるようになります。
Excel 操作用の Graph API

※ REST API で利用できるため、プログラミング言語を問わず任意の言語で操作ができるようになっていますので、Java 以外のプログラミング言語でもどうぞお試しください。

今回、私は上記の REST API を利用して Java のサンプル・コードを作成しました。
サンプル・コード:「GitHub : Office-365-Excel-REST-API-for-Java」
またサンプル・コードがどのように動作するのかをわかりやすくするため、サンプル・アプリケーションのデモ動画も撮りましたので、どうぞ下記のデモ動画もご覧ください。

今回作成したサンプル・アプリケーションは Java EE 7 のアプリケーションとして作成しました。そこで、Java EE 準拠のアプリケーション・サーバであれば、いずれの環境でも動作します。私は、Payara Server 4.1.1.162 (GlassFish) で動作確認をしていますが、少しの変更を行うだけで、アプリケーション・サーバではなく、Servlet Container(Tomcat/Jetty) でも動かすことができます。

追記:
Office 365 を無料でお試しいただく為の設定手順 (ステップ・バイ・ステップの画面ダンプ) や Tomcat 用の設定方法に関しては 「GitHub : README.md もしくは README-4-Tomcat.md」に記載しています。

アプリケーションの実装の詳細
このサンプル・アプリケーションは Java EE 7 で実装しています。

まず、GUI (フロントエンド) のビュー・テクノロジーとして JavaServer Faces (PirmeFaces) を利用しています。しかし、フロント技術はこのサンプルでは重要でありません。慣れ親しんだフロント・テクノロジーをご利用ください。

実際の、Excel 操作の要は、com.yoshio3.restclient パッケージ配下で実装しています。
特に com.yoshio3.restclient.services サービスが重要で、Excel REST API で用意されている各種機能(REST 呼び出し)をラッピングしたメソッドを実装しています。
また、Excel REST API のリクエスト・ボディ、もしくはレスポンス・ボディに含む JSON のデータは、すべて com.yoshio3.restclient.jaxb.entities パッケージ配下のクラスにマッピングしています。例えば、Excel のワーク・シートやテーブルを取得した際に取得できる情報はすべて com.yoshio3.restclient.jaxb.entities.excel パッケージに含まれています。このマッピングした Java オブジェクトを操作することで、実際の JSON データを意識せずにプログラムができます。

また、Office 365 に接続するためには、Azure Active Directory で認証を行う必要があります。今までは、「Microsoft Azure Active Directory Authentication Library (ADAL) for Java」を利用してきました。しかし、今回 Azure AD で認証を行うために必要最低限の軽量な Servlet Filter (AzureADAuthServletFilter) を独自に実装しました。

Servlet Filter : AzureADAuthServletFilter.java
アクセス・トークン:AccessToken.java
Auth サービス: OAuth2Service.java

まだ一部実装が足りない部分(TODO)はありますが、Azure AD の認証のフローをご理解頂く上で、このサーブレット・フィルタはご参考いただけるのではないかと思います。また、Servlet Filter なので認可はできませんが、Tomcat/Jetty のような Servlet Container でも動作します。認可が必要な方は、以前作成した「Azure AD 認証・認可サンプル」をご参照ください。

Java ユーザの皆様も、Office 365 の OneDrive に存在する Excel ファイルを直接 Java から操作してみませんか?

Have fan Excel with Java !!

2016年8月31日 at 8:00 AM

Microsoft Cognitive サービスによる OCR 解析

マイクロソフトの Cognitive サービスには OCR (光学式文字認識:画像に含まれる文字列をテキストデータとして抽出) の機能があります。現在はプレビュー版としてこの機能が提供されています。
Cognitive Services : Computer Vision API – v1.0 OCR

● Java のサンプル・アプリケーションについて
JAX-RS Client API を使って、Java の OCR サンプルを作り下記に公開しました。ご興味ある方はお試しください。
https://github.com/yoshioterada/OCR-Sample-of-Cognitive-Service

※ 本プログラムをお試しいただくためには、Subscription ID を入手して頂く必要があります。コチラ(Cognitive Services Computer Vision)より「Get started for free」のボタンを押し「Computer Vision – Preview 5,000 transactions per month, 20 per minute. 」にチェックし「Subscribe」ボタンを押して「Subscription ID」を入手してください。入手した ID を、プログラム中の SUBSCRIPTION_ID に記載してください。

画像は、以下の3種類の方法で指定できます。

1. 画像が置かれている URI を指定
2. ローカル・ディレクトリを含む絶対パスでファイル名を指定
3. 画像の byte[] を指定

public class Main {

    private final static String SUBSCRIPTION_ID = "*******************************************";

    public static void main(String argv[]) {
        OCRService service = new OCRService(SUBSCRIPTION_ID);

        // GET the result of OCR from specified URI
        String pictURI = "http://businessnetwork.jp/Portals/0/SP2016/PSTN/img/1604_microsoft_top.jpg";
        Optional<OCRResponseJSONBody> result = service.getOCRAnalysisResult(pictURI);
        result.ifPresent(resultBody -> service.printOCRResult(resultBody));
        
        //GET the result of OCR from the local file
        try {
            Optional<OCRResponseJSONBody> result2 = service.getOCRAnalysisResult(Paths.get("/Users/terada/Downloads/aaa.jpeg"));
            result2.ifPresent(resultBody -> service.printOCRResult(resultBody));
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

下記に、本プログラムを利用した解析結果の例をご紹介します。

●解析結果例1
まず、解析結果として、とてもうまくいった例をご紹介します。例として、sansan さんのサンプル名刺を利用させていただきました。

解析したらこんな結果が得られました。完全に一致していますね!!

Cognitive-OCR1//embedr.flickr.com/assets/client-code.js

●解析結果例2
次に私の名刺を解析しました(メールと電話番号だけ伏せさせてください)。
Cognitive-OCR3//embedr.flickr.com/assets/client-code.js
その結果、こうなりました。
Cognitive-OCR2//embedr.flickr.com/assets/client-code.js
「Microsoft」が「Mi(「0S0升」、「Blog」が「引log」になっています。どうやら、現時点で日本語と英語がまざると、日本語解析が英語解析より優先度強くはたらき、ローマ字に似た日本語の文字を当てはめるみたいです。例えば「@yoshioterada」が「yoshiote「ada」と解析された場合もあります。

●日英がまざる場合の現時点の回避策

現時点では(ワークアラウンドとして)、日本語解析と英語解析を2度実行し有効な文字列を抽出するのが良いのではないかと思っています。

実際に、OCR 処理用の REST URL は下記になります。
https://api.projectoxford.ai/vision/v1.0/ocr?language=en&detectOrientation=true&#8221;

ここで引数に language を指定しますが、language=en,language=ja で、それぞれ英語か日本語の解析を切り替えます。日英両方を含む場合、現時点のワークアラウンドとして、”en” と “ja” の2回解析し、取得結果から意味的に有効な方を使うというのも良いかもしれません。

実際に、language=en を指定し、英語解析で名刺を解析させると、下記のように「Mi(「0S0升」と解析されていた箇所も正しく「Microsoft」と、そして「Blog」も正しく解析できていました。

Cognitive-OCR4//embedr.flickr.com/assets/client-code.js

REST の呼び出し結果(JSON)を確認すると1文字ずつ文字を抽出し認識しているようです。1行単位(つまり文字の前後関係)では解析はしていないので、1行を抜き出し本当に意味のある正しい文字列になっているかどうかを判定するような処理を入れれば精度はあがるのではないかと思います。(例えば「Mi(「0S0升」や「引log」のように1行中に1バイト文字と2バイト文字が混合しているなどはおかしい可能性が高いです。あと o(オー) と 0(ゼロ) も間違える場合があります。さらに l(エル), I(大文字のアイ), 1(イチ)も同様です。 怪しい場合には Bing の検索 API で探すという手もありかもしれません。)

こちらについては、Java に限らずどの言語を利用しても同じ結果が得られると想定しますので、本国の開発チームには多言語対応への課題としてフィードバックしたいと思っています。

まだプレビュー版ですが、1月辺り 5,000 処理、もしくは1分間辺り 20 処理までは無料でご利用いただけます。どうぞお試し版(プレビュー)としてご利用ください。

2016年8月5日 at 8:00 AM

日本で 2 人目の Java Champion になりました

Java Champion

2016 年 7 月 1 日、 櫻庭祐一 さんに続いて、日本で 2 人目の Java Champion になりました。Java Champion のコミュニティ・サイトにも正式に、下記の通り名前が記載されました。

Java Champion は現在、世界で約 400 名位存在します。
Java Champion の bio 一覧はこちら

Java Champion になるためには、こちらに記載されている基準に従い、既存の Java Champion からのノミネーションと、他の Champion からの投票結果により可否がきまります。
※ Microsoft MVP の場合、Microsoft が承認しますが、Java Champion の場合は既存の Champion が選考します。

基準を一部抜粋します。

  • Java Champions are leaders
  • Java Champions are technical luminaries
  • Java Champions are independent-minded and credible
  • Java Champions are involved with some really cool applications of Java
    Technology or some humanitarian or educational effort.
  • Java Champions are able to evangelize or influence other developers

今回、私は Sun Microsystems 時代からエバンジェリスト仲間として大変お世話になった、Arun Gupta 氏 (現 Couchbase で Developer Advocacy の VP) にノミネートいただき投票結果の末なることができました。

Microsoft の社員としては、おそらく Neal Gafter 氏 (Java SE の元開発者 & Java Puzzlers の著者としても有名 ) に次ぐ2人目?!ではないかと思います。
ご参考:InfoQ : Javaの未来についてのNeal Gafter氏とのディスカッション

現在、Neal 氏は Visual Studio の開発を中心にご担当されていらっしゃいますので、Microsoft で Java の情報発信をしている社員(エバンジェリスト)が Java Champion になるのは、おそらく私が初めてではないかと思います。

日本の櫻庭祐一さんをはじめ、世界の名だたる先輩 Java Champion の名を汚さないように、New Java Champion として今後も継続して Java を応援しながらコミュニティ活動を継続したいと思います。そして、マイクロソフトの Java エバンジェリストとして、クラウド環境 (Microsoft Azure) における Java の活用で、開発者の皆様に有益な情報をお届けるように今後も精進していきたいと思います。

皆様、ぜひ今後ともどうぞよろしくお願いします。

2016年7月8日 at 8:00 AM

過去の投稿


Java Champion & Evangelist

Translate

ご注意

このエントリは個人の見解であり、所属する会社の公式見解ではありません

カレンダー

2020年1月
« 12月    
 12345
6789101112
13141516171819
20212223242526
2728293031  

カテゴリー

Twitter

clustermap

ブログ統計情報

  • 1,171,016 hits

RSSフィード

アーカイブ