はじめに

第20回の「Azure Management LibraryでC#からAzureを操作する」では、C#からAzureを操作する方法を解説しましたが、今回は同様のアプリケーションをJavaで作成してきます。説明がやや重複する部分もでてきますが、なるべく本記事のみで理解できるよう構成しています。お時間があれば前回と対比していただくことで多様なAzureへの操作方法が提供されていることがご理解いただけると思います。

本稿での開発環境は以下の通りです。Javaによるプログラミング経験とAzureの概要を理解している方を対象としています。

・Oracle JDK 11.0
・Azure CLI 2.0.46
・Eclipse Pleiades 2018-9 Javaパッケージ

上記はいずれも本稿で利用したバージョンです。Java用のAzure SDKライブラリ自身は、JDK 7.0以降で動作可能です。また統合開発環境(IDE)としてEclipseを利用しますが、基本的にMavenプロジェクトを扱うこととができれば他のIDEを利用していただいても構いません。

Azure REST APIとは

第20回の繰り返しにはなりますが簡単に説明すると、Azureには、「Azure REST API」と呼ばれるAzure自身を管理するためのAPI群が用意されており、リソースの作成、情報取得、更新、削除などの操作が提供されています。これをJavaから操作するライブラリが「Azure Management Libraries for Java」として提供されており、Javaから簡易にAzureを操作することができるようになっています。

資格情報を作成する

ポータル画面からAzureを利用する場合を考えてみますと、ブラウザからユーザーとパスワードを入力して目的のサブスクリプションにアクセスできる権限を取得できますが、自分が作成したアプリケーションやサービス、自動化ツールからサブスクリプションを操作するためにはどのようにしたらよいでしょうか。Azureではサービスプリンシパルと呼ばれる資格情報をあらかじめ作成しておき、その資格情報に対してサブスクリプションを操作する権限を割り当てAzureを操作します。

第20回ではPowerShellにて操作を行いましたが、同様の方法はAzure CLIでも提供されているので、今回はこちらで実施します。「第18回Azureをコマンドラインツールから操作してみよう」を参考に、az loginコマンドでサブスクリプションに接続し、az account showコマンドを実行します。アカウント情報が表示されるので、サブスクリプションID(id)をメモしておきます(リスト1)。

アカウント情報の確認

C:\>az account show
{
  "environmentName": "AzureCloud",
  "id": " aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee ", 
  "isDefault": true,
  "name": "Visual Studio Ultimate with MSDN (MVP)",
  "state": "Enabled",
  "tenantId": "bbbbbbbb-bbbb-cccc-dddd-eeeeeeeeeeee",
  "user": {
    "name": "xxxxxxx@example.com",
    "type": "user"
  }
}

Azure PowerShellの例ではアプリケーションオブジェクトとサービスプリンシパルオブジェクトを別々に作成していましたが、Azure CLIでは一つのコマンドで作成可能です。

次に、az ad sp コマンドでアプリケーションオブジェクトとサービスプリンシパルオブジェクトを一括で作成します(リスト2)。password引数には任意の複雑な文字列を指定してください。Azure PowerShellでは2回に分けて作成していたオブジェクトですが、Azure CLIでは一括で作成することができます。

サービスプリンシパルオブジェクトの作成

C:\>az ad sp create-for-rbac --name MynaviJavaApp --password "**********"
{
  "appId": "84a6e8a7-e7ae-4b48-b236-c00bfa393775",
  "displayName": "MynaviJavaApp",
  "name": "http://MynaviJavaApp",
  "password": "**********",
  "tenant": "bbbbbbbb-bbbb-cccc-dddd-eeeeeeeeeeee"
}

必要な情報は、クライアントID(appId)、クライアントシークレット(password)、テナントID(tenant)です。ここまで操作すると最終的に以下の情報が取得できているはずです。

表1 資格情報の値

名前 本稿での例
サブスクリプションID aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
テナントID bbbbbbbb-bbbb-cccc-dddd-eeeeeeeeeeee
クライアントID 84a6e8a7-e7ae-4b48-b236-c00bfa393775
クラアントシークレット(*) **********

(*)アクセスキーや、パスワードとも呼ばれます。機密情報ですので第三者に渡さないようにしてください。

ポータルから適切な権限が付与されたか確認してみます。ポータルから「サブスクリプション」一覧を開き該当サブスクリプションを選択します。メニューから「アクセス制御 (IAM)」を選んだ後、上部タブから「ロール割り当て」を選択します。すると、このサブスクリプションに割り当てられたアイテム一覧が表示されます。この中に、「MynaviJavaApp」が表示されていれば正しく権限が設定されています(図1)。

  • 権限の割り当て確認

    権限の割り当て確認

JavaからAzureを操作する

