405 lines
13 KiB
YAML
405 lines
13 KiB
YAML
AWSTemplateFormatVersion: '2010-09-09'
|
|
Description: (SO8032) - Extension for Comfy on AWS - EC2 Instance
|
|
Parameters:
|
|
StackName:
|
|
Type: String
|
|
Description: "The Stack Name of the ESD API"
|
|
keyPairName:
|
|
Description: Name of the key pair to use for the EC2 instance
|
|
Type: AWS::EC2::KeyPair::KeyName
|
|
ConstraintDescription: Must be the name of an existing EC2 KeyPair.
|
|
InstanceType:
|
|
Description: EC2 Instance Type of the Comfy to deploy
|
|
Type: String
|
|
AllowedValues:
|
|
- g4dn.xlarge
|
|
- g4dn.2xlarge
|
|
- g4dn.4xlarge
|
|
- g4dn.8xlarge
|
|
- g4dn.12xlarge
|
|
- g5.2xlarge
|
|
- g5.4xlarge
|
|
- g5.8xlarge
|
|
- g5.12xlarge
|
|
Default: g5.2xlarge
|
|
NumberOfInferencePorts:
|
|
Description: The number of inference ports
|
|
Type: Number
|
|
MinValue: 1
|
|
MaxValue: 5
|
|
Default: 1
|
|
|
|
Mappings:
|
|
RegionToAmiId:
|
|
us-east-1:
|
|
AMI: ami-02a07d31009cc8717
|
|
us-east-2:
|
|
AMI: ami-02a912b010cf774bd
|
|
ap-southeast-1:
|
|
AMI: ami-06f0228bde7a6dac2
|
|
ap-northeast-1:
|
|
AMI: ami-0f9b45ca95cee6386
|
|
ap-northeast-2:
|
|
AMI: ami-0aba6dcbc1be4e85e
|
|
us-west-1:
|
|
AMI: ami-0ea5aefd1471f67b2
|
|
us-west-2:
|
|
AMI: ami-09d4fb52761c3d78d
|
|
|
|
|
|
Resources:
|
|
|
|
LambdaExecutionRole:
|
|
Type: AWS::IAM::Role
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Principal:
|
|
Service: lambda.amazonaws.com
|
|
Action: sts:AssumeRole
|
|
Policies:
|
|
- PolicyName: LambdaExecutionPolicy
|
|
PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Action:
|
|
- logs:CreateLogGroup
|
|
- logs:CreateLogStream
|
|
- logs:PutLogEvents
|
|
- cloudformation:DescribeStacks
|
|
Resource: "*"
|
|
- Effect: Allow
|
|
Action:
|
|
- lambda:InvokeFunction
|
|
Resource: "*"
|
|
|
|
LambdaFunction:
|
|
Type: AWS::Lambda::Function
|
|
Properties:
|
|
Handler: index.handler
|
|
Role: !GetAtt LambdaExecutionRole.Arn
|
|
Code:
|
|
ZipFile: |
|
|
# --- BEGIN PYTHON CODE ---
|
|
import boto3
|
|
import cfnresponse
|
|
|
|
client = boto3.client('cloudformation')
|
|
|
|
def handler(event, context):
|
|
try:
|
|
if event['RequestType'] == 'Delete':
|
|
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
|
|
return
|
|
|
|
name = event['ResourceProperties']['StackName']
|
|
response = client.describe_stacks(StackName=name)
|
|
stacks = response.get('Stacks')
|
|
|
|
if len(stacks) == 0:
|
|
raise Exception('StackName Not Found')
|
|
|
|
S3BucketName = ''
|
|
ApiGatewayUrl = ''
|
|
ApiGatewayUrlToken = ''
|
|
|
|
for stack in stacks:
|
|
stack_status = stack.get('StackStatus')
|
|
assert stack_status in ['CREATE_COMPLETE',
|
|
'UPDATE_COMPLETE'], 'stack is not CREATE_COMPLETE or UPDATE_COMPLETE'
|
|
outputs = stack.get('Outputs')
|
|
if outputs:
|
|
for output in outputs:
|
|
key = output.get('OutputKey')
|
|
value = output.get('OutputValue')
|
|
|
|
if key == 'S3BucketName':
|
|
S3BucketName = value
|
|
|
|
if key == 'ApiGatewayUrl':
|
|
ApiGatewayUrl = value
|
|
|
|
if key == 'ApiGatewayUrlToken':
|
|
ApiGatewayUrlToken = value
|
|
|
|
cfnresponse.send(event, context, cfnresponse.SUCCESS, {
|
|
'S3BucketName': S3BucketName,
|
|
'ApiGatewayUrl': ApiGatewayUrl,
|
|
'ApiGatewayUrlToken': ApiGatewayUrlToken,
|
|
})
|
|
except Exception as e:
|
|
cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)}, reason=str(e))
|
|
|
|
# --- END PYTHON CODE ---
|
|
Runtime: python3.8
|
|
Timeout: 30
|
|
|
|
ApiGwResource:
|
|
Type: Custom::MyCustomResource
|
|
Properties:
|
|
ServiceToken: !GetAtt LambdaFunction.Arn
|
|
StackName: !Ref StackName
|
|
|
|
ComfyVPC:
|
|
Type: AWS::EC2::VPC
|
|
DependsOn: ApiGwResource
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
CidrBlock: 10.0.0.0/16
|
|
EnableDnsSupport: true
|
|
EnableDnsHostnames: true
|
|
|
|
ComfySubnet:
|
|
Type: AWS::EC2::Subnet
|
|
DependsOn: ApiGwResource
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
VpcId: !Ref ComfyVPC
|
|
CidrBlock: 10.0.1.0/24
|
|
MapPublicIpOnLaunch: true
|
|
|
|
ComfyInstanceRole:
|
|
Type: AWS::IAM::Role
|
|
DependsOn: ApiGwResource
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Principal:
|
|
Service: [ ec2.amazonaws.com ]
|
|
Action: [ 'sts:AssumeRole' ]
|
|
Path: "/"
|
|
Policies:
|
|
- PolicyName: PutObjectToSpecificBucket
|
|
PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Action: [ 's3:PutObject', 's3:GetObject', 's3:ListBucket', 's3:HeadObject' ]
|
|
Resource: [ '*' ]
|
|
- PolicyName: EcrPolicy
|
|
PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Action: [ 'ecr:*' ]
|
|
Resource: [ '*' ]
|
|
|
|
ComfyInstanceProfile:
|
|
Type: AWS::IAM::InstanceProfile
|
|
DependsOn: ApiGwResource
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
Path: "/"
|
|
Roles:
|
|
- !Ref ComfyInstanceRole
|
|
|
|
ComfySecurityGroup:
|
|
Type: AWS::EC2::SecurityGroup
|
|
DependsOn: ApiGwResource
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
VpcId: !Ref ComfyVPC
|
|
GroupName: !Sub ${AWS::StackName}-sg
|
|
GroupDescription: Security group for SD WebUI EC2 instance
|
|
SecurityGroupIngress:
|
|
- IpProtocol: tcp
|
|
FromPort: 22
|
|
ToPort: 22
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 10000
|
|
ToPort: 11000
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 80
|
|
ToPort: 80
|
|
CidrIp: 0.0.0.0/0
|
|
|
|
ComfyInternetGateway:
|
|
Type: AWS::EC2::InternetGateway
|
|
DependsOn: ApiGwResource
|
|
DeletionPolicy: Delete
|
|
|
|
ComfyVPCGatewayAttachment:
|
|
Type: AWS::EC2::VPCGatewayAttachment
|
|
DependsOn: ApiGwResource
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
VpcId: !Ref ComfyVPC
|
|
InternetGatewayId: !Ref ComfyInternetGateway
|
|
|
|
ComfyRouteTable:
|
|
Type: AWS::EC2::RouteTable
|
|
DependsOn: ApiGwResource
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
VpcId: !Ref ComfyVPC
|
|
|
|
ComfyRoute:
|
|
Type: AWS::EC2::Route
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
RouteTableId: !Ref ComfyRouteTable
|
|
DestinationCidrBlock: 0.0.0.0/0
|
|
GatewayId: !Ref ComfyInternetGateway
|
|
|
|
ComfySubnetRouteTableAssociation:
|
|
Type: AWS::EC2::SubnetRouteTableAssociation
|
|
DependsOn: ApiGwResource
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
SubnetId: !Ref ComfySubnet
|
|
RouteTableId: !Ref ComfyRouteTable
|
|
|
|
ComfyEC2Dev:
|
|
Type: AWS::EC2::Instance
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
InstanceType: !Ref InstanceType
|
|
IamInstanceProfile: !Ref ComfyInstanceProfile
|
|
SubnetId: !Ref ComfySubnet
|
|
ImageId: !FindInMap [ RegionToAmiId, !Ref AWS::Region, AMI ]
|
|
BlockDeviceMappings:
|
|
- DeviceName: /dev/sda1
|
|
Ebs:
|
|
VolumeSize: 1024
|
|
VolumeType: gp2
|
|
KeyName: !Ref keyPairName
|
|
SecurityGroupIds:
|
|
- !GetAtt ComfySecurityGroup.GroupId
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub "comfy-on-aws"
|
|
UserData:
|
|
'Fn::Base64': !Sub |
|
|
#!/bin/bash
|
|
set -euxo pipefail
|
|
|
|
mkdir -p ~/.aws
|
|
echo "[default]
|
|
region = ${AWS::Region}" > ~/.aws/config
|
|
|
|
echo "COMFY_API_URL=${ApiGwResource.ApiGatewayUrl}" >> /etc/environment
|
|
echo "COMFY_API_TOKEN=${ApiGwResource.ApiGatewayUrlToken}" >> /etc/environment
|
|
echo "COMFY_BUCKET_NAME=${ApiGwResource.S3BucketName}" >> /etc/environment
|
|
echo "DISABLE_AUTO_SYNC=false" >> /etc/environment
|
|
echo "DISABLE_AWS_PROXY=false" >> /etc/environment
|
|
echo "AWS_REGION=${AWS::Region}" >> /etc/environment
|
|
echo "PROCESS_NUMBER=${NumberOfInferencePorts}" >> /etc/environment
|
|
echo "ESD_VERSION=dev" >> /etc/environment
|
|
echo "SERVICE_TYPE=comfy" >> /etc/environment
|
|
|
|
source /etc/environment
|
|
|
|
wget https://github.com/peak/s5cmd/releases/download/v2.2.2/s5cmd_2.2.2_Linux-64bit.tar.gz
|
|
tar xzvf s5cmd_2.2.2_Linux-64bit.tar.gz
|
|
cp s5cmd /usr/local/bin/
|
|
rm -rf s5cmd_2.2.2_Linux-64bit.tar.gz
|
|
|
|
s5cmd cp "s3://aws-gcr-solutions-${AWS::Region}/stable-diffusion-aws-extension-github-mainline/$ESD_VERSION/src.tar" "/tmp/src.tar"
|
|
sudo rm -rf /root/stable-diffusion-aws-extension
|
|
sudo mkdir -p /root/stable-diffusion-aws-extension/
|
|
tar --overwrite -xf "/tmp/src.tar" -C "/root/stable-diffusion-aws-extension/"
|
|
rm -rf /tmp/src.tar
|
|
|
|
sleep 150
|
|
|
|
while sudo fuser /var/lib/apt/lists/lock >/dev/null 2>&1 ; do
|
|
echo "Waiting for other apt process to finish..."
|
|
sleep 1
|
|
done
|
|
|
|
while sudo fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 ; do
|
|
echo "Waiting for other apt process to finish..."
|
|
sleep 1
|
|
done
|
|
|
|
sudo apt update && sudo apt install jq supervisor nginx -y
|
|
sudo cp -f /root/stable-diffusion-aws-extension/workshop/comfy_nginx_proxy.conf /etc/nginx/sites-available/default
|
|
sudo cp -f /root/stable-diffusion-aws-extension/workshop/comfy_custom_502.html /usr/share/nginx/html/custom_502.html
|
|
sudo cp -f /root/stable-diffusion-aws-extension/workshop/comfy_custom_502.html /usr/share/nginx/html/index.html
|
|
sudo ufw allow 'Nginx HTTP'
|
|
sudo systemctl enable nginx
|
|
sudo systemctl restart nginx
|
|
|
|
aws ecr get-login-password --region ${AWS::Region} | docker login --username AWS --password-stdin 366590864501.dkr.ecr.${AWS::Region}.amazonaws.com
|
|
docker pull 366590864501.dkr.ecr.${AWS::Region}.amazonaws.com/esd-inference:dev
|
|
|
|
cat > comfy.service <<EOF
|
|
[Unit]
|
|
Description=Comfy Service
|
|
After=network.target
|
|
StartLimitIntervalSec=0
|
|
|
|
[Service]
|
|
WorkingDirectory=/root/stable-diffusion-aws-extension/
|
|
ExecStart=bash docker_start.sh
|
|
Type=simple
|
|
Restart=always
|
|
RestartSec=5
|
|
User=root
|
|
StartLimitAction=reboot
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
|
|
EOF
|
|
sudo mv comfy.service /etc/systemd/system
|
|
sudo chown root:root /etc/systemd/system/comfy.service
|
|
|
|
sudo systemctl enable docker
|
|
sudo systemctl start docker
|
|
|
|
sudo systemctl enable comfy.service
|
|
sudo systemctl start comfy.service
|
|
|
|
# Step1: EC2 init
|
|
# tail -f /var/log/cloud-init-output.log
|
|
#
|
|
# Step2: Comfy init
|
|
# sudo journalctl -u comfy -f
|
|
#
|
|
# Step3: Comfy start
|
|
# tail -f /root/stable-diffusion-aws-extension/container/*.log
|
|
#
|
|
# sudo journalctl -u comfy --no-pager -n 200
|
|
# docker images -q | xargs docker rmi -f
|
|
|
|
ComfyEIP:
|
|
Type: AWS::EC2::EIP
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub "comfy-on-aws"
|
|
|
|
ComfyEIPAssociation:
|
|
Type: AWS::EC2::EIPAssociation
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
AllocationId: !GetAtt ComfyEIP.AllocationId
|
|
InstanceId: !Ref ComfyEC2Dev
|
|
|
|
Outputs:
|
|
Designer:
|
|
Description: URL for Designer
|
|
Value: !Sub http://${ComfyEIP}:10000
|
|
DesignerDockerfile:
|
|
Description: Dockerfile for EC2 and SageMaker
|
|
Value: /root/stable-diffusion-aws-extension/container/comfy_10000.Dockerfile
|
|
NumberOfInferencePorts:
|
|
Description: The number of inference ports
|
|
Value: !Sub ${NumberOfInferencePorts}
|
|
NumberOfInferencePortsStart:
|
|
Description: The first inference start port
|
|
Value: !Sub http://${ComfyEIP}:10001
|
|
PageUrlOfEC2Connect:
|
|
Description: URL of EC2 Connect Page
|
|
Value: !Sub https://${AWS::Region}.console.aws.amazon.com/ec2/home?region=${AWS::Region}#ConnectToInstance:instanceId=${ComfyEC2Dev}
|