FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

AWSのPythonインタフェースboto3を使用してEC2インスタンスにジョブを流し込む

f:id:msyksphinz:20190818215623p:plain

AWSコマンドラインから扱う方法についていろいろ勉強している。 最終的にはローカルマシンで実行している処理をAWSに流し込めるようになりたいが、そのためにはまずはPythonインタフェースであるboto3から、コマンドを流し込んで実行できなければならない。 boto3からAWSLinuxを操作するための方法について調査した。

最終的に実現したいことは、ローカルマシンのLLVMリポジトリAWSに転送し、ビルドして、その結果を回収してくること。

という訳で、

  1. AWS上でEC2インスタンスを立ち上げ、Amazon Linux 2をブートする
  2. EC2インスタンス上で必要なツールをインストールし、LLVMをビルドする環境を整える。
  3. LLVMリポジトリとビルドディレクトリをS3からダウンロードする。
  4. ビルドを実行する
  5. 結果をS3に書き戻す

という手順をローカルマシンからboto3を経由して実行したい。 このフローを作成した。

  1. AWS EC2インスタンスの立ち上げ

これにはboto3の`create_instanceを用いる。今回はSpotインスタンスを使用して料金を安く抑える作戦に出た。

blockDeviceMappings = [{
    "DeviceName": "/dev/xvda",
    "Ebs": {
        "SnapshotId": "snap-08a7cb489033af8c7",
        "DeleteOnTermination": True,
        "VolumeType": "gp2",
        'VolumeSize': 100
        }
    }]

def create_instance(instance_type):
    print("Launching EC2 ...")
    ec2_resource = boto3.resource('ec2')
    # tag_specification = [{'ResourceType': 'spot-instances-request'}, ]
    instance_market_options={
    'MarketType': 'spot',
    'SpotOptions': {
        'MaxPrice': '0.27',
        'SpotInstanceType': 'one-time',
    }
    }

    instances = ec2_resource.create_instances(ImageId='ami-0c3fd0f5d33134a76',
                                          MaxCount=1, MinCount=1,
                                          InstanceType=instance_type,
                                          IamInstanceProfile={'Name': 'SSM_Access'},
                                          InstanceMarketOptions=instance_market_options,
                                              BlockDeviceMappings=blockDeviceMappings,
    )
    time.sleep(5.0)


    instance = instances[0]
    return instance
  1. EC2インスタンス上で必要なツールをインストールし、LLVMをビルドする環境を整える。

Amazon Linux 2はcmakeのバージョンが古いため、cmakeだと手動でアップグレードする。これはcmakeを最新に置き換えたAMIを用意すれば省略できるだろうが、ここではとりあえずインストールから実行している。

    cmake_install_command_list = ['yum install -y gcc gcc-c++ ncurses-devel',
                                  'wget https://cmake.org/files/v3.10/cmake-3.10.0.tar.gz -O /tmp/cmake-3.10.0.tar.gz &&'
                                  'cd /tmp/ && tar xfz cmake-3.10.0.tar.gz &&'
                                  'cd /tmp/cmake-3.10.0 && ./bootstrap &> log &&'
                                  'make -j16 -C /tmp/cmake-3.10.0/ &&'
                                  'make -j16 install -C /tmp/cmake-3.10.0/ && '
                                  'whereis cmake',
    ]
    execute_command_list(instance.instance_id, cmake_install_command_list)
  1. LLVMリポジトリとビルドディレクトリをS3からダウンロードする。

これはAWSs3 syncコマンドを使った。boto3でs3とEC2インスタンス間でsyncする機能について調査したのだが、良く分からなかったのでそのままawsコマンドを流して実行した。

    command_list = ['yum install update',
                    'yum install -y clang',
                    'aws s3 sync s3://llvm-bucket/build-myriscvx /home/ec2-user/build-myriscvx',
                    'aws s3 sync s3://llvm-bucket/llvm-myriscvx /home/ec2-user/llvm-myriscvx',
                    'aws s3 sync s3://llvm-bucket/myriscvx-tests /home/ec2-user/myriscvx-tests',
    ]
    execute_command_list(instance.instance_id, command_list)
  1. ビルドを実行する

これもmakeコマンドを流すだけである。

    command_list = ['cd /home/ec2-user/build-myriscvx && make -j16']
    execute_command_list(instance.instance_id, command_list)
  1. 結果をS3に書き戻す

ビルド結果をs3 syncコマンドでs3バケットに書き戻した。

    command_list = ['aws s3 sync /home/ec2-user/build-myriscvx s3://llvm-bucket/build-myriscvx']
    execute_command_list(instance.instance_id, command_list)

これをc5.4xlarge上で実行した。実行時間は大体30分程度であった。

問題点としては以下だと思う。

  • AWS EC2インスタンスの立ち上げに時間がかかる。これは短い時間で何度もビルドするような場合は一度立ち上げたEC2をTerminateせずに、再利用するという方法がある。
  • AWS EC2インスタンスとS3の同期に時間がかかる。これも一度立ち上げたEC2を短い間隔で再利用する場合には、Terminateしないという機能を実装すればよいと思う。

このあたりの機能を改良していく。

ソースコードは以下。

gist.github.com