AWSのEC2上でblenderを動作させてNice DCVを使ってリモート接続する方法
はじめに
blenderなどの3Dアプリケーションを利用する場合、そこそこのマシンスペックが必要になります。
私は、Mac Book(ノートPC)を愛用しているのですが、少々厳しい(デュアルコアだし、GPUも無い)です。
そこで、AWS上のEC2でblenderを動作させ、Nice DCVで接続することにします。
blenderの公式サイトを参考にすると、2022年10月現在のオススメスペックは以下の通りです。
- 64-bit eight core CPU
- 32 GB RAM
- 2560×1440 display
- Three button mouse or pen+tablet
- Graphics card with 8 GB RAM
上記を満たすには、g4dn.2xlarge (8コア、32GbyteのRAM) 程度がちょうど良さそうですね。
設定手順
今回は、手元のmacから接続します。EC2インスタンスは、LinuxとWindowsが選択できますが、Linux側を選択します。
(ここは、慣れている方で良いと思います。)
ざっくりとは、以下の手順です。
- blenderとNice DCV設定済みのAMIからEC2インスタンスを起動
- ユーザ作成 (Nice DCVで接続した時のログイン用兼作業用)
- Nice DCVの設定ファイルの書き換え
- クライアントのインストール(既にインストール済みでなければ)
EC2インスタンスの起動
- AMIは、「Nimble Studio Linux Workstation AMI」を選択します。
- EC2インスタンスでは、Nice DCVで利用する8443ポートを空けておきます。
- EC2のIAMRoleを設定します。
- 以下の通り、Nice DCVのライセンスを取得できる様に設定します。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::dcv-license.ap-northeast-1/*" } ] }
ユーザの作成
起動したEC2インスタンスにログインします(以下、SSHでログインしている前提)。
centosなので、amazon linuxのデフォルトユーザec2-userではなく、centosユーザでのログインとなります。
(1)ユーザを作成します。
sudo adduser [USER_NAME]
(2)パスワードを変更します。
sudo passwd [USER_NAME]
(3)wheelグループへ追加します。
sudo usermod -aG wheel [USER_NAME]
Nice DCVの設定
nice DCVの設定で、作成したユーザでのログインを許可します。
まずは、permissionファイルの作成します。
作成するpermissionファイル( /etc/dcv/permissions.conf としました)の内容は、以下の通りです。
[permissions] [USER_NAME] allow builtin %owner% allow builtin
※[USER_NAME]は、上で作成したユーザ名に置き換えてください。
次に、そのファイルを、設定ファイル (/etc/dcv/dcv.conf)で指定します。
[session-management/automatic-console-session] permissions-file='/etc/dcv/permissions.conf'
後は、dcvserverを再起動して、上の設定を読み込みます。
sudo systemctl restart dcvserver
Nice DCVクライアントのインストール
以下から、ご自分の端末に合うアプリをインストールしてください。
docs.aws.amazon.com
後は、Nice DCVクライアントを起動して、接続します。
ちなみに、グローバルIPを調べたい場合は、以下が便利です。
curl ifconfig.io
SSHのProxyCommandを利用してEC2インスタンスを自動で起動する設定
毎回、EC2インスタンスの起動・終了を実施するのは面倒です。
そこで、SSHのProxyCommandとSSMエージェントを利用し、sshコマンドを実行すると、自動でEC2が起動する様にします。
また、cron コマンドを利用して、一定時間操作がない場合は、自動で終了する様に設定します。
EC2インスタンスのIAM Roleの設定
- AWSにて、あらかじめ用意されている「AmazonSSMManagedInstanceCore」を追加します。
- これで、SSMが利用できる様になります。
- 注:SSMのエージェントは、上で選択したAMIでは、既にインストール済みのため、特段することはないですが、もしSSMエージェントがない場合は、追加します。
IAMユーザのプロファイルのポリシー
接続にいくユーザの権限として、以下を付与します。
インスタンスの起動や終了、ssm周りの権限を付与しています。
とりあえず、グローバルIPで絞っています。ころころ変わって面倒な場合は、MFA認証を必須にするなどでも良いと思います。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "ec2:StartInstances", "Resource": [ "arn:aws:ec2:ap-northeast-1:[AWS アカウントのID]:instance/[EC2インスタンスのID]", ], "Condition": { "IpAddress": { "aws:SourceIp": "[接続元のIPアドレス]" #ここは必要に応じて } } }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": "ec2:DescribeInstances", "Resource": "*", "Condition": { "IpAddress": { "aws:SourceIp": "[接続元のIPアドレス]" } } }, { "Sid": "VisualEditor2", "Effect": "Allow", "Action": "ec2:StopInstances", "Resource": [ "arn:aws:ec2:ap-northeast-1:[AWSアカウントのID]:instance/[EC2インスタンスのID]", ] }, { "Sid": "VisualEditor3", "Effect": "Allow", "Action": "ssm:StartSession", "Resource": [ "arn:aws:ec2:ap-northeast-1:[AWSアカウントのID]:instance/[EC2インスタンスのID]", "arn:aws:ssm:ap-northeast-1::document/AWS-StartSSHSession" ] }, { "Effect": "Allow", "Action": [ "ssm:TerminateSession", "ssm:ResumeSession" ], "Resource": [ "arn:aws:ssm:*:*:session/${aws:username}-*" ] } ] }
SSH ProxyCommandの設定
インスタンス起動のスクリプトの準備
まずは、インスタンスを起動するためのスクリプトを用意します。
ここでは、IAMユーザのプロファイルを「blender」としています。ここは、前の章のポリシーが付いていれば何でも良いです。
渡されたIDのインスタンスが「stopped」状態であれば、起動する様にしています。
(10秒待っているのは、wait_until_running関数だけだと、初回の接続に失敗することがあったためです。)
import time import boto3 import argparse class Agent(): def __init__(self,host): self._TARGET_INSTANCE_ID = host self._PROFILE_NAME = "blender" self._REGION_NAME = "ap-northeast-1" self._session = boto3.Session(profile_name=self._PROFILE_NAME) self._ec2 = self._session.resource("ec2",region_name=self._REGION_NAME) def start_instance(self): target_instance = self._ec2.Instance(self._TARGET_INSTANCE_ID) status = target_instance.state["Name"] if status == "running": return True elif status == "stopped": target_instance.start() target_instance.wait_until_running() time.sleep(10) target_instance.reload() return target_instance.state["Name"] == "running" else: return False def stop_instance(self): target_instance = self._ec2.Instance(self._TARGET_INSTANCE_ID) target_instance.stop() target_instance.wait_until_stopped() target_instance.reload() return target_instance.state["Name"] == "stopped" def setup_arg_parser(): parser = argparse.ArgumentParser(description="start ec2") parser.add_argument("--host",help="EC2 instance ID",required=True) return parser def main(): parser = setup_arg_parser() args = parser.parse_args() agent = Agent(host=args.host) if agent.start_instance(): print("EC2 instance is running") else: agent.stop_instance() print("Failed to start the instance") if __name__ == "__main__": main()
上のpythonスクリプトは、setup_blender.pyとして保存しました。
次に、bashコマンドで、ラップしておきます。
pythonの環境をvirtualenvで設定しているので、環境を呼び出してから、pythonファイルを実行しているだけです。
#!/bin/bash HOST=$1 source [virtualenvを設定したパス]/bin/activate python [pythonファイルを置いたパス]/setup_blender.py --host $HOST
.ssh/configの設定
HOST blender_ec2 HostName [EC2インスタンスのID] User centos Port 22 IdentityFile ~/.ssh/[SSHのキー※インスタンス作成時に設定したもの] ProxyCommand sh -c "[パス]/setup.sh %h; aws ssm start-session --profile blender --region ap-northeast-1 --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
※blenderと言うIAMユーザのプロファイルを作っています。
上記を全て設定すると、以下を実行するだけで、EC2インスタンスの起動を自動で実施してくれます。
ssh blender_ec2
一定時間操作がない場合、cronによりEC2インスタンスを自動で終了する
以下の、シャットダウンスクリプトを、cronで、5分置きに実行する様にしました。
動きとしては、5分して、ローカルからのsshセッションが1本も無ければ・・・
まずは、フラグを立て(/tmpにファイルを作成し)ます。
再び5分して、フラグが立った状態で、なおsshセッションが1本も無ければインスタンスを落とします。
なので、少なくとも5分は待ってくれて、最長でも10分以内に落としてくれる動きを想定しています。
#/bin/bash SESSION_COUNT=`w -h | grep localhost | wc -l` THERE_IS_NO_SESSION=/tmp/there_is_no_session if [ $SESSION_COUNT -gt 0 ] then rm -rf $THERE_IS_NO_SESSION elif [ -e $THERE_IS_NO_SESSION ] then rm -rf $THERE_IS_NO_SESSION sudo shutdown -h now else touch $THERE_IS_NO_SESSION fi
これを、cronに設定します。
*/5 * * * * /usr/local/bin/shutdown.sh
(/usr/local/bin/にshutdown.shとして置いています。)