Skip to content

Commit 2bb64a6

Browse files
Stable Diffusion Example (#25)
1 parent e13aa09 commit 2bb64a6

File tree

7 files changed

+446
-0
lines changed

7 files changed

+446
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<p align="center">
2+
<img src="https://github.com/intel/terraform-intel-aws-vm/blob/main/images/logo-classicblue-800px.png?raw=true" alt="Intel Logo" width="250"/>
3+
</p>
4+
5+
# Intel® Optimized Cloud Modules for Terraform
6+
7+
© Copyright 2023, Intel Corporation
8+
9+
## AWS M7i EC2 Instance with 4th Generation Intel® Xeon® Scalable Processor (Sapphire Rapids) & Intel® Cloud Optimized Recipe for Stable Diffusion
10+
11+
This demo will showcase Intel® OpenVino Optimized Stable Diffusion CPU inference using 4th Gen Xeon Scalable Processors with Intel® AMS on AWS.
12+
13+
## Architecture Diagram
14+
15+
<p align="center">
16+
<img src="https://github.com/intel/terraform-intel-aws-vm/blob/main/images/gen-ai-stable-diffusion.png?raw=true" alt="stable-diffusion" width="750"/>
17+
</p>
18+
19+
## IMPORTANT:Modify variables.tf and add your public to cidr_blocks = "0.0.0.0/0".
20+
21+
Use https://www.ipchicken.com/ to find your Public IP address
22+
23+
24+
## Usage - Modify variables.tf and main.tf as needed
25+
26+
**variables.tf**
27+
28+
If needed, modify the region to target a specific AWS Region
29+
30+
```hcl
31+
...
32+
33+
default = [
34+
{
35+
from_port = 22
36+
to_port = 22
37+
protocol = "tcp"
38+
cidr_blocks = "192.0.0.0/8"
39+
40+
},
41+
42+
variable "region" {
43+
description = "Target AWS region to deploy EC2 in."
44+
type = string
45+
default = "us-east-1"
46+
}
47+
48+
...
49+
```
50+
51+
**main.tf**
52+
53+
If needed, modify main.tf
54+
55+
```hcl
56+
...
57+
58+
module "ec2-vm" {
59+
source = "intel/aws-vm/intel"
60+
key_name = aws_key_pair.TF_key.key_name
61+
instance_type = "m7i.4xlarge"
62+
availability_zone = "us-east-1a"
63+
ami = data.aws_ami.ubuntu-linux-2204.id
64+
user_data = data.cloudinit_config.ansible.rendered
65+
66+
root_block_device = [{
67+
volume_size = "100"
68+
}]
69+
70+
tags = {
71+
Name = "stable-diffusion-test-vm-${random_id.rid.dec}"
72+
Owner = "OwnerName-${random_id.rid.dec}",
73+
Duration = "2"
74+
}
75+
}
76+
77+
...
78+
```
79+
80+
## Running the Demo using AWS CloudShell
81+
82+
1. Open your AWS account and click the Cloudshell prompt (terminal button on top right of page)
83+
84+
2. Install Terraform
85+
86+
```bash
87+
git clone https://github.com/tfutils/tfenv.git ~/.tfenv
88+
mkdir ~/bin
89+
ln -s ~/.tfenv/bin/* ~/bin/
90+
tfenv install 1.6.0
91+
tfenv use 1.6.0
92+
```
93+
94+
3. Clone, if needed modify files, and run Terraform
95+
96+
```bash
97+
git clone https://github.com/intel/terraform-intel-aws-vm.git
98+
cd terraform-intel-aws-vm/examples/gen-ai-stable-diffusion
99+
# Make any necessary modifications to variables.tf and main.tf before running the Terraform commands below
100+
terraform init
101+
terraform apply
102+
```
103+
104+
105+
```bash
106+
WAIT ~3 MINUTES
107+
```
108+
109+
4. After the Terraform module successfully creates the EC2 instance, **wait ~3 minutes** for the recipe to download/install pre-requisites and Stable Diffusion before continuing.
110+
111+
5. Navigate to the folder from where you ran **'terraform apply'**. Terraform created a **tfkey.private** key.
112+
113+
2. Change the tfkey.private permissions
114+
115+
```bash
116+
chmod 400 tfkey.private
117+
```
118+
119+
3. SSH into your new Virtual Machine
120+
121+
```bash
122+
ssh ubuntu@<Public_IP_Address_EC2_Instance> -i tfkey.private
123+
```
124+
125+
3. Once you are logged into the EC2 instance, run the command
126+
127+
```bash
128+
source /usr/local/bin/run_demo.sh
129+
```
130+
131+
4. The application will download the Stable Diffusion Model and optimized it using Intel® OpenVino
132+
133+
5. When the application is ready, on your computer open a browser and **Browse to http://<VM_PLUBLIC_IP>:5000**
134+
135+
6. OPTIONAL - You can also start the default not-optimized demo by running. **Browse to port 5001 instead http://<VM_PLUBLIC_IP>:5001**
136+
137+
```bash
138+
source /usr/local/bin/not_optimized_run_demo.sh
139+
```
140+
141+
7. You can now generate images by entering prompts
142+
143+
8. To delete the demo, exit the VM instance by pressing Ctrl-C to break out of Stable Diffusion
144+
145+
```bash
146+
terraform destroy
147+
```
148+
149+
## If not using the AWS Cloud Shell
150+
151+
152+
1. Install AWS CLI and run ``` aws configure``` to configure your AWS credentials
153+
154+
2. Follow the same steps to run terraform, provision, ssh, and start the demo from your local workstation/laptop
155+
156+
## Considerations
157+
158+
- The AWS region where this example is run should have a default VPC
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#cloud-config
2+
package_update: true
3+
package_upgrade: true
4+
5+
package:
6+
- git
7+
8+
ansible:
9+
install_method: distro
10+
package_name: ansible
11+
pull:
12+
url: "https://github.com/intel/optimized-cloud-recipes.git"
13+
playbook_name: "recipes/ai-stable_diffusion-amx-ubuntu/recipe.yml"
14+
15+
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Provision EC2 Instance on Icelake on Amazon Linux OS in default vpc. It is configured to create the EC2 in
2+
# US-East-1 region. The region is provided in variables.tf in this example folder.
3+
4+
# This example also create an EC2 key pair. Associate the public key with the EC2 instance. Create the private key
5+
# in the local system where terraform apply is done. Create a new scurity group to open up the SSH port
6+
# 22 to a specific IP CIDR block
7+
8+
######### PLEASE NOTE TO CHANGE THE IP CIDR BLOCK TO ALLOW SSH FROM YOUR OWN ALLOWED IP ADDRESS FOR SSH #########
9+
10+
data "cloudinit_config" "ansible" {
11+
gzip = true
12+
base64_encode = true
13+
14+
part {
15+
filename = "cloud_init"
16+
content_type = "text/cloud-config"
17+
content = templatefile(
18+
"cloud_init.yml",
19+
{}
20+
)
21+
}
22+
}
23+
24+
data "aws_ami" "ubuntu-linux-2204" {
25+
most_recent = true
26+
owners = ["099720109477"] # Canonical
27+
filter {
28+
name = "name"
29+
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
30+
}
31+
filter {
32+
name = "virtualization-type"
33+
values = ["hvm"]
34+
}
35+
}
36+
37+
resource "random_id" "rid" {
38+
byte_length = 5
39+
}
40+
41+
# RSA key of size 4096 bits
42+
resource "tls_private_key" "rsa" {
43+
algorithm = "RSA"
44+
rsa_bits = 4096
45+
}
46+
47+
resource "aws_key_pair" "TF_key" {
48+
key_name = "TF_key-${random_id.rid.dec}"
49+
public_key = tls_private_key.rsa.public_key_openssh
50+
}
51+
52+
resource "local_file" "TF_private_key" {
53+
content = tls_private_key.rsa.private_key_pem
54+
filename = "tfkey.private"
55+
}
56+
resource "aws_security_group" "ssh_security_group" {
57+
description = "security group to configure ports for ssh"
58+
name_prefix = "ssh_security_group"
59+
}
60+
61+
# Modify the `ingress_rules` variable in the variables.tf file to allow the required ports for your CIDR ranges
62+
resource "aws_security_group_rule" "ingress_rules" {
63+
count = length(var.ingress_rules)
64+
type = "ingress"
65+
security_group_id = aws_security_group.ssh_security_group.id
66+
from_port = var.ingress_rules[count.index].from_port
67+
to_port = var.ingress_rules[count.index].to_port
68+
protocol = var.ingress_rules[count.index].protocol
69+
cidr_blocks = [var.ingress_rules[count.index].cidr_blocks]
70+
}
71+
72+
resource "aws_network_interface_sg_attachment" "sg_attachment" {
73+
count = length(module.ec2-vm)
74+
security_group_id = aws_security_group.ssh_security_group.id
75+
network_interface_id = module.ec2-vm[count.index].primary_network_interface_id
76+
}
77+
78+
# Modify the `vm_count` variable in the variables.tf file to create the required number of EC2 instances
79+
module "ec2-vm" {
80+
count = var.vm_count
81+
source = "intel/aws-vm/intel"
82+
key_name = aws_key_pair.TF_key.key_name
83+
instance_type = "m7i.8xlarge"
84+
availability_zone = "us-east-1c"
85+
ami = data.aws_ami.ubuntu-linux-2204.id
86+
user_data = data.cloudinit_config.ansible.rendered
87+
88+
root_block_device = [{
89+
volume_size = "100"
90+
}]
91+
92+
tags = {
93+
Name = "stable-diffusion-vm-${count.index}-${random_id.rid.dec}"
94+
Owner = "OwnerName-${random_id.rid.dec}",
95+
Duration = "2"
96+
}
97+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
output "id" {
2+
description = "The ID of the instance"
3+
value = try(module.ec2-vm.id, module.ec2-vm.id, "")
4+
}
5+
6+
output "arn" {
7+
description = "The ARN of the instance"
8+
value = try(module.ec2-vm.arn, "")
9+
}
10+
11+
output "capacity_reservation_specification" {
12+
description = "Capacity reservation specification of the instance"
13+
value = try(module.ec2-vm.capacity_reservation_specification, "")
14+
}
15+
16+
output "instance_state" {
17+
description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`"
18+
value = try(module.ec2-vm.instance_state, "")
19+
}
20+
21+
output "outpost_arn" {
22+
description = "The ARN of the Outpost the instance is assigned to"
23+
value = try(module.ec2-vm.outpost_arn, "")
24+
}
25+
26+
output "password_data" {
27+
description = "Base-64 encoded encrypted password data for the instance. Useful for getting the administrator password for instances running Microsoft Windows. This attribute is only exported if `get_password_data` is true"
28+
value = try(module.ec2-vm.password_data, "")
29+
}
30+
31+
output "primary_network_interface_id" {
32+
description = "The ID of the instance's primary network interface"
33+
value = try(module.ec2-vm.primary_network_interface_id, "")
34+
}
35+
36+
output "private_dns" {
37+
description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC"
38+
value = try(module.ec2-vm.private_dns, "")
39+
}
40+
41+
output "public_dns" {
42+
description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC"
43+
value = try(module.ec2-vm.public_dns, "")
44+
}
45+
46+
output "public_ip" {
47+
description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached"
48+
value = try(module.ec2-vm.public_ip, "")
49+
}
50+
51+
output "private_ip" {
52+
description = "The private IP address assigned to the instance."
53+
value = try(module.ec2-vm.private_ip, "")
54+
}
55+
56+
output "ipv6_addresses" {
57+
description = "The IPv6 address assigned to the instance, if applicable."
58+
value = try(module.ec2-vm.ipv6_addresses, [])
59+
}
60+
61+
output "tags_all" {
62+
description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block"
63+
value = try(module.ec2-vm.tags_all, {})
64+
}
65+
66+
output "spot_bid_status" {
67+
description = "The current bid status of the Spot Instance Request"
68+
value = try(module.ec2-vm.spot_bid_status, "")
69+
}
70+
71+
output "spot_request_state" {
72+
description = "The current request state of the Spot Instance Request"
73+
value = try(module.ec2-vm.spot_request_state, "")
74+
}
75+
76+
output "spot_instance_id" {
77+
description = "The Instance ID (if any) that is currently fulfilling the Spot Instance request"
78+
value = try(module.ec2-vm.spot_instance_id, "")
79+
}
80+
81+
################################################################################
82+
# IAM Role / Instance Profile
83+
################################################################################
84+
85+
output "iam_role_name" {
86+
description = "The name of the IAM role"
87+
value = try(module.ec2-vm.aws_iam_role.name, null)
88+
}
89+
90+
output "iam_role_arn" {
91+
description = "The Amazon Resource Name (ARN) specifying the IAM role"
92+
value = try(module.ec2-vm.aws_iam_role.arn, null)
93+
}
94+
95+
output "iam_role_unique_id" {
96+
description = "Stable and unique string identifying the IAM role"
97+
value = try(module.ec2-vm.aws_iam_role.unique_id, null)
98+
}
99+
100+
output "iam_instance_profile_arn" {
101+
description = "ARN assigned by AWS to the instance profile"
102+
value = try(module.ec2-vm.aws_iam_instance_profile.arn, null)
103+
}
104+
105+
output "iam_instance_profile_id" {
106+
description = "Instance profile's ID"
107+
value = try(module.ec2-vm.aws_iam_instance_profile.id, null)
108+
}
109+
110+
output "iam_instance_profile_unique" {
111+
description = "Stable and unique string identifying the IAM instance profile"
112+
value = try(module.ec2-vm.aws_iam_instance_profile.unique_id, null)
113+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
provider "aws" {
2+
# Environment Variables used for Authentication
3+
region = var.region
4+
}

0 commit comments

Comments
 (0)