Skip to content
This repository was archived by the owner on Apr 20, 2023. It is now read-only.

Commit 61deb95

Browse files
authored
Merge pull request #42 from msavela/ui-support
Metaflow UI Cloudformation stack support.
2 parents d192d5e + 8fe47e6 commit 61deb95

File tree

2 files changed

+287
-6
lines changed

2 files changed

+287
-6
lines changed

aws/cloudformation/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,16 @@ Did you choose to enable "APIBasicAuth" and/or "CustomRole" and are wondering ho
4949
2. From the AWS Console, navigate to "Services" and select "API Gateway" from "Networking & Content Delivery" (or search for it in the search bar). Click your API, select "API Keys" from the left side, select the API that corresponds to your Stack name, and click "show" next to "API Key".
5050

5151
- **CustomRole** - This template can create an optional role that can be assumed by users (or applications) that includes limited permissions to only the resources required by Metaflow, including access only to the Amazon S3 bucket, AWS Batch Compute Environment, and Amazon Sagemaker Notebook Instance created by this template. You will, however, need to modify the trust policy for the role to grant access to the principals (users/roles/accounts) who will assume it, and you'll also need to have your users configure an appropriate role-assumption profile. The ARN of the Custom Role can be found in the "Output" tab of the CloudFormation stack under `MetaflowUserRoleArn`. To modify the trust policy to allow new principals, follow the directions [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/roles-managingrole-editing-console.html#roles-managingrole_edit-trust-policy). Once you've granted access to the principals of your choice, have your users create a new Profile for the AWS CLI that assumes the role ARN by following the directions [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html).
52+
53+
### Optional Metaflow User Interface (`EnableUI` -parameter)
54+
55+
Please note: This section can be ignored if `EnableUI` -parameter is disabled (this is the default value).
56+
57+
User Interface is provided as part of the `metaflow-cfn-template.yml` template and doesn't require any additional
58+
configuration besides enabling the `EnableUI` -parameter. You can follow the [AWS CloudFormation Deployment](https://admin-docs.metaflow.org/metaflow-on-aws/deployment-guide/aws-cloudformation-deployment#steps-for-aws-cloudformation-deployment) instructions.
59+
60+
Once deployed the Cloudformation Stack will provide two outputs:
61+
- `UIServiceUrl` - Application Load Balancer endpoint
62+
- `UIServiceCloudfrontUrl` - Cloudfront distribution (using ALB) endpoint with HTTPS enabled (preferred)
63+
64+
Please note: Metaflow User Interface doesn't provide any authentication by default.

aws/cloudformation/metaflow-cfn-template.yml

Lines changed: 274 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
AWSTemplateFormatVersion: '2010-09-09'
2-
Description: Stack for complete deployment of Metaflow (last-updated-date 02/09/2021)
2+
Description: Stack for complete deployment of Metaflow (last-updated-date 10/26/2021)
33

44
Parameters:
55
SagemakerInstance:
@@ -73,6 +73,11 @@ Parameters:
7373
Type: String
7474
Default: ''
7575
Description: 'Additional IAM Policy ARN to attach to Batch Compute Environment (leave empty, unless you know what you are doing)'
76+
EnableUI:
77+
Type: String
78+
Default: 'false'
79+
AllowedValues: ['false', 'true']
80+
Description: 'Enable Metaflow UI'
7681

7782
Mappings:
7883
ServiceInfo:
@@ -96,13 +101,29 @@ Mappings:
96101
value: 1
97102
Role:
98103
value: ""
104+
105+
ServiceInfoUI:
106+
ServiceName:
107+
value: 'metaflow-ui-service'
108+
ImageUrl:
109+
value: 'netflixoss/metaflow_metadata_service'
110+
ContainerPort:
111+
value: 8083
112+
ContainerCpu:
113+
value: 4096
114+
ContainerMemory:
115+
value: 16384
116+
DesiredCount:
117+
value: 1
118+
99119
Conditions:
100120
EnableAuth: !Equals [ !Ref APIBasicAuth, 'true']
101121
EnableRole: !Equals [ !Ref CustomRole, 'true']
102122
EnableFargateOnBatch: !Equals [ !Ref BatchType, 'fargate']
103123
EnableSagemaker: !Equals [ !Ref EnableSagemaker, 'true']
104124
IsGov: !Equals [ !Ref IAMPartition, 'aws-us-gov']
105125
EnableAddtionalWorkerPolicy: !Not [ !Equals [ !Ref AdditionalWorkerPolicyArn, ''] ]
126+
EnableUI: !Equals [ !Ref EnableUI, 'true']
106127
Resources:
107128
VPC:
108129
Type: AWS::EC2::VPC
@@ -294,11 +315,16 @@ Resources:
294315
PolicyDocument:
295316
Version: '2012-10-17'
296317
Statement:
297-
Sid: ObjectAccessMetadataService
298-
Effect: Allow
299-
Action:
300-
- s3:GetObject
301-
Resource: !Join ['', [ !GetAtt 'MetaflowS3Bucket.Arn', '/*' ]]
318+
- Sid: ObjectAccessMetadataService
319+
Effect: Allow
320+
Action:
321+
- s3:GetObject
322+
Resource: !Join ['', [ !GetAtt 'MetaflowS3Bucket.Arn', '/*' ]]
323+
- Sid: ObjectAccessMetadataServiceNonExistentKeys
324+
Effect: Allow
325+
Action:
326+
- s3:ListBucket
327+
Resource: !GetAtt 'MetaflowS3Bucket.Arn'
302328
- PolicyName: DenyPresignedBatch
303329
PolicyDocument:
304330
Version: '2012-10-17'
@@ -1357,6 +1383,237 @@ Resources:
13571383
TimeToLiveSpecification:
13581384
AttributeName: ttl
13591385
Enabled: true
1386+
1387+
# --- Metaflow UI resources begin ---
1388+
1389+
# UI: Ingress rules
1390+
1391+
IngressRuleUIService:
1392+
Type: AWS::EC2::SecurityGroupIngress
1393+
Condition: EnableUI
1394+
Properties:
1395+
Description: "Allow API Calls Internally (UI service)"
1396+
GroupId: !Ref FargateSecurityGroup
1397+
IpProtocol: tcp
1398+
FromPort: !FindInMap ["ServiceInfoUI", "ContainerPort", "value"]
1399+
ToPort: !FindInMap ["ServiceInfoUI", "ContainerPort", "value"]
1400+
CidrIp: !GetAtt 'VPC.CidrBlock'
1401+
1402+
# UI: Load balancer
1403+
1404+
ALBUISecurityGroup:
1405+
Type: AWS::EC2::SecurityGroup
1406+
Condition: EnableUI
1407+
Properties:
1408+
GroupDescription: "Access to the public facing load balancer"
1409+
VpcId: !Ref VPC
1410+
SecurityGroupIngress:
1411+
# Allow access to ALB from anywhere on the internet
1412+
- CidrIp: 0.0.0.0/0
1413+
IpProtocol: -1
1414+
ALBUI:
1415+
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
1416+
Condition: EnableUI
1417+
Properties:
1418+
Scheme: internet-facing
1419+
Type: application
1420+
Subnets:
1421+
- !Ref Subnet1
1422+
- !Ref Subnet2
1423+
SecurityGroups: [!Ref ALBUISecurityGroup]
1424+
ALBUIListener:
1425+
Type: AWS::ElasticLoadBalancingV2::Listener
1426+
Condition: EnableUI
1427+
DependsOn:
1428+
- ALBUI
1429+
Properties:
1430+
DefaultActions:
1431+
- TargetGroupArn: !Ref ALBUITargetGroupUIService
1432+
Type: "forward"
1433+
LoadBalancerArn: !Ref ALBUI
1434+
Port: 80
1435+
Protocol: HTTP
1436+
ALBUITargetGroupUIService:
1437+
Type: AWS::ElasticLoadBalancingV2::TargetGroup
1438+
Condition: EnableUI
1439+
Properties:
1440+
HealthCheckIntervalSeconds: 6
1441+
HealthCheckPath: /ping
1442+
HealthCheckProtocol: HTTP
1443+
HealthCheckTimeoutSeconds: 5
1444+
HealthyThresholdCount: 2
1445+
TargetType: ip
1446+
Port: !FindInMap ["ServiceInfoUI", "ContainerPort", "value"]
1447+
Protocol: HTTP
1448+
UnhealthyThresholdCount: 2
1449+
VpcId: !Ref VPC
1450+
1451+
# UI: Coudfront distribution
1452+
1453+
CloudFrontDistributionUI:
1454+
Type: AWS::CloudFront::Distribution
1455+
Condition: EnableUI
1456+
DependsOn:
1457+
- ALBUI
1458+
Properties:
1459+
DistributionConfig:
1460+
Origins:
1461+
- DomainName: !GetAtt "ALBUI.DNSName"
1462+
Id: !Ref ALBUI
1463+
CustomOriginConfig:
1464+
HTTPPort: 80
1465+
OriginProtocolPolicy: http-only
1466+
OriginKeepaliveTimeout: 60
1467+
OriginReadTimeout: 30
1468+
OriginSSLProtocols:
1469+
- TLSv1
1470+
- TLSv1.1
1471+
- TLSv1.2
1472+
- SSLv3
1473+
Enabled: true
1474+
HttpVersion: http2
1475+
DefaultCacheBehavior:
1476+
AllowedMethods:
1477+
- GET
1478+
- HEAD
1479+
- DELETE
1480+
- OPTIONS
1481+
- PATCH
1482+
- POST
1483+
- PUT
1484+
Compress: true
1485+
DefaultTTL: 0
1486+
MinTTL: 0
1487+
MaxTTL: 0
1488+
SmoothStreaming: false
1489+
TargetOriginId: !Ref ALBUI
1490+
ForwardedValues:
1491+
QueryString: true
1492+
Cookies:
1493+
Forward: none
1494+
ViewerProtocolPolicy: redirect-to-https
1495+
CacheBehaviors:
1496+
- AllowedMethods:
1497+
- GET
1498+
- HEAD
1499+
- DELETE
1500+
- OPTIONS
1501+
- PATCH
1502+
- POST
1503+
- PUT
1504+
Compress: false
1505+
PathPattern: /api/*
1506+
DefaultTTL: 0
1507+
MinTTL: 0
1508+
MaxTTL: 0
1509+
SmoothStreaming: false
1510+
TargetOriginId: !Ref ALBUI
1511+
ForwardedValues:
1512+
QueryString: true
1513+
Cookies:
1514+
Forward: none
1515+
ViewerProtocolPolicy: redirect-to-https
1516+
PriceClass: PriceClass_All
1517+
IPV6Enabled: true
1518+
1519+
# UI: ECS Cluster task definition & service
1520+
1521+
TaskDefinitionUIService:
1522+
Type: AWS::ECS::TaskDefinition
1523+
Condition: EnableUI
1524+
Properties:
1525+
Family: !FindInMap ["ServiceInfoUI", "ServiceName", "value"]
1526+
Cpu: !FindInMap ["ServiceInfoUI", "ContainerCpu", "value"]
1527+
Memory: !FindInMap ["ServiceInfoUI", "ContainerMemory", "value"]
1528+
NetworkMode: awsvpc
1529+
RequiresCompatibilities:
1530+
- FARGATE
1531+
ExecutionRoleArn: !Ref 'ECSTaskExecutionRole'
1532+
TaskRoleArn: !GetAtt 'MetadataSvcECSTaskRole.Arn'
1533+
ContainerDefinitions:
1534+
- Name: !FindInMap ["ServiceInfoUI", "ServiceName", "value"]
1535+
Environment:
1536+
- Name: "MF_METADATA_DB_HOST"
1537+
Value: !GetAtt 'RDSMasterInstance.Endpoint.Address'
1538+
- Name: "MF_METADATA_DB_PORT"
1539+
Value: "5432"
1540+
- Name: "MF_METADATA_DB_USER"
1541+
Value: !Join ['', ['{{resolve:secretsmanager:', !Ref MyRDSSecret, ':SecretString:username}}' ]]
1542+
- Name: "MF_METADATA_DB_PSWD"
1543+
Value: !Join ['', ['{{resolve:secretsmanager:', !Ref MyRDSSecret, ':SecretString:password}}' ]]
1544+
- Name: "MF_METADATA_DB_NAME"
1545+
Value: "metaflow"
1546+
- Name: "UI_ENABLED"
1547+
Value: "1"
1548+
Cpu: !FindInMap ["ServiceInfoUI", "ContainerCpu", "value"]
1549+
Memory: !FindInMap ["ServiceInfoUI", "ContainerMemory", "value"]
1550+
Image: !FindInMap ["ServiceInfoUI", "ImageUrl", "value"]
1551+
Command:
1552+
[
1553+
"/opt/latest/bin/python3",
1554+
"-m",
1555+
"services.ui_backend_service.ui_server",
1556+
]
1557+
PortMappings:
1558+
- ContainerPort:
1559+
!FindInMap ["ServiceInfoUI", "ContainerPort", "value"]
1560+
LogConfiguration:
1561+
LogDriver: awslogs
1562+
Options:
1563+
awslogs-group:
1564+
!Join [
1565+
"",
1566+
[
1567+
"/ecs/",
1568+
!Ref "AWS::StackName",
1569+
"-",
1570+
!FindInMap ["ServiceInfoUI", "ServiceName", "value"],
1571+
],
1572+
]
1573+
awslogs-region: !Ref "AWS::Region"
1574+
awslogs-stream-prefix: "ecs"
1575+
ServiceLogGroupUIService:
1576+
Type: AWS::Logs::LogGroup
1577+
Condition: EnableUI
1578+
Properties:
1579+
LogGroupName:
1580+
!Join [
1581+
"",
1582+
[
1583+
"/ecs/",
1584+
!Ref "AWS::StackName",
1585+
"-",
1586+
!FindInMap ["ServiceInfoUI", "ServiceName", "value"],
1587+
],
1588+
]
1589+
ECSFargateServiceUIService:
1590+
Type: AWS::ECS::Service
1591+
Condition: EnableUI
1592+
DependsOn: ALBUIListener
1593+
Properties:
1594+
ServiceName: !FindInMap ["ServiceInfoUI", "ServiceName", "value"]
1595+
Cluster: !Ref 'ECSCluster'
1596+
LaunchType: FARGATE
1597+
DeploymentConfiguration:
1598+
MaximumPercent: 200
1599+
MinimumHealthyPercent: 75
1600+
DesiredCount: !FindInMap ["ServiceInfoUI", "DesiredCount", "value"]
1601+
NetworkConfiguration:
1602+
AwsvpcConfiguration:
1603+
AssignPublicIp: ENABLED
1604+
SecurityGroups:
1605+
- !Ref FargateSecurityGroup
1606+
Subnets:
1607+
- !Ref Subnet1
1608+
- !Ref Subnet2
1609+
TaskDefinition: !Ref TaskDefinitionUIService
1610+
LoadBalancers:
1611+
- ContainerName: !FindInMap ["ServiceInfoUI", "ServiceName", "value"]
1612+
ContainerPort: !FindInMap ["ServiceInfoUI", "ContainerPort", "value"]
1613+
TargetGroupArn: !Ref ALBUITargetGroupUIService
1614+
1615+
# --- Metaflow UI resources end ---
1616+
13601617
Outputs:
13611618
MetaflowDataStoreS3Url:
13621619
Description: Amazon S3 URL for Metaflow DataStore [METAFLOW_DATASTORE_SYSROOT_S3]
@@ -1400,3 +1657,14 @@ Outputs:
14001657
MigrationFunctionName:
14011658
Description: "Name of DB Migration Function"
14021659
Value: !Ref ExecuteDBMigration
1660+
1661+
# Metaflow UI outputs
1662+
1663+
UIServiceUrl:
1664+
Description: "ALB URL for Metadata UI (Open to Public Access)"
1665+
Value: !Sub "http://${ALBUI.DNSName}/"
1666+
Condition: EnableUI
1667+
UIServiceCloudfrontUrl:
1668+
Description: "Cloudfront URL for Metadata UI (Open to Public Access)"
1669+
Value: !Sub "https://${CloudFrontDistributionUI.DomainName}/"
1670+
Condition: EnableUI

0 commit comments

Comments
 (0)