LoginSignup
16
9

More than 3 years have passed since last update.

Azure Batchを使ってコンテナでバッチを動かそう

Last updated at Posted at 2019-08-22

はじめに

コンテナにロジックを閉じ込め任意のインスタンスで動かすことができるAWS Batchが便利で使っていたのですが、今の案件はAzureでしたのでAzure Batchを使ってみました。これもコンセプトはAWSと同じです。
Azureは相変わらずドキュメントやQiitaなどにもあまり記事がないので少しでもお役に立てれば幸いです。

ちなみに今回JavaSDKで実装していますが、画面上からバッチの定義を行ったり他の言語のSDKを使った場合も同じ設定値に設定することで動かすことができますので参考になるかと思います。

Azure Batch

AzureBatchでは任意のプログラム(Shellも)を、指定された大きさのインスタンスで動かすことが可能なサービスです。
AWS Batchのようにコンテナ内のプログラムを動かすことが可能です。ちなみにAWS(※)ではCloudWatchEventsを使ってスケジュールさせていましたが、AzureBatchではスケジュール機能が組み込まれています。

※ AWSの場合は、CloudWatchEvents -> Lambda -> AWS Batchって感じで動かす必要があります

前準備

コンテナで動かすプログラムはこんな感じです。
ちゃんと指定されたインスタンスで動いているかどうか確認するためにOSなどの情報を出してみましょう。

ちなみにJavaでOSの情報をだすにはhttps://github.com/oshi/oshiが便利ですよ。

public class BatchMain {

    public static void main(String[] args) {

        System.out.println("execute main method.");

        System.out.println("Environment Variables");
        System.getenv().forEach((k,v) -> System.out.println(k + ":" + v));

        var si = new SystemInfo();
        System.out.println("OS: " + si.getOperatingSystem());

        var hardware = si.getHardware();
        System.out.println("Processor: " + hardware.getProcessor());

        var memory = hardware.getMemory();
        System.out.println("Memory: " + memory.getAvailable() + " / " + memory.getTotal());

        System.exit(0);
    }
}

さてこれをAzure Container Registryにpushしていきます。いつも通りjibを使ってpushします。
gradle.propertiesにUSERNAMEとPASSWORDを忘れずに書いておいてください。

jib {
    to {
        image = 'xxxxx.azurecr.io/batch:0.0.1-SNAPSHOT'
        auth {
            username = "${USERNAME}"
            password = "${PASSWORD}"
        }
    }
}
gradlew jib

Azure Batchのアカウントを作る

「batch accounts」を選択します。

image.png

batch アカウントを作りましょう。

image.png

batch account, url, primary access keyをコピーしておきます。これはプログラムで指定するときに利用します。

image.png

プールを作る

Azure Batchでは実行環境の定義をPoolで行います。プールの設定はジョブごとに作る必要はなく環境が変わらないのであれば一つ大丈夫です。AWSでいうとComputing Environmentかな。

サポートされる仮想マシンイメージ(Linux)はこちらに記載がありますがcentos or ubuntuのみになります。
自分で用意することももちろん可能です。

指定する値はAzureの管理コンソールから探したほうが簡単でしょう

image.png


public class Pool {

    public static final String POOL_ID = "pool_1";

    public static void main(String[] args) throws IOException {
        BatchClient client = BatchClient.open(new BatchSharedKeyCredentials(
                "https://xxxxx.japaneast.batch.azure.com",
                "xxxx",
                "xxxxxx"));

        ContainerRegistry containerRegistry = new ContainerRegistry()
                .withRegistryServer("xxxxxx.azurecr.io")
                .withUserName("xxxxxx")
                .withPassword("xxxxxxxxx");

        ContainerConfiguration containerConfiguration = new ContainerConfiguration();
        containerConfiguration.withContainerRegistries(Arrays.asList(containerRegistry));
        containerConfiguration.withContainerImageNames(Arrays.asList("xxxx.azurecr.io/batch:0.0.1-SNAPSHOT"));

        ImageReference imageReference = new ImageReference();
        imageReference.withPublisher("microsoft-azure-batch");
        imageReference.withOffer("ubuntu-server-container");
        imageReference.withSku("16-04-lts");
        imageReference.withVersion("latest");

        // VM Configuration
        VirtualMachineConfiguration virtualMachineConfiguration = new VirtualMachineConfiguration();
        virtualMachineConfiguration.withImageReference(imageReference);
        virtualMachineConfiguration.withContainerConfiguration(containerConfiguration);
        virtualMachineConfiguration.withNodeAgentSKUId("batch.node.ubuntu 16.04");

        // Create Pool
        client.poolOperations().createPool(POOL_ID, "standard_d1_v2", virtualMachineConfiguration, 1);
    }

}

シンプルに動かす

Poolで定義した情報をもとにJOB、Taskを動かしてみます。
まずはJOBを作ります。


public class SimpleJob {

    public static final String POOL_ID = "pool_1";

    public static final String JOB_ID = "job_1";

    public static void main(String[] args) throws IOException {
        BatchClient client = BatchClient.open(new BatchSharedKeyCredentials(
                "https://xxxxx.japaneast.batch.azure.com",
                "xxxx",
                "xxxxxx"));

        PoolInformation poolInformation = new PoolInformation();
        poolInformation.withPoolId(POOL_ID);

        // CreateJob
        client.jobOperations().createJob(JOB_ID, poolInformation);
    }
}

JOB内でタスクを動かします。

public class SimpleTask {

    public static void main(String[] args) throws IOException, InterruptedException {

        BatchClient client = BatchClient.open(new BatchSharedKeyCredentials(
                "https://xxxxx.japaneast.batch.azure.com",
                "xxxx",
                "xxxxxx"));

        TaskAddParameter parameter = new TaskAddParameter();
        parameter.withId("task1")
                .withUserIdentity(new UserIdentity().withAutoUser(new AutoUserSpecification().withElevationLevel(ElevationLevel.ADMIN).withScope(AutoUserScope.TASK)))
                .withContainerSettings(new TaskContainerSettings().withImageName("xxxx.azurecr.io/batch:0.0.1-SNAPSHOT")
                        .withContainerRunOptions("--rm"))
                .withConstraints(new TaskConstraints().withMaxTaskRetryCount(-1)).withCommandLine("");
        client.taskOperations().createTask(ScheduleJob.JOB_ID, parameter);

        long timeout = 300 * 1000;
        long startTime = System.currentTimeMillis();

        while (System.currentTimeMillis() - startTime <= timeout) {
            CloudTask task = client.taskOperations().getTask(ScheduleJob.JOB_ID, parameter.id());

            if (task.state() != TaskState.COMPLETED) {
                Thread.sleep(1000);
            }
        }
    }
}

これを実行するとAzureの管理画面上で確認できます。

image.png

動いたJOBをクリックすると、Taskの画面が表示され出力された内容は画面上から見ることができます。

指定された時間にJOBを実行する

JOBの時間をwithDoNotRunUntilで指定します。JOBが実行されると動くタスクも合わせて定義します。


public class ScheduleJob {

    public static final String POOL_ID = "pool_1";

    public static final String JOB_ID = "job_5";

    public static void main(String[] args) throws IOException {
        BatchClient client = BatchClient.open(new BatchSharedKeyCredentials(
                "https://xxxxx.japaneast.batch.azure.com",
                "xxxx",
                "xxxxxx"));

        // Create Schedule SimpleJob
        DateTime scheduleDateTime = new DateTime(2019,8,22,4,30, DateTimeZone.UTC);
        Schedule schedule = new Schedule().withDoNotRunUntil(scheduleDateTime);

        // pool
        PoolInformation poolInformation = new PoolInformation();
        poolInformation.withPoolId(POOL_ID);

        // container
        JobManagerTask task = new JobManagerTask();
        task.withId("scheduletask")
                .withUserIdentity(new UserIdentity().withAutoUser(new AutoUserSpecification().withElevationLevel(ElevationLevel.ADMIN).withScope(AutoUserScope.TASK)))
                .withContainerSettings(new TaskContainerSettings().withImageName("xxxxx.azurecr.io/batch:0.0.1-SNAPSHOT")
                        .withContainerRunOptions("--rm"))
                .withCommandLine("");

        JobSpecification jobSpecification = new JobSpecification().withPoolInfo(poolInformation).withJobManagerTask(task);

        client.jobScheduleOperations().createJobSchedule(JOB_ID,schedule, jobSpecification);
    }
}

指定された時間から繰り返し動かす(Cron)

初回に動く時刻をDoNotRunUntilで指定し、RecurrenceIntervalで繰り返し動かす時間を指定します。
DoNotRunUntilを指定しない場合は、JOBを定義された時間から繰り返し動かすことになります。

public class CronScheduleJob {

    public static final String POOL_ID = "pool_1";

    public static final String JOB_ID = "job_7";

    public static void main(String[] args) throws IOException {
        BatchClient client = BatchClient.open(new BatchSharedKeyCredentials(
                "https://xxxxx.japaneast.batch.azure.com",
                "xxxx",
                "xxxxxx"));

        // Create Schedule SimpleJob
        DateTime startDateTime = new DateTime(2019,8,22,4,45, DateTimeZone.UTC);
        Period period = new Period(0,1,0,0);
        Schedule schedule = new Schedule().withRecurrenceInterval(period).withDoNotRunUntil(startDateTime);

        // pool
        PoolInformation poolInformation = new PoolInformation();
        poolInformation.withPoolId(POOL_ID);

        // container
        JobManagerTask task = new JobManagerTask();
        task.withId("cronscheduletask")
                .withUserIdentity(new UserIdentity().withAutoUser(new AutoUserSpecification().withElevationLevel(ElevationLevel.ADMIN).withScope(AutoUserScope.TASK)))
                .withContainerSettings(new TaskContainerSettings().withImageName("xxxxx.azurecr.io/batch:0.0.1-SNAPSHOT")
                        .withContainerRunOptions("--rm"))
                .withCommandLine("");

        JobSpecification jobSpecification = new JobSpecification().withPoolInfo(poolInformation).withJobManagerTask(task);

        client.jobScheduleOperations().createJobSchedule(JOB_ID,schedule, jobSpecification);
    }
}

参考

16
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
9