AWSをコマンドラインから扱う方法についていろいろ勉強している。 最終的にはローカルマシンで実行している処理をAWSに流し込めるようになりたいが、そのためにはまずはPythonインタフェースであるboto3から、コマンドを流し込んで実行できなければならない。 boto3からAWSのLinuxを操作するための方法について調査した。
最終的に実現したいことは、ローカルマシンのLLVMリポジトリをAWSに転送し、ビルドして、その結果を回収してくること。
という訳で、
- AWS上でEC2インスタンスを立ち上げ、Amazon Linux 2をブートする
- EC2インスタンス上で必要なツールをインストールし、LLVMをビルドする環境を整える。
- LLVMのリポジトリとビルドディレクトリをS3からダウンロードする。
- ビルドを実行する
- 結果をS3に書き戻す
という手順をローカルマシンからboto3を経由して実行したい。 このフローを作成した。
これには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
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)
これはAWSのs3 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)
- ビルドを実行する
これもmakeコマンドを流すだけである。
command_list = ['cd /home/ec2-user/build-myriscvx && make -j16']
execute_command_list(instance.instance_id, command_list)
- 結果を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しないという機能を実装すればよいと思う。
このあたりの機能を改良していく。
ソースコードは以下。