LoginSignup
4
3

More than 3 years have passed since last update.

AWS CodeBuildを利用してUnity ML-AgentsのDockerイメージを作成する(v0.9.1対応)

Posted at

Unity ML-AgentsのDockerイメージを作成するのに、AWS CodeBuild(CodeBuild)を利用してみました。
CodeBuildでUnity ML-Agentsのソースを取得してビルド、ビルドができたらAmazon Elastic Container Registry(ECR)のリポジトリにイメージをPushします。

Unity ML-AgentsやCodeBuildについては省略。

同じようなことをGCPのGoogle Cloud Buildでもやっているので、GCPな方はそちらをご参考ください。

Google Cloud Buildを利用してUnity ML-AgentsのDockerイメージを作成する(v0.9.1対応) - Qiita
https://qiita.com/kai_kou/items/5eabbaa2b564527e0b4e

前提

  • AWSアカウントがある
  • ローカルでaws コマンドが利用できる
  • ローカルでDockerが実行できる

手順

AWS CloudFormation(CFn)で環境構築する

CFnを利用して、必要となるリソースを作成します。

  • InputBucket: S3バケット。ソース置き場(使わない)
  • OutputBucket: S3バケット。アーティファクト(使わない)
  • ECRRepository: ECRリポジトリ。DockerイメージをPushします
  • CodeBuildServiceRole: CodeBuildで利用するサービスロール
  • CodeBuildProject: CodeBuildのプロジェクト

InputBucketOutputBucket は利用しないのですが、CodeBuildのプロジェクトを作成・実行する際に必須となるので用意しています。

テンプレート作成するのに下記を参考にさせてもらいました。

AWS CodeBuildを使ってDockerイメージをビルドし、Amazon EC2 Container Registry(ECR)へpushする | DevelopersIO
https://dev.classmethod.jp/tool/docker/20170225-codebuild-docker/

CodeBuild で Docker イメージに Git のコミットIDをタグ付けてバージョン管理する | DevelopersIO
https://dev.classmethod.jp/cloud/aws/docker-image-tag-git-commit-id-by-codebuild/

DockerイメージをCodeBuildでビルドする場合、プロジェクト作成時にPrivilegedMode を指定しないとだめだったのがポイントです。

CodeBuildでDocker in Dockerする(CloudFormation) - Qiita
https://qiita.com/sot528/items/ab0285b9907a29be840a

AWS::CodeBuild::Project Environment - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-environment.html

ECRリポジトリにRepositoryPolicyText を指定していますが、これはPushしたイメージを別のCodeBuildでPullする場合に必要となります。

CodeBuild の Amazon ECR サンプル - AWS CodeBuild
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-ecr.html

template.yaml
---
AWSTemplateFormatVersion: 2010-09-09
Description: Create Unity ML-Agents Docker Image

Parameters:
  ProjectName:
    Description: Project Name for CodeBuild
    Default: ml-agents-build-test
    Type: String
  InputBucketName:
    Description: Input Bucket Name
    Default: codebuild-input
    Type: String
  OutputBucketName:
    Description: Output Bucket Name
    Default: codebuild-output
    Type: String
  ECRRepositoryName:
    Description: ECR Repository Name
    Default: ml-agents
    Type: String