それではファーストステップとして、これらの資格情報を利用してサブスクリプションに定義されているリソースグループ一覧を取得してみましょう。

コンソールアプリの作成とマネジメントライブラリのインストール

アプリケーションのひな形作成にはEclipseのMavenプロジェクトを利用します。MavenとはJavaにおける標準的なビルドツールです。他のIDEやコマンドラインでも扱うことができます。

Eclipseの場合は、「ファイル」-「新規」を選択し、Mavenプロジェクトを選択してください。図2のダイアログが表示されます。「シンプルなプロジェクトの作成」と「デフォルトワークスペースロケーションの使用」にチェックを入れ[次へ]をクリックします。

  • 新規Mavenプロジェクトの作成

    新規Mavenプロジェクトの作成

引き続き図3のダイアログが表示されるので、プロジェクトの設定値として表2を入力して[完了]をクリックします。

表2 プロジェクトの設定値

ラベル
グループId jp.mynavi.azure
アーティファクトId MyNaviJavaApp
  • 新規Mavenプロジェクトの作成(2)

    新規Mavenプロジェクトの作成(2)

図4のとおりワークスペースにプロジェクトが作成されるのでpom.xmlファイルを編集し、properties要素とdependencies要素を追加します(リスト3)。properties要素は明示的にJava 11を使うよう指示し、dependencies要素はAzure SDKへの依存を示すもので、ビルド時に必要なライブラリが自動的にダウンロードされます。

  • プロジェクトの内容|

    プロジェクトの内容

pom.xmlファイル

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>jp.mynavi.azure</groupId>
    <artifactId>MyNaviJavaApp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>11</java.version>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <maven.compiler.source>${java.version}</maven.compiler.source>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure</artifactId>
            <version>1.16.0</version>
        </dependency>
    </dependencies>
</project>

pom.xmlファイルの編集が終わったら、プロジェクトのコンテキストメニューから、「Maven」-「プロジェクトの更新」を選択し、プロジェクト構成を更新します。

最後にメインクラスを追加します。プロジェクトのコンテキストメニューから、「新規」-「クラス」を選択し、表3どおりに入力し、jp.mynavi.azure.Appクラスを作成します(図5)。

  • クラスの追加

    クラスの追加

表3 クラスの作成

ラベル
パッケージ jp.mynavi.azure
名前 App

以上でプロジェクトの準備は完了です。

リソースグループ一覧を取得する

APIを通してリソースを作成する前に、疎通を兼ねてリソースグループ一覧を取得するプログラムを実行してみましょう。まずは、App.javaを以下にように書き換えます(リスト4)。

リソースグループの取得(App.java)

package jp.mynavi.azure;

import com.microsoft.azure.credentials.ApplicationTokenCredentials;
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.compute.KnownLinuxVirtualMachineImage;
import com.microsoft.azure.management.compute.VirtualMachine;
import com.microsoft.azure.management.compute.VirtualMachineSizeTypes;
import com.microsoft.azure.management.network.Network;
import com.microsoft.azure.management.resources.ResourceGroup;
import com.microsoft.azure.management.resources.fluentcore.arm.Region;

public class App {
    // (1)
    private static String subscriptionId = "サブスクリプションID";
    private static String tenantId = "テナントID";
    private static String clientId = "クライアントID";
    private static String clientSecret = "クライアントシークレット";

    public static void main(String[] args) throws Exception {

        // (2) 資格情報の取得
        ApplicationTokenCredentials creds = new ApplicationTokenCredentials(clientId, tenantId, clientSecret, null);

        // (3) サブスクリプションIDを指定してAzureオブジェクトを取得
        Azure azure = Azure.configure()
                .authenticate(creds)
                .withSubscription(subscriptionId);

        // (4) リソースグループの取得
        for (ResourceGroup rg : azure.resourceGroups().list()) {
            System.out.println(rg.name());
            System.out.println(rg.regionName());
        }
    }
}

(1)では、先ほどメモしておいた各情報を実際の値に書き換えてください。
(2)では、それらの情報より、ApplicationTokenCredentialsオブジェクトを取得します。
(3)では、資格情報を元にwithSubscriptionメソッドで操作するサブスクリプションを指定し、Azureクラスを取得します。Azureクラスは、Azureのリソースを操作する基点のクラスとなります。
(4)では、AzureクラスのresourceGroupメソッドを呼び出し、ResourceGroupsインタフェースを取得した後、listメソッドからリソースグループ一覧を取得しています

では実行してみましょう。App.javaクラスを選択し、コンテキストメニューから「実行」-「Javaアプリケーション」を選択します。正しく実行され、リソースグループの一覧が表示されたでしょうか?例外が発生する場合は、設定を再度確認してみてください。

さて、前述したとおりAzureクラスは、Azureを操作する基点になります。定義されている代表的なメソッドは下表の通りです。

表4 Azureクラスの代表的なメソッド

メソッド名 説明
appServices Appサービスを管理するためのエントリポイント
networks 仮想ネットワークを管理するためエントリポイント
resourceGroups リソースグループを管理するためのエントリポイント
redisCaches Redisキャッシュを管理するためのエントリポイント
sqlServers SQLデータベースを管理するためのエントリポイント
virtualMachines 仮想マシンを管理すつためのエントリポイント

仮想マシンを作成する

正しくAzureの情報を取得できたところで、次に仮想マシンの作成、操作をしてみましょう。あらかじめ作成する仮想マシンのパラメーターを決めておきます(表5)。

表5:仮想マシンのパラメーター一覧

リソース 名前
ロケーション 東日本
リソースグループ名 mynavijava
仮想ネットワーク mynavijavavnet 10.0.0.0/16
仮想マシン名 subnet 10.0.0.1/24
仮想マシンのOS mynavijava-vm
仮想マシンのサイズ Ubuntu 16.04 LTS
仮想マシンのDNS名 Basic_A1 mynavijava-vm(Azureリージョンで一意)

先ほどの同様にApp1.javaを新規に作成し、プログラムをリスト5に書き換えて実行してみましょう。ただし、withNewPrimaryPublicIPAddressの引数は最終的にDNS名の一部となるため、リージョンで一意な名前が必要です。またwithAdminPasswordの引数には、要件にあったパスワードを設定してから実行してください。

仮想マシンの作成(App1.java)

package jp.mynavi.azure;

import com.microsoft.azure.credentials.ApplicationTokenCredentials;
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.compute.KnownLinuxVirtualMachineImage;
import com.microsoft.azure.management.compute.VirtualMachine;
import com.microsoft.azure.management.compute.VirtualMachineSizeTypes;
import com.microsoft.azure.management.network.Network;
import com.microsoft.azure.management.resources.ResourceGroup;
import com.microsoft.azure.management.resources.fluentcore.arm.Region;

public class App1 {

    private static String subscriptionId = "サブスクリプションID";
    private static String tenantId = "テナントID";
    private static String clientId = "クライアントID";
    private static String clientSecret = "クライアントシークレット";

    public static void main(String[] args) throws Exception {

        ApplicationTokenCredentials creds = new ApplicationTokenCredentials(clientId, tenantId, clientSecret, null);

        Azure azure = Azure.configure()
                .authenticate(creds)
                .withSubscription(subscriptionId);

        // (1) リソースグループの作成
        ResourceGroup resourceGroup = azure.resourceGroups()
                .define("mynavijava")
                .withRegion(Region.JAPAN_EAST)
                .create();

        // (2) 仮想ネットワークの作成
        Network network = azure.networks()
                .define("mynavijavavnet")
                .withRegion(Region.JAPAN_EAST)
                .withExistingResourceGroup(resourceGroup)
                .withAddressSpace("10.0.0.0/16")
                .withSubnet("subnet-1", "10.0.1.0/24")
                .create();

        // (3) 仮想マシンの作成
        VirtualMachine vm = azure.virtualMachines()
               .define("mynavijava-vm")
                .withRegion(Region.JAPAN_EAST)
                .withExistingResourceGroup(resourceGroup)
                .withExistingPrimaryNetwork(network)
                .withSubnet("subnet-1")
                .withPrimaryPrivateIPAddressDynamic()
                .withNewPrimaryPublicIPAddress("mynavijava-vm")
                .withPopularLinuxImage(KnownLinuxVirtualMachineImage.UBUNTU_SERVER_16_04_LTS)
                .withRootUsername("azureuser")
                .withRootPassword("Password123!!##")
                .withSize(VirtualMachineSizeTypes.BASIC_A1)
                .create();

        System.out.println(vm.name() + "の作成が完了しました");
    }
}

しばらく時間はかかりますが、仮想マシンが作成されますので、ポータルで確認してみましょう(図6)

  • 仮想マシン作成後のポータル

    仮想マシン作成後のポータル

リスト8では、リソースグループの作成、仮想ネットワークの作成、仮想マシンの作成と3つにわかれていますが、いずれもdefineメソッドからcreateメソッドまでメソッド呼び出しを連鎖させているのがわかると思います。このようなメソッドを連鎖させて呼び出すAPIを一般的にFluent APIと呼びますが、初見でもなんとなく処理の流れが理解できるのではないかと思います。細かい点を見ていきますと、(1)のリソースグループの作成では、defineメソッドでmynavijavaというリソースグループ名を定義したのち、後続のwithRegionメソッドでリソースグループのリージョンを東日本に設定し、最後のcreateメソッドでリソースグループの作成を行います。(2)の仮想ネットワークの作成も同様で、defineメソッドで名前を定義し、リージョンを設定、アドレス空間等を設定し、最後のcreateメソッドで仮想ネットワークを作成します。

(3)の仮想マシンの作成も同様です。一点注意してほしいのは、withNewPrimaryPublicIPAddressメソッドに指定する名前は、DNS名の一部に使われるため、Azureリージョン内で一意な必要があるのと、要件にあったパスワードを設定しないと例外が発生します。

最後にSSHで仮想マシンにログインできれば、正しく仮想マシン作成できています。

  • SSHでの仮想マシンへの接続

    SSHでの仮想マシンへの接続

情報取得、停止、開始などの操作を行う

仮想マシンが作成できたところで、仮想マシンの情報を取得したり、停止や開始などの操作を行ってみたいと思います。 前述したとおりazure.virtualMachinesメソッドが仮想マシンを管理するエントリポイントとなります。例えば、リソースグループ名と仮想マシン名を指定してgetByResourceGroupメソッドを呼び出すと、目的の仮想マシンのインスタンスを取得できます。まずは、このインスタンスから代表的な情報を表示してみましょう(リスト6)。

仮想マシンの情報取得(App2.java)

package jp.mynavi.azure;

import com.microsoft.azure.credentials.ApplicationTokenCredentials;
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.compute.VirtualMachine;

public class App2{

    private static String subscriptionId = "サブスクリプションID";
    private static String tenantId = "テナントID";
    private static String clientId = "クライアントID";
    private static String clientSecret = "クライアントシークレット";

   public static void main(String[] args) throws Exception {

        ApplicationTokenCredentials creds = new ApplicationTokenCredentials(clientId, tenantId, clientSecret, null);

        Azure azure = Azure.configure()
                .authenticate(creds)
                .withSubscription(subscriptionId);

        // (1) リソースグループとVM名からVirtualMachineオブジェクトを取得
        VirtualMachine vm = azure.virtualMachines().getByResourceGroup("mynavijava", "mynavijava-vm");

        // (2) 各種情報の取得
        System.out.println("コンピュータ名 :" + vm.osProfile().computerName());
        System.out.println("管理者名       :" + vm.osProfile().adminUsername());
        System.out.println("VMサイズ       :" + vm.size());
        System.out.println("DISKサイズ     :" + vm.osDiskSize());
        System.out.println("ステータス0    :" + vm.instanceView().statuses().get(0).code() + " " + vm.instanceView().statuses().get(0).displayStatus());
        System.out.println("ステータス0    :" + vm.instanceView().statuses().get(1).code() + " " + vm.instanceView().statuses().get(1).displayStatus());
        System.out.println("OS Publisher   :" + vm.storageProfile().imageReference().publisher());
        System.out.println("OS Offer       :" + vm.storageProfile().imageReference().offer());
        System.out.println("OS Sku         :" + vm.storageProfile().imageReference().sku());
        System.out.println("OS Version     :" + vm.storageProfile().imageReference().version());

    }
}

以下のような結果が得られると思います。プロパティの意味については後ほど紹介するAPIリファレンスで確認できます。

コンピュータ名 :mynavijava-vm
管理者名       :azureuser
VMサイズ       :Basic_A1
DISKサイズ     :30
ステータス0    :ProvisioningState/succeeded Provisioning succeeded
ステータス1    :PowerState/running VM running
OS Publisher   :Canonical
OS Offer       :UbuntuServer
OS Sku         :16.04.0-LTS
OS Version     :latest

次にdeallocateメソッドを呼び出してみましょう。これで仮想マシンを停止(課金されない状態)することができます(リスト8)。ポータルで仮想マシンの状態を確認し、停止済み(割り当て解除)と表示されていることが確認できます。

仮想マシンの停止

        VirtualMachine vm = azure.virtualMachines().getByResourceGroup("mynavijava", "mynavijava-vm");
        vm.deallocate();

開始するには、Startメソッドを呼びます(リスト9)

仮想マシンの開始

        VirtualMachine vm = azure.virtualMachines().getByResourceGroup("mynavijava", "mynavijava-vm");
        vm.start();

このほかにも、おおよそポータルから取得できる項目や操作はAPIを通して実行可能です。

さらに詳しい情報が欲しい場合は、「APIリファレンス」を参考にしてください。

まとめ

簡単なプログラム例でしたが、AzureをJavaから操作する方法が理解いただけたかと思います。これらを活用し専用のAzureツールを作成することで、開発や運用効率を高めていくことができると思います。

WINGSプロジェクト 森島政人 著/山田祥寛監修
<WINGSプロジェクトについて>テクニカル執筆プロジェクト(代表山田祥寛)。海外記事の翻訳から、主にWeb開発分野の書籍・雑誌/Web記事の執筆、講演等を幅広く手がける。一緒に執筆をできる有志を募集中