Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

ecs.sh 6.8 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  1. #!/bin/bash
  2. set -euo pipefail
  3. # Load environment variables
  4. if [ ! -f .env ]; then
  5. echo ".env file not found! Please include AWS_REGION, ECR_REPO_NAME, IMAGE_TAG."
  6. exit 1
  7. fi
  8. set -a
  9. source .env
  10. set +a
  11. echo "AWS_REGION=$AWS_REGION"
  12. echo "ECR_REPO_NAME=$ECR_REPO_NAME"
  13. echo "IMAGE_TAG=$IMAGE_TAG"
  14. echo
  15. CLUSTER_NAME="tumor-classifier-cluster"
  16. SERVICE_NAME="tumor-classifier-service"
  17. echo "CLUSTER_NAME=$CLUSTER_NAME"
  18. echo "SERVICE_NAME=$SERVICE_NAME"
  19. ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text --no-cli-pager)
  20. VPC_ID=$(aws ec2 describe-vpcs \
  21. --region "$AWS_REGION" \
  22. --filters Name=isDefault,Values=true \
  23. --query 'Vpcs[0].VpcId' --output text --no-cli-pager)
  24. if [ "$VPC_ID" == "None" ] || [ -z "$VPC_ID" ]; then
  25. echo "No default VPC found in region $AWS_REGION."
  26. exit 1
  27. fi
  28. echo "VPC_ID=$VPC_ID"
  29. SUBNET_IDS=$(aws ec2 describe-subnets \
  30. --region "$AWS_REGION" \
  31. --filters Name=vpc-id,Values="$VPC_ID" Name=map-public-ip-on-launch,Values=true \
  32. --query 'Subnets[].SubnetId' --output text --no-cli-pager)
  33. if [ -z "$SUBNET_IDS" ]; then
  34. echo "No public subnets found in VPC $VPC_ID."
  35. exit 1
  36. fi
  37. echo "SUBNET_IDS=$SUBNET_IDS"
  38. echo
  39. ECR_URI="${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPO_NAME}:${IMAGE_TAG}"
  40. echo "ECR_URI: $ECR_URI"
  41. echo
  42. # 1. Create ECS Cluster if needed
  43. if aws ecs describe-clusters --clusters "$CLUSTER_NAME" --query 'clusters[0].status' --output text --no-cli-pager 2>/dev/null | grep -q ACTIVE; then
  44. echo "ECS Cluster $CLUSTER_NAME exists."
  45. else
  46. echo "Creating ECS Cluster: $CLUSTER_NAME"
  47. aws ecs create-cluster --cluster-name "$CLUSTER_NAME" --no-cli-pager >/dev/null
  48. fi
  49. # 2. Create IAM Role if needed
  50. ROLE_NAME="ecsTaskExecutionRole"
  51. if aws iam get-role --role-name "$ROLE_NAME" --no-cli-pager >/dev/null 2>&1; then
  52. echo "IAM Role $ROLE_NAME exists."
  53. else
  54. echo "Creating IAM Role $ROLE_NAME"
  55. aws iam create-role --role-name "$ROLE_NAME" --assume-role-policy-document file://<(cat <<EOF
  56. {
  57. "Version": "2012-10-17",
  58. "Statement": [{
  59. "Effect": "Allow",
  60. "Principal": { "Service": "ecs-tasks.amazonaws.com" },
  61. "Action": "sts:AssumeRole"
  62. }]
  63. }
  64. EOF
  65. ) --no-cli-pager >/dev/null
  66. aws iam attach-role-policy \
  67. --role-name "$ROLE_NAME" \
  68. --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy \
  69. --no-cli-pager
  70. echo "Waiting for IAM role propagation..."
  71. sleep 10
  72. fi
  73. # 3. Create Security Group allowing inbound TCP 9696
  74. SG_NAME="${CLUSTER_NAME}-http-sg"
  75. SG_ID=$(aws ec2 describe-security-groups \
  76. --filters Name=group-name,Values="$SG_NAME" \
  77. --query 'SecurityGroups[0].GroupId' --output text --no-cli-pager 2>/dev/null || echo "None")
  78. if [ "$SG_ID" == "None" ]; then
  79. echo "Creating Security Group: $SG_NAME"
  80. SG_ID=$(aws ec2 create-security-group \
  81. --group-name "$SG_NAME" \
  82. --description "Allow TCP port 9696 traffic" \
  83. --vpc-id "$VPC_ID" --query GroupId --output text --no-cli-pager)
  84. aws ec2 authorize-security-group-ingress \
  85. --group-id "$SG_ID" \
  86. --protocol tcp --port 9696 --cidr 0.0.0.0/0 \
  87. --no-cli-pager >/dev/null
  88. echo "Security Group created: $SG_ID"
  89. else
  90. echo "Security Group $SG_NAME exists: $SG_ID"
  91. fi
  92. # 4. Register Task Definition with port 9696 & AWS Logs config
  93. TASK_DEF_NAME="${SERVICE_NAME}-task"
  94. echo "Registering ECS Task Definition $TASK_DEF_NAME..."
  95. TASK_DEF_ARN=$(aws ecs register-task-definition \
  96. --family "$TASK_DEF_NAME" \
  97. --network-mode "awsvpc" \
  98. --requires-compatibilities "FARGATE" \
  99. --cpu "512" \
  100. --memory "1024" \
  101. --execution-role-arn "arn:aws:iam::${ACCOUNT_ID}:role/${ROLE_NAME}" \
  102. --container-definitions "$(cat <<EOF
  103. [
  104. {
  105. "name": "${SERVICE_NAME}-container",
  106. "image": "${ECR_URI}",
  107. "portMappings": [
  108. {
  109. "containerPort": 9696,
  110. "hostPort": 9696,
  111. "protocol": "tcp"
  112. }
  113. ],
  114. "essential": true,
  115. "logConfiguration": {
  116. "logDriver": "awslogs",
  117. "options": {
  118. "awslogs-group": "/ecs/${SERVICE_NAME}",
  119. "awslogs-region": "${AWS_REGION}",
  120. "awslogs-stream-prefix": "ecs"
  121. }
  122. }
  123. }
  124. ]
  125. EOF
  126. )" --query 'taskDefinition.taskDefinitionArn' --output text --no-cli-pager)
  127. echo "Task Definition ARN: $TASK_DEF_ARN"
  128. echo
  129. # 5. Create or Update ECS Service
  130. SERVICE_EXISTS=$(aws ecs describe-services \
  131. --cluster "$CLUSTER_NAME" \
  132. --services "$SERVICE_NAME" \
  133. --query 'services[0].status' --output text --no-cli-pager 2>/dev/null || echo "NONE")
  134. # Convert space-separated SUBNET_IDS to JSON array of quoted strings
  135. read -ra SUBNET_ARRAY <<< "$SUBNET_IDS"
  136. # Build JSON array string correctly, with commas between quoted subnet IDs
  137. SUBNETS_JSON="["
  138. for subnet in "${SUBNET_ARRAY[@]}"; do
  139. # Trim any whitespace (optional)
  140. subnet=$(echo "$subnet" | xargs)
  141. SUBNETS_JSON+="\"${subnet}\","
  142. done
  143. SUBNETS_JSON="${SUBNETS_JSON%,}]" # Remove trailing comma and close array
  144. echo "Using subnets JSON: $SUBNETS_JSON"
  145. echo "Using subnets JSON: $SUBNETS_JSON"
  146. if [ "$SERVICE_EXISTS" == "ACTIVE" ]; then
  147. echo "Updating ECS Service..."
  148. aws ecs update-service \
  149. --cluster "$CLUSTER_NAME" \
  150. --service "$SERVICE_NAME" \
  151. --task-definition "$TASK_DEF_ARN" \
  152. --no-cli-pager >/dev/null
  153. else
  154. echo "Creating ECS Service..."
  155. aws ecs create-service \
  156. --cluster "$CLUSTER_NAME" \
  157. --service-name "$SERVICE_NAME" \
  158. --task-definition "$TASK_DEF_ARN" \
  159. --desired-count 1 \
  160. --launch-type FARGATE \
  161. --network-configuration "awsvpcConfiguration={subnets=$SUBNETS_JSON,securityGroups=[\"$SG_ID\"],assignPublicIp=ENABLED}" \
  162. --region "$AWS_REGION" \
  163. --output text --no-cli-pager >/dev/null
  164. fi
  165. echo
  166. echo "Waiting for ECS service to stabilize (30s)..."
  167. sleep 30
  168. # 6. Show Service Details
  169. echo
  170. echo "ECS Service Status:"
  171. aws ecs describe-services \
  172. --cluster "$CLUSTER_NAME" \
  173. --services "$SERVICE_NAME" \
  174. --query 'services[0].[serviceName,status,desiredCount,runningCount]' \
  175. --output table --no-cli-pager
  176. echo
  177. echo "Running Task(s):"
  178. TASKS=$(aws ecs list-tasks \
  179. --cluster "$CLUSTER_NAME" \
  180. --service-name "$SERVICE_NAME" \
  181. --query 'taskArns' --output text --no-cli-pager)
  182. echo "$TASKS"
  183. echo
  184. echo "Public IP(s) of running task(s):"
  185. for TASK_ARN in $TASKS; do
  186. ENI_ID=$(aws ecs describe-tasks \
  187. --cluster "$CLUSTER_NAME" \
  188. --tasks "$TASK_ARN" \
  189. --query 'tasks[0].attachments[].details[?name==`networkInterfaceId`].value | [0]' \
  190. --output text --no-cli-pager)
  191. if [ -z "$ENI_ID" ] || [ "$ENI_ID" == "None" ]; then
  192. echo "Warning: No network interface ID found for task $TASK_ARN"
  193. continue
  194. fi
  195. PUBLIC_IP=$(aws ec2 describe-network-interfaces \
  196. --network-interface-ids "$ENI_ID" \
  197. --query 'NetworkInterfaces[0].Association.PublicIp' \
  198. --output text --no-cli-pager)
  199. echo "Task: $TASK_ARN | Public IP: $PUBLIC_IP"
  200. done
  201. echo
  202. echo "✅ Deployment complete. Visit your app using the public IP(s) above on port 9696."
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...