Resources:
  InputBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${InputBucketName}
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True

  OutputBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${OutputBucketName}
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True

  ECRRepository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Sub ${ECRRepositoryName}
      RepositoryPolicyText:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codebuild.amazonaws.com
            Action:
              - ecr:GetDownloadUrlForLayer
              - ecr:BatchGetImage
              - ecr:BatchCheckLayerAvailability

  CodeBuildServiceRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codebuild.amazonaws.com
            Action:
                - sts:AssumeRole
      Policies:
        - PolicyName: !Sub CodeBuildPolicy-${ProjectName}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Resource:
                  - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${ProjectName}
                  - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${ProjectName}:*
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
              - Effect: Allow
                Resource:
                  - !Sub arn:aws:s3:::codepipeline-${AWS::Region}-*
                Action:
                  - s3:PutObject
                  - s3:GetObject
                  - s3:GetObjectVersion
              - Effect: Allow
                Resource:
                  - !Sub arn:aws:s3:::${InputBucketName}/*
                Action:
                  - s3:GetObject
                  - s3:GetObjectVersion
              - Effect: Allow
                Resource:
                  - !Sub arn:aws:s3:::${OutputBucketName}/*
                Action:
                  - s3:PutObject
              - Effect: Allow
                Resource:
                  - "*"
                Action:
                  - ecr:BatchCheckLayerAvailability
                  - ecr:CompleteLayerUpload
                  - ecr:GetAuthorizationToken
                  - ecr:InitiateLayerUpload
                  - ecr:PutImage
                  - ecr:UploadLayerPart

  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Ref ProjectName
      Description: this is a test prj
      ServiceRole: !Ref CodeBuildServiceRole
      Artifacts:
        Location: !Ref OutputBucketName
        Type: S3
        Name: artifacts
        Path: !Sub ${ProjectName}
        NamespaceType: BUILD_ID
      Environment:
        Type: LINUX_CONTAINER
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/standard:2.0
        PrivilegedMode: True
      Source:
        Location: !Join [ "/", [ !Ref InputBucketName, "dummy.zip" ] ]
        Type: S3
      TimeoutInMinutes: 10
      Tags:
        - Key: Name
          Value: !Ref ProjectName

テンプレートが用意できたらAWS CLIでスタック作成します。サービスロールを作成するので--capabilities CAPABILITY_IAM が必要になります。
--stack-name--region はお好みで。--parameters を指定するとバケット名やプロジェクト名も指定できます。

> cd テンプレートがあるディレクトリ
> aws cloudformation create-stack \
  --stack-name kai-ml-agents-build \
  --template-body file://template.yaml \
  --capabilities CAPABILITY_IAM \
  --region ap-northeast-1 \
  --parameters '[
      {
        "ParameterKey": "ProjectName",
        "ParameterValue": "ml-agents-build-test"
      },
      {
        "ParameterKey": "InputBucketName",
        "ParameterValue": "kai-ml-agents-build-input"
      },
      {
        "ParameterKey": "OutputBucketName",
        "ParameterValue": "kai-ml-agents-build-output"
      },
      {
        "ParameterKey": "ECRRepositoryName",
        "ParameterValue": "ml-agents"
      }
  ]'

{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/kai-ml-agents-build/0fa901a0-f56f-11e9-b734-06fcc76a2472"
}

スタック実行が完了したか確認します。"CREATE_COMPLETE" になったらOK。

> aws cloudformation describe-stacks \
  --region ap-northeast-1 \
  --stack-name kai-ml-agents-build \
  --query "Stacks[0].StackStatus"

"CREATE_COMPLETE"

CodeBuildのビルド実行準備

作成したCodeBuildのプロジェクトでビルド実行するための前準備をします。

S3バケットにダミーファイルをアップロードする

Unity ML-Agentsのソースはビルド実行時に取得するので、ビルドに必要となるソースがありません。
それでも、CodeBuildでビルド実行するにはCFnでプロジェクト作成時に指定したSource.Location のファイルがないとビルド実行時にダウンロードエラーとなるのでダミーのファイルを用意します。ファイルはZipファイルじゃないとだめでした。

> touch dummy.txt
> zip dummy.zip dummy.txt
  adding: dummy.txt (stored 0%)

> aws s3 cp dummy.zip s3://kai-ml-agents-build-input/
upload: ./dummy.zip to s3://kai-ml-agents-build-input/dummy.zip

buildspec.yamlを用意する

CodeBuildのプロジェクトでビルド実行する際の手順を記述したbuildspec.yaml を用意します。

buildspec.yaml
version: 0.2

phases:
  install:
    runtime-versions:
      docker: 18
  pre_build:
    commands:
      - echo Clone ML-Agents...
      - git clone https://github.com/Unity-Technologies/ml-agents.git -b $IMAGE_TAG --depth 1
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)
      - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay&
      - timeout 15 sh -c "until docker info; do echo .; sleep 1; done"
      - AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
  build:
    commands:
      - docker build -t $ECR_REPOSITORY_NAME:$IMAGE_TAG ./ml-agents
      - docker tag $ECR_REPOSITORY_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$ECR_REPOSITORY_NAME:$IMAGE_TAG
  post_build:
    commands:
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$ECR_REPOSITORY_NAME:$IMAGE_TAG

ポイントは以下となります。

DockerイメージをビルドするのにDockerデーモンを初期化する

DockerイメージをCodeBuildでビルドするのに、プロジェクト作成時にPrivilegedMode を指定しましたが、ビルド時にもDockerデーモンを初期化する必要がありました。

AWS::CodeBuild::Project Environment - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-environment.html

ビルドが Docker デーモンと連係動作できるように、Docker デーモンも起動する必要があります。これを行う 1 つの方法は、以下のビルドコマンドを実行してビルド仕様のインストールフェーズで Docker デーモンを初期化することです。(指定したビルド環境イメージの提供元が Docker 対応の AWS CodeBuild である場合は、これらのコマンドを実行しないでください。)

buildspec.yaml抜粋
  pre_build:
    commands:
      (略)
      - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay&
      - timeout 15 sh -c "until docker info; do echo .; sleep 1; done"
      (略)

ビルド実行する

buildspec.yaml が用意できたらCodeBuildのプロジェクトでビルド実行します。
だいたい10分くらいでビルド完了します。CFnでプロジェクト作成時にタイムアウト時間を10分にしましたが、念の為--timeout-in-minutes-override オプションで20分に変更しています。

> aws codebuild start-build \
  --region ap-northeast-1 \
  --project-name ml-agents-build-test \
  --buildspec-override file://buildspec.yaml \
  --timeout-in-minutes-override 20 \
  --environment-variables-override '[
    {
      "name": "ECR_REPOSITORY_NAME",
      "value": "ml-agents",
      "type": "PLAINTEXT"
    },
    {
      "name": "IMAGE_TAG",
      "value": "0.9.1",
      "type": "PLAINTEXT"
    }
  ]'

{
    "build": {
        "id": "ml-agents-build-test:17bfb5c6-8c8e-480c-a445-9e5dbb4b6004",
        "arn": "arn:aws:codebuild:ap-northeast-1:xxxxxxxxxxxx:build/ml-agents-build-test:17bfb5c6-8c8e-480c-a445-9e5dbb4b6004",
        "startTime": 1571821284.995,
        "currentPhase": "QUEUED",
        "buildStatus": "IN_PROGRESS",
(略)

aws codebuild batch-get-builds コマンドでビルドが完了したか確認します。各フェーズのステータスがSUCCEEDED で最後に"phaseType": "COMPLETED" があったらビルド完了です。

> aws codebuild batch-get-builds \
  --region ap-northeast-1 \
  --ids ml-agents-build-test:17bfb5c6-8c8e-480c-a445-9e5dbb4b6004 \
  --query "builds[0].phases"

[
    {
        "phaseStatus": "SUCCEEDED",
        "endTime": 1571821285.18,
        "phaseType": "SUBMITTED",
        "durationInSeconds": 0,
        "startTime": 1571821284.995
    },
    {
        "phaseStatus": "SUCCEEDED",
        "endTime": 1571821286.424,
        "phaseType": "QUEUED",
        "durationInSeconds": 1,
        "startTime": 1571821285.18
    },
    {
        "contexts": [
            {
                "message": "",
                "statusCode": ""
            }
        ],
        "phaseType": "PROVISIONING",
        "phaseStatus": "SUCCEEDED",
        "durationInSeconds": 21,
        "startTime": 1571821286.424,
        "endTime": 1571821307.801
    },
    {
        "contexts": [
            {
                "message": "",
                "statusCode": ""
            }
        ],
        "phaseType": "DOWNLOAD_SOURCE",
        "phaseStatus": "SUCCEEDED",
        "durationInSeconds": 0,
        "startTime": 1571821307.801,
        "endTime": 1571821308.509
    },
    {
        "contexts": [
            {
                "message": "",
                "statusCode": ""
            }
        ],
        "phaseType": "INSTALL",
        "phaseStatus": "SUCCEEDED",
        "durationInSeconds": 0,
        "startTime": 1571821308.509,
        "endTime": 1571821308.667
    },
    {
        "contexts": [
            {
                "message": "",
                "statusCode": ""
            }
        ],
        "phaseType": "PRE_BUILD",
        "phaseStatus": "SUCCEEDED",
        "durationInSeconds": 17,
        "startTime": 1571821308.667,
        "endTime": 1571821326.049
    },
    {
        "contexts": [
            {
                "message": "",
                "statusCode": ""
            }
        ],
        "phaseType": "BUILD",
        "phaseStatus": "SUCCEEDED",
        "durationInSeconds": 744,
        "startTime": 1571821326.049,
        "endTime": 1571822070.764
    },
    {
        "contexts": [
            {
                "message": "",
                "statusCode": ""
            }
        ],
        "phaseType": "POST_BUILD",
        "phaseStatus": "SUCCEEDED",
        "durationInSeconds": 38,
        "startTime": 1571822070.764,
        "endTime": 1571822109.51
    },
    {
        "contexts": [
            {
                "message": "",
                "statusCode": ""
            }
        ],
        "phaseType": "UPLOAD_ARTIFACTS",
        "phaseStatus": "SUCCEEDED",
        "durationInSeconds": 0,
        "startTime": 1571822109.51,
        "endTime": 1571822109.701
    },
    {
        "contexts": [
            {
                "message": "",
                "statusCode": ""
            }
        ],
        "phaseType": "FINALIZING",
        "phaseStatus": "SUCCEEDED",
        "durationInSeconds": 2,
        "startTime": 1571822109.701,
        "endTime": 1571822111.876
    },
    {
        "phaseType": "COMPLETED",
        "startTime": 1571822111.876
    }
]

AWS ECRのリポジトリからイメージを取得する

AWS ECRのリポジトリにイメージが登録されたか確認して、実際にイメージを取得・利用してみます。
<AWS_ACCOUNT_ID><REGION> は置き換えてください。

> aws ecr list-images \
  --repository-name ml-agents \
  --region <REGION>

{
    "imageIds": [
        {
            "imageTag": "0.9.1",
            "imageDigest": "sha256:b9da2732606536ada8d3eabe258ac44286ae8c0706c9325d008880a2f2855f1c"
        }
    ]
}


# デフォルトレジストリに対してDockerを認証する
> $(aws ecr get-login --no-include-email --region <REGION>)

WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded


> docker pull <AWS_ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/ml-agents:0.9.1

(略)
1b38598abf23: Pull complete
Digest: sha256:b9da2732606536ada8d3eabe258ac44286ae8c0706c9325d008880a2f2855f1c
Status: Downloaded newer image for <AWS_ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/ml-agents:0.9.1
<AWS_ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/ml-agents:0.9.1


> docker run -it --rm \
  <AWS_ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/ml-agents:0.9.1



                        ▄▄▄▓▓▓▓
                   ╓▓▓▓▓▓▓█▓▓▓▓▓
              ,▄▄▄m▀▀▀'  ,▓▓▓▀▓▓▄                           ▓▓▓  ▓▓▌
            ▄▓▓▓▀'      ▄▓▓▀  ▓▓▓      ▄▄     ▄▄ ,▄▄ ▄▄▄▄   ,▄▄ ▄▓▓▌▄ ▄▄▄    ,▄▄
          ▄▓▓▓▀        ▄▓▓▀   ▐▓▓▌     ▓▓▌   ▐▓▓ ▐▓▓▓▀▀▀▓▓▌ ▓▓▓ ▀▓▓▌▀ ^▓▓▌  ╒▓▓▌
        ▄▓▓▓▓▓▄▄▄▄▄▄▄▄▓▓▓      ▓▀      ▓▓▌   ▐▓▓ ▐▓▓    ▓▓▓ ▓▓▓  ▓▓▌   ▐▓▓▄ ▓▓▌
        ▀▓▓▓▓▀▀▀▀▀▀▀▀▀▀▓▓▄     ▓▓      ▓▓▌   ▐▓▓ ▐▓▓    ▓▓▓ ▓▓▓  ▓▓▌    ▐▓▓▐▓▓
          ^█▓▓▓        ▀▓▓▄   ▐▓▓▌     ▓▓▓▓▄▓▓▓▓ ▐▓▓    ▓▓▓ ▓▓▓  ▓▓▓▄    ▓▓▓▓`
            '▀▓▓▓▄      ^▓▓▓  ▓▓▓       └▀▀▀▀ ▀▀ ^▀▀    `▀▀ `▀▀   '▀▀    ▐▓▓▌
               ▀▀▀▀▓▄▄▄   ▓▓▓▓▓▓,                                      ▓▓▓▓▀
                   `▀█▓▓▓▓▓▓▓▓▓▌
                        ¬`▀▀▀█▓


Usage:
      mlagents-learn <trainer-config-path> [options]
      mlagents-learn --help

Dockerコンテナでmlagents-learn コマンドが実行されたのが確認できました。やったぜ

実際にML-Agentsを動作させる手順は下記をご参考ください。

DockerでUnity ML-Agentsを動作させる(v0.9.1対応) - Qiita
https://qiita.com/kai_kou/items/0c2f3c7d22363fd91e4e

参考

DockerイメージをCodeBuildでビルドするのに、プロジェクト作成時にPrivilegedMode を指定しましたが、ビルド時にもDockerデーモンを初期化する必要がありました。

Google Cloud Buildを利用してUnity ML-AgentsのDockerイメージを作成する(v0.9.1対応) - Qiita
https://qiita.com/kai_kou/items/5eabbaa2b564527e0b4e

AWS CodeBuildを使ってDockerイメージをビルドし、Amazon EC2 Container Registry(ECR)へpushする | DevelopersIO
https://dev.classmethod.jp/tool/docker/20170225-codebuild-docker/

CodeBuild で Docker イメージに Git のコミットIDをタグ付けてバージョン管理する | DevelopersIO
https://dev.classmethod.jp/cloud/aws/docker-image-tag-git-commit-id-by-codebuild/

CodeBuildでDocker in Dockerする(CloudFormation) - Qiita
https://qiita.com/sot528/items/ab0285b9907a29be840a

AWS::CodeBuild::Project Environment - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-environment.html

AWS::CodeBuild::Project Environment - AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-environment.html

Amazon ECR で AWS CLI を使用する - Amazon ECR
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/ECR_AWSCLI.html

CodeBuild のビルドの詳細を表示する - AWS CodeBuild https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/view-build-details.html#view-build-details-cli

ビルド環境の環境変数 - AWS CodeBuild
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-env-vars.html

CodeBuildでビルドプロジェクトを作成する-AWS CodeBuild
https://docs.aws.amazon.com/codebuild/latest/userguide/create-project.html#create-project-cli

CodeBuild のビルドの詳細を表示する - AWS CodeBuild
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/view-build-details.html

CodeBuild のビルド仕様に関するリファレンス - AWS CodeBuild
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html#runtime-versions-buildspec-file

CodeBuild でビルドを実行する - AWS CodeBuild
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/run-build.html#run-build-cli

CodeBuild の Docker サンプル - AWS CodeBuild
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-docker.html

Amazon ECR レジストリ - Amazon ECR
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/Registries.html#registry_auth

CodeBuild の Amazon ECR サンプル - AWS CodeBuild
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-ecr.html

4
3
0

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
4
3