From bccb285ef872f86095bfd4d301fe0add7b40f8c1 Mon Sep 17 00:00:00 2001 From: Miguel Varela Ramos Date: Wed, 30 Dec 2020 18:55:03 +0000 Subject: [PATCH 01/20] Remove API gateway from cli and operator --- cli/cmd/cluster.go | 63 --- cli/cmd/lib_cluster_config_aws.go | 19 +- docs/clusters/aws/rest-api-gateway.md | 1 + pkg/lib/aws/apigateway.go | 373 ------------------ pkg/lib/aws/clients.go | 9 - pkg/operator/config/config.go | 29 -- pkg/operator/config/errors.go | 48 --- pkg/operator/operator/gateway.go | 173 -------- pkg/operator/operator/k8s.go | 12 +- pkg/operator/resources/batchapi/api.go | 28 -- pkg/operator/resources/errors.go | 8 - pkg/operator/resources/realtimeapi/api.go | 25 -- pkg/operator/resources/trafficsplitter/api.go | 23 -- pkg/operator/resources/validations.go | 5 - .../clusterconfig/api_gateway_setting.go | 75 ---- pkg/types/clusterconfig/cluster_config_aws.go | 31 +- pkg/types/clusterconfig/config_key.go | 2 - pkg/types/spec/validations.go | 29 -- pkg/types/userconfig/api.go | 14 - pkg/types/userconfig/api_gateway_type.go | 78 ---- pkg/types/userconfig/config_key.go | 2 - pkg/types/userconfig/errors.go | 32 -- 22 files changed, 11 insertions(+), 1068 deletions(-) delete mode 100644 pkg/lib/aws/apigateway.go delete mode 100644 pkg/operator/config/errors.go delete mode 100644 pkg/operator/operator/gateway.go delete mode 100644 pkg/types/clusterconfig/api_gateway_setting.go delete mode 100644 pkg/types/userconfig/api_gateway_type.go delete mode 100644 pkg/types/userconfig/errors.go diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 3a2f6f6e03..473879c42d 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -222,27 +222,11 @@ var _clusterUpCmd = &cobra.Command{ exit.Error(err) } - if clusterConfig.APIGatewaySetting == clusterconfig.PublicAPIGatewaySetting { - err = createOrReplaceAPIGateway(awsClient, clusterConfig.ClusterName, clusterConfig.Tags) - if err != nil { - exit.Error(err) - } - } - out, exitCode, err := runManagerWithClusterConfig("/root/install.sh", clusterConfig, awsCreds, nil, nil) if err != nil { - if clusterConfig.APIGatewaySetting == clusterconfig.PublicAPIGatewaySetting { - awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion - awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion - } exit.Error(err) } if exitCode == nil || *exitCode != 0 { - if clusterConfig.APIGatewaySetting == clusterconfig.PublicAPIGatewaySetting { - awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion - awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterConfig.ClusterName) // best effort deletion - } - eksCluster, err := awsClient.EKSClusterOrNil(clusterConfig.ClusterName) if err != nil { helpStr := "\ndebugging tips (may or may not apply to this error):" @@ -516,27 +500,6 @@ var _clusterDownCmd = &cobra.Command{ prompt.YesOrExit(fmt.Sprintf("your cluster named \"%s\" in %s will be spun down and all apis will be deleted, are you sure you want to continue?", *accessConfig.ClusterName, *accessConfig.Region), "", "") } - fmt.Print("○ deleting api gateway ") - deletedAPIGateway, errAPIGateway := awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, *accessConfig.ClusterName) - _, errVPCLink := awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, *accessConfig.ClusterName) - if errAPIGateway != nil { - fmt.Printf("\n\nunable to delete cortex's api gateway (see error below); if it still exists after the cluster has been deleted, please delete it via the api gateway console: https://%s.console.aws.amazon.com/apigateway/main/apis\n", *accessConfig.Region) - errors.PrintError(errAPIGateway) - } - if errVPCLink != nil { - fmt.Printf("\n\nunable to delete cortex's vpc link (see error below); if it still exists after the cluster has been deleted, please delete it via the api gateway console: https://%s.console.aws.amazon.com/apigateway/main/vpc-links\n", *accessConfig.Region) - errors.PrintError(errVPCLink) - } - if errAPIGateway == nil && errVPCLink == nil { - if deletedAPIGateway != nil { - fmt.Println("✓") - } else { - fmt.Println("(n/a)") - } - } else { - fmt.Println() - } - fmt.Print("○ deleting dashboard ") err = awsClient.DeleteDashboard(*accessConfig.ClusterName) if err != nil { @@ -1111,32 +1074,6 @@ func createOrClearDashboard(awsClient *aws.Client, dashboardName string) error { return nil } -// createOrReplaceAPIGateway creates an API gateway for the cluster (or clears an existing one if it already exists) -func createOrReplaceAPIGateway(awsClient *aws.Client, clusterName string, tags map[string]string) error { - fmt.Print("○ creating api gateway: ", clusterName) - - _, err := awsClient.DeleteVPCLinkByTag(clusterconfig.ClusterNameTag, clusterName) - if err != nil { - fmt.Print("\n\n") - return errors.Append(err, fmt.Sprintf("\n\nunable to delete existing vpc link with tag %s=%s; please delete it via the api gateway console: https://%s.console.aws.amazon.com/apigateway/main/vpc-links", clusterconfig.ClusterNameTag, clusterName, awsClient.Region)) - } - - _, err = awsClient.DeleteAPIGatewayByTag(clusterconfig.ClusterNameTag, clusterName) - if err != nil { - fmt.Print("\n\n") - return errors.Append(err, fmt.Sprintf("\n\nunable to delete existing api gateway with tag %s=%s; please delete it via the api gateway console: https://%s.console.aws.amazon.com/apigateway/main/apis", clusterconfig.ClusterNameTag, clusterName, awsClient.Region)) - } - - _, err = awsClient.CreateAPIGateway(clusterName, tags) - if err != nil { - fmt.Print("\n\n") - return err - } - - fmt.Println(" ✓") - return nil -} - // Will return error if load balancer can't be found func getAWSOperatorLoadBalancer(clusterName string, awsClient *aws.Client) (*elbv2.LoadBalancer, error) { loadBalancer, err := awsClient.FindLoadBalancer(map[string]string{ diff --git a/cli/cmd/lib_cluster_config_aws.go b/cli/cmd/lib_cluster_config_aws.go index 020a9648ee..3bc4a57559 100644 --- a/cli/cmd/lib_cluster_config_aws.go +++ b/cli/cmd/lib_cluster_config_aws.go @@ -333,11 +333,6 @@ func setConfigFieldsFromCached(userClusterConfig *clusterconfig.Config, cachedCl } userClusterConfig.OperatorLoadBalancerScheme = cachedClusterConfig.OperatorLoadBalancerScheme - if userClusterConfig.APIGatewaySetting != cachedClusterConfig.APIGatewaySetting { - return clusterconfig.ErrorConfigCannotBeChangedOnUpdate(clusterconfig.APIGatewaySettingKey, cachedClusterConfig.APIGatewaySetting) - } - userClusterConfig.APIGatewaySetting = cachedClusterConfig.APIGatewaySetting - if s.Obj(cachedClusterConfig.VPCCIDR) != s.Obj(userClusterConfig.VPCCIDR) { return clusterconfig.ErrorConfigCannotBeChangedOnUpdate(clusterconfig.VPCCIDRKey, cachedClusterConfig.VPCCIDR) } @@ -404,10 +399,7 @@ func setConfigFieldsFromCached(userClusterConfig *clusterconfig.Config, cachedCl userClusterConfig.Spot = cachedClusterConfig.Spot if userClusterConfig.Spot != nil && *userClusterConfig.Spot { - err := userClusterConfig.FillEmptySpotFields(awsClient) - if err != nil { - return err - } + userClusterConfig.FillEmptySpotFields() } if userClusterConfig.SpotConfig != nil && s.Obj(userClusterConfig.SpotConfig) != s.Obj(cachedClusterConfig.SpotConfig) { @@ -541,10 +533,6 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsCreds A } fmt.Printf("cortex will also create an s3 bucket (%s) and a cloudwatch log group (%s)%s\n\n", clusterConfig.Bucket, clusterConfig.ClusterName, privateSubnetMsg) - if clusterConfig.APIGatewaySetting == clusterconfig.NoneAPIGatewaySetting { - fmt.Print(fmt.Sprintf("warning: you've disabled API Gateway cluster-wide, so APIs will not be able to create API Gateway endpoints (they will still be reachable via the API load balancer; see https://docs.cortex.dev/v/%s/ for more information)\n\n", consts.CortexVersionMinor)) - } - if clusterConfig.OperatorLoadBalancerScheme == clusterconfig.InternalLoadBalancerScheme { fmt.Print(fmt.Sprintf("warning: you've configured the operator load balancer to be internal; you must configure VPC Peering to connect your CLI to your cluster operator (see https://docs.cortex.dev/v/%s/)\n\n", consts.CortexVersionMinor)) } @@ -618,16 +606,13 @@ func clusterConfigConfirmationStr(clusterConfig clusterconfig.Config, awsCreds A if clusterConfig.OperatorLoadBalancerScheme != defaultConfig.OperatorLoadBalancerScheme { items.Add(clusterconfig.OperatorLoadBalancerSchemeUserKey, clusterConfig.OperatorLoadBalancerScheme) } - if clusterConfig.APIGatewaySetting != defaultConfig.APIGatewaySetting { - items.Add(clusterconfig.APIGatewaySettingUserKey, clusterConfig.APIGatewaySetting) - } if clusterConfig.Spot != nil && *clusterConfig.Spot != *defaultConfig.Spot { items.Add(clusterconfig.SpotUserKey, s.YesNo(clusterConfig.Spot != nil && *clusterConfig.Spot)) if clusterConfig.SpotConfig != nil { defaultSpotConfig := clusterconfig.SpotConfig{} - clusterconfig.AutoGenerateSpotConfig(awsClient, &defaultSpotConfig, *clusterConfig.Region, *clusterConfig.InstanceType) + clusterconfig.AutoGenerateSpotConfig(&defaultSpotConfig, *clusterConfig.Region, *clusterConfig.InstanceType) if !strset.New(clusterConfig.SpotConfig.InstanceDistribution...).IsEqual(strset.New(defaultSpotConfig.InstanceDistribution...)) { items.Add(clusterconfig.InstanceDistributionUserKey, clusterConfig.SpotConfig.InstanceDistribution) diff --git a/docs/clusters/aws/rest-api-gateway.md b/docs/clusters/aws/rest-api-gateway.md index c5abdea21d..52d9f603b4 100644 --- a/docs/clusters/aws/rest-api-gateway.md +++ b/docs/clusters/aws/rest-api-gateway.md @@ -1,3 +1,4 @@ + # REST API Gateway When `api_gateway: public` is set in your API's `networking` configuration (which is the default setting), Cortex will create an "HTTP" API Gateway in AWS for your API (see the [networking docs](networking.md) for more information). diff --git a/pkg/lib/aws/apigateway.go b/pkg/lib/aws/apigateway.go deleted file mode 100644 index 7403fb23f4..0000000000 --- a/pkg/lib/aws/apigateway.go +++ /dev/null @@ -1,373 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package aws - -import ( - "fmt" - "strings" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/apigatewayv2" - "github.com/cortexlabs/cortex/pkg/lib/errors" -) - -// CreateAPIGateway Creates a new API Gateway with the default stage -func (c *Client) CreateAPIGateway(name string, tags map[string]string) (string, error) { - createAPIResponse, err := c.APIGatewayV2().CreateApi(&apigatewayv2.CreateApiInput{ - Name: aws.String(name), - ProtocolType: aws.String(apigatewayv2.ProtocolTypeHttp), - Tags: aws.StringMap(tags), - }) - if err != nil { - return "", errors.Wrap(err, "failed to create api gateway") - } - if createAPIResponse.ApiId == nil { - return "", errors.ErrorUnexpected("failed to create api gateway") - } - - _, err = c.APIGatewayV2().CreateStage(&apigatewayv2.CreateStageInput{ - ApiId: createAPIResponse.ApiId, - AutoDeploy: aws.Bool(true), - StageName: aws.String("$default"), - Tags: aws.StringMap(tags), - }) - if err != nil { - c.DeleteAPIGateway(*createAPIResponse.ApiId) // best effort cleanup - return "", errors.Wrap(err, "failed to create $default api gateway stage") - } - - return *createAPIResponse.ApiId, nil -} - -// GetVPCLinkByTag Gets a VPC Link by tag (returns nil if there are no matches) -func (c *Client) GetVPCLinkByTag(tagName string, tagValue string) (*apigatewayv2.VpcLink, error) { - var nextToken *string - - for { - vpcLinks, err := c.APIGatewayV2().GetVpcLinks(&apigatewayv2.GetVpcLinksInput{ - NextToken: nextToken, - }) - if err != nil { - return nil, errors.Wrap(err, "failed to get vpc links") - } - - for _, vpcLink := range vpcLinks.Items { - for tag, value := range vpcLink.Tags { - if tag == tagName && *value == tagValue { - return vpcLink, nil - } - } - } - - nextToken = vpcLinks.NextToken - if nextToken == nil { - break - } - } - - return nil, nil -} - -// GetAPIGatewayByTag Gets an API Gateway by tag (returns nil if there are no matches) -func (c *Client) GetAPIGatewayByTag(tagName string, tagValue string) (*apigatewayv2.Api, error) { - var nextToken *string - - for { - apis, err := c.APIGatewayV2().GetApis(&apigatewayv2.GetApisInput{ - NextToken: nextToken, - }) - if err != nil { - return nil, errors.Wrap(err, "failed to get api gateways") - } - - for _, api := range apis.Items { - for tag, value := range api.Tags { - if tag == tagName && *value == tagValue { - return api, nil - } - } - } - - nextToken = apis.NextToken - if nextToken == nil { - break - } - } - - return nil, nil -} - -// DeleteVPCLinkByTag Deletes a VPC Link by tag (returns the deleted VPC Link, or nil if it was not found) -func (c *Client) DeleteVPCLinkByTag(tagName string, tagValue string) (*apigatewayv2.VpcLink, error) { - vpcLink, err := c.GetVPCLinkByTag(tagName, tagValue) - if err != nil { - return nil, err - } else if vpcLink == nil { - return nil, nil - } - - _, err = c.APIGatewayV2().DeleteVpcLink(&apigatewayv2.DeleteVpcLinkInput{ - VpcLinkId: vpcLink.VpcLinkId, - }) - if err != nil { - return nil, errors.Wrap(err, "failed to delete vpc link "+*vpcLink.VpcLinkId) - } - - return vpcLink, nil -} - -// DeleteAPIGatewayByTag Deletes an API Gateway by tag (returns the deleted API Gateway, or nil if it was not found) -func (c *Client) DeleteAPIGatewayByTag(tagName string, tagValue string) (*apigatewayv2.Api, error) { - apiGateway, err := c.GetAPIGatewayByTag(tagName, tagValue) - if err != nil { - return nil, err - } else if apiGateway == nil { - return nil, nil - } - - err = c.DeleteAPIGateway(*apiGateway.ApiId) - if err != nil { - return nil, err - } - - return apiGateway, nil -} - -// DeleteAPIGateway Deletes an API Gateway by ID (returns an error if the API Gateway does not exist) -func (c *Client) DeleteAPIGateway(apiGatewayID string) error { - // Delete mappings in case user added a custom domain name (otherwise this will block API Gateway deletion) - err := c.DeleteAPIGatewayMappings(apiGatewayID) - if err != nil { - return err - } - - _, err = c.APIGatewayV2().DeleteApi(&apigatewayv2.DeleteApiInput{ - ApiId: aws.String(apiGatewayID), - }) - if err != nil { - return errors.Wrap(err, "failed to delete api gateway "+apiGatewayID) - } - - return nil -} - -// DeleteAPIGatewayMappingsForDomainName deletes all API mappings that point to the provided api gateway from the provided domain name -func (c *Client) DeleteAPIGatewayMappingsForDomainName(apiGatewayID string, domainName string) error { - var nextToken *string - - for { - apiMappings, err := c.APIGatewayV2().GetApiMappings(&apigatewayv2.GetApiMappingsInput{ - DomainName: aws.String(domainName), - NextToken: nextToken, - }) - if err != nil { - return errors.Wrap(err, "failed to get api mappings") - } - - for _, apiMapping := range apiMappings.Items { - if *apiMapping.ApiId != apiGatewayID { - continue - } - - _, err := c.APIGatewayV2().DeleteApiMapping(&apigatewayv2.DeleteApiMappingInput{ - DomainName: aws.String(domainName), - ApiMappingId: apiMapping.ApiMappingId, - }) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("failed to delete api mapping %s in domain %s", *apiMapping.ApiMappingId, domainName)) - } - } - - nextToken = apiMappings.NextToken - if nextToken == nil { - break - } - } - - return nil -} - -// DeleteAPIGatewayMappings deletes all API mappings that point to the provided api gateway -func (c *Client) DeleteAPIGatewayMappings(apiGatewayID string) error { - var nextToken *string - - for { - domainNames, err := c.APIGatewayV2().GetDomainNames(&apigatewayv2.GetDomainNamesInput{ - NextToken: nextToken, - }) - if err != nil { - return errors.Wrap(err, "failed to get domain names") - } - - for _, domainName := range domainNames.Items { - err := c.DeleteAPIGatewayMappingsForDomainName(apiGatewayID, *domainName.DomainName) - if err != nil { - return err - } - } - - nextToken = domainNames.NextToken - if nextToken == nil { - break - } - } - - return nil -} - -// GetVPCLinkIntegration gets the VPC Link integration in an API Gateway, or nil if unable to find it -func (c *Client) GetVPCLinkIntegration(apiGatewayID string, vpcLinkID string) (*apigatewayv2.Integration, error) { - var nextToken *string - - for { - integrations, err := c.APIGatewayV2().GetIntegrations(&apigatewayv2.GetIntegrationsInput{ - ApiId: &apiGatewayID, - NextToken: nextToken, - }) - if err != nil { - return nil, errors.Wrap(err, "failed to get api gateway integrations for api gateway "+apiGatewayID) - } - - // find integration which is connected to the VPC link - for _, integration := range integrations.Items { - if *integration.ConnectionId == vpcLinkID { - return integration, nil - } - } - - nextToken = integrations.NextToken - if nextToken == nil { - break - } - } - - return nil, nil -} - -// GetRouteIntegrationID returns the integration which is attached to a endpoint route, or empty string if unable to find it -func (c *Client) GetRouteIntegrationID(apiGatewayID string, endpoint string) (string, error) { - route, err := c.GetRoute(apiGatewayID, endpoint) - if err != nil { - return "", err - } - if route == nil { - return "", nil - } - - return ExtractRouteIntegrationID(route), nil -} - -// ExtractRouteIntegrationID extracts the integration ID which is attached to a route, or "" if no route is attached -func ExtractRouteIntegrationID(route *apigatewayv2.Route) string { - if route == nil || route.Target == nil { - return "" - } - - // trim of prefix of integrationID. - // Note: Integrations get attached to routes via a target of the format integrations/ - integrationID := strings.TrimPrefix(*route.Target, "integrations/") - return integrationID -} - -// GetRoute retrieves the route matching an endpoint, or nil if unable to find it -func (c *Client) GetRoute(apiGatewayID string, endpoint string) (*apigatewayv2.Route, error) { - var nextToken *string - - for { - routes, err := c.APIGatewayV2().GetRoutes(&apigatewayv2.GetRoutesInput{ - ApiId: &apiGatewayID, - NextToken: nextToken, - }) - if err != nil { - return nil, errors.Wrap(err, "failed to get api gateway routes for api gateway "+apiGatewayID) - } - - // find route which matches the endpoint - for _, route := range routes.Items { - if *route.RouteKey == "ANY "+endpoint { - return route, nil - } - } - - nextToken = routes.NextToken - if nextToken == nil { - break - } - } - - return nil, nil -} - -// CreateRoute creates a new route and attaches the route to the integration -func (c *Client) CreateRoute(apiGatewayID string, integrationID string, endpoint string) error { - _, err := c.APIGatewayV2().CreateRoute(&apigatewayv2.CreateRouteInput{ - ApiId: &apiGatewayID, - RouteKey: aws.String("ANY " + endpoint), - Target: aws.String("integrations/" + integrationID), - }) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("failed to create %s route for api gateway %s with integration %s", endpoint, apiGatewayID, integrationID)) - } - return nil -} - -// CreateHTTPIntegration creates new HTTP integration for API Gateway, returns integration ID -func (c *Client) CreateHTTPIntegration(apiGatewayID string, targetEndpoint string) (string, error) { - integrationResponse, err := c.APIGatewayV2().CreateIntegration(&apigatewayv2.CreateIntegrationInput{ - ApiId: &apiGatewayID, - IntegrationType: aws.String("HTTP_PROXY"), - IntegrationUri: &targetEndpoint, - PayloadFormatVersion: aws.String("1.0"), - IntegrationMethod: aws.String("ANY"), - }) - if err != nil { - return "", errors.Wrap(err, fmt.Sprintf("failed to create api gateway integration for endpoint %s in api gateway %s", targetEndpoint, apiGatewayID)) - } - return *integrationResponse.IntegrationId, nil -} - -// DeleteIntegration deletes an integration from API Gateway -func (c *Client) DeleteIntegration(apiGatewayID string, integrationID string) error { - _, err := c.APIGatewayV2().DeleteIntegration(&apigatewayv2.DeleteIntegrationInput{ - ApiId: &apiGatewayID, - IntegrationId: &integrationID, - }) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("failed to delete api gateway integration %s in api gateway %s", integrationID, apiGatewayID)) - } - return nil -} - -// DeleteRoute deletes a route from API Gateway, and returns the deleted route (or nil if it wasn't found) -func (c *Client) DeleteRoute(apiGatewayID string, endpoint string) (*apigatewayv2.Route, error) { - route, err := c.GetRoute(apiGatewayID, endpoint) - if err != nil { - return nil, err - } else if route == nil { - return nil, nil - } - - _, err = c.APIGatewayV2().DeleteRoute(&apigatewayv2.DeleteRouteInput{ - ApiId: &apiGatewayID, - RouteId: route.RouteId, - }) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("failed to delete api gateway route %s with endpoint %s in api gateway %s", *route.RouteId, endpoint, apiGatewayID)) - } - - return route, nil -} diff --git a/pkg/lib/aws/clients.go b/pkg/lib/aws/clients.go index 11ff04b5cc..ed03b6026c 100644 --- a/pkg/lib/aws/clients.go +++ b/pkg/lib/aws/clients.go @@ -18,7 +18,6 @@ package aws import ( "github.com/aws/aws-sdk-go/service/acm" - "github.com/aws/aws-sdk-go/service/apigatewayv2" "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/cloudformation" "github.com/aws/aws-sdk-go/service/cloudwatch" @@ -49,7 +48,6 @@ type clients struct { autoscaling *autoscaling.AutoScaling cloudWatchLogs *cloudwatchlogs.CloudWatchLogs cloudWatch *cloudwatch.CloudWatch - apiGatewayV2 *apigatewayv2.ApiGatewayV2 serviceQuotas *servicequotas.ServiceQuotas cloudFormation *cloudformation.CloudFormation iam *iam.IAM @@ -153,13 +151,6 @@ func (c *Client) CloudWatch() *cloudwatch.CloudWatch { return c.clients.cloudWatch } -func (c *Client) APIGatewayV2() *apigatewayv2.ApiGatewayV2 { - if c.clients.apiGatewayV2 == nil { - c.clients.apiGatewayV2 = apigatewayv2.New(c.sess) - } - return c.clients.apiGatewayV2 -} - func (c *Client) ServiceQuotas() *servicequotas.ServiceQuotas { if c.clients.serviceQuotas == nil { c.clients.serviceQuotas = servicequotas.New(c.sess) diff --git a/pkg/operator/config/config.go b/pkg/operator/config/config.go index 78d27194c0..85eccfd52e 100644 --- a/pkg/operator/config/config.go +++ b/pkg/operator/config/config.go @@ -34,7 +34,6 @@ import ( ) const _clusterConfigPath = "/configs/cluster/cluster.yaml" -const _clusterConfigBackupPath = "/configs/cluster-aws/cluster-aws.yaml" var ( Provider types.ProviderType @@ -84,34 +83,6 @@ func Init() error { } Cluster.OperatorID = hashedAccountID Cluster.ClusterID = hash.String(Cluster.ClusterName + *Cluster.Region + hashedAccountID) - - if Cluster.APIGatewaySetting == clusterconfig.PublicAPIGatewaySetting { - apiGateway, err := AWS.GetAPIGatewayByTag(clusterconfig.ClusterNameTag, Cluster.ClusterName) - if err != nil { - return err - } else if apiGateway == nil { - return ErrorNoAPIGateway() - } - Cluster.APIGateway = apiGateway - - if Cluster.APILoadBalancerScheme == clusterconfig.InternalLoadBalancerScheme { - vpcLink, err := AWS.GetVPCLinkByTag(clusterconfig.ClusterNameTag, Cluster.ClusterName) - if err != nil { - return err - } else if vpcLink == nil { - return ErrorNoVPCLink() - } - Cluster.VPCLink = vpcLink - - integration, err := AWS.GetVPCLinkIntegration(*Cluster.APIGateway.ApiId, *Cluster.VPCLink.VpcLinkId) - if err != nil { - return err - } else if integration == nil { - return ErrorNoVPCLinkIntegration() - } - Cluster.VPCLinkIntegration = integration - } - } } else { AWS, err = aws.NewAnonymousClient() if err != nil { diff --git a/pkg/operator/config/errors.go b/pkg/operator/config/errors.go deleted file mode 100644 index 67fc3cb35b..0000000000 --- a/pkg/operator/config/errors.go +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - "github.com/cortexlabs/cortex/pkg/lib/errors" -) - -const ( - ErrNoAPIGateway = "config.no_api_gateway" - ErrNoVPCLink = "config.no_vpc_link" - ErrNoVPCLinkIntegration = "config.no_vpc_link_integration" -) - -func ErrorNoAPIGateway() error { - return errors.WithStack(&errors.Error{ - Kind: ErrNoAPIGateway, - Message: "unable to locate cortex's api gateway", - }) -} - -func ErrorNoVPCLink() error { - return errors.WithStack(&errors.Error{ - Kind: ErrNoVPCLink, - Message: "unable to locate cortex's vpc link", - }) -} - -func ErrorNoVPCLinkIntegration() error { - return errors.WithStack(&errors.Error{ - Kind: ErrNoVPCLinkIntegration, - Message: "unable to locate cortex's api gateway vpc link integration", - }) -} diff --git a/pkg/operator/operator/gateway.go b/pkg/operator/operator/gateway.go deleted file mode 100644 index 1828da75b6..0000000000 --- a/pkg/operator/operator/gateway.go +++ /dev/null @@ -1,173 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package operator - -import ( - "github.com/cortexlabs/cortex/pkg/lib/aws" - "github.com/cortexlabs/cortex/pkg/lib/urls" - "github.com/cortexlabs/cortex/pkg/operator/config" - "github.com/cortexlabs/cortex/pkg/types/clusterconfig" - "github.com/cortexlabs/cortex/pkg/types/spec" - "github.com/cortexlabs/cortex/pkg/types/userconfig" - istioclientnetworking "istio.io/client-go/pkg/apis/networking/v1beta1" -) - -func AddAPIToAPIGateway(endpoint string, apiGatewayType userconfig.APIGatewayType) error { - if config.Cluster.APIGateway == nil { - return nil - } - - if apiGatewayType == userconfig.NoneAPIGatewayType { - return nil - } - - apiGatewayID := *config.Cluster.APIGateway.ApiId - - // check if API Gateway route already exists - existingRoute, err := config.AWS.GetRoute(apiGatewayID, endpoint) - if err != nil { - return err - } else if existingRoute != nil { - return nil - } - - if config.Cluster.APILoadBalancerScheme == clusterconfig.InternalLoadBalancerScheme { - err = config.AWS.CreateRoute(apiGatewayID, *config.Cluster.VPCLinkIntegration.IntegrationId, endpoint) - if err != nil { - return err - } - } - - if config.Cluster.APILoadBalancerScheme == clusterconfig.InternetFacingLoadBalancerScheme { - loadBalancerURL, err := APILoadBalancerURL() - if err != nil { - return err - } - - targetEndpoint := urls.Join(loadBalancerURL, endpoint) - - integrationID, err := config.AWS.CreateHTTPIntegration(apiGatewayID, targetEndpoint) - if err != nil { - return err - } - - err = config.AWS.CreateRoute(apiGatewayID, integrationID, endpoint) - if err != nil { - return err - } - } - - return nil -} - -func RemoveAPIFromAPIGateway(endpoint string, apiGatewayType userconfig.APIGatewayType) error { - if config.Cluster.APIGateway == nil { - return nil - } - - if apiGatewayType == userconfig.NoneAPIGatewayType { - return nil - } - - apiGatewayID := *config.Cluster.APIGateway.ApiId - - route, err := config.AWS.DeleteRoute(apiGatewayID, endpoint) - if err != nil { - return err - } - - if config.Cluster.APILoadBalancerScheme == clusterconfig.InternetFacingLoadBalancerScheme && route != nil { - integrationID := aws.ExtractRouteIntegrationID(route) - if integrationID != "" { - err = config.AWS.DeleteIntegration(apiGatewayID, integrationID) - if err != nil { - return err - } - } - } - - return nil -} - -func UpdateAPIGateway( - prevEndpoint string, - prevAPIGatewayType userconfig.APIGatewayType, - newEndpoint string, - newAPIGatewayType userconfig.APIGatewayType, -) error { - if config.Cluster.APIGateway == nil { - return nil - } - - if prevAPIGatewayType == userconfig.NoneAPIGatewayType && newAPIGatewayType == userconfig.NoneAPIGatewayType { - return nil - } - - if prevAPIGatewayType == userconfig.PublicAPIGatewayType && newAPIGatewayType == userconfig.NoneAPIGatewayType { - return RemoveAPIFromAPIGateway(prevEndpoint, prevAPIGatewayType) - } - - if prevAPIGatewayType == userconfig.NoneAPIGatewayType && newAPIGatewayType == userconfig.PublicAPIGatewayType { - return AddAPIToAPIGateway(newEndpoint, newAPIGatewayType) - } - - if prevEndpoint == newEndpoint { - return nil - } - - // the endpoint has changed - if err := AddAPIToAPIGateway(newEndpoint, newAPIGatewayType); err != nil { - return err - } - if err := RemoveAPIFromAPIGateway(prevEndpoint, prevAPIGatewayType); err != nil { - return err - } - - return nil -} - -func RemoveAPIFromAPIGatewayK8s(virtualService *istioclientnetworking.VirtualService) error { - if virtualService == nil { - return nil // API is not running - } - - apiGatewayType, err := userconfig.APIGatewayFromAnnotations(virtualService) - if err != nil { - return err - } - - endpoint, err := GetEndpointFromVirtualService(virtualService) - if err != nil { - return err - } - - return RemoveAPIFromAPIGateway(endpoint, apiGatewayType) -} - -func UpdateAPIGatewayK8s(prevVirtualService *istioclientnetworking.VirtualService, newAPI *spec.API) error { - prevAPIGatewayType, err := userconfig.APIGatewayFromAnnotations(prevVirtualService) - if err != nil { - return err - } - - prevEndpoint, err := GetEndpointFromVirtualService(prevVirtualService) - if err != nil { - return err - } - - return UpdateAPIGateway(prevEndpoint, prevAPIGatewayType, *newAPI.Networking.Endpoint, newAPI.Networking.APIGateway) -} diff --git a/pkg/operator/operator/k8s.go b/pkg/operator/operator/k8s.go index d0844d9537..b57d1710b3 100644 --- a/pkg/operator/operator/k8s.go +++ b/pkg/operator/operator/k8s.go @@ -930,15 +930,11 @@ func APIEndpoint(api *spec.API) (string, error) { var err error baseAPIEndpoint := "" - if config.Provider == types.AWSProviderType && api.Networking.APIGateway == userconfig.PublicAPIGatewayType && config.Cluster.APIGateway != nil { - baseAPIEndpoint = *config.Cluster.APIGateway.ApiEndpoint - } else { - baseAPIEndpoint, err = APILoadBalancerURL() - if err != nil { - return "", err - } - baseAPIEndpoint = strings.Replace(baseAPIEndpoint, "https://", "http://", 1) + baseAPIEndpoint, err = APILoadBalancerURL() + if err != nil { + return "", err } + baseAPIEndpoint = strings.Replace(baseAPIEndpoint, "https://", "http://", 1) return urls.Join(baseAPIEndpoint, *api.Networking.Endpoint), nil } diff --git a/pkg/operator/resources/batchapi/api.go b/pkg/operator/resources/batchapi/api.go index 8d3ea44a5e..9984ffecdf 100644 --- a/pkg/operator/resources/batchapi/api.go +++ b/pkg/operator/resources/batchapi/api.go @@ -58,17 +58,6 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string) (*spec.API, string, return nil, "", err } - err = operator.AddAPIToAPIGateway(*api.Networking.Endpoint, api.Networking.APIGateway) - if err != nil { - routines.RunWithPanicHandler(func() { - deleteK8sResources(api.Name) - }, false) - routines.RunWithPanicHandler(func() { - operator.RemoveAPIFromAPIGateway(*api.Networking.Endpoint, api.Networking.APIGateway) - }, false) - return nil, "", err - } - err := ensureLogGroupForAPI(api.Name) if err != nil { return nil, "", err @@ -87,10 +76,6 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string) (*spec.API, string, return nil, "", err } - if err := operator.UpdateAPIGatewayK8s(prevVirtualService, api); err != nil { - return nil, "", err - } - return api, fmt.Sprintf("updated %s", api.Resource.UserString()), nil } @@ -99,12 +84,7 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string) (*spec.API, string, func DeleteAPI(apiName string, keepCache bool) error { // best effort deletion, so don't handle error yet - virtualService, vsErr := config.K8s.GetVirtualService(operator.K8sName(apiName)) - err := parallel.RunFirstErr( - func() error { - return vsErr - }, func() error { return deleteK8sResources(apiName) }, @@ -117,14 +97,6 @@ func DeleteAPI(apiName string, keepCache bool) error { func() error { return config.AWS.DeleteQueuesWithPrefix(apiQueueNamePrefix(apiName)) }, - func() error { - err := operator.RemoveAPIFromAPIGatewayK8s(virtualService) - if err != nil { - return err - } - - return nil - }, ) if err != nil { diff --git a/pkg/operator/resources/errors.go b/pkg/operator/resources/errors.go index 4b658e7203..31f4c5ed55 100644 --- a/pkg/operator/resources/errors.go +++ b/pkg/operator/resources/errors.go @@ -35,7 +35,6 @@ const ( ErrJobIDRequired = "resources.job_id_required" ErrRealtimeAPIUsedByTrafficSplitter = "resources.realtime_api_used_by_traffic_splitter" ErrAPIsNotDeployed = "resources.apis_not_deployed" - ErrAPIGatewayDisabled = "resources.api_gateway_disabled" ) func ErrorOperationIsOnlySupportedForKind(resource operator.DeployedResource, supportedKind userconfig.Kind, supportedKinds ...userconfig.Kind) error { @@ -101,10 +100,3 @@ func ErrorAPIsNotDeployed(notDeployedAPIs []string) error { Message: message, }) } - -func ErrorAPIGatewayDisabled(apiGatewayType userconfig.APIGatewayType) error { - return errors.WithStack(&errors.Error{ - Kind: ErrAPIGatewayDisabled, - Message: fmt.Sprintf("%s is not permitted because api gateway is disabled cluster-wide (valid values are %s)", s.UserStr(apiGatewayType), s.UserStrsAnd(userconfig.APIGatewayTypeStrings())), - }) -} diff --git a/pkg/operator/resources/realtimeapi/api.go b/pkg/operator/resources/realtimeapi/api.go index ef52006798..c903f20134 100644 --- a/pkg/operator/resources/realtimeapi/api.go +++ b/pkg/operator/resources/realtimeapi/api.go @@ -75,13 +75,6 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string, force bool) (*spec.A } if config.Provider == types.AWSProviderType { - err = operator.AddAPIToAPIGateway(*api.Networking.Endpoint, api.Networking.APIGateway) - if err != nil { - routines.RunWithPanicHandler(func() { - deleteK8sResources(api.Name) - }, false) - return nil, "", err - } err = addAPIToDashboard(config.Cluster.ClusterName, api.Name) if err != nil { errors.PrintError(err) @@ -112,11 +105,6 @@ func UpdateAPI(apiConfig *userconfig.API, projectID string, force bool) (*spec.A if err := applyK8sResources(api, prevDeployment, prevService, prevVirtualService); err != nil { return nil, "", err } - if config.Provider == types.AWSProviderType { - if err := operator.UpdateAPIGatewayK8s(prevVirtualService, api); err != nil { - return nil, "", err - } - } return api, fmt.Sprintf("updating %s", api.Resource.UserString()), nil } @@ -177,13 +165,7 @@ func RefreshAPI(apiName string, force bool) (string, error) { } func DeleteAPI(apiName string, keepCache bool) error { - // best effort deletion, so don't handle error yet - virtualService, vsErr := config.K8s.GetVirtualService(operator.K8sName(apiName)) - err := parallel.RunFirstErr( - func() error { - return vsErr - }, func() error { return deleteK8sResources(apiName) }, @@ -195,13 +177,6 @@ func DeleteAPI(apiName string, keepCache bool) error { deleteBucketResources(apiName) return nil }, - // delete API from API Gateway - func() error { - if config.Provider == types.AWSProviderType { - return operator.RemoveAPIFromAPIGatewayK8s(virtualService) - } - return nil - }, // delete api from cloudwatch dashboard func() error { if config.Provider == types.AWSProviderType { diff --git a/pkg/operator/resources/trafficsplitter/api.go b/pkg/operator/resources/trafficsplitter/api.go index a4d0654cab..578d0d6723 100644 --- a/pkg/operator/resources/trafficsplitter/api.go +++ b/pkg/operator/resources/trafficsplitter/api.go @@ -51,13 +51,6 @@ func UpdateAPI(apiConfig *userconfig.API, force bool) (*spec.API, string, error) return nil, "", err } - err = operator.AddAPIToAPIGateway(*api.Networking.Endpoint, api.Networking.APIGateway) - if err != nil { - routines.RunWithPanicHandler(func() { - deleteK8sResources(api.Name) - }, false) - return nil, "", err - } return api, fmt.Sprintf("created %s", api.Resource.UserString()), nil } @@ -70,9 +63,6 @@ func UpdateAPI(apiConfig *userconfig.API, force bool) (*spec.API, string, error) return nil, "", err } - if err := operator.UpdateAPIGatewayK8s(prevVirtualService, api); err != nil { - return nil, "", err - } return api, fmt.Sprintf("updated %s", api.Resource.UserString()), nil } @@ -80,12 +70,7 @@ func UpdateAPI(apiConfig *userconfig.API, force bool) (*spec.API, string, error) } func DeleteAPI(apiName string, keepCache bool) error { - // best effort deletion, so don't handle error yet - virtualService, vsErr := config.K8s.GetVirtualService(operator.K8sName(apiName)) err := parallel.RunFirstErr( - func() error { - return vsErr - }, func() error { return deleteK8sResources(apiName) }, @@ -97,14 +82,6 @@ func DeleteAPI(apiName string, keepCache bool) error { deleteS3Resources(apiName) return nil }, - // delete API from API Gateway - func() error { - err := operator.RemoveAPIFromAPIGatewayK8s(virtualService) - if err != nil { - return err - } - return nil - }, ) if err != nil { diff --git a/pkg/operator/resources/validations.go b/pkg/operator/resources/validations.go index 1b4babd7be..a078258187 100644 --- a/pkg/operator/resources/validations.go +++ b/pkg/operator/resources/validations.go @@ -29,7 +29,6 @@ import ( "github.com/cortexlabs/cortex/pkg/operator/config" "github.com/cortexlabs/cortex/pkg/operator/operator" "github.com/cortexlabs/cortex/pkg/types" - "github.com/cortexlabs/cortex/pkg/types/clusterconfig" "github.com/cortexlabs/cortex/pkg/types/spec" "github.com/cortexlabs/cortex/pkg/types/userconfig" istioclientnetworking "istio.io/client-go/pkg/apis/networking/v1beta1" @@ -125,10 +124,6 @@ func ValidateClusterAPIs(apis []userconfig.API, projectFiles spec.ProjectFiles) return errors.Wrap(err, api.Identify()) } } - - if config.Provider == types.AWSProviderType && api.Networking.APIGateway != userconfig.NoneAPIGatewayType && config.Cluster.APIGatewaySetting == clusterconfig.NoneAPIGatewaySetting { - return errors.Wrap(ErrorAPIGatewayDisabled(api.Networking.APIGateway), api.Identify(), userconfig.NetworkingKey, userconfig.APIGatewayKey) - } } dups := spec.FindDuplicateNames(apis) diff --git a/pkg/types/clusterconfig/api_gateway_setting.go b/pkg/types/clusterconfig/api_gateway_setting.go deleted file mode 100644 index 2546bbd612..0000000000 --- a/pkg/types/clusterconfig/api_gateway_setting.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package clusterconfig - -type APIGatewaySetting int - -const ( - UnknownAPIGatewaySetting APIGatewaySetting = iota - PublicAPIGatewaySetting - NoneAPIGatewaySetting -) - -var _apiGatewaySettings = []string{ - "unknown", - "public", - "none", -} - -func APIGatewaySettingFromString(s string) APIGatewaySetting { - for i := 0; i < len(_apiGatewaySettings); i++ { - if s == _apiGatewaySettings[i] { - return APIGatewaySetting(i) - } - } - return UnknownAPIGatewaySetting -} - -func APIGatewaySettingStrings() []string { - return _apiGatewaySettings[1:] -} - -func (t APIGatewaySetting) String() string { - return _apiGatewaySettings[t] -} - -// MarshalText satisfies TextMarshaler -func (t APIGatewaySetting) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -// UnmarshalText satisfies TextUnmarshaler -func (t *APIGatewaySetting) UnmarshalText(text []byte) error { - enum := string(text) - for i := 0; i < len(_apiGatewaySettings); i++ { - if enum == _apiGatewaySettings[i] { - *t = APIGatewaySetting(i) - return nil - } - } - - *t = UnknownAPIGatewaySetting - return nil -} - -// UnmarshalBinary satisfies BinaryUnmarshaler -// Needed for msgpack -func (t *APIGatewaySetting) UnmarshalBinary(data []byte) error { - return t.UnmarshalText(data) -} - -// MarshalBinary satisfies BinaryMarshaler -func (t APIGatewaySetting) MarshalBinary() ([]byte, error) { - return []byte(t.String()), nil -} diff --git a/pkg/types/clusterconfig/cluster_config_aws.go b/pkg/types/clusterconfig/cluster_config_aws.go index b262b9253b..885cd78fb2 100644 --- a/pkg/types/clusterconfig/cluster_config_aws.go +++ b/pkg/types/clusterconfig/cluster_config_aws.go @@ -26,7 +26,6 @@ import ( "strings" "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/apigatewayv2" "github.com/cortexlabs/cortex/pkg/consts" "github.com/cortexlabs/cortex/pkg/lib/aws" cr "github.com/cortexlabs/cortex/pkg/lib/configreader" @@ -72,7 +71,6 @@ type Config struct { NATGateway NATGateway `json:"nat_gateway" yaml:"nat_gateway"` APILoadBalancerScheme LoadBalancerScheme `json:"api_load_balancer_scheme" yaml:"api_load_balancer_scheme"` OperatorLoadBalancerScheme LoadBalancerScheme `json:"operator_load_balancer_scheme" yaml:"operator_load_balancer_scheme"` - APIGatewaySetting APIGatewaySetting `json:"api_gateway" yaml:"api_gateway"` VPCCIDR *string `json:"vpc_cidr,omitempty" yaml:"vpc_cidr,omitempty"` Telemetry bool `json:"telemetry" yaml:"telemetry"` ImageOperator string `json:"image_operator" yaml:"image_operator"` @@ -108,9 +106,6 @@ type InternalConfig struct { ClusterID string `json:"cluster_id"` IsOperatorInCluster bool `json:"is_operator_in_cluster"` InstanceMetadata aws.InstanceMetadata `json:"instance_metadata"` - APIGateway *apigatewayv2.Api `json:"api_gateway"` - VPCLink *apigatewayv2.VpcLink `json:"vpc_link"` - VPCLinkIntegration *apigatewayv2.Integration `json:"vpc_link_integration"` } // The bare minimum to identify a cluster @@ -344,16 +339,6 @@ var UserValidation = &cr.StructValidation{ return LoadBalancerSchemeFromString(str), nil }, }, - { - StructField: "APIGatewaySetting", - StringValidation: &cr.StringValidation{ - AllowedValues: APIGatewaySettingStrings(), - Default: PublicAPIGatewaySetting.String(), - }, - Parser: func(str string) (interface{}, error) { - return APIGatewaySettingFromString(str), nil - }, - }, { StructField: "VPCCIDR", StringPtrValidation: &cr.StringPtrValidation{ @@ -617,7 +602,7 @@ func (cc *Config) Validate(awsClient *aws.Client) error { } if cc.Spot != nil && *cc.Spot { - cc.FillEmptySpotFields(awsClient) + cc.FillEmptySpotFields() primaryInstance := aws.InstanceMetadatas[*cc.Region][primaryInstanceType] @@ -740,7 +725,7 @@ func CheckSpotInstancePriceCompatibility(target aws.InstanceMetadata, suggested return nil } -func AutoGenerateSpotConfig(awsClient *aws.Client, spotConfig *SpotConfig, region string, instanceType string) error { +func AutoGenerateSpotConfig(spotConfig *SpotConfig, region string, instanceType string) { primaryInstance := aws.InstanceMetadatas[region][instanceType] cleanedDistribution := []string{instanceType} for _, spotInstance := range spotConfig.InstanceDistribution { @@ -773,19 +758,13 @@ func AutoGenerateSpotConfig(awsClient *aws.Client, spotConfig *SpotConfig, regio spotConfig.InstancePools = pointer.Int64(int64(_maxInstancePools)) } } - - return nil } -func (cc *Config) FillEmptySpotFields(awsClient *aws.Client) error { +func (cc *Config) FillEmptySpotFields() { if cc.SpotConfig == nil { cc.SpotConfig = &SpotConfig{} } - err := AutoGenerateSpotConfig(awsClient, cc.SpotConfig, *cc.Region, *cc.InstanceType) - if err != nil { - return err - } - return nil + AutoGenerateSpotConfig(cc.SpotConfig, *cc.Region, *cc.InstanceType) } func applyPromptDefaults(defaults Config) *Config { @@ -1141,7 +1120,6 @@ func (cc *Config) UserTable() table.KeyValuePairs { items.Add(NATGatewayUserKey, cc.NATGateway) items.Add(APILoadBalancerSchemeUserKey, cc.APILoadBalancerScheme) items.Add(OperatorLoadBalancerSchemeUserKey, cc.OperatorLoadBalancerScheme) - items.Add(APIGatewaySettingUserKey, cc.APIGatewaySetting) if cc.VPCCIDR != nil { items.Add(VPCCIDRKey, *cc.VPCCIDR) } @@ -1216,7 +1194,6 @@ func (cc *Config) TelemetryEvent() map[string]interface{} { event["nat_gateway"] = cc.NATGateway event["api_load_balancer_scheme"] = cc.APILoadBalancerScheme event["operator_load_balancer_scheme"] = cc.OperatorLoadBalancerScheme - event["api_gateway"] = cc.APIGatewaySetting if cc.VPCCIDR != nil { event["vpc_cidr._is_defined"] = true } diff --git a/pkg/types/clusterconfig/config_key.go b/pkg/types/clusterconfig/config_key.go index 3936ab11c2..48bfb8c45c 100644 --- a/pkg/types/clusterconfig/config_key.go +++ b/pkg/types/clusterconfig/config_key.go @@ -45,7 +45,6 @@ const ( NATGatewayKey = "nat_gateway" APILoadBalancerSchemeKey = "api_load_balancer_scheme" OperatorLoadBalancerSchemeKey = "operator_load_balancer_scheme" - APIGatewaySettingKey = "api_gateway" VPCCIDRKey = "vpc_cidr" TelemetryKey = "telemetry" ImageOperatorKey = "image_operator" @@ -92,7 +91,6 @@ const ( NATGatewayUserKey = "nat gateway" APILoadBalancerSchemeUserKey = "api load balancer scheme" OperatorLoadBalancerSchemeUserKey = "operator load balancer scheme" - APIGatewaySettingUserKey = "api gateway" VPCCIDRUserKey = "vpc cidr" TelemetryUserKey = "telemetry" ImageOperatorUserKey = "operator image" diff --git a/pkg/types/spec/validations.go b/pkg/types/spec/validations.go index 94d923edea..e637211b81 100644 --- a/pkg/types/spec/validations.go +++ b/pkg/types/spec/validations.go @@ -292,35 +292,6 @@ func networkingValidation( }, } - if provider == types.AWSProviderType || provider == types.LocalProviderType { - defaultAPIGatewayType := userconfig.PublicAPIGatewayType - if awsClusterConfig != nil && awsClusterConfig.APIGatewaySetting == clusterconfig.NoneAPIGatewaySetting { - defaultAPIGatewayType = userconfig.NoneAPIGatewayType - } - - structFieldValidation = append(structFieldValidation, &cr.StructFieldValidation{ - StructField: "APIGateway", - StringValidation: &cr.StringValidation{ - AllowedValues: userconfig.APIGatewayTypeStrings(), - Default: defaultAPIGatewayType.String(), - }, - Parser: func(str string) (interface{}, error) { - return userconfig.APIGatewayTypeFromString(str), nil - }, - }) - } else { - structFieldValidation = append(structFieldValidation, &cr.StructFieldValidation{ - StructField: "APIGateway", - StringValidation: &cr.StringValidation{ - CantBeSpecifiedErrStr: pointer.String("only supported on AWS clusters"), - Default: userconfig.NoneAPIGatewayType.String(), - }, - Parser: func(str string) (interface{}, error) { - return userconfig.APIGatewayTypeFromString(str), nil - }, - }) - } - if kind == userconfig.RealtimeAPIKind { structFieldValidation = append(structFieldValidation, &cr.StructFieldValidation{ StructField: "LocalPort", diff --git a/pkg/types/userconfig/api.go b/pkg/types/userconfig/api.go index adaef3859b..61cfc9edca 100644 --- a/pkg/types/userconfig/api.go +++ b/pkg/types/userconfig/api.go @@ -95,7 +95,6 @@ type ServerSideBatching struct { type Networking struct { Endpoint *string `json:"endpoint" yaml:"endpoint"` LocalPort *int `json:"local_port" yaml:"local_port"` - APIGateway APIGatewayType `json:"api_gateway" yaml:"api_gateway"` } type Compute struct { @@ -206,7 +205,6 @@ func (api *API) ToK8sAnnotations() map[string]string { if api.Networking != nil { annotations[EndpointAnnotationKey] = *api.Networking.Endpoint - annotations[APIGatewayAnnotationKey] = api.Networking.APIGateway.String() } if api.Autoscaling != nil { @@ -225,14 +223,6 @@ func (api *API) ToK8sAnnotations() map[string]string { return annotations } -func APIGatewayFromAnnotations(k8sObj kmeta.Object) (APIGatewayType, error) { - apiGatewayType := APIGatewayTypeFromString(k8sObj.GetAnnotations()[APIGatewayAnnotationKey]) - if apiGatewayType == UnknownAPIGatewayType { - return UnknownAPIGatewayType, ErrorUnknownAPIGatewayType() - } - return apiGatewayType, nil -} - func AutoscalingFromAnnotations(k8sObj kmeta.Object) (*Autoscaling, error) { a := Autoscaling{} @@ -467,9 +457,6 @@ func (networking *Networking) UserStr(provider types.ProviderType) string { if provider != types.LocalProviderType && networking.Endpoint != nil { sb.WriteString(fmt.Sprintf("%s: %s\n", EndpointKey, *networking.Endpoint)) } - if provider == types.AWSProviderType { - sb.WriteString(fmt.Sprintf("%s: %s\n", APIGatewayKey, networking.APIGateway)) - } return sb.String() } @@ -601,7 +588,6 @@ func (api *API) TelemetryEvent(provider types.ProviderType) map[string]interface if api.Networking != nil { event["networking._is_defined"] = true - event["networking.api_gateway"] = api.Networking.APIGateway if api.Networking.Endpoint != nil { event["networking.endpoint._is_defined"] = true if urls.CanonicalizeEndpoint(api.Name) != *api.Networking.Endpoint { diff --git a/pkg/types/userconfig/api_gateway_type.go b/pkg/types/userconfig/api_gateway_type.go deleted file mode 100644 index 6b3cdacf29..0000000000 --- a/pkg/types/userconfig/api_gateway_type.go +++ /dev/null @@ -1,78 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package userconfig - -type APIGatewayType int - -const ( - UnknownAPIGatewayType APIGatewayType = iota - PublicAPIGatewayType - NoneAPIGatewayType -) - -var _apiGatewayTypes = []string{ - "unknown", - "public", - "none", -} - -func APIGatewayTypeFromString(s string) APIGatewayType { - for i := 0; i < len(_apiGatewayTypes); i++ { - if s == _apiGatewayTypes[i] { - return APIGatewayType(i) - } - } - return UnknownAPIGatewayType -} - -func APIGatewayTypeStrings() []string { - return _apiGatewayTypes[1:] -} - -func (t APIGatewayType) String() string { - return _apiGatewayTypes[t] -} - -// MarshalText satisfies TextMarshaler -func (t APIGatewayType) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -// UnmarshalText satisfies TextUnmarshaler -func (t *APIGatewayType) UnmarshalText(text []byte) error { - enum := string(text) - for i := 0; i < len(_apiGatewayTypes); i++ { - if enum == _apiGatewayTypes[i] { - *t = APIGatewayType(i) - return nil - } - } - - *t = UnknownAPIGatewayType - return nil -} - -// UnmarshalBinary satisfies BinaryUnmarshaler -// Needed for msgpack -func (t *APIGatewayType) UnmarshalBinary(data []byte) error { - return t.UnmarshalText(data) -} - -// MarshalBinary satisfies BinaryMarshaler -func (t APIGatewayType) MarshalBinary() ([]byte, error) { - return []byte(t.String()), nil -} diff --git a/pkg/types/userconfig/config_key.go b/pkg/types/userconfig/config_key.go index 1b36325511..7b25c49fbb 100644 --- a/pkg/types/userconfig/config_key.go +++ b/pkg/types/userconfig/config_key.go @@ -68,7 +68,6 @@ const ( ModelTypeKey = "model_type" // Networking - APIGatewayKey = "api_gateway" EndpointKey = "endpoint" LocalPortKey = "local_port" @@ -98,7 +97,6 @@ const ( // K8s annotation EndpointAnnotationKey = "networking.cortex.dev/endpoint" - APIGatewayAnnotationKey = "networking.cortex.dev/api-gateway" ProcessesPerReplicaAnnotationKey = "predictor.cortex.dev/processes-per-replica" ThreadsPerProcessAnnotationKey = "predictor.cortex.dev/threads-per-process" MinReplicasAnnotationKey = "autoscaling.cortex.dev/min-replicas" diff --git a/pkg/types/userconfig/errors.go b/pkg/types/userconfig/errors.go deleted file mode 100644 index ae752120a8..0000000000 --- a/pkg/types/userconfig/errors.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2020 Cortex Labs, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package userconfig - -import ( - "github.com/cortexlabs/cortex/pkg/lib/errors" -) - -const ( - ErrUnknownAPIGatewayType = "userconfig.unknown_api_gateway_type" -) - -func ErrorUnknownAPIGatewayType() error { - return errors.WithStack(&errors.Error{ - Kind: ErrUnknownAPIGatewayType, - Message: "unknown api gateway type", - }) -} From d532f3dc61315e0d71e8ba458350ad4961a2bd72 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Thu, 31 Dec 2020 08:15:00 -0800 Subject: [PATCH 02/20] Update networking.md --- docs/clusters/aws/networking.md | 117 +------------------------------- 1 file changed, 3 insertions(+), 114 deletions(-) diff --git a/docs/clusters/aws/networking.md b/docs/clusters/aws/networking.md index 1f694d1dfd..6df37935ce 100644 --- a/docs/clusters/aws/networking.md +++ b/docs/clusters/aws/networking.md @@ -1,118 +1,7 @@ # Networking -![api architecture diagram](https://user-images.githubusercontent.com/808475/84695323-8507dd00-aeff-11ea-8b32-5a55cef76c79.png) +![api architecture diagram](https://user-images.githubusercontent.com/808475/103417256-dd6e9700-4b3e-11eb-901e-90425f1f8fd4.png) -APIs are deployed with a public API Gateway by default (the API Gateway forwards requests to the API load balancer). Each API can be independently configured to not create the API Gateway endpoint by setting `api_gateway: none` in the `networking` field of the Realtime API configuration and Batch API configuration. If the API Gateway endpoint is not created, your API can still be accessed via the API load balancer; `cortex get API_NAME` will show the load balancer endpoint if API Gateway is disabled. API Gateway is enabled by default, and is generally recommended unless it doesn't support your use case due to limitations such as the 29 second request timeout, or if you are keeping your APIs private to your VPC. See below for common configurations. To disable API Gateway cluster-wide (thereby enforcing that all APIs cannot create API Gateway endpoints), set `api_gateway: none` in your [cluster configuration](install.md) file (before creating your cluster). +All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your [cluster configuration](install.md) file (before creating your cluster). This will make your API only accessible through VPC Peering. -By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your [cluster configuration](install.md) file (before creating your cluster). This will force external traffic to go through your API Gateway endpoint, or if you disabled API Gateway for your API, it will make your API only accessible through VPC Peering. Note that if API Gateway is used, endpoints will be public regardless of `api_load_balancer_scheme`. See below for common configurations. - -The API Gateway that Cortex creates in AWS is the "HTTP" type. If you need to use AWS's "REST" API Gateway, see [here](rest-api-gateway.md). - -## Common API networking configurations - -### Public https endpoint (with API Gateway) - -This is the most common configuration for public APIs. [Custom domains](custom-domain.md) can be used with this setup, but are not required. - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internal -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: public # this is the default, so can be omitted -``` - -### Private https endpoint - -You can configure your API to be private. If you do this, you must use [VPC Peering](vpc-peering.md) to connect to your APIs. - -The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests (e.g. `curl -k`). Alternatively, you can set up a [custom domain](custom-domain.md), which will use ACM to provision SSL certs for your domain. - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internal # this is the default, so can be omitted - -# use this to configure a custom domain -# if you don't use a custom domain, clients will need to skip certificate verification when making HTTPS requests (e.g. `curl -k`) -ssl_certificate_arn: arn:aws:acm:us-west-2:***:certificate/*** -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: none -``` - -### Private http endpoint - -You can configure your API to be private. If you do this, you must use [VPC Peering](vpc-peering.md) to connect to your APIs. - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internal # this is the default, so can be omitted -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: none -``` - -### Public https endpoint (without API Gateway) - -API gateway is generally recommended for public https APIs, but there may be a situation where you don't wish to use it (e.g. requests take longer than 29 seconds to complete, which is the max for API Gateway). In this case, clients can connect directly to the API load balancer. - -The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests (e.g. `curl -k`). Alternatively, you can set up a [custom domain](custom-domain.md), which will use ACM to provision SSL certs for your domain. - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internet-facing # this is the default, so can be omitted - -# use this to configure a custom domain -# if you don't use a custom domain, clients will need to skip certificate verification when making HTTPS requests (e.g. `curl -k`) -ssl_certificate_arn: arn:aws:acm:us-west-2:***:certificate/*** -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: none -``` - -### Public http endpoint - -If you don't wish to use https for your public API, you can simply disable API gateway (your API will be accessed directly via the API load balancer): - -```yaml -# cluster.yaml - -api_load_balancer_scheme: internet-facing # this is the default, so can be omitted -``` - -```yaml -# cortex.yaml - -- name: my-api - ... - networking: - api_gateway: none -``` +The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to make HTTP requests or skip certificate verification when making HTTPS requests (e.g. `curl -k`). Alternatively, you can enable HTTPS by using a custom domain or by creating an API Gateway to forward requests to your API load balancer. From 56be2b1422b2d2c711d6a305add6f8539fa58787 Mon Sep 17 00:00:00 2001 From: Miguel Varela Ramos Date: Thu, 31 Dec 2020 18:28:12 +0000 Subject: [PATCH 03/20] WIP: API Gateway removal from docs --- docs/clusters/aws/install.md | 3 - .../networking/custom_domain/api-gateway.md | 3 + .../aws/networking/custom_domain/dns.md | 68 +++++++++ .../aws/networking/custom_domain/index.md | 15 ++ .../custom_domain/original.md} | 0 .../https/api-gateway.md} | 57 +++----- docs/clusters/aws/networking/https/index.md | 5 + .../aws/networking/https/load-balancer.md | 134 ++++++++++++++++++ .../{networking.md => networking/index.md} | 8 +- .../aws/{ => networking}/vpc-peering.md | 0 docs/clusters/aws/security.md | 4 +- docs/clusters/aws/uninstall.md | 2 +- docs/summary.md | 12 +- docs/workloads/realtime/configuration.md | 3 - 14 files changed, 264 insertions(+), 50 deletions(-) create mode 100644 docs/clusters/aws/networking/custom_domain/api-gateway.md create mode 100644 docs/clusters/aws/networking/custom_domain/dns.md create mode 100644 docs/clusters/aws/networking/custom_domain/index.md rename docs/clusters/aws/{custom-domain.md => networking/custom_domain/original.md} (100%) rename docs/clusters/aws/{rest-api-gateway.md => networking/https/api-gateway.md} (84%) create mode 100644 docs/clusters/aws/networking/https/index.md create mode 100644 docs/clusters/aws/networking/https/load-balancer.md rename docs/clusters/aws/{networking.md => networking/index.md} (73%) rename docs/clusters/aws/{ => networking}/vpc-peering.md (100%) diff --git a/docs/clusters/aws/install.md b/docs/clusters/aws/install.md index 904f2c8810..cb1854c5ec 100644 --- a/docs/clusters/aws/install.md +++ b/docs/clusters/aws/install.md @@ -61,9 +61,6 @@ api_load_balancer_scheme: internet-facing # note: if using "internal", you must configure VPC Peering to connect your CLI to your cluster operator operator_load_balancer_scheme: internet-facing -# API Gateway [public (API Gateway will be used by default, can be disabled per API) | none (API Gateway will be disabled for all APIs)] -api_gateway: public - # additional tags to assign to AWS resources (all resources will automatically be tagged with cortex.dev/cluster-name: ) tags: # : map of key/value pairs diff --git a/docs/clusters/aws/networking/custom_domain/api-gateway.md b/docs/clusters/aws/networking/custom_domain/api-gateway.md new file mode 100644 index 0000000000..5a82f630cd --- /dev/null +++ b/docs/clusters/aws/networking/custom_domain/api-gateway.md @@ -0,0 +1,3 @@ +# Custom Domain with API Gateway + +TODO diff --git a/docs/clusters/aws/networking/custom_domain/dns.md b/docs/clusters/aws/networking/custom_domain/dns.md new file mode 100644 index 0000000000..01570cf596 --- /dev/null +++ b/docs/clusters/aws/networking/custom_domain/dns.md @@ -0,0 +1,68 @@ +# Custom Domain Without API Gateway + +## Configure Domain Name Servers (DNS) + +### Step 1 + +Decide on a subdomain that you want to dedicate to Cortex APIs. For example if your domain is `example.com`, a valid subdomain can be `api.example.com`. + +This guide will use `cortexlabs.dev` as the example domain and `api.cortexlabs.dev` as the subdomain. + +### Step 2 + +We will set up a hosted zone on Route 53 to manage the DNS records for the subdomain. Go to the [Route 53 console](https://console.aws.amazon.com/route53/home) and click "Hosted Zones". + +![step 2](https://user-images.githubusercontent.com/4365343/82210754-a6b07d00-98dd-11ea-9cec-9f6b07282aa8.png) + +### Step 3 + +Click "Create Hosted Zone" and then enter your subdomain as the domain name for your hosted zone and click "Create". + +![step 3](https://user-images.githubusercontent.com/4365343/82211091-4968fb80-98de-11ea-8ec4-8d26d1aea77a.png) + +### Step 4 + +Take note of the values in the NS record. + +![step 4](https://user-images.githubusercontent.com/4365343/82211656-386cba00-98df-11ea-8c86-4961082b5f49.png) + +### Step 5 + +Navigate to your root DNS service provider (e.g. Google Domains, AWS Route 53, Go Daddy). Your root DNS service provider is typically the registrar where you purchased your domain (unless you have transferred DNS management elsewhere). The procedure for adding DNS records may vary based on your service provider. + +We are going to add an NS (name server) record that specifies that any traffic to your subdomain should use the name servers of your hosted zone in Route 53 for DNS resolution. + +`cortexlabs.dev` is managed by Google Domains. The image below is a screenshot for adding a DNS record in Google Domains (your UI may differ based on your DNS service provider). + +![step 5](https://user-images.githubusercontent.com/4365343/82211959-bcbf3d00-98df-11ea-834d-692b3bcf9332.png) + +## Add the Load Balancer to the DNS Records + +### Step 1 + +Navigate to your [EC2 Load Balancer console](https://us-west-2.console.aws.amazon.com/ec2/v2/home#LoadBalancers:sort=loadBalancerName) and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag. + +Take note of the load balancer's name. + +![step 2](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) + +### Step 2 + +Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API load balancer (leave "Name" blank). + +![step 3](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) + +## Using your new endpoint + +Wait a few minutes to allow the DNS changes to propagate. You may now use your subdomain in place of your API load balancer endpoint in your client. For example, this curl request: + +```bash +curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/text-generator -X POST -H "Content-Type: application/json" -d @sample.json +``` + +Would become: + +```bash +# replace load balancer url with your subdomain +curl http://api.cortexlabs.dev/text-generator -X POST -H "Content-Type: application/json" -d @sample.json +``` diff --git a/docs/clusters/aws/networking/custom_domain/index.md b/docs/clusters/aws/networking/custom_domain/index.md new file mode 100644 index 0000000000..11c479908a --- /dev/null +++ b/docs/clusters/aws/networking/custom_domain/index.md @@ -0,0 +1,15 @@ +# Custom Domain + +You can use any custom domain (that you own) for your prediction endpoints. +For example, you can make your API accessible via `api.example.com/text-generator`. +This guide will demonstrate how to create a dedicated subdomain in +AWS Route 53 and use an SSL certificate provisioned by AWS Certificate Manager (ACM). + +There are two methods for achieving this, and which method to use depends on whether you're +using API Gateway or not (without API Gateway, requests are sent directly to the API +load balancer instead). API Gateway needs to be setup first in order + +Follow one of the guides below to setup a custom domain for your API: + +- [Without API Gateway](dns.md) +- [With API Gateway](api-gateway.md) diff --git a/docs/clusters/aws/custom-domain.md b/docs/clusters/aws/networking/custom_domain/original.md similarity index 100% rename from docs/clusters/aws/custom-domain.md rename to docs/clusters/aws/networking/custom_domain/original.md diff --git a/docs/clusters/aws/rest-api-gateway.md b/docs/clusters/aws/networking/https/api-gateway.md similarity index 84% rename from docs/clusters/aws/rest-api-gateway.md rename to docs/clusters/aws/networking/https/api-gateway.md index 52d9f603b4..738af2313c 100644 --- a/docs/clusters/aws/rest-api-gateway.md +++ b/docs/clusters/aws/networking/https/api-gateway.md @@ -1,9 +1,8 @@ -# REST API Gateway +# Setting up HTTP with API Gateway -When `api_gateway: public` is set in your API's `networking` configuration (which is the default setting), Cortex will create an "HTTP" API Gateway in AWS for your API (see the [networking docs](networking.md) for more information). - -However, there may be situations where you need to use AWS's "REST" API Gateway, e.g. to enforce IAM-based auth. Until [#1197](https://github.com/cortexlabs/cortex/issues/1197) is resolved, a REST API Gateway can be used by following these steps. +There may be situations where you need to use AWS's "REST" API Gateway, e.g. to enforce IAM-based auth. +This guide covers setting up HTTPS with AWS's "REST" API Gateway. If your API load balancer is internet-facing (which is the default, or you explicitly set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster), use the [first section](#if-your-api-load-balancer-is-internet-facing) of this guide. @@ -13,36 +12,29 @@ If your API load balancer is internal (i.e. you set `api_load_balancer_scheme: i ### Step 1 -Disable the default API Gateway: - -* If you haven't created your cluster yet, you can set `api_gateway: none` in your cluster configuration file before creating your cluster. -* If you have already created your cluster, you can set `api_gateway: none` in the `networking` field of your Realtime API configuration and/or Batch API configuration, and then re-deploy your API. - -### Step 2 - Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build" ![step 1](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) -### Step 3 +### Step 2 Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API" ![step 2](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) -### Step 4 +### Step 3 Select "Actions" > "Create Resource" ![step 3](https://user-images.githubusercontent.com/808475/80154502-8b6b7f80-8574-11ea-9c78-7d9f277bf55b.png) -### Step 5 +### Step 4 Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" ![step 4](https://user-images.githubusercontent.com/808475/80154565-ad650200-8574-11ea-8753-808cd35902e2.png) -### Step 6 +### Step 5 Select "HTTP Proxy" and set "Endpoint URL" to "http:///{proxy}". You can get your base API endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a9eaf69fd125947abb1065f62de59047-81cdebc0275f7d96.elb.us-west-2.amazonaws.com/{proxy}`. @@ -50,19 +42,19 @@ Leave "Content Handling" set to "Passthrough" and Click "Save". ![step 5](https://user-images.githubusercontent.com/808475/80154735-13ea2000-8575-11ea-83ca-58f182df83c6.png) -### Step 7 +### Step 6 Select "Actions" > "Deploy API" ![step 6](https://user-images.githubusercontent.com/808475/80154802-2c5a3a80-8575-11ea-9ab3-de89885fd658.png) -### Step 8 +### Step 7 Create a new stage (e.g. "dev") and click "Deploy" ![step 7](https://user-images.githubusercontent.com/808475/80154859-4431be80-8575-11ea-9305-50384b1f9847.png) -### Step 9 +### Step 8 Copy your "Invoke URL" @@ -92,80 +84,73 @@ Delete the API Gateway before spinning down your Cortex cluster: ### Step 1 -Disable the default API Gateway: - -* If you haven't created your cluster yet, you can set `api_gateway: none` in your cluster configuration file before creating your cluster. -* If you have already created your cluster, you can set `api_gateway: none` in the `networking` field of your Realtime API configuration and/or Batch API configuration, and then re-deploy your API. - -### Step 2 - Navigate to AWS's EC2 Load Balancer dashboard and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag: ![step 1](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) Take note of the load balancer's name. -### Step 3 +### Step 2 Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), click "VPC Links" on the left sidebar, and click "Create" ![step 2](https://user-images.githubusercontent.com/808475/80142466-0c6c4c00-8560-11ea-8293-eb5e5572b797.png) -### Step 4 +### Step 3 Select "VPC link for REST APIs", name your VPC link (e.g. "cortex"), select the API load balancer (identified in Step 1), and click "Create" ![step 3](https://user-images.githubusercontent.com/808475/80143027-03c84580-8561-11ea-92de-9ed0a5dfa593.png) -### Step 5 +### Step 4 Wait for the VPC link to be created (it will take a few minutes) ![step 4](https://user-images.githubusercontent.com/808475/80144088-bbaa2280-8562-11ea-901b-8520eb253df7.png) -### Step 6 +### Step 5 Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build" ![step 5](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) -### Step 7 +### Step 6 Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API" ![step 6](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) -### Step 8 +### Step 7 Select "Actions" > "Create Resource" ![step 7](https://user-images.githubusercontent.com/808475/80141938-3cffb600-855f-11ea-9c1c-132ca4503b7a.png) -### Step 9 +### Step 8 Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" ![step 8](https://user-images.githubusercontent.com/808475/80142124-80f2bb00-855f-11ea-8e4e-9413146e0815.png) -### Step 10 +### Step 9 Select "VPC Link", select "Use Proxy Integration", choose your newly-created VPC Link, and set "Endpoint URL" to "http:///{proxy}". You can get your base API endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/{proxy}`. Click "Save" ![step 9](https://user-images.githubusercontent.com/808475/80147407-4f322200-8568-11ea-8ef5-df5164c1375f.png) -### Step 11 +### Step 10 Select "Actions" > "Deploy API" ![step 10](https://user-images.githubusercontent.com/808475/80147555-86083800-8568-11ea-86af-1b1e38c9d322.png) -### Step 12 +### Step 11 Create a new stage (e.g. "dev") and click "Deploy" ![step 11](https://user-images.githubusercontent.com/808475/80147631-a7692400-8568-11ea-8a09-13dbd50b17b9.png) -### Step 13 +### Step 12 Copy your "Invoke URL" diff --git a/docs/clusters/aws/networking/https/index.md b/docs/clusters/aws/networking/https/index.md new file mode 100644 index 0000000000..ccb102e1f2 --- /dev/null +++ b/docs/clusters/aws/networking/https/index.md @@ -0,0 +1,5 @@ +# Setting up HTTPS + +In order to set up HTTPS for you API you can choose one of the following options: +- [Setting up HTTPS through the load balancer](load-balancer.md) +- [Setting up HTTPS with AWS's API Gateway](api-gateway.md) diff --git a/docs/clusters/aws/networking/https/load-balancer.md b/docs/clusters/aws/networking/https/load-balancer.md new file mode 100644 index 0000000000..7b9066a0e4 --- /dev/null +++ b/docs/clusters/aws/networking/https/load-balancer.md @@ -0,0 +1,134 @@ +# Setting up HTTPS through the load balancer + +This guide assumes you have a custom domain assigned to your API. If you haven't set up custom domain yet, please follow this [guide](../custom_domain/dns.md). + +## Generate a certificate for your domain + +### Step 1 + +We are going to create an SSL certificate for your subdomain. Go to the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home) and click "Get Started" under the "Provision certificates" section. + +![step 6](https://user-images.githubusercontent.com/4365343/82202340-c04ac800-98cf-11ea-9472-89dd6d67eb0d.png) + +### Step 2 + +Select "Request a public certificate" and then "Request a certificate". + +![step 7](https://user-images.githubusercontent.com/4365343/82202654-3e0ed380-98d0-11ea-8c57-025f0b69c54f.png) + +### Step 3 + +Enter your subdomain and then click "Next". + +![step 8](https://user-images.githubusercontent.com/4365343/82224652-1cbedf00-98f2-11ea-912b-466cee2f6e25.png) + +### Step 4 + +Select "DNS validation" and then click "Next". + +![step 9](https://user-images.githubusercontent.com/4365343/82205311-66003600-98d4-11ea-90e3-da7e8b0b2b9c.png) + +### Step 5 + +Add tags for searchability (optional) then click "Review". + +![step 10](https://user-images.githubusercontent.com/4365343/82206485-52ee6580-98d6-11ea-95a9-1d0ebafc178a.png) + +### Step 6 + +Click "Confirm and request". + +![step 11](https://user-images.githubusercontent.com/4365343/82206602-84ffc780-98d6-11ea-9f2f-ce383404ec67.png) + +### Step 7 + +Click "Create record in Route 53". A popup will appear indicating that a Record is going to be added to Route 53. Click "Create" to automatically add the DNS record to your subdomain's hosted zone. Then click "Continue". + +![step 12](https://user-images.githubusercontent.com/4365343/82223539-c8ffc600-98f0-11ea-93a2-044aa0c9670d.png) + +### Step 8 + +Wait for the Certificate Status to be "issued". This might take a few minutes. + +![step 13](https://user-images.githubusercontent.com/4365343/82209663-a616e700-98db-11ea-95cb-c6efedadb942.png) + +### Step 9 + +Take note of the certificate's ARN. The certificate is ineligible for renewal because it is currently not being used. It will be eligible for renewal after it is used in Cortex. + +![step 14](https://user-images.githubusercontent.com/4365343/82222684-9e613d80-98ef-11ea-98c0-5a20b457f062.png) + +## Configure the API load balancer + +### Step 1 + +Add the following field to your cluster configuration: + +```yaml +# cluster.yaml + +... + +ssl_certificate_arn: +``` + +and then create a Cortex cluster. + +```bash +$ cortex cluster up --config cluster.yaml +``` + +### Step 2 + +After your cluster has been created, navigate to your [EC2 Load Balancer console](https://us-west-2.console.aws.amazon.com/ec2/v2/home#LoadBalancers:sort=loadBalancerName) and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag. + +Take note of the load balancer's name. + +![step 2](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) + +### Step 3 + +Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API load balancer (leave "Name" blank). + +![step 3](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) + +## Using your new endpoint + +Wait a few minutes to allow the DNS changes to propagate. You may now use your subdomain in place of your API load balancer endpoint in your client. For example, this curl request: + +```bash +curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/text-generator -X POST -H "Content-Type: application/json" -d @sample.json +``` + +Would become: + +```bash +# replace loadbalancer url with your subdomain +curl https://api.cortexlabs.dev/text-generator -X POST -H "Content-Type: application/json" -d @sample.json +``` + +## Debugging connectivity issues + +You could run into connectivity issues if you make a request to your API without waiting long enough for your DNS records to propagate after creating them (it usually takes 5-10 mintues). If you are updating existing DNS records, it could take anywhere from a few minutes to 48 hours for the DNS cache to expire (until then, your previous DNS configuration will be used). + +To test connectivity, try the following steps: + +1. Deploy any api (e.g. examples/pytorch/iris-classifier). +1. Make an HTTPS GET request to the your api e.g. `curl https://api.cortexlabs.dev/iris-classifier` or enter the url in your browser. +1. If you run into an error such as `curl: (6) Could not resolve host: api.cortexlabs.dev` wait a few minutes and make the HTTPS Get request from another device that hasn't made a request to that url in a while. A successful request looks like this: + +```text +{"message":"make a prediction by sending a post request to this endpoint with a json payload",...} +``` + +## Cleanup + +Spin down your Cortex cluster. + +Delete the hosted zone for your subdomain in the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:): + +![delete hosted zone](https://user-images.githubusercontent.com/4365343/82228729-81306d00-98f7-11ea-8570-e9de15f5267f.png) + +Delete your certificate from the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home): + +![delete certificate](https://user-images.githubusercontent.com/4365343/82228835-a624e000-98f7-11ea-92e2-cb4fb0f591e2.png) diff --git a/docs/clusters/aws/networking.md b/docs/clusters/aws/networking/index.md similarity index 73% rename from docs/clusters/aws/networking.md rename to docs/clusters/aws/networking/index.md index 6df37935ce..1ee31a8be8 100644 --- a/docs/clusters/aws/networking.md +++ b/docs/clusters/aws/networking/index.md @@ -2,6 +2,12 @@ ![api architecture diagram](https://user-images.githubusercontent.com/808475/103417256-dd6e9700-4b3e-11eb-901e-90425f1f8fd4.png) -All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your [cluster configuration](install.md) file (before creating your cluster). This will make your API only accessible through VPC Peering. +All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your [cluster configuration](../install.md) file (before creating your cluster). This will make your API only accessible through VPC Peering. The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to make HTTP requests or skip certificate verification when making HTTPS requests (e.g. `curl -k`). Alternatively, you can enable HTTPS by using a custom domain or by creating an API Gateway to forward requests to your API load balancer. + +## Networking Topics + +- [Custom Domain](custom_domain/index.md) +- [HTTPS](https/index.md) +- [VPC Peering](vpc-peering.md) diff --git a/docs/clusters/aws/vpc-peering.md b/docs/clusters/aws/networking/vpc-peering.md similarity index 100% rename from docs/clusters/aws/vpc-peering.md rename to docs/clusters/aws/networking/vpc-peering.md diff --git a/docs/clusters/aws/security.md b/docs/clusters/aws/security.md index e2d400a5b1..ee1fd56436 100644 --- a/docs/clusters/aws/security.md +++ b/docs/clusters/aws/security.md @@ -6,11 +6,11 @@ By default, instances are created in public subnets and are assigned public IP a ## Private APIs -See [networking](networking.md) for a discussion of API visibility. +See [networking](networking/index.md) for a discussion of API visibility. ## Private operator -By default, the Cortex cluster operator's load balancer is internet-facing, and therefore publicly accessible (the operator is what the `cortex` CLI connects to). The operator validates that the CLI user is an active IAM user in the same AWS account as the Cortex cluster (see [below](#cli)). Therefore it is usually unnecessary to configure the operator's load balancer to be private, but this can be done by by setting `operator_load_balancer_scheme: internal` in your [cluster configuration](install.md) file. If you do this, you will need to configure [VPC Peering](vpc-peering.md) to allow your CLI to connect to the Cortex operator (this will be necessary to run any `cortex` commands). +By default, the Cortex cluster operator's load balancer is internet-facing, and therefore publicly accessible (the operator is what the `cortex` CLI connects to). The operator validates that the CLI user is an active IAM user in the same AWS account as the Cortex cluster (see [below](#cli)). Therefore it is usually unnecessary to configure the operator's load balancer to be private, but this can be done by by setting `operator_load_balancer_scheme: internal` in your [cluster configuration](install.md) file. If you do this, you will need to configure [VPC Peering](networking/vpc-peering.md) to allow your CLI to connect to the Cortex operator (this will be necessary to run any `cortex` commands). ## IAM permissions diff --git a/docs/clusters/aws/uninstall.md b/docs/clusters/aws/uninstall.md index 7fa23e09a6..929a549f2c 100644 --- a/docs/clusters/aws/uninstall.md +++ b/docs/clusters/aws/uninstall.md @@ -25,7 +25,7 @@ aws s3 rb --force s3:// aws logs describe-log-groups --log-group-name-prefix= --query logGroups[*].[logGroupName] --output text | xargs -I {} aws logs delete-log-group --log-group-name {} ``` -If you've configured a custom domain for your APIs, you can remove the SSL Certificate and Hosted Zone for the domain by following these [instructions](custom-domain.md#cleanup). +If you've configured a custom domain for your APIs, you can remove the SSL Certificate and Hosted Zone for the domain by following these [instructions](networking/custom_domain/original.md#cleanup). ## Troubleshooting diff --git a/docs/summary.md b/docs/summary.md index 9d16be3748..863eb531dc 100644 --- a/docs/summary.md +++ b/docs/summary.md @@ -42,10 +42,14 @@ * [Spot instances](clusters/aws/spot.md) * [GPUs](clusters/aws/gpu.md) * [Inferentia](clusters/aws/inferentia.md) - * [Networking](clusters/aws/networking.md) - * [VPC peering](clusters/aws/vpc-peering.md) - * [Custom domain](clusters/aws/custom-domain.md) - * [REST API Gateway](clusters/aws/rest-api-gateway.md) + * [Networking](clusters/aws/networking/index.md) + * [Custom Domain](clusters/aws/networking/custom_domain/index.md) + * [With API Gateway](clusters/aws/networking/custom_domain/api-gateway.md) + * [Without API Gateway](clusters/aws/networking/custom_domain/dns.md) + * [HTTPS](clusters/aws/networking/https/index.md) + * [Load Balancer Certificate](clusters/aws/networking/https/load-balancer.md) + * [API Gateway](clusters/aws/networking/https/api-gateway.md) + * [VPC peering](clusters/aws/networking/vpc-peering.md) * [Setting up kubectl](clusters/aws/kubectl.md) * [Uninstall](clusters/aws/uninstall.md) * GCP diff --git a/docs/workloads/realtime/configuration.md b/docs/workloads/realtime/configuration.md index bf18e9f634..bb1b238021 100644 --- a/docs/workloads/realtime/configuration.md +++ b/docs/workloads/realtime/configuration.md @@ -30,7 +30,6 @@ log_level: # log level that can be "debug", "info", "warning" or "error" (default: "info") networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) (aws only) compute: cpu: # CPU request per replica, e.g. 200m or 1 (200m is equivalent to 0.2) (default: 200m) gpu: # GPU request per replica (default: 0) @@ -87,7 +86,6 @@ log_level: # log level that can be "debug", "info", "warning" or "error" (default: "info") networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) (aws only) compute: cpu: # CPU request per replica, e.g. 200m or 1 (200m is equivalent to 0.2) (default: 200m) gpu: # GPU request per replica (default: 0) @@ -138,7 +136,6 @@ log_level: # log level that can be "debug", "info", "warning" or "error" (default: "info") networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) (aws only) compute: cpu: # CPU request per replica, e.g. 200m or 1 (200m is equivalent to 0.2) (default: 200m) gpu: # GPU request per replica (default: 0) From d978f95614d16b1789db460044941f3028584c49 Mon Sep 17 00:00:00 2001 From: Miguel Varela Ramos Date: Thu, 31 Dec 2020 18:47:56 +0000 Subject: [PATCH 04/20] Reorganized AWS compute related docs into its own category --- docs/clusters/aws/{ => compute}/gpu.md | 0 docs/clusters/aws/{ => compute}/inferentia.md | 0 docs/clusters/aws/{ => compute}/spot.md | 0 docs/clusters/aws/networking/https/index.md | 2 +- docs/summary.md | 7 ++++--- 5 files changed, 5 insertions(+), 4 deletions(-) rename docs/clusters/aws/{ => compute}/gpu.md (100%) rename docs/clusters/aws/{ => compute}/inferentia.md (100%) rename docs/clusters/aws/{ => compute}/spot.md (100%) diff --git a/docs/clusters/aws/gpu.md b/docs/clusters/aws/compute/gpu.md similarity index 100% rename from docs/clusters/aws/gpu.md rename to docs/clusters/aws/compute/gpu.md diff --git a/docs/clusters/aws/inferentia.md b/docs/clusters/aws/compute/inferentia.md similarity index 100% rename from docs/clusters/aws/inferentia.md rename to docs/clusters/aws/compute/inferentia.md diff --git a/docs/clusters/aws/spot.md b/docs/clusters/aws/compute/spot.md similarity index 100% rename from docs/clusters/aws/spot.md rename to docs/clusters/aws/compute/spot.md diff --git a/docs/clusters/aws/networking/https/index.md b/docs/clusters/aws/networking/https/index.md index ccb102e1f2..be89601e4d 100644 --- a/docs/clusters/aws/networking/https/index.md +++ b/docs/clusters/aws/networking/https/index.md @@ -1,5 +1,5 @@ # Setting up HTTPS -In order to set up HTTPS for you API you can choose one of the following options: +In order to set up HTTPS for your API you can choose one of the following options: - [Setting up HTTPS through the load balancer](load-balancer.md) - [Setting up HTTPS with AWS's API Gateway](api-gateway.md) diff --git a/docs/summary.md b/docs/summary.md index 863eb531dc..c036ffa1b1 100644 --- a/docs/summary.md +++ b/docs/summary.md @@ -39,9 +39,10 @@ * [Install](clusters/aws/install.md) * [Update](clusters/aws/update.md) * [Security](clusters/aws/security.md) - * [Spot instances](clusters/aws/spot.md) - * [GPUs](clusters/aws/gpu.md) - * [Inferentia](clusters/aws/inferentia.md) + * Compute + * [Spot instances](clusters/aws/compute/spot.md) + * [GPUs](clusters/aws/compute/gpu.md) + * [Inferentia](clusters/aws/compute/inferentia.md) * [Networking](clusters/aws/networking/index.md) * [Custom Domain](clusters/aws/networking/custom_domain/index.md) * [With API Gateway](clusters/aws/networking/custom_domain/api-gateway.md) From 61b46c1a0fe3b71bd8ceb1557448bb0b2a3cd843 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Thu, 31 Dec 2020 15:07:56 -0800 Subject: [PATCH 05/20] WIP - update docs --- docs/clusters/aws/networking/api-gateway.md | 147 ++++++++++++ docs/clusters/aws/networking/custom-domain.md | 136 +++++++++++ .../networking/custom_domain/api-gateway.md | 3 - .../aws/networking/custom_domain/dns.md | 68 ------ .../aws/networking/custom_domain/index.md | 15 -- .../aws/networking/custom_domain/original.md | 220 ------------------ .../aws/networking/https/api-gateway.md | 179 -------------- docs/clusters/aws/networking/https/index.md | 5 - .../aws/networking/https/load-balancer.md | 134 ----------- docs/clusters/aws/networking/index.md | 10 +- docs/clusters/aws/networking/vpc-peering.md | 2 +- docs/summary.md | 8 +- 12 files changed, 289 insertions(+), 638 deletions(-) create mode 100644 docs/clusters/aws/networking/api-gateway.md create mode 100644 docs/clusters/aws/networking/custom-domain.md delete mode 100644 docs/clusters/aws/networking/custom_domain/api-gateway.md delete mode 100644 docs/clusters/aws/networking/custom_domain/dns.md delete mode 100644 docs/clusters/aws/networking/custom_domain/index.md delete mode 100644 docs/clusters/aws/networking/custom_domain/original.md delete mode 100644 docs/clusters/aws/networking/https/api-gateway.md delete mode 100644 docs/clusters/aws/networking/https/index.md delete mode 100644 docs/clusters/aws/networking/https/load-balancer.md diff --git a/docs/clusters/aws/networking/api-gateway.md b/docs/clusters/aws/networking/api-gateway.md new file mode 100644 index 0000000000..d4e1e9986b --- /dev/null +++ b/docs/clusters/aws/networking/api-gateway.md @@ -0,0 +1,147 @@ +# API Gateway (HTTPS) + +AWS API Gateway can be configured to forward requests to your Cortex APIs. This can be useful as a simple way to supporte HTTPS traffic (as an alternative to custom domains), or to leverage other features provided by API Gateway. Please note that one limitation of API Gateway is that there is a 30-second time limit for all requests. + +If your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster), use the [first section](#internet-facing-load-balancer) of this guide. + +If your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster), use the [second section](#internal-load-balancer) of this guide. + +## Internet-facing load balancer + +_This section applies if your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster). If your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file), see the [internal load balancer](#internal-load-balancer) section below._ + +### Create an API Gateway + +Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build". + +![](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) + +Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API". + +![](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) + +Select "Actions" > "Create Resource": + +![](https://user-images.githubusercontent.com/808475/80154502-8b6b7f80-8574-11ea-9c78-7d9f277bf55b.png) + +Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" + +![](https://user-images.githubusercontent.com/808475/80154565-ad650200-8574-11ea-8753-808cd35902e2.png) + +Select "HTTP Proxy" and set "Endpoint URL" to "http:///{proxy}". You can get your API load balancer endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a9eaf69fd125947abb1065f62de59047-81cdebc0275f7d96.elb.us-west-2.amazonaws.com/{proxy}`. + +Leave "Content Handling" set to "Passthrough" and Click "Save". + +![](https://user-images.githubusercontent.com/808475/80154735-13ea2000-8575-11ea-83ca-58f182df83c6.png) + +Select "Actions" > "Deploy API" + +![](https://user-images.githubusercontent.com/808475/80154802-2c5a3a80-8575-11ea-9ab3-de89885fd658.png) + +Create a new stage (e.g. "dev") and click "Deploy" + +![](https://user-images.githubusercontent.com/808475/80154859-4431be80-8575-11ea-9305-50384b1f9847.png) + +Copy your "Invoke URL" + +![](https://user-images.githubusercontent.com/808475/80154911-5dd30600-8575-11ea-9682-1a7328783011.png) + +### Use your new endpoint + +You may now use the "Invoke URL" in place of your API load balancer endpoint in your client. For example, this curl request: + +```bash +curl http://a9eaf69fd125947abb1065f62de59047-81cdebc0275f7d96.elb.us-west-2.amazonaws.com/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json +``` + +Would become: + +```bash +curl https://31qjv48rs6.execute-api.us-west-2.amazonaws.com/dev/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json +``` + +### Cleanup + +Delete the API Gateway before spinning down your Cortex cluster: + +![](https://user-images.githubusercontent.com/808475/80155073-bdc9ac80-8575-11ea-99a1-95c0579da79e.png) + +## Internal load balancer + +_This section applies if your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster). If your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file), see the [internet-facing load balancer](#internet-facing-load-balancer) section above._ + +### Create a VPC Link + +Navigate to AWS's EC2 Load Balancer dashboard and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag: + +![](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) + +Take note of the load balancer's name. + +Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), click "VPC Links" on the left sidebar, and click "Create" + +![](https://user-images.githubusercontent.com/808475/80142466-0c6c4c00-8560-11ea-8293-eb5e5572b797.png) + +Select "VPC link for REST APIs", name your VPC link (e.g. "cortex"), select the API load balancer (identified in Step 1), and click "Create" + +![](https://user-images.githubusercontent.com/808475/80143027-03c84580-8561-11ea-92de-9ed0a5dfa593.png) + +Wait for the VPC link to be created (it will take a few minutes) + +![](https://user-images.githubusercontent.com/808475/80144088-bbaa2280-8562-11ea-901b-8520eb253df7.png) + +### Create an API Gateway + +Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build" + +![](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) + +Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API" + +![](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) + +Select "Actions" > "Create Resource" + +![](https://user-images.githubusercontent.com/808475/80141938-3cffb600-855f-11ea-9c1c-132ca4503b7a.png) + +Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" + +![](https://user-images.githubusercontent.com/808475/80142124-80f2bb00-855f-11ea-8e4e-9413146e0815.png) + +Select "VPC Link", select "Use Proxy Integration", choose your newly-created VPC Link, and set "Endpoint URL" to "http:///{proxy}". You can get your API load balancer endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/{proxy}`. Click "Save" + +![](https://user-images.githubusercontent.com/808475/80147407-4f322200-8568-11ea-8ef5-df5164c1375f.png) + +Select "Actions" > "Deploy API" + +![](https://user-images.githubusercontent.com/808475/80147555-86083800-8568-11ea-86af-1b1e38c9d322.png) + +Create a new stage (e.g. "dev") and click "Deploy" + +![](https://user-images.githubusercontent.com/808475/80147631-a7692400-8568-11ea-8a09-13dbd50b17b9.png) + +Copy your "Invoke URL" + +![](https://user-images.githubusercontent.com/808475/80147716-c798e300-8568-11ea-9aef-7dd6fdf4a68a.png) + +### Use your new endpoint + +You may now use the "Invoke URL" in place of your API load balancer endpoint in your client. For example, this curl request: + +```bash +curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json +``` + +Would become: + +```bash +curl https://lrivodooqh.execute-api.us-west-2.amazonaws.com/dev/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json +``` + +### Cleanup + +Delete the API Gateway and VPC Link before spinning down your Cortex cluster: + +![](https://user-images.githubusercontent.com/808475/80149163-05970680-856b-11ea-9f82-61f4061a3321.png) + +![](https://user-images.githubusercontent.com/808475/80149204-1ba4c700-856b-11ea-83f7-9741c78b6b95.png) diff --git a/docs/clusters/aws/networking/custom-domain.md b/docs/clusters/aws/networking/custom-domain.md new file mode 100644 index 0000000000..eede9fc818 --- /dev/null +++ b/docs/clusters/aws/networking/custom-domain.md @@ -0,0 +1,136 @@ +# Custom domain + +You can use any custom domain (that you own) for your prediction endpoints. For example, you can make your API accessible via `api.example.com/text-generator`. This guide will demonstrate how to create a dedicated subdomain in AWS Route 53 and use an SSL certificate provisioned by AWS Certificate Manager (if desired). + +## Configure DNS + +Decide on a subdomain that you want to dedicate to Cortex APIs. For example if your domain is `example.com`, a valid subdomain can be `api.example.com`. This guide will use `cortexlabs.dev` as the example domain and `api.cortexlabs.dev` as the subdomain. + +We will set up a hosted zone on Route 53 to manage the DNS records for the subdomain. Go to the [Route 53 console](https://console.aws.amazon.com/route53/home) and click "Hosted Zones". + +![hosted zones](https://user-images.githubusercontent.com/4365343/82210754-a6b07d00-98dd-11ea-9cec-9f6b07282aa8.png) + +Click "Create Hosted Zone" and then enter your subdomain as the domain name for your hosted zone and click "Create". + +![create hosted zone](https://user-images.githubusercontent.com/4365343/82211091-4968fb80-98de-11ea-8ec4-8d26d1aea77a.png) + +Take note of the values in the NS record. + +![view ns record](https://user-images.githubusercontent.com/4365343/82211656-386cba00-98df-11ea-8c86-4961082b5f49.png) + +Navigate to your root DNS service provider (e.g. Google Domains, AWS Route 53, Go Daddy). Your root DNS service provider is typically the registrar where you purchased your domain (unless you have transferred DNS management elsewhere). The procedure for adding DNS records may vary based on your service provider. + +We are going to add an NS (name server) record that specifies that any traffic to your subdomain should use the name servers of your hosted zone in Route 53 for DNS resolution. + +`cortexlabs.dev` is managed by Google Domains. The image below is a screenshot for adding a DNS record in Google Domains (your UI may differ based on your DNS service provider). + +![add ns record](https://user-images.githubusercontent.com/4365343/82211959-bcbf3d00-98df-11ea-834d-692b3bcf9332.png) + +## Generate an SSL certificate + +You can skip this section (and continue to [add the DNS record](#add-dns-record)) if you don't need an SSL certificate for your custom domain. If you don't use an SSL certificate, you will need to skip certificate verification when making HTTPS requests to your APIs (e.g. `curl -k https://***`), or make HTTP requests instead (e.g. `curl http://***`). + +To create an SSL certificate, go to the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home) and click "Get Started" under the "Provision certificates" section. + +![acm](https://user-images.githubusercontent.com/4365343/82202340-c04ac800-98cf-11ea-9472-89dd6d67eb0d.png) + +Select "Request a public certificate" and then "Request a certificate". + +![request certificate](https://user-images.githubusercontent.com/4365343/82202654-3e0ed380-98d0-11ea-8c57-025f0b69c54f.png) + +Enter your subdomain and then click "Next". + +![enter subdomain](https://user-images.githubusercontent.com/4365343/82224652-1cbedf00-98f2-11ea-912b-466cee2f6e25.png) + +Select "DNS validation" and then click "Next". + +![dns validation](https://user-images.githubusercontent.com/4365343/82205311-66003600-98d4-11ea-90e3-da7e8b0b2b9c.png) + +Add tags for searchability (optional) then click "Review". + +![add tags](https://user-images.githubusercontent.com/4365343/82206485-52ee6580-98d6-11ea-95a9-1d0ebafc178a.png) + +Click "Confirm and request". + +![confirm](https://user-images.githubusercontent.com/4365343/82206602-84ffc780-98d6-11ea-9f2f-ce383404ec67.png) + +Click "Create record in Route 53". A popup will appear indicating that a Record is going to be added to Route 53. Click "Create" to automatically add the DNS record to your subdomain's hosted zone. Then click "Continue". + +![create record](https://user-images.githubusercontent.com/4365343/82223539-c8ffc600-98f0-11ea-93a2-044aa0c9670d.png) + +Wait for the Certificate Status to be "issued". This might take a few minutes. + +![wait for issued](https://user-images.githubusercontent.com/4365343/82209663-a616e700-98db-11ea-95cb-c6efedadb942.png) + +Take note of the certificate's ARN. The certificate is ineligible for renewal because it is currently not being used. It will be eligible for renewal once it's used in Cortex. + +![arn](https://user-images.githubusercontent.com/4365343/82222684-9e613d80-98ef-11ea-98c0-5a20b457f062.png) + +Add the following field to your cluster configuration: + +```yaml +# cluster.yaml + +... + +ssl_certificate_arn: +``` + +Create a Cortex cluster: + +```bash +$ cortex cluster up --config cluster.yaml +``` + +## Add DNS record + +Navigate to your [EC2 Load Balancer console](https://us-west-2.console.aws.amazon.com/ec2/v2/home#LoadBalancers:sort=loadBalancerName) and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag. + +Take note of the load balancer's name. + +![locate load balancer](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) + +Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API load balancer (leave "Name" blank). + +![create record set](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) + +## Use your new endpoint + +Wait a few minutes to allow the DNS changes to propagate. You may now use your subdomain in place of your API load balancer endpoint in your client. For example, this curl request: + +```bash +curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/text-generator -X POST -H "Content-Type: application/json" -d @sample.json +``` + +Would become: + +```bash +# add the `-k` flag or use http:// instead of https:// if you didn't configure an SSL certificate +curl https://api.cortexlabs.dev/text-generator -X POST -H "Content-Type: application/json" -d @sample.json +``` + +## Debugging connectivity issues + +You could run into connectivity issues if you make a request to your API without waiting long enough for your DNS records to propagate after creating them (it usually takes 5-10 mintues). If you are updating existing DNS records, it could take anywhere from a few minutes to 48 hours for the DNS cache to expire (until then, your previous DNS configuration will be used). + +To test connectivity, try the following steps: + +1. Deploy any api (e.g. examples/pytorch/iris-classifier). +1. Make a GET request to the your api (e.g. `curl https://api.cortexlabs.dev/iris-classifier` or paste the url into your browser). +1. If you run into an error such as `curl: (6) Could not resolve host: api.cortexlabs.dev` wait a few minutes and make the GET request from another device that hasn't made a request to that url in a while. A successful request looks like this: + +```text +{"message":"make a prediction by sending a post request to this endpoint with a json payload",...} +``` + +## Cleanup + +Spin down your Cortex cluster. + +Delete the hosted zone for your subdomain in the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:): + +![delete hosted zone](https://user-images.githubusercontent.com/4365343/82228729-81306d00-98f7-11ea-8570-e9de15f5267f.png) + +If you created an SSL certificate, delete it from the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home): + +![delete certificate](https://user-images.githubusercontent.com/4365343/82228835-a624e000-98f7-11ea-92e2-cb4fb0f591e2.png) diff --git a/docs/clusters/aws/networking/custom_domain/api-gateway.md b/docs/clusters/aws/networking/custom_domain/api-gateway.md deleted file mode 100644 index 5a82f630cd..0000000000 --- a/docs/clusters/aws/networking/custom_domain/api-gateway.md +++ /dev/null @@ -1,3 +0,0 @@ -# Custom Domain with API Gateway - -TODO diff --git a/docs/clusters/aws/networking/custom_domain/dns.md b/docs/clusters/aws/networking/custom_domain/dns.md deleted file mode 100644 index 01570cf596..0000000000 --- a/docs/clusters/aws/networking/custom_domain/dns.md +++ /dev/null @@ -1,68 +0,0 @@ -# Custom Domain Without API Gateway - -## Configure Domain Name Servers (DNS) - -### Step 1 - -Decide on a subdomain that you want to dedicate to Cortex APIs. For example if your domain is `example.com`, a valid subdomain can be `api.example.com`. - -This guide will use `cortexlabs.dev` as the example domain and `api.cortexlabs.dev` as the subdomain. - -### Step 2 - -We will set up a hosted zone on Route 53 to manage the DNS records for the subdomain. Go to the [Route 53 console](https://console.aws.amazon.com/route53/home) and click "Hosted Zones". - -![step 2](https://user-images.githubusercontent.com/4365343/82210754-a6b07d00-98dd-11ea-9cec-9f6b07282aa8.png) - -### Step 3 - -Click "Create Hosted Zone" and then enter your subdomain as the domain name for your hosted zone and click "Create". - -![step 3](https://user-images.githubusercontent.com/4365343/82211091-4968fb80-98de-11ea-8ec4-8d26d1aea77a.png) - -### Step 4 - -Take note of the values in the NS record. - -![step 4](https://user-images.githubusercontent.com/4365343/82211656-386cba00-98df-11ea-8c86-4961082b5f49.png) - -### Step 5 - -Navigate to your root DNS service provider (e.g. Google Domains, AWS Route 53, Go Daddy). Your root DNS service provider is typically the registrar where you purchased your domain (unless you have transferred DNS management elsewhere). The procedure for adding DNS records may vary based on your service provider. - -We are going to add an NS (name server) record that specifies that any traffic to your subdomain should use the name servers of your hosted zone in Route 53 for DNS resolution. - -`cortexlabs.dev` is managed by Google Domains. The image below is a screenshot for adding a DNS record in Google Domains (your UI may differ based on your DNS service provider). - -![step 5](https://user-images.githubusercontent.com/4365343/82211959-bcbf3d00-98df-11ea-834d-692b3bcf9332.png) - -## Add the Load Balancer to the DNS Records - -### Step 1 - -Navigate to your [EC2 Load Balancer console](https://us-west-2.console.aws.amazon.com/ec2/v2/home#LoadBalancers:sort=loadBalancerName) and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag. - -Take note of the load balancer's name. - -![step 2](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) - -### Step 2 - -Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API load balancer (leave "Name" blank). - -![step 3](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) - -## Using your new endpoint - -Wait a few minutes to allow the DNS changes to propagate. You may now use your subdomain in place of your API load balancer endpoint in your client. For example, this curl request: - -```bash -curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/text-generator -X POST -H "Content-Type: application/json" -d @sample.json -``` - -Would become: - -```bash -# replace load balancer url with your subdomain -curl http://api.cortexlabs.dev/text-generator -X POST -H "Content-Type: application/json" -d @sample.json -``` diff --git a/docs/clusters/aws/networking/custom_domain/index.md b/docs/clusters/aws/networking/custom_domain/index.md deleted file mode 100644 index 11c479908a..0000000000 --- a/docs/clusters/aws/networking/custom_domain/index.md +++ /dev/null @@ -1,15 +0,0 @@ -# Custom Domain - -You can use any custom domain (that you own) for your prediction endpoints. -For example, you can make your API accessible via `api.example.com/text-generator`. -This guide will demonstrate how to create a dedicated subdomain in -AWS Route 53 and use an SSL certificate provisioned by AWS Certificate Manager (ACM). - -There are two methods for achieving this, and which method to use depends on whether you're -using API Gateway or not (without API Gateway, requests are sent directly to the API -load balancer instead). API Gateway needs to be setup first in order - -Follow one of the guides below to setup a custom domain for your API: - -- [Without API Gateway](dns.md) -- [With API Gateway](api-gateway.md) diff --git a/docs/clusters/aws/networking/custom_domain/original.md b/docs/clusters/aws/networking/custom_domain/original.md deleted file mode 100644 index 3c99c6b479..0000000000 --- a/docs/clusters/aws/networking/custom_domain/original.md +++ /dev/null @@ -1,220 +0,0 @@ -# Set up a custom domain - -You can use any custom domain (that you own) for your prediction endpoints. For example, you can make your API accessible via `api.example.com/text-generator`. This guide will demonstrate how to create a dedicated subdomain in AWS Route 53 and use an SSL certificate provisioned by AWS Certificate Manager (ACM). - -There are two methods for achieving this, and which method to use depends on whether you're using API Gateway or not (without API Gateway, requests are sent directly to the API load balancer instead). API Gateway is enabled by default. - -The first set of steps are the same whether or not you're using API Gateway. If you aren't using API gateway, follow this guide before creating your Cortex cluster. - -_note: you must own a domain and be able to modify its DNS records to complete this guide._ - -## Generate a certificate for your domain - -### Step 1 - -Decide on a subdomain that you want to dedicate to Cortex APIs. For example if your domain is `example.com`, a valid subdomain can be `api.example.com`. - -This guide will use `cortexlabs.dev` as the example domain and `api.cortexlabs.dev` as the subdomain. - -### Step 2 - -We will set up a hosted zone on Route 53 to manage the DNS records for the subdomain. Go to the [Route 53 console](https://console.aws.amazon.com/route53/home) and click "Hosted Zones". - -![step 2](https://user-images.githubusercontent.com/4365343/82210754-a6b07d00-98dd-11ea-9cec-9f6b07282aa8.png) - -### Step 3 - -Click "Create Hosted Zone" and then enter your subdomain as the domain name for your hosted zone and click "Create". - -![step 3](https://user-images.githubusercontent.com/4365343/82211091-4968fb80-98de-11ea-8ec4-8d26d1aea77a.png) - -### Step 4 - -Take note of the values in the NS record. - -![step 4](https://user-images.githubusercontent.com/4365343/82211656-386cba00-98df-11ea-8c86-4961082b5f49.png) - -### Step 5 - -Navigate to your root DNS service provider (e.g. Google Domains, AWS Route 53, Go Daddy). Your root DNS service provider is typically the registrar where you purchased your domain (unless you have transferred DNS management elsewhere). The procedure for adding DNS records may vary based on your service provider. - -We are going to add an NS (name server) record that specifies that any traffic to your subdomain should use the name servers of your hosted zone in Route 53 for DNS resolution. - -`cortexlabs.dev` is managed by Google Domains. The image below is a screenshot for adding a DNS record in Google Domains (your UI may differ based on your DNS service provider). - -![step 5](https://user-images.githubusercontent.com/4365343/82211959-bcbf3d00-98df-11ea-834d-692b3bcf9332.png) - -### Step 6 - -We are now going to create an SSL certificate for your subdomain. Go to the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home) and click "Get Started" under the "Provision certificates" section. - -![step 6](https://user-images.githubusercontent.com/4365343/82202340-c04ac800-98cf-11ea-9472-89dd6d67eb0d.png) - -### Step 7 - -Select "Request a public certificate" and then "Request a certificate". - -![step 7](https://user-images.githubusercontent.com/4365343/82202654-3e0ed380-98d0-11ea-8c57-025f0b69c54f.png) - -### Step 8 - -Enter your subdomain and then click "Next". - -![step 8](https://user-images.githubusercontent.com/4365343/82224652-1cbedf00-98f2-11ea-912b-466cee2f6e25.png) - -### Step 9 - -Select "DNS validation" and then click "Next". - -![step 9](https://user-images.githubusercontent.com/4365343/82205311-66003600-98d4-11ea-90e3-da7e8b0b2b9c.png) - -### Step 10 - -Add tags for searchability (optional) then click "Review". - -![step 10](https://user-images.githubusercontent.com/4365343/82206485-52ee6580-98d6-11ea-95a9-1d0ebafc178a.png) - -### Step 11 - -Click "Confirm and request". - -![step 11](https://user-images.githubusercontent.com/4365343/82206602-84ffc780-98d6-11ea-9f2f-ce383404ec67.png) - -### Step 12 - -Click "Create record in Route 53". A popup will appear indicating that a Record is going to be added to Route 53. Click "Create" to automatically add the DNS record to your subdomain's hosted zone. Then click "Continue". - -![step 12](https://user-images.githubusercontent.com/4365343/82223539-c8ffc600-98f0-11ea-93a2-044aa0c9670d.png) - -### Step 13 - -Wait for the Certificate Status to be "issued". This might take a few minutes. - -![step 13](https://user-images.githubusercontent.com/4365343/82209663-a616e700-98db-11ea-95cb-c6efedadb942.png) - -### Step 14 - -Take note of the certificate's ARN. The certificate is ineligible for renewal because it is currently not being used. It will be eligible for renewal after it is used in Cortex. - -![step 14](https://user-images.githubusercontent.com/4365343/82222684-9e613d80-98ef-11ea-98c0-5a20b457f062.png) - -If you are using API Gateway, continue to the next section to [configure API Gateway](#configure-api-gateway). Otherwise (i.e. clients connect directly to your API load balancer) skip to [configure the API load balancer](#configure-the-api-load-balancer). - -## Configure API Gateway - -_If you aren't using API Gateway (i.e. clients connect directly to your API load balancer), skip this section and [configure the API load balancer](#configure-the-api-load-balancer) instead._ - -### Step 1 - -Navigate to the [API Gateway console](https://us-west-2.console.aws.amazon.com/apigateway) (make sure that the region in top right matches your Cortex region). Click "Custom domain names" and then click "Create". - -![step 1](https://user-images.githubusercontent.com/808475/84082403-a105fe80-a994-11ea-8015-0df9aeef07b1.png) - -### Step 2 - -Type in the name of your domain and choose the Regional endpoint type, TLS 1.2, and the ACM certificate that you created earlier. Then click "Create". - -![step 2](https://user-images.githubusercontent.com/808475/84082448-b8dd8280-a994-11ea-9ef7-6bb33b3a403b.png) - -### Step 3 - -This should take you back to the custom domains page, and you should see your new custom domain. Make sure your API is selected. Take note of the API Gateway domain name (we will use this later), and click "Configure API mappings". - -![step 3](https://user-images.githubusercontent.com/808475/84084960-62267780-a999-11ea-8a6b-4be9cfca2a9c.png) - -### Step 4 - -Click "Add new mapping". - -![step 4](https://user-images.githubusercontent.com/808475/84082516-d7dc1480-a994-11ea-9cae-d4fb1ac1e767.png) - -### Step 5 - -Select your API Gateway, choose the "$default" stage, and lave "Path" blank. Click Save. - -![step 5](https://user-images.githubusercontent.com/808475/84082553-e5919a00-a994-11ea-9bc3-cf5f9eb869eb.png) - -### Step 6 - -Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API Gateway (the target name should match the "API Gateway domain name" show in step 3). Leave "Name" blank. - -![step 6](https://user-images.githubusercontent.com/808475/84083366-54232780-a996-11ea-9bc6-2c9945a160d4.png) - -Proceed to [using your new endpoint](#using-your-new-endpoint). - -## Configure the API load balancer - -_If you are using API Gateway, this section does not apply; follow the instructions above to [configure API Gateway](#configure-api-gateway) instead._ - -### Step 1 - -Add the following field to your cluster configuration: - -```yaml -# cluster.yaml - -... - -ssl_certificate_arn: -``` - -and then create a Cortex cluster. - -```bash -$ cortex cluster up --config cluster.yaml -``` - -### Step 2 - -After your cluster has been created, navigate to your [EC2 Load Balancer console](https://us-west-2.console.aws.amazon.com/ec2/v2/home#LoadBalancers:sort=loadBalancerName) and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag. - -Take note of the load balancer's name. - -![step 2](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) - -### Step 3 - -Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API load balancer (leave "Name" blank). - -![step 3](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) - -## Using your new endpoint - -Wait a few minutes to allow the DNS changes to propagate. You may now use your subdomain in place of your API load balancer endpoint in your client. For example, this curl request: - -```bash -curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/text-generator -X POST -H "Content-Type: application/json" -d @sample.json -``` - -Would become: - -```bash -# replace loadbalancer url with your subdomain -curl https://api.cortexlabs.dev/text-generator -X POST -H "Content-Type: application/json" -d @sample.json -``` - -## Debugging connectivity issues - -You could run into connectivity issues if you make a request to your API without waiting long enough for your DNS records to propagate after creating them (it usually takes 5-10 mintues). If you are updating existing DNS records, it could take anywhere from a few minutes to 48 hours for the DNS cache to expire (until then, your previous DNS configuration will be used). - -To test connectivity, try the following steps: - -1. Deploy any api (e.g. examples/pytorch/iris-classifier). -1. Make an HTTPS GET request to the your api e.g. `curl https://api.cortexlabs.dev/iris-classifier` or enter the url in your browser. -1. If you run into an error such as `curl: (6) Could not resolve host: api.cortexlabs.dev` wait a few minutes and make the HTTPS Get request from another device that hasn't made a request to that url in a while. A successful request looks like this: - -```text -{"message":"make a prediction by sending a post request to this endpoint with a json payload",...} -``` - -## Cleanup - -Spin down your Cortex cluster. - -Delete the hosted zone for your subdomain in the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:): - -![delete hosted zone](https://user-images.githubusercontent.com/4365343/82228729-81306d00-98f7-11ea-8570-e9de15f5267f.png) - -Delete your certificate from the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home): - -![delete certificate](https://user-images.githubusercontent.com/4365343/82228835-a624e000-98f7-11ea-92e2-cb4fb0f591e2.png) diff --git a/docs/clusters/aws/networking/https/api-gateway.md b/docs/clusters/aws/networking/https/api-gateway.md deleted file mode 100644 index 738af2313c..0000000000 --- a/docs/clusters/aws/networking/https/api-gateway.md +++ /dev/null @@ -1,179 +0,0 @@ - -# Setting up HTTP with API Gateway - -There may be situations where you need to use AWS's "REST" API Gateway, e.g. to enforce IAM-based auth. -This guide covers setting up HTTPS with AWS's "REST" API Gateway. - -If your API load balancer is internet-facing (which is the default, or you explicitly set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster), use the [first section](#if-your-api-load-balancer-is-internet-facing) of this guide. - -If your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster), use the [second section](#if-your-api-load-balancer-is-internal) of this guide. - -## If your API load balancer is internet-facing - -### Step 1 - -Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build" - -![step 1](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) - -### Step 2 - -Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API" - -![step 2](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) - -### Step 3 - -Select "Actions" > "Create Resource" - -![step 3](https://user-images.githubusercontent.com/808475/80154502-8b6b7f80-8574-11ea-9c78-7d9f277bf55b.png) - -### Step 4 - -Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" - -![step 4](https://user-images.githubusercontent.com/808475/80154565-ad650200-8574-11ea-8753-808cd35902e2.png) - -### Step 5 - -Select "HTTP Proxy" and set "Endpoint URL" to "http:///{proxy}". You can get your base API endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a9eaf69fd125947abb1065f62de59047-81cdebc0275f7d96.elb.us-west-2.amazonaws.com/{proxy}`. - -Leave "Content Handling" set to "Passthrough" and Click "Save". - -![step 5](https://user-images.githubusercontent.com/808475/80154735-13ea2000-8575-11ea-83ca-58f182df83c6.png) - -### Step 6 - -Select "Actions" > "Deploy API" - -![step 6](https://user-images.githubusercontent.com/808475/80154802-2c5a3a80-8575-11ea-9ab3-de89885fd658.png) - -### Step 7 - -Create a new stage (e.g. "dev") and click "Deploy" - -![step 7](https://user-images.githubusercontent.com/808475/80154859-4431be80-8575-11ea-9305-50384b1f9847.png) - -### Step 8 - -Copy your "Invoke URL" - -![step 8](https://user-images.githubusercontent.com/808475/80154911-5dd30600-8575-11ea-9682-1a7328783011.png) - -### Using your new endpoint - -You may now use the "Invoke URL" in place of your APIs endpoint in your client. For example, this curl request: - -```bash -curl http://a9eaf69fd125947abb1065f62de59047-81cdebc0275f7d96.elb.us-west-2.amazonaws.com/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json -``` - -Would become: - -```bash -curl https://31qjv48rs6.execute-api.us-west-2.amazonaws.com/dev/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json -``` - -### Cleanup - -Delete the API Gateway before spinning down your Cortex cluster: - -![delete api gateway](https://user-images.githubusercontent.com/808475/80155073-bdc9ac80-8575-11ea-99a1-95c0579da79e.png) - -## If your API load balancer is internal - -### Step 1 - -Navigate to AWS's EC2 Load Balancer dashboard and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag: - -![step 1](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) - -Take note of the load balancer's name. - -### Step 2 - -Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), click "VPC Links" on the left sidebar, and click "Create" - -![step 2](https://user-images.githubusercontent.com/808475/80142466-0c6c4c00-8560-11ea-8293-eb5e5572b797.png) - -### Step 3 - -Select "VPC link for REST APIs", name your VPC link (e.g. "cortex"), select the API load balancer (identified in Step 1), and click "Create" - -![step 3](https://user-images.githubusercontent.com/808475/80143027-03c84580-8561-11ea-92de-9ed0a5dfa593.png) - -### Step 4 - -Wait for the VPC link to be created (it will take a few minutes) - -![step 4](https://user-images.githubusercontent.com/808475/80144088-bbaa2280-8562-11ea-901b-8520eb253df7.png) - -### Step 5 - -Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), select "REST API" under "Choose an API type", and click "Build" - -![step 5](https://user-images.githubusercontent.com/808475/78293216-18269e80-74dd-11ea-9e68-86922c2cbc7c.png) - -### Step 6 - -Select "REST" and "New API", name your API (e.g. "cortex"), select either "Regional" or "Edge optimized" (depending on your preference), and click "Create API" - -![step 6](https://user-images.githubusercontent.com/808475/78293434-66d43880-74dd-11ea-92d6-692158171a3f.png) - -### Step 7 - -Select "Actions" > "Create Resource" - -![step 7](https://user-images.githubusercontent.com/808475/80141938-3cffb600-855f-11ea-9c1c-132ca4503b7a.png) - -### Step 8 - -Select "Configure as proxy resource" and "Enable API Gateway CORS", and click "Create Resource" - -![step 8](https://user-images.githubusercontent.com/808475/80142124-80f2bb00-855f-11ea-8e4e-9413146e0815.png) - -### Step 9 - -Select "VPC Link", select "Use Proxy Integration", choose your newly-created VPC Link, and set "Endpoint URL" to "http:///{proxy}". You can get your base API endpoint via `cortex cluster info`; make sure to prepend `http://` and append `/{proxy}`. For example, mine is: `http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/{proxy}`. Click "Save" - -![step 9](https://user-images.githubusercontent.com/808475/80147407-4f322200-8568-11ea-8ef5-df5164c1375f.png) - -### Step 10 - -Select "Actions" > "Deploy API" - -![step 10](https://user-images.githubusercontent.com/808475/80147555-86083800-8568-11ea-86af-1b1e38c9d322.png) - -### Step 11 - -Create a new stage (e.g. "dev") and click "Deploy" - -![step 11](https://user-images.githubusercontent.com/808475/80147631-a7692400-8568-11ea-8a09-13dbd50b17b9.png) - -### Step 12 - -Copy your "Invoke URL" - -![step 12](https://user-images.githubusercontent.com/808475/80147716-c798e300-8568-11ea-9aef-7dd6fdf4a68a.png) - -### Using your new endpoint - -You may now use the "Invoke URL" in place of your APIs endpoint in your client. For example, this curl request: - -```bash -curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json -``` - -Would become: - -```bash -curl https://lrivodooqh.execute-api.us-west-2.amazonaws.com/dev/iris-classifier -X POST -H "Content-Type: application/json" -d @sample.json -``` - -### Cleanup - -Delete the API Gateway and VPC Link before spinning down your Cortex cluster: - -![delete api](https://user-images.githubusercontent.com/808475/80149163-05970680-856b-11ea-9f82-61f4061a3321.png) - -![delete vpc link](https://user-images.githubusercontent.com/808475/80149204-1ba4c700-856b-11ea-83f7-9741c78b6b95.png) diff --git a/docs/clusters/aws/networking/https/index.md b/docs/clusters/aws/networking/https/index.md deleted file mode 100644 index be89601e4d..0000000000 --- a/docs/clusters/aws/networking/https/index.md +++ /dev/null @@ -1,5 +0,0 @@ -# Setting up HTTPS - -In order to set up HTTPS for your API you can choose one of the following options: -- [Setting up HTTPS through the load balancer](load-balancer.md) -- [Setting up HTTPS with AWS's API Gateway](api-gateway.md) diff --git a/docs/clusters/aws/networking/https/load-balancer.md b/docs/clusters/aws/networking/https/load-balancer.md deleted file mode 100644 index 7b9066a0e4..0000000000 --- a/docs/clusters/aws/networking/https/load-balancer.md +++ /dev/null @@ -1,134 +0,0 @@ -# Setting up HTTPS through the load balancer - -This guide assumes you have a custom domain assigned to your API. If you haven't set up custom domain yet, please follow this [guide](../custom_domain/dns.md). - -## Generate a certificate for your domain - -### Step 1 - -We are going to create an SSL certificate for your subdomain. Go to the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home) and click "Get Started" under the "Provision certificates" section. - -![step 6](https://user-images.githubusercontent.com/4365343/82202340-c04ac800-98cf-11ea-9472-89dd6d67eb0d.png) - -### Step 2 - -Select "Request a public certificate" and then "Request a certificate". - -![step 7](https://user-images.githubusercontent.com/4365343/82202654-3e0ed380-98d0-11ea-8c57-025f0b69c54f.png) - -### Step 3 - -Enter your subdomain and then click "Next". - -![step 8](https://user-images.githubusercontent.com/4365343/82224652-1cbedf00-98f2-11ea-912b-466cee2f6e25.png) - -### Step 4 - -Select "DNS validation" and then click "Next". - -![step 9](https://user-images.githubusercontent.com/4365343/82205311-66003600-98d4-11ea-90e3-da7e8b0b2b9c.png) - -### Step 5 - -Add tags for searchability (optional) then click "Review". - -![step 10](https://user-images.githubusercontent.com/4365343/82206485-52ee6580-98d6-11ea-95a9-1d0ebafc178a.png) - -### Step 6 - -Click "Confirm and request". - -![step 11](https://user-images.githubusercontent.com/4365343/82206602-84ffc780-98d6-11ea-9f2f-ce383404ec67.png) - -### Step 7 - -Click "Create record in Route 53". A popup will appear indicating that a Record is going to be added to Route 53. Click "Create" to automatically add the DNS record to your subdomain's hosted zone. Then click "Continue". - -![step 12](https://user-images.githubusercontent.com/4365343/82223539-c8ffc600-98f0-11ea-93a2-044aa0c9670d.png) - -### Step 8 - -Wait for the Certificate Status to be "issued". This might take a few minutes. - -![step 13](https://user-images.githubusercontent.com/4365343/82209663-a616e700-98db-11ea-95cb-c6efedadb942.png) - -### Step 9 - -Take note of the certificate's ARN. The certificate is ineligible for renewal because it is currently not being used. It will be eligible for renewal after it is used in Cortex. - -![step 14](https://user-images.githubusercontent.com/4365343/82222684-9e613d80-98ef-11ea-98c0-5a20b457f062.png) - -## Configure the API load balancer - -### Step 1 - -Add the following field to your cluster configuration: - -```yaml -# cluster.yaml - -... - -ssl_certificate_arn: -``` - -and then create a Cortex cluster. - -```bash -$ cortex cluster up --config cluster.yaml -``` - -### Step 2 - -After your cluster has been created, navigate to your [EC2 Load Balancer console](https://us-west-2.console.aws.amazon.com/ec2/v2/home#LoadBalancers:sort=loadBalancerName) and locate the Cortex API load balancer. You can determine which is the API load balancer by inspecting the `kubernetes.io/service-name` tag. - -Take note of the load balancer's name. - -![step 2](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) - -### Step 3 - -Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API load balancer (leave "Name" blank). - -![step 3](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) - -## Using your new endpoint - -Wait a few minutes to allow the DNS changes to propagate. You may now use your subdomain in place of your API load balancer endpoint in your client. For example, this curl request: - -```bash -curl http://a5044e34a352d44b0945adcd455c7fa3-32fa161d3e5bcbf9.elb.us-west-2.amazonaws.com/text-generator -X POST -H "Content-Type: application/json" -d @sample.json -``` - -Would become: - -```bash -# replace loadbalancer url with your subdomain -curl https://api.cortexlabs.dev/text-generator -X POST -H "Content-Type: application/json" -d @sample.json -``` - -## Debugging connectivity issues - -You could run into connectivity issues if you make a request to your API without waiting long enough for your DNS records to propagate after creating them (it usually takes 5-10 mintues). If you are updating existing DNS records, it could take anywhere from a few minutes to 48 hours for the DNS cache to expire (until then, your previous DNS configuration will be used). - -To test connectivity, try the following steps: - -1. Deploy any api (e.g. examples/pytorch/iris-classifier). -1. Make an HTTPS GET request to the your api e.g. `curl https://api.cortexlabs.dev/iris-classifier` or enter the url in your browser. -1. If you run into an error such as `curl: (6) Could not resolve host: api.cortexlabs.dev` wait a few minutes and make the HTTPS Get request from another device that hasn't made a request to that url in a while. A successful request looks like this: - -```text -{"message":"make a prediction by sending a post request to this endpoint with a json payload",...} -``` - -## Cleanup - -Spin down your Cortex cluster. - -Delete the hosted zone for your subdomain in the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:): - -![delete hosted zone](https://user-images.githubusercontent.com/4365343/82228729-81306d00-98f7-11ea-8570-e9de15f5267f.png) - -Delete your certificate from the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home): - -![delete certificate](https://user-images.githubusercontent.com/4365343/82228835-a624e000-98f7-11ea-92e2-cb4fb0f591e2.png) diff --git a/docs/clusters/aws/networking/index.md b/docs/clusters/aws/networking/index.md index 1ee31a8be8..e24b2028bb 100644 --- a/docs/clusters/aws/networking/index.md +++ b/docs/clusters/aws/networking/index.md @@ -2,12 +2,8 @@ ![api architecture diagram](https://user-images.githubusercontent.com/808475/103417256-dd6e9700-4b3e-11eb-901e-90425f1f8fd4.png) -All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your [cluster configuration](../install.md) file (before creating your cluster). This will make your API only accessible through VPC Peering. +All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). This will make your API only accessible through [VPC Peering](vpc-peering.md). -The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to make HTTP requests or skip certificate verification when making HTTPS requests (e.g. `curl -k`). Alternatively, you can enable HTTPS by using a custom domain or by creating an API Gateway to forward requests to your API load balancer. +The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests to your APIs (e.g. `curl -k https://***`), or make HTTP requests instead (e.g. `curl http://***`). Alternatively, you can enable HTTPS by using a [custom domain](custom-domain.md) or by [creating an API Gateway](api-gateway.md) to forward requests to your API load balancer. -## Networking Topics - -- [Custom Domain](custom_domain/index.md) -- [HTTPS](https/index.md) -- [VPC Peering](vpc-peering.md) +There is a separate load balancer for the Cortex operator. By default, the operator load balancer is public. You can configure your operator load balancer to be private by setting `operator_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). You can use [VPC Peering](vpc-peering.md) to enable your Cortex CLI to connect to your cluster operator from another VPC. diff --git a/docs/clusters/aws/networking/vpc-peering.md b/docs/clusters/aws/networking/vpc-peering.md index 1c635590a9..93a32484f6 100644 --- a/docs/clusters/aws/networking/vpc-peering.md +++ b/docs/clusters/aws/networking/vpc-peering.md @@ -2,7 +2,7 @@ If you are using an internal operator load balancer (i.e. you set `operator_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster), you can use VPC Peering to enable your Cortex CLI to connect to your cluster operator from another VPC so that you may run `cortex` commands. Note that because the operator validates that the CLI user is an active IAM user in the same AWS account as the Cortex cluster, it is usually unnecessary to configure the operator's load balancer to be internal. -If you are using an internal API load balancer (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster) and you disabled API Gateway for your API (i.e. you set `api_gateway: none` in the `networking` field of your api configuration), you can use VPC Peering to enable prediction requests from another VPC. +If you are using an internal API load balancer (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster), you can use VPC Peering to make prediction requests from another VPC. This guide illustrates how to create a VPC Peering connection between a VPC of your choice and the Cortex load balancers. diff --git a/docs/summary.md b/docs/summary.md index c036ffa1b1..142840aebd 100644 --- a/docs/summary.md +++ b/docs/summary.md @@ -44,12 +44,8 @@ * [GPUs](clusters/aws/compute/gpu.md) * [Inferentia](clusters/aws/compute/inferentia.md) * [Networking](clusters/aws/networking/index.md) - * [Custom Domain](clusters/aws/networking/custom_domain/index.md) - * [With API Gateway](clusters/aws/networking/custom_domain/api-gateway.md) - * [Without API Gateway](clusters/aws/networking/custom_domain/dns.md) - * [HTTPS](clusters/aws/networking/https/index.md) - * [Load Balancer Certificate](clusters/aws/networking/https/load-balancer.md) - * [API Gateway](clusters/aws/networking/https/api-gateway.md) + * [Custom domain](clusters/aws/networking/custom-domain.md) + * [API Gateway (HTTPS)](clusters/aws/networking/api-gateway.md) * [VPC peering](clusters/aws/networking/vpc-peering.md) * [Setting up kubectl](clusters/aws/kubectl.md) * [Uninstall](clusters/aws/uninstall.md) From 1ba179f5ddb00d7d70f9199216203d5ba293f1a8 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Thu, 31 Dec 2020 15:10:30 -0800 Subject: [PATCH 06/20] Remove image captions --- docs/clusters/aws/networking/custom-domain.md | 34 +++++++++---------- docs/clusters/aws/networking/vpc-peering.md | 26 +++++++------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/clusters/aws/networking/custom-domain.md b/docs/clusters/aws/networking/custom-domain.md index eede9fc818..088fc0dced 100644 --- a/docs/clusters/aws/networking/custom-domain.md +++ b/docs/clusters/aws/networking/custom-domain.md @@ -8,15 +8,15 @@ Decide on a subdomain that you want to dedicate to Cortex APIs. For example if y We will set up a hosted zone on Route 53 to manage the DNS records for the subdomain. Go to the [Route 53 console](https://console.aws.amazon.com/route53/home) and click "Hosted Zones". -![hosted zones](https://user-images.githubusercontent.com/4365343/82210754-a6b07d00-98dd-11ea-9cec-9f6b07282aa8.png) +![](https://user-images.githubusercontent.com/4365343/82210754-a6b07d00-98dd-11ea-9cec-9f6b07282aa8.png) Click "Create Hosted Zone" and then enter your subdomain as the domain name for your hosted zone and click "Create". -![create hosted zone](https://user-images.githubusercontent.com/4365343/82211091-4968fb80-98de-11ea-8ec4-8d26d1aea77a.png) +![](https://user-images.githubusercontent.com/4365343/82211091-4968fb80-98de-11ea-8ec4-8d26d1aea77a.png) Take note of the values in the NS record. -![view ns record](https://user-images.githubusercontent.com/4365343/82211656-386cba00-98df-11ea-8c86-4961082b5f49.png) +![](https://user-images.githubusercontent.com/4365343/82211656-386cba00-98df-11ea-8c86-4961082b5f49.png) Navigate to your root DNS service provider (e.g. Google Domains, AWS Route 53, Go Daddy). Your root DNS service provider is typically the registrar where you purchased your domain (unless you have transferred DNS management elsewhere). The procedure for adding DNS records may vary based on your service provider. @@ -24,7 +24,7 @@ We are going to add an NS (name server) record that specifies that any traffic t `cortexlabs.dev` is managed by Google Domains. The image below is a screenshot for adding a DNS record in Google Domains (your UI may differ based on your DNS service provider). -![add ns record](https://user-images.githubusercontent.com/4365343/82211959-bcbf3d00-98df-11ea-834d-692b3bcf9332.png) +![](https://user-images.githubusercontent.com/4365343/82211959-bcbf3d00-98df-11ea-834d-692b3bcf9332.png) ## Generate an SSL certificate @@ -32,39 +32,39 @@ You can skip this section (and continue to [add the DNS record](#add-dns-record) To create an SSL certificate, go to the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home) and click "Get Started" under the "Provision certificates" section. -![acm](https://user-images.githubusercontent.com/4365343/82202340-c04ac800-98cf-11ea-9472-89dd6d67eb0d.png) +![](https://user-images.githubusercontent.com/4365343/82202340-c04ac800-98cf-11ea-9472-89dd6d67eb0d.png) Select "Request a public certificate" and then "Request a certificate". -![request certificate](https://user-images.githubusercontent.com/4365343/82202654-3e0ed380-98d0-11ea-8c57-025f0b69c54f.png) +![](https://user-images.githubusercontent.com/4365343/82202654-3e0ed380-98d0-11ea-8c57-025f0b69c54f.png) Enter your subdomain and then click "Next". -![enter subdomain](https://user-images.githubusercontent.com/4365343/82224652-1cbedf00-98f2-11ea-912b-466cee2f6e25.png) +![](https://user-images.githubusercontent.com/4365343/82224652-1cbedf00-98f2-11ea-912b-466cee2f6e25.png) Select "DNS validation" and then click "Next". -![dns validation](https://user-images.githubusercontent.com/4365343/82205311-66003600-98d4-11ea-90e3-da7e8b0b2b9c.png) +![](https://user-images.githubusercontent.com/4365343/82205311-66003600-98d4-11ea-90e3-da7e8b0b2b9c.png) Add tags for searchability (optional) then click "Review". -![add tags](https://user-images.githubusercontent.com/4365343/82206485-52ee6580-98d6-11ea-95a9-1d0ebafc178a.png) +![](https://user-images.githubusercontent.com/4365343/82206485-52ee6580-98d6-11ea-95a9-1d0ebafc178a.png) Click "Confirm and request". -![confirm](https://user-images.githubusercontent.com/4365343/82206602-84ffc780-98d6-11ea-9f2f-ce383404ec67.png) +![](https://user-images.githubusercontent.com/4365343/82206602-84ffc780-98d6-11ea-9f2f-ce383404ec67.png) Click "Create record in Route 53". A popup will appear indicating that a Record is going to be added to Route 53. Click "Create" to automatically add the DNS record to your subdomain's hosted zone. Then click "Continue". -![create record](https://user-images.githubusercontent.com/4365343/82223539-c8ffc600-98f0-11ea-93a2-044aa0c9670d.png) +![](https://user-images.githubusercontent.com/4365343/82223539-c8ffc600-98f0-11ea-93a2-044aa0c9670d.png) Wait for the Certificate Status to be "issued". This might take a few minutes. -![wait for issued](https://user-images.githubusercontent.com/4365343/82209663-a616e700-98db-11ea-95cb-c6efedadb942.png) +![](https://user-images.githubusercontent.com/4365343/82209663-a616e700-98db-11ea-95cb-c6efedadb942.png) Take note of the certificate's ARN. The certificate is ineligible for renewal because it is currently not being used. It will be eligible for renewal once it's used in Cortex. -![arn](https://user-images.githubusercontent.com/4365343/82222684-9e613d80-98ef-11ea-98c0-5a20b457f062.png) +![](https://user-images.githubusercontent.com/4365343/82222684-9e613d80-98ef-11ea-98c0-5a20b457f062.png) Add the following field to your cluster configuration: @@ -88,11 +88,11 @@ Navigate to your [EC2 Load Balancer console](https://us-west-2.console.aws.amazo Take note of the load balancer's name. -![locate load balancer](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) +![](https://user-images.githubusercontent.com/808475/80142777-961c1980-8560-11ea-9202-40964dbff5e9.png) Go back to the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:) and select the hosted zone you created earlier. Click "Create Record Set", and add an Alias record that routes traffic to your Cortex cluster's API load balancer (leave "Name" blank). -![create record set](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) +![](https://user-images.githubusercontent.com/808475/84083422-6ac97e80-a996-11ea-9679-be37268a2133.png) ## Use your new endpoint @@ -129,8 +129,8 @@ Spin down your Cortex cluster. Delete the hosted zone for your subdomain in the [Route 53 console](https://console.aws.amazon.com/route53/home#hosted-zones:): -![delete hosted zone](https://user-images.githubusercontent.com/4365343/82228729-81306d00-98f7-11ea-8570-e9de15f5267f.png) +![](https://user-images.githubusercontent.com/4365343/82228729-81306d00-98f7-11ea-8570-e9de15f5267f.png) If you created an SSL certificate, delete it from the [ACM console](https://us-west-2.console.aws.amazon.com/acm/home): -![delete certificate](https://user-images.githubusercontent.com/4365343/82228835-a624e000-98f7-11ea-92e2-cb4fb0f591e2.png) +![](https://user-images.githubusercontent.com/4365343/82228835-a624e000-98f7-11ea-92e2-cb4fb0f591e2.png) diff --git a/docs/clusters/aws/networking/vpc-peering.md b/docs/clusters/aws/networking/vpc-peering.md index 93a32484f6..10638ffc8c 100644 --- a/docs/clusters/aws/networking/vpc-peering.md +++ b/docs/clusters/aws/networking/vpc-peering.md @@ -10,15 +10,15 @@ This guide illustrates how to create a VPC Peering connection between a VPC of y Navigate to AWS's EC2 Load Balancer dashboard and locate the Cortex operator's load balancer. You can determine which is the operator load balancer by inspecting the `kubernetes.io/service-name` tag: -![step 1a](https://user-images.githubusercontent.com/808475/80126132-804e2a80-8547-11ea-8ce4-57d3fd96e2c4.png) +![](https://user-images.githubusercontent.com/808475/80126132-804e2a80-8547-11ea-8ce4-57d3fd96e2c4.png) Click back to the "Description" tab and note the VPC ID of the load balancer and the ID of each of the subnets associated with the load balancer: -![step 1b](https://user-images.githubusercontent.com/808475/80127144-c2c43700-8548-11ea-95b4-ce9d1df024cc.png) +![](https://user-images.githubusercontent.com/808475/80127144-c2c43700-8548-11ea-95b4-ce9d1df024cc.png) Navigate to AWS's VPC dashboard and identify the ID and CIDR block of Cortex's VPC: -![step 1c](https://user-images.githubusercontent.com/808475/80125554-af17d100-8546-11ea-96ec-00e2aaee7100.png) +![](https://user-images.githubusercontent.com/808475/80125554-af17d100-8546-11ea-96ec-00e2aaee7100.png) The VPC ID here should match that of the load balancer. @@ -28,33 +28,33 @@ Identify the ID and CIDR block of the VPC from which you'd like to connect to th In my case, I have a VPC in the same AWS account and region, and I can locate its ID and CIDR block from AWS's VPC dashboard: -![step 2](https://user-images.githubusercontent.com/808475/80125729-eb4b3180-8546-11ea-8d20-6bc2478747ae.png) +![](https://user-images.githubusercontent.com/808475/80125729-eb4b3180-8546-11ea-8d20-6bc2478747ae.png) ## Step 3 From AWS's VPC dashboard, navigate to the "Peering Connections" page, and click "Create Peering Connection": -![step 3a](https://user-images.githubusercontent.com/808475/80127600-67df0f80-8549-11ea-9e10-765a6e273b54.png) +![](https://user-images.githubusercontent.com/808475/80127600-67df0f80-8549-11ea-9e10-765a6e273b54.png) Name your new VPC Peering Connection (I used "cortex-operator", but "cortex" or "cortex-api" may make more sense depending on your use case). Then configure the connection such that the "Requester" is the VPC from which you'll connect to the Cortex VPC, and the "Accepter" is Cortex's VPC (from step 1). -![step 3b](https://user-images.githubusercontent.com/808475/80131545-3f5a1400-854f-11ea-9ca0-c51433d3fa3d.png) +![](https://user-images.githubusercontent.com/808475/80131545-3f5a1400-854f-11ea-9ca0-c51433d3fa3d.png) Click "Create Peering Connection", navigate back to the Peering Connections dashboard, select the newly created peering connection, and click "Actions" > "Accept Request": -![step 3c](https://user-images.githubusercontent.com/808475/80132168-21d97a00-8550-11ea-8c22-79c65710d369.png) +![](https://user-images.githubusercontent.com/808475/80132168-21d97a00-8550-11ea-8c22-79c65710d369.png) -![step 3d](https://user-images.githubusercontent.com/808475/80132179-26059780-8550-11ea-80fc-6670fcab7026.png) +![](https://user-images.githubusercontent.com/808475/80132179-26059780-8550-11ea-80fc-6670fcab7026.png) ## Step 4 Navigate to the VPC Route Tables page. Select the route table for the VPC from which you'd like to connect to the Cortex cluster (in my case, I just have one route table for this VPC). Select the "Routes" tab, and click "Edit routes": -![step 4a](https://user-images.githubusercontent.com/808475/80135180-b940cc00-8554-11ea-8162-c7409090897b.png) +![](https://user-images.githubusercontent.com/808475/80135180-b940cc00-8554-11ea-8162-c7409090897b.png) Add a route where the "Destination" is the CIDR block for Cortex's VPC (identified in Step 1), and the "Target" is the newly-created Peering Connection: -![step 4b](https://user-images.githubusercontent.com/808475/80137033-78968200-8557-11ea-9d84-9221b772f0fc.png) +![](https://user-images.githubusercontent.com/808475/80137033-78968200-8557-11ea-9d84-9221b772f0fc.png) Do not create new route tables or change subnet associations. @@ -62,11 +62,11 @@ Do not create new route tables or change subnet associations. Navigate back to the VPC Route Tables page. There will be a route table for each of the subnets associated with the Cortex operator load balancer (identified in Step 1): -![step 5a](https://user-images.githubusercontent.com/808475/80138244-5dc50d00-8559-11ea-9248-fc201d011530.png) +![](https://user-images.githubusercontent.com/808475/80138244-5dc50d00-8559-11ea-9248-fc201d011530.png) For each of these route tables, click "Edit routes" and add a new route where the "Destination" is the CIDR block for the VPC from which you will be connecting to the Cortex cluster (identified in Step 2), and the "Target" is the newly-created Peering Connection: -![step 5b](https://user-images.githubusercontent.com/808475/80138653-f78cba00-8559-11ea-8444-406e218c3bab.png) +![](https://user-images.githubusercontent.com/808475/80138653-f78cba00-8559-11ea-8444-406e218c3bab.png) Repeat adding this route for each route table associated with the Cortex operator's subnets; in my case there were three. Do not create new route tables or change subnet associations. @@ -76,4 +76,4 @@ You should now be able to use the Cortex CLI and make prediction requests from y Delete the VPC Peering connection before spinning down your Cortex cluster: -![cleanup](https://user-images.githubusercontent.com/808475/80138851-57836080-855a-11ea-92f1-06d501932a41.png) +![](https://user-images.githubusercontent.com/808475/80138851-57836080-855a-11ea-92f1-06d501932a41.png) From c64ffdb1594ae5d74bf0ddadc4834bb9761e9125 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Thu, 31 Dec 2020 15:11:45 -0800 Subject: [PATCH 07/20] Fix link --- docs/clusters/aws/uninstall.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/clusters/aws/uninstall.md b/docs/clusters/aws/uninstall.md index 929a549f2c..65313cb1fb 100644 --- a/docs/clusters/aws/uninstall.md +++ b/docs/clusters/aws/uninstall.md @@ -25,7 +25,7 @@ aws s3 rb --force s3:// aws logs describe-log-groups --log-group-name-prefix= --query logGroups[*].[logGroupName] --output text | xargs -I {} aws logs delete-log-group --log-group-name {} ``` -If you've configured a custom domain for your APIs, you can remove the SSL Certificate and Hosted Zone for the domain by following these [instructions](networking/custom_domain/original.md#cleanup). +If you've configured a custom domain for your APIs, you can remove the SSL Certificate and Hosted Zone for the domain by following these [instructions](networking/custom-domain.md#cleanup). ## Troubleshooting From 8e1a0a8f65a6516a4e94cca71355d341a481bd74 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Thu, 31 Dec 2020 15:19:44 -0800 Subject: [PATCH 08/20] Update vpc peering --- docs/clusters/aws/networking/api-gateway.md | 2 +- docs/clusters/aws/networking/vpc-peering.md | 18 +++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/docs/clusters/aws/networking/api-gateway.md b/docs/clusters/aws/networking/api-gateway.md index d4e1e9986b..23f77b0dc6 100644 --- a/docs/clusters/aws/networking/api-gateway.md +++ b/docs/clusters/aws/networking/api-gateway.md @@ -82,7 +82,7 @@ Go to the [API Gateway console](https://console.aws.amazon.com/apigateway/home), ![](https://user-images.githubusercontent.com/808475/80142466-0c6c4c00-8560-11ea-8293-eb5e5572b797.png) -Select "VPC link for REST APIs", name your VPC link (e.g. "cortex"), select the API load balancer (identified in Step 1), and click "Create" +Select "VPC link for REST APIs", name your VPC link (e.g. "cortex"), select the API load balancer, and click "Create". ![](https://user-images.githubusercontent.com/808475/80143027-03c84580-8561-11ea-92de-9ed0a5dfa593.png) diff --git a/docs/clusters/aws/networking/vpc-peering.md b/docs/clusters/aws/networking/vpc-peering.md index 10638ffc8c..4443de4466 100644 --- a/docs/clusters/aws/networking/vpc-peering.md +++ b/docs/clusters/aws/networking/vpc-peering.md @@ -6,7 +6,7 @@ If you are using an internal API load balancer (i.e. you set `api_load_balancer_ This guide illustrates how to create a VPC Peering connection between a VPC of your choice and the Cortex load balancers. -## Step 1 +## Gather Cortex's VPC information Navigate to AWS's EC2 Load Balancer dashboard and locate the Cortex operator's load balancer. You can determine which is the operator load balancer by inspecting the `kubernetes.io/service-name` tag: @@ -22,7 +22,7 @@ Navigate to AWS's VPC dashboard and identify the ID and CIDR block of Cortex's V The VPC ID here should match that of the load balancer. -## Step 2 +## Create peering connection Identify the ID and CIDR block of the VPC from which you'd like to connect to the Cortex VPC. @@ -30,13 +30,11 @@ In my case, I have a VPC in the same AWS account and region, and I can locate it ![](https://user-images.githubusercontent.com/808475/80125729-eb4b3180-8546-11ea-8d20-6bc2478747ae.png) -## Step 3 - From AWS's VPC dashboard, navigate to the "Peering Connections" page, and click "Create Peering Connection": ![](https://user-images.githubusercontent.com/808475/80127600-67df0f80-8549-11ea-9e10-765a6e273b54.png) -Name your new VPC Peering Connection (I used "cortex-operator", but "cortex" or "cortex-api" may make more sense depending on your use case). Then configure the connection such that the "Requester" is the VPC from which you'll connect to the Cortex VPC, and the "Accepter" is Cortex's VPC (from step 1). +Name your new VPC Peering Connection (I used "cortex-operator", but "cortex" or "cortex-api" may make more sense depending on your use case). Then configure the connection such that the "Requester" is the VPC from which you'll connect to the Cortex VPC, and the "Accepter" is Cortex's VPC. ![](https://user-images.githubusercontent.com/808475/80131545-3f5a1400-854f-11ea-9ca0-c51433d3fa3d.png) @@ -46,25 +44,23 @@ Click "Create Peering Connection", navigate back to the Peering Connections dash ![](https://user-images.githubusercontent.com/808475/80132179-26059780-8550-11ea-80fc-6670fcab7026.png) -## Step 4 +## Update route tables Navigate to the VPC Route Tables page. Select the route table for the VPC from which you'd like to connect to the Cortex cluster (in my case, I just have one route table for this VPC). Select the "Routes" tab, and click "Edit routes": ![](https://user-images.githubusercontent.com/808475/80135180-b940cc00-8554-11ea-8162-c7409090897b.png) -Add a route where the "Destination" is the CIDR block for Cortex's VPC (identified in Step 1), and the "Target" is the newly-created Peering Connection: +Add a route where the "Destination" is the CIDR block for Cortex's VPC, and the "Target" is the newly-created Peering Connection: ![](https://user-images.githubusercontent.com/808475/80137033-78968200-8557-11ea-9d84-9221b772f0fc.png) Do not create new route tables or change subnet associations. -## Step 5 - -Navigate back to the VPC Route Tables page. There will be a route table for each of the subnets associated with the Cortex operator load balancer (identified in Step 1): +Navigate back to the VPC Route Tables page. There will be a route table for each of the subnets associated with the Cortex operator load balancer: ![](https://user-images.githubusercontent.com/808475/80138244-5dc50d00-8559-11ea-9248-fc201d011530.png) -For each of these route tables, click "Edit routes" and add a new route where the "Destination" is the CIDR block for the VPC from which you will be connecting to the Cortex cluster (identified in Step 2), and the "Target" is the newly-created Peering Connection: +For each of these route tables, click "Edit routes" and add a new route where the "Destination" is the CIDR block for the VPC from which you will be connecting to the Cortex cluster, and the "Target" is the newly-created Peering Connection: ![](https://user-images.githubusercontent.com/808475/80138653-f78cba00-8559-11ea-8444-406e218c3bab.png) From e257a307e0d50da379f9ecd4c2a60b70f8108f7a Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Thu, 31 Dec 2020 15:23:06 -0800 Subject: [PATCH 09/20] Move compute back to original location --- docs/clusters/aws/{compute => }/gpu.md | 0 docs/clusters/aws/{compute => }/inferentia.md | 0 docs/clusters/aws/{compute => }/spot.md | 0 docs/summary.md | 7 +++---- 4 files changed, 3 insertions(+), 4 deletions(-) rename docs/clusters/aws/{compute => }/gpu.md (100%) rename docs/clusters/aws/{compute => }/inferentia.md (100%) rename docs/clusters/aws/{compute => }/spot.md (100%) diff --git a/docs/clusters/aws/compute/gpu.md b/docs/clusters/aws/gpu.md similarity index 100% rename from docs/clusters/aws/compute/gpu.md rename to docs/clusters/aws/gpu.md diff --git a/docs/clusters/aws/compute/inferentia.md b/docs/clusters/aws/inferentia.md similarity index 100% rename from docs/clusters/aws/compute/inferentia.md rename to docs/clusters/aws/inferentia.md diff --git a/docs/clusters/aws/compute/spot.md b/docs/clusters/aws/spot.md similarity index 100% rename from docs/clusters/aws/compute/spot.md rename to docs/clusters/aws/spot.md diff --git a/docs/summary.md b/docs/summary.md index 142840aebd..b22cfc6f4f 100644 --- a/docs/summary.md +++ b/docs/summary.md @@ -39,10 +39,9 @@ * [Install](clusters/aws/install.md) * [Update](clusters/aws/update.md) * [Security](clusters/aws/security.md) - * Compute - * [Spot instances](clusters/aws/compute/spot.md) - * [GPUs](clusters/aws/compute/gpu.md) - * [Inferentia](clusters/aws/compute/inferentia.md) + * [Spot instances](clusters/aws/spot.md) + * [GPUs](clusters/aws/gpu.md) + * [Inferentia](clusters/aws/inferentia.md) * [Networking](clusters/aws/networking/index.md) * [Custom domain](clusters/aws/networking/custom-domain.md) * [API Gateway (HTTPS)](clusters/aws/networking/api-gateway.md) From 54343fc82108bfde31605900b2c33aa251e290e1 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Thu, 31 Dec 2020 15:40:46 -0800 Subject: [PATCH 10/20] Update docs --- docs/clusters/aws/networking/api-gateway.md | 4 ++-- docs/clusters/aws/networking/custom-domain.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/clusters/aws/networking/api-gateway.md b/docs/clusters/aws/networking/api-gateway.md index 23f77b0dc6..71dd08dc53 100644 --- a/docs/clusters/aws/networking/api-gateway.md +++ b/docs/clusters/aws/networking/api-gateway.md @@ -8,7 +8,7 @@ If your API load balancer is internal (i.e. you set `api_load_balancer_scheme: i ## Internet-facing load balancer -_This section applies if your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster). If your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file), see the [internal load balancer](#internal-load-balancer) section below._ +_This section applies if your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster). If your API load balancer is internal, see the [internal load balancer](#internal-load-balancer) section below._ ### Create an API Gateway @@ -68,7 +68,7 @@ Delete the API Gateway before spinning down your Cortex cluster: ## Internal load balancer -_This section applies if your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster). If your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file), see the [internet-facing load balancer](#internet-facing-load-balancer) section above._ +_This section applies if your API load balancer is internal (i.e. you set `api_load_balancer_scheme: internal` in your cluster configuration file before creating your cluster). If your API load balancer is internet-facing, see the [internet-facing load balancer](#internet-facing-load-balancer) section above._ ### Create a VPC Link diff --git a/docs/clusters/aws/networking/custom-domain.md b/docs/clusters/aws/networking/custom-domain.md index 088fc0dced..8fd3ca9054 100644 --- a/docs/clusters/aws/networking/custom-domain.md +++ b/docs/clusters/aws/networking/custom-domain.md @@ -1,6 +1,6 @@ # Custom domain -You can use any custom domain (that you own) for your prediction endpoints. For example, you can make your API accessible via `api.example.com/text-generator`. This guide will demonstrate how to create a dedicated subdomain in AWS Route 53 and use an SSL certificate provisioned by AWS Certificate Manager (if desired). +You can use any custom domain (that you own) for your prediction endpoints. For example, you can make your API accessible via `api.example.com/text-generator`. This guide will demonstrate how to create a dedicated subdomain in AWS Route 53 and, if desired, configure your API load balancer to use an SSL certificate provisioned by AWS Certificate Manager. ## Configure DNS From c4e7903179e5ed6143c320a8fd5741871d9d5456 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Thu, 31 Dec 2020 15:50:46 -0800 Subject: [PATCH 11/20] Format --- dev/format.sh | 4 ++-- pkg/types/clusterconfig/cluster_config_aws.go | 10 +++++----- pkg/types/userconfig/api.go | 4 ++-- pkg/types/userconfig/config_key.go | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/dev/format.sh b/dev/format.sh index d8bd71dbee..e40988b8e6 100755 --- a/dev/format.sh +++ b/dev/format.sh @@ -68,7 +68,7 @@ xargs -0 -L1 bash -c 'test "$(tail -c 1 "$0")" && echo "" >> "$0"' || true) ! -path "./.git/*" \ ! -name ".*" \ -print0 | \ -xargs -0 -L1 bash -c 'test "$(tail -c 2 "$0")" || (trimmed=$(printf "%s" "$(< $0)") && echo "$trimmed" > "$0")' || true) +xargs -0 -L1 bash -c 'test "$(tail -c 2 "$0")" || [ ! -s "$0" ] || (trimmed=$(printf "%s" "$(< $0)") && echo "$trimmed" > "$0")' || true) # Remove new lines at beginning of file (cd "$ROOT" && find . -type f \ @@ -77,4 +77,4 @@ xargs -0 -L1 bash -c 'test "$(tail -c 2 "$0")" || (trimmed=$(printf "%s" "$(< $0 ! -path "./.git/*" \ ! -name ".*" \ -print0 | \ -xargs -0 -L1 bash -c 'test "$(head -c 1 "$0")" || (trimmed=$(sed '"'"'/./,$!d'"'"' "$0") && echo "$trimmed" > "$0")' || true) +xargs -0 -L1 bash -c 'test "$(head -c 1 "$0")" || [ ! -s "$0" ] || (trimmed=$(sed '"'"'/./,$!d'"'"' "$0") && echo "$trimmed" > "$0")' || true) diff --git a/pkg/types/clusterconfig/cluster_config_aws.go b/pkg/types/clusterconfig/cluster_config_aws.go index 885cd78fb2..70a6afe9b5 100644 --- a/pkg/types/clusterconfig/cluster_config_aws.go +++ b/pkg/types/clusterconfig/cluster_config_aws.go @@ -101,11 +101,11 @@ type InternalConfig struct { Config // Populated by operator - APIVersion string `json:"api_version"` - OperatorID string `json:"operator_id"` - ClusterID string `json:"cluster_id"` - IsOperatorInCluster bool `json:"is_operator_in_cluster"` - InstanceMetadata aws.InstanceMetadata `json:"instance_metadata"` + APIVersion string `json:"api_version"` + OperatorID string `json:"operator_id"` + ClusterID string `json:"cluster_id"` + IsOperatorInCluster bool `json:"is_operator_in_cluster"` + InstanceMetadata aws.InstanceMetadata `json:"instance_metadata"` } // The bare minimum to identify a cluster diff --git a/pkg/types/userconfig/api.go b/pkg/types/userconfig/api.go index 61cfc9edca..01afbd9b2f 100644 --- a/pkg/types/userconfig/api.go +++ b/pkg/types/userconfig/api.go @@ -93,8 +93,8 @@ type ServerSideBatching struct { } type Networking struct { - Endpoint *string `json:"endpoint" yaml:"endpoint"` - LocalPort *int `json:"local_port" yaml:"local_port"` + Endpoint *string `json:"endpoint" yaml:"endpoint"` + LocalPort *int `json:"local_port" yaml:"local_port"` } type Compute struct { diff --git a/pkg/types/userconfig/config_key.go b/pkg/types/userconfig/config_key.go index 7b25c49fbb..1de3463d37 100644 --- a/pkg/types/userconfig/config_key.go +++ b/pkg/types/userconfig/config_key.go @@ -68,8 +68,8 @@ const ( ModelTypeKey = "model_type" // Networking - EndpointKey = "endpoint" - LocalPortKey = "local_port" + EndpointKey = "endpoint" + LocalPortKey = "local_port" // Compute CPUKey = "cpu" From 4b63f224d974ea93929b939d2c9bd961deffa668 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Sun, 3 Jan 2021 21:49:37 -0800 Subject: [PATCH 12/20] Update api-gateway.md --- docs/clusters/aws/networking/api-gateway.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/clusters/aws/networking/api-gateway.md b/docs/clusters/aws/networking/api-gateway.md index 71dd08dc53..bb23a7d914 100644 --- a/docs/clusters/aws/networking/api-gateway.md +++ b/docs/clusters/aws/networking/api-gateway.md @@ -1,6 +1,6 @@ # API Gateway (HTTPS) -AWS API Gateway can be configured to forward requests to your Cortex APIs. This can be useful as a simple way to supporte HTTPS traffic (as an alternative to custom domains), or to leverage other features provided by API Gateway. Please note that one limitation of API Gateway is that there is a 30-second time limit for all requests. +AWS API Gateway can be configured to forward requests to your Cortex APIs. This can be useful as a simple way to support HTTPS traffic (as an alternative to [custom domains](custom-domains.md)), or to leverage other features provided by API Gateway. Please note that one limitation of API Gateway is that there is a 30-second time limit for all requests. If your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster), use the [first section](#internet-facing-load-balancer) of this guide. From 283d8af5cb17b267dce47feff0aa864fcaa38427 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Sun, 3 Jan 2021 21:50:04 -0800 Subject: [PATCH 13/20] Update api-gateway.md --- docs/clusters/aws/networking/api-gateway.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/clusters/aws/networking/api-gateway.md b/docs/clusters/aws/networking/api-gateway.md index bb23a7d914..fdd09d85cc 100644 --- a/docs/clusters/aws/networking/api-gateway.md +++ b/docs/clusters/aws/networking/api-gateway.md @@ -1,6 +1,6 @@ # API Gateway (HTTPS) -AWS API Gateway can be configured to forward requests to your Cortex APIs. This can be useful as a simple way to support HTTPS traffic (as an alternative to [custom domains](custom-domains.md)), or to leverage other features provided by API Gateway. Please note that one limitation of API Gateway is that there is a 30-second time limit for all requests. +AWS API Gateway can be configured to forward requests to your Cortex APIs. This can be useful as a simple way to support HTTPS traffic (as an alternative to using a [custom domain](custom-domain.md)), or to leverage other features provided by API Gateway. Please note that one limitation of API Gateway is that there is a 30-second time limit for all requests. If your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster), use the [first section](#internet-facing-load-balancer) of this guide. From 2e7af647f10305d5c6ee37d58834ec9d675e32ce Mon Sep 17 00:00:00 2001 From: Miguel Varela Ramos Date: Mon, 4 Jan 2021 15:35:13 +0000 Subject: [PATCH 14/20] Remove API Gateway from manager and docs --- docs/clusters/aws/security.md | 3 +- docs/workloads/batch/configuration.md | 3 - docs/workloads/realtime/troubleshooting.md | 2 +- .../traffic-splitter/configuration.md | 1 - manager/create_gateway_integration.py | 79 ------------------- manager/get_api_gateway_endpoint.py | 36 --------- manager/get_api_gateway_id.py | 36 --------- manager/info.sh | 10 --- manager/install.sh | 73 ----------------- 9 files changed, 2 insertions(+), 241 deletions(-) delete mode 100644 manager/create_gateway_integration.py delete mode 100644 manager/get_api_gateway_endpoint.py delete mode 100644 manager/get_api_gateway_id.py diff --git a/docs/clusters/aws/security.md b/docs/clusters/aws/security.md index ee1fd56436..7abb474068 100644 --- a/docs/clusters/aws/security.md +++ b/docs/clusters/aws/security.md @@ -42,7 +42,7 @@ It is recommended to use an IAM user with the `AdministratorAccess` policy to cr A process called the Cortex operator runs on your cluster and is responsible for deploying and managing your APIs on the cluster. The operator will use the designated cluster credentials (e.g. `--cluster-aws-key` or `$CLUSTER_AWS_ACCESS_KEY_ID`) if specified, otherwise it will default to using the credentials used to spin up the cluster (e.g. `--aws-key` or `$AWS_ACCESS_KEY_ID`). -The operator requires read permissions for any S3 bucket containing exported models, read/write permissions for the Cortex S3 bucket, read permissions for ECR, read permissions for ELB, read/write permissions for API Gateway, read/write permissions for CloudWatch metrics, and read/write permissions for the Cortex CloudWatch log group. The policy below may be used to restrict the Operator's access: +The operator requires read permissions for any S3 bucket containing exported models, read/write permissions for the Cortex S3 bucket, read permissions for ECR, read permissions for ELB, read/write permissions for CloudWatch metrics, and read/write permissions for the Cortex CloudWatch log group. The policy below may be used to restrict the Operator's access: ```json { @@ -59,7 +59,6 @@ The operator requires read permissions for any S3 bucket containing exported mod "ecr:GetAuthorizationToken", "ecr:BatchGetImage", "elasticloadbalancing:Describe*", - "apigateway:*", "cloudwatch:*", "logs:*", "sqs:*" diff --git a/docs/workloads/batch/configuration.md b/docs/workloads/batch/configuration.md index 0a7653b090..fcf8ecc958 100644 --- a/docs/workloads/batch/configuration.md +++ b/docs/workloads/batch/configuration.md @@ -16,7 +16,6 @@ log_level: # log level that can be "debug", "info", "warning" or "error" (default: "info") networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) compute: cpu: # CPU request per worker, e.g. 200m or 1 (200m is equivalent to 0.2) (default: 200m) gpu: # GPU request per worker (default: 0) @@ -52,7 +51,6 @@ log_level: # log level that can be "debug", "info", "warning" or "error" (default: "info") networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) compute: cpu: # CPU request per worker, e.g. 200m or 1 (200m is equivalent to 0.2) (default: 200m) gpu: # GPU request per worker (default: 0) @@ -82,7 +80,6 @@ log_level: # log level that can be "debug", "info", "warning" or "error" (default: "info") networking: endpoint: # the endpoint for the API (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) compute: cpu: # CPU request per worker, e.g. 200m or 1 (200m is equivalent to 0.2) (default: 200m) gpu: # GPU request per worker (default: 0) diff --git a/docs/workloads/realtime/troubleshooting.md b/docs/workloads/realtime/troubleshooting.md index 956fa21ea9..7f498003e4 100644 --- a/docs/workloads/realtime/troubleshooting.md +++ b/docs/workloads/realtime/troubleshooting.md @@ -7,7 +7,7 @@ When making prediction requests to your API, it's possible to get a `{"message": 1. It's possible that your API is simply not ready yet. You can check the status of your API with `cortex get API_NAME`, and stream the logs with `cortex logs API_NAME`. 1. Your API may have errored during initialization or while responding to a previous request. `cortex get API_NAME` will show the status of your API, and you can view the logs with `cortex logs API_NAME`. -It is also possible to receive a `{"message":"Service Unavailable"}` error message (with HTTP status code `503`) if you are using an API Gateway endpoint for your API and if your request exceeds API Gateway's 29 second timeout. If you don't know whether you are using API Gateway, you can run `cortex get ` and check if `networking.api_gateway` is not set to `none` in the api configuration. If the request is exceeding the API Gateway timeout, your client should receive the `{"message":"Service Unavailable"}` response ~29 seconds after making the request. To confirm that this is the issue, you can modify your `predict()` function to immediately return a response (e.g. `return "ok"`), re-deploy your API, wait for the update to complete, and try making a request. If your client successfully receives the "ok" response, it is likely that the API Gateway timeout is occurring. You can either modify your `predict()` implementation to take less time, run on faster hardware (e.g. GPUs), or disable API Gateway for this API by setting `api_gateway: none` in the `networking` field of the API configuration. +It is also possible to receive a `{"message":"Service Unavailable"}` error message (with HTTP status code `503`) if you are using an API Gateway endpoint for your API and if your request exceeds API Gateway's 29 second timeout. If the request is exceeding the API Gateway timeout, your client should receive the `{"message":"Service Unavailable"}` response ~29 seconds after making the request. To confirm that this is the issue, you can modify your `predict()` function to immediately return a response (e.g. `return "ok"`), re-deploy your API, wait for the update to complete, and try making a request. If your client successfully receives the "ok" response, it is likely that the API Gateway timeout is occurring. You can either modify your `predict()` implementation to take less time, run on faster hardware (e.g. GPUs), or disable API Gateway. ## API is stuck updating diff --git a/docs/workloads/traffic-splitter/configuration.md b/docs/workloads/traffic-splitter/configuration.md index 423d382ee3..2111153b75 100644 --- a/docs/workloads/traffic-splitter/configuration.md +++ b/docs/workloads/traffic-splitter/configuration.md @@ -5,7 +5,6 @@ kind: TrafficSplitter networking: endpoint: # the endpoint for the Traffic Splitter (default: ) - api_gateway: public | none # whether to create a public API Gateway endpoint for this API (if not, the API will still be accessible via the load balancer) (default: public, unless disabled cluster-wide) apis: # list of Realtime APIs to target - name: # name of a Realtime API that is already running or is included in the same configuration file (required) weight: # percentage of traffic to route to the Realtime API (all weights must sum to 100) (required) diff --git a/manager/create_gateway_integration.py b/manager/create_gateway_integration.py deleted file mode 100644 index 574ee4a8c2..0000000000 --- a/manager/create_gateway_integration.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2020 Cortex Labs, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import boto3 -import sys -import os - - -def get_istio_api_gateway_elb_arn(client_elb): - paginator = client_elb.get_paginator("describe_load_balancers") - for elb_page in paginator.paginate(): - for elb in elb_page["LoadBalancers"]: - elb_arn = elb["LoadBalancerArn"] - elb_tags = client_elb.describe_tags(ResourceArns=[elb_arn])["TagDescriptions"][0][ - "Tags" - ] - - is_from_cluster = False - is_api_load_balancer = False - for tag in elb_tags: - if ( - tag["Key"] == "cortex.dev/cluster-name" - and tag["Value"] == os.environ["CORTEX_CLUSTER_NAME"] - ): - is_from_cluster = True - if ( - tag["Key"] == "kubernetes.io/service-name" - and tag["Value"] == "istio-system/ingressgateway-apis" - ): - is_api_load_balancer = True - - if is_from_cluster and is_api_load_balancer: - return elb_arn - - raise Exception("Could not find ingressgateway-apis ELB") - - -def get_listener_arn(elb_arn, client_elb): - paginator = client_elb.get_paginator("describe_listeners") - for listener_page in paginator.paginate(LoadBalancerArn=elb_arn): - for listener in listener_page["Listeners"]: - if listener["Port"] == 80: - return listener["ListenerArn"] - raise Exception(f"Could not find port 80 listener on elb {elb_arn}") - - -def create_gateway_integration(api_id, vpc_link_id): - client_elb = boto3.client("elbv2", region_name=os.environ["CORTEX_REGION"]) - client_apigateway = boto3.client("apigatewayv2", region_name=os.environ["CORTEX_REGION"]) - - elb_arn = get_istio_api_gateway_elb_arn(client_elb) - listener_arn = get_listener_arn(elb_arn, client_elb) - - client_apigateway.create_integration( - ApiId=api_id, - ConnectionId=vpc_link_id, - ConnectionType="VPC_LINK", - IntegrationType="HTTP_PROXY", - IntegrationUri=listener_arn, - PayloadFormatVersion="1.0", - IntegrationMethod="ANY", - ) - - -if __name__ == "__main__": - api_id = str(sys.argv[1]) - vpc_link_id = str(sys.argv[2]) - create_gateway_integration(api_id, vpc_link_id) diff --git a/manager/get_api_gateway_endpoint.py b/manager/get_api_gateway_endpoint.py deleted file mode 100644 index 4a185704be..0000000000 --- a/manager/get_api_gateway_endpoint.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2020 Cortex Labs, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import boto3 -import os - - -def get_api_gateway_endpoint(): - cluster_name = os.environ["CORTEX_CLUSTER_NAME"] - region = os.environ["CORTEX_REGION"] - client_apigateway = boto3.client("apigatewayv2", region_name=region) - - paginator = client_apigateway.get_paginator("get_apis") - for api_gateway_page in paginator.paginate(): - for api_gateway in api_gateway_page["Items"]: - if api_gateway["Tags"].get("cortex.dev/cluster-name") == cluster_name: - return api_gateway["ApiEndpoint"] - - raise Exception( - f"your cluster's api gateway (in {region} with tag cortex.dev/cluster-name={cluster_name}) does not exist" - ) - - -if __name__ == "__main__": - print(get_api_gateway_endpoint(), end="") diff --git a/manager/get_api_gateway_id.py b/manager/get_api_gateway_id.py deleted file mode 100644 index ba25790ddb..0000000000 --- a/manager/get_api_gateway_id.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2020 Cortex Labs, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import boto3 -import os - - -def get_api_gateway_id(): - cluster_name = os.environ["CORTEX_CLUSTER_NAME"] - region = os.environ["CORTEX_REGION"] - client_apigateway = boto3.client("apigatewayv2", region_name=region) - - paginator = client_apigateway.get_paginator("get_apis") - for api_gateway_page in paginator.paginate(): - for api_gateway in api_gateway_page["Items"]: - if api_gateway["Tags"].get("cortex.dev/cluster-name") == cluster_name: - return api_gateway["ApiId"] - - raise Exception( - f"your cluster's api gateway (in {region} with tag cortex.dev/cluster-name={cluster_name}) does not exist" - ) - - -if __name__ == "__main__": - print(get_api_gateway_id(), end="") diff --git a/manager/info.sh b/manager/info.sh index a682d17f8b..0dc75895da 100755 --- a/manager/info.sh +++ b/manager/info.sh @@ -26,10 +26,6 @@ function get_api_load_balancer_endpoint() { kubectl -n=istio-system get service ingressgateway-apis -o json | tr -d '[:space:]' | sed 's/.*{\"hostname\":\"\(.*\)\".*/\1/' } -function get_api_gateway_endpoint() { - python get_api_gateway_endpoint.py -} - if ! eksctl utils describe-stacks --cluster=$CORTEX_CLUSTER_NAME --region=$CORTEX_REGION >/dev/null 2>&1; then echo "error: there is no cluster named \"$CORTEX_CLUSTER_NAME\" in $CORTEX_REGION; please update your configuration to point to an existing cortex cluster or create a cortex cluster with \`cortex cluster up\`" exit 1 @@ -40,13 +36,7 @@ out=$(kubectl get pods 2>&1 || true); if [[ "$out" == *"must be logged in to the operator_endpoint=$(get_operator_endpoint) api_load_balancer_endpoint=$(get_api_load_balancer_endpoint) -if [ "$CORTEX_API_GATEWAY" == "public" ]; then - api_gateway_endpoint=$(get_api_gateway_endpoint) -fi echo -e "\033[1mendpoints:\033[0m" echo "operator: $operator_endpoint" # before modifying this, search for this prefix echo "api load balancer: $api_load_balancer_endpoint" -if [ "$CORTEX_API_GATEWAY" == "public" ]; then - echo "api gateway: $api_gateway_endpoint" -fi diff --git a/manager/install.sh b/manager/install.sh index 46e1805943..db6f6f5d16 100755 --- a/manager/install.sh +++ b/manager/install.sh @@ -44,10 +44,6 @@ function cluster_up_aws() { start_pre_download_images - if [ "$CORTEX_API_LOAD_BALANCER_SCHEME" == "internal" ] && [ "$CORTEX_API_GATEWAY" == "public" ]; then - create_vpc_link - fi - echo -n "○ updating cluster configuration " setup_configmap setup_secrets @@ -85,10 +81,6 @@ function cluster_up_aws() { echo "✓" fi - if [ "$CORTEX_API_LOAD_BALANCER_SCHEME" == "internal" ] && [ "$CORTEX_API_GATEWAY" == "public" ]; then - create_vpc_link_integration - fi - restart_operator validate_cortex @@ -404,61 +396,6 @@ function suspend_az_rebalance() { fi } -function create_vpc_link() { - # get VPC ID - vpc_id=$(aws ec2 describe-vpcs --region $CORTEX_REGION --filters Name=tag:cortex.dev/cluster-name,Values=$CORTEX_CLUSTER_NAME | jq .Vpcs[0].VpcId | tr -d '"') - if [ "$vpc_id" = "" ] || [ "$vpc_id" = "null" ]; then - echo "unable to find cortex vpc" - exit 1 - fi - - # filter all private subnets belonging to cortex cluster - private_subnets=$(aws ec2 describe-subnets --region $CORTEX_REGION --filters Name=vpc-id,Values=$vpc_id Name=tag:Name,Values=*Private* | jq -s '.[].Subnets[].SubnetId' | tr -d '"') - if [ "$private_subnets" = "" ] || [ "$private_subnets" = "null" ]; then - echo "unable to find cortex private subnets" - exit 1 - fi - - # get default security group for cortex VPC - default_security_group=$(aws ec2 describe-security-groups --region $CORTEX_REGION --filters Name=vpc-id,Values=$vpc_id Name=group-name,Values=default | jq -c .SecurityGroups[].GroupId | tr -d '"') - if [ "$default_security_group" = "" ] || [ "$default_security_group" = "null" ]; then - echo "unable to find cortex default security group" - exit 1 - fi - - # create VPC Link - create_vpc_link_output=$(aws apigatewayv2 create-vpc-link --region $CORTEX_REGION --tags "$CORTEX_TAGS_JSON" --name $CORTEX_CLUSTER_NAME --subnet-ids $private_subnets --security-group-ids $default_security_group) - vpc_link_id=$(echo $create_vpc_link_output | jq .VpcLinkId | tr -d '"') - if [ "$vpc_link_id" = "" ] || [ "$vpc_link_id" = "null" ]; then - echo -e "unable to extract vpc link ID from create-vpc-link output:\n$create_vpc_link_output" - exit 1 - fi -} - -# must be called after create_vpc_link() since $vpc_link_id is reused -function create_vpc_link_integration() { - echo -n "○ creating api gateway vpc link integration " - api_id=$(python get_api_gateway_id.py) - python create_gateway_integration.py $api_id $vpc_link_id - echo "✓" - echo -n "○ waiting for api gateway vpc link integration " - until [ "$(aws apigatewayv2 get-vpc-link --region $CORTEX_REGION --vpc-link-id $vpc_link_id | jq .VpcLinkStatus | tr -d '"')" = "AVAILABLE" ]; do echo -n "."; sleep 3; done - echo " ✓" -} - -function setup_istio() { - envsubst < manifests/istio-namespace.yaml | kubectl apply -f - >/dev/null - - if ! grep -q "istio-customgateway-certs" <<< $(kubectl get secret -n istio-system); then - WEBSITE=localhost - openssl req -subj "/C=US/CN=$WEBSITE" -newkey rsa:2048 -nodes -keyout $WEBSITE.key -x509 -days 3650 -out $WEBSITE.crt >/dev/null 2>&1 - kubectl create -n istio-system secret tls istio-customgateway-certs --key $WEBSITE.key --cert $WEBSITE.crt >/dev/null - fi - - python render_template.py $CORTEX_CLUSTER_CONFIG_FILE manifests/istio.yaml.j2 > /workspace/istio.yaml - output_if_error istio-${ISTIO_VERSION}/bin/istioctl install -f /workspace/istio.yaml -} - function start_pre_download_images() { registry="quay.io/cortexlabs" tag="$CORTEX_VERSION" @@ -773,15 +710,9 @@ function print_endpoints_aws() { operator_endpoint=$(get_operator_endpoint_aws) api_load_balancer_endpoint=$(get_api_load_balancer_endpoint_aws) - if [ "$CORTEX_API_GATEWAY" == "public" ]; then - api_gateway_endpoint=$(get_api_gateway_endpoint) - fi echo "operator: $operator_endpoint" # before modifying this, search for this prefix echo "api load balancer: $api_load_balancer_endpoint" - if [ "$CORTEX_API_GATEWAY" == "public" ]; then - echo "api gateway: $api_gateway_endpoint" - fi } function get_operator_endpoint_aws() { @@ -792,10 +723,6 @@ function get_api_load_balancer_endpoint_aws() { kubectl -n=istio-system get service ingressgateway-apis -o json | tr -d '[:space:]' | sed 's/.*{\"hostname\":\"\(.*\)\".*/\1/' } -function get_api_gateway_endpoint() { - python get_api_gateway_endpoint.py -} - function print_endpoints_gcp() { echo "" From 5337a566711ff65154249fca3cd2a42b00e4ac9f Mon Sep 17 00:00:00 2001 From: Miguel Varela Ramos Date: Mon, 4 Jan 2021 17:28:25 +0000 Subject: [PATCH 15/20] Re-add setup_istio function, which was deleted by mistake --- manager/install.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/manager/install.sh b/manager/install.sh index db6f6f5d16..b76846de96 100755 --- a/manager/install.sh +++ b/manager/install.sh @@ -396,6 +396,19 @@ function suspend_az_rebalance() { fi } +function setup_istio() { + envsubst < manifests/istio-namespace.yaml | kubectl apply -f - >/dev/null + + if ! grep -q "istio-customgateway-certs" <<< $(kubectl get secret -n istio-system); then + WEBSITE=localhost + openssl req -subj "/C=US/CN=$WEBSITE" -newkey rsa:2048 -nodes -keyout $WEBSITE.key -x509 -days 3650 -out $WEBSITE.crt >/dev/null 2>&1 + kubectl create -n istio-system secret tls istio-customgateway-certs --key $WEBSITE.key --cert $WEBSITE.crt >/dev/null + fi + + python render_template.py $CORTEX_CLUSTER_CONFIG_FILE manifests/istio.yaml.j2 > /workspace/istio.yaml + output_if_error istio-${ISTIO_VERSION}/bin/istioctl install -f /workspace/istio.yaml +} + function start_pre_download_images() { registry="quay.io/cortexlabs" tag="$CORTEX_VERSION" From 7293eab44a0968cebf4746bbd6fe9dce7e97e4c7 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Mon, 4 Jan 2021 10:09:03 -0800 Subject: [PATCH 16/20] Update docs --- .../clusters/aws/networking/{api-gateway.md => https.md} | 9 +++++++-- docs/summary.md | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) rename docs/clusters/aws/networking/{api-gateway.md => https.md} (95%) diff --git a/docs/clusters/aws/networking/api-gateway.md b/docs/clusters/aws/networking/https.md similarity index 95% rename from docs/clusters/aws/networking/api-gateway.md rename to docs/clusters/aws/networking/https.md index fdd09d85cc..54cdf819a2 100644 --- a/docs/clusters/aws/networking/api-gateway.md +++ b/docs/clusters/aws/networking/https.md @@ -1,6 +1,11 @@ -# API Gateway (HTTPS) +# HTTPS (via API Gateway) -AWS API Gateway can be configured to forward requests to your Cortex APIs. This can be useful as a simple way to support HTTPS traffic (as an alternative to using a [custom domain](custom-domain.md)), or to leverage other features provided by API Gateway. Please note that one limitation of API Gateway is that there is a 30-second time limit for all requests. +If you would like to support HTTPS endpoints for your Cortex APIs, here are a few options: + +* Custom domain with an SSL certificate: See [here](custom-domain.md) for instructions. +* AWS API Gateway: This is the simplest approach if a custom domain is not required; continue reading this guide for instructions. + +Please note that one limitation of API Gateway is that there is a 30-second time limit for all requests. If your API load balancer is internet-facing (which is the default, or you set `api_load_balancer_scheme: internet-facing` in your cluster configuration file before creating your cluster), use the [first section](#internet-facing-load-balancer) of this guide. diff --git a/docs/summary.md b/docs/summary.md index b22cfc6f4f..45becf43df 100644 --- a/docs/summary.md +++ b/docs/summary.md @@ -44,7 +44,7 @@ * [Inferentia](clusters/aws/inferentia.md) * [Networking](clusters/aws/networking/index.md) * [Custom domain](clusters/aws/networking/custom-domain.md) - * [API Gateway (HTTPS)](clusters/aws/networking/api-gateway.md) + * [HTTPS (via API Gateway)](clusters/aws/networking/https.md) * [VPC peering](clusters/aws/networking/vpc-peering.md) * [Setting up kubectl](clusters/aws/kubectl.md) * [Uninstall](clusters/aws/uninstall.md) From c02e004347257f05fa2a490f7cd33c6915074a5e Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Mon, 4 Jan 2021 10:21:32 -0800 Subject: [PATCH 17/20] Update index.md --- docs/clusters/aws/networking/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/clusters/aws/networking/index.md b/docs/clusters/aws/networking/index.md index e24b2028bb..1388c5cc18 100644 --- a/docs/clusters/aws/networking/index.md +++ b/docs/clusters/aws/networking/index.md @@ -4,6 +4,6 @@ All APIs share a single API load balancer. By default, the API load balancer is public. You can configure your API load balancer to be private by setting `api_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). This will make your API only accessible through [VPC Peering](vpc-peering.md). -The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests to your APIs (e.g. `curl -k https://***`), or make HTTP requests instead (e.g. `curl http://***`). Alternatively, you can enable HTTPS by using a [custom domain](custom-domain.md) or by [creating an API Gateway](api-gateway.md) to forward requests to your API load balancer. +The SSL certificate on the API load balancer is autogenerated during installation using `localhost` as the Common Name (CN). Therefore, clients will need to skip certificate verification when making HTTPS requests to your APIs (e.g. `curl -k https://***`), or make HTTP requests instead (e.g. `curl http://***`). Alternatively, you can enable HTTPS by using a [custom domain](custom-domain.md) or by [creating an API Gateway](https.md) to forward requests to your API load balancer. There is a separate load balancer for the Cortex operator. By default, the operator load balancer is public. You can configure your operator load balancer to be private by setting `operator_load_balancer_scheme: internal` in your cluster configuration file (before creating your cluster). You can use [VPC Peering](vpc-peering.md) to enable your Cortex CLI to connect to your cluster operator from another VPC. From 356d1100fa7dced74df80e9d4ca3116b690a35b6 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Mon, 4 Jan 2021 12:38:08 -0800 Subject: [PATCH 18/20] Update find_missing_docs_links.py --- dev/find_missing_docs_links.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dev/find_missing_docs_links.py b/dev/find_missing_docs_links.py index c488103f0d..2972687126 100644 --- a/dev/find_missing_docs_links.py +++ b/dev/find_missing_docs_links.py @@ -56,7 +56,7 @@ def get_links_from_file(file): with open(file) as f: for line in f: for link in re.findall(r"\]\((.+?)\)", line): - if link.startswith("http"): + if is_external_link(link): link_infos.append((file, n, link, None, None)) continue if link.startswith("#"): @@ -87,7 +87,7 @@ def check_links(link_infos): for link_info in link_infos: src_file, line_num, original_link_text, target_file, header = link_info - if original_link_text.startswith("http"): + if is_external_link(original_link_text): http_link_infos.append(link_info) continue @@ -174,5 +174,9 @@ def err_str(src_file, line_num, original_link_text, reason): return f"{clean_src_file}:{line_num}: {original_link_text} ({reason})" +def is_external_link(link): + return link.startswith("http://") or link.startswith("https://") + + if __name__ == "__main__": main() From 1df4a33153bed80bd44e085478050931f9f0f360 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Mon, 4 Jan 2021 23:33:06 -0800 Subject: [PATCH 19/20] Update docs --- docs/clusters/aws/install.md | 2 +- docs/clusters/aws/uninstall.md | 2 +- docs/clusters/aws/update.md | 2 +- docs/workloads/realtime/troubleshooting.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/clusters/aws/install.md b/docs/clusters/aws/install.md index cb1854c5ec..189683b9b5 100644 --- a/docs/clusters/aws/install.md +++ b/docs/clusters/aws/install.md @@ -67,7 +67,7 @@ tags: # : map of key/value pairs # enable spot instances spot: false -# SSL certificate ARN (only necessary when using a custom domain without API Gateway) +# SSL certificate ARN (only necessary when using a custom domain) ssl_certificate_arn: # primary CIDR block for the cluster's VPC diff --git a/docs/clusters/aws/uninstall.md b/docs/clusters/aws/uninstall.md index 65313cb1fb..ca6a4654b9 100644 --- a/docs/clusters/aws/uninstall.md +++ b/docs/clusters/aws/uninstall.md @@ -43,4 +43,4 @@ On rare occasions, `cortex cluster down` may not be able to spin down your Corte If deleting the stack fails, navigate to the EC2 dashboard in the AWS console, delete the load balancers that are associated with the cluster, and try again (you can determine which load balancers are associated with the cluster by setting the correct region in the console and checking the `cortex.dev/cluster-name` tag on all load balancers). If the problem still persists, delete any other AWS resources that are blocking the stack deletion and try again. -1. In rare cases, you may need to delete other AWS resources associated with your Cortex cluster. For each the following resources, go to the appropriate AWS Dashboard (in the region that your cluster was in), and confirm that there are no resources left behind by the cluster: API Gateway API, API Gateway VPC Link, CloudWatch Dashboard, SQS Queues, S3 Bucket, and CloudWatch LogGroups (the Cortex bucket and log groups are not deleted by `cluster down` in order to preserve your data). +1. In rare cases, you may need to delete other AWS resources associated with your Cortex cluster. For each the following resources, go to the appropriate AWS Dashboard (in the region that your cluster was in), and confirm that there are no resources left behind by the cluster: CloudWatch Dashboard, SQS Queues, S3 Bucket, and CloudWatch LogGroups (the Cortex bucket and log groups are not deleted by `cluster down` in order to preserve your data). diff --git a/docs/clusters/aws/update.md b/docs/clusters/aws/update.md index d5f6959fb7..30af4288b7 100644 --- a/docs/clusters/aws/update.md +++ b/docs/clusters/aws/update.md @@ -29,7 +29,7 @@ In production environments, you can upgrade your cluster without downtime if you 1. Spin up a new cluster. For example: `cortex cluster up --config new-cluster.yaml --configure-env new` (this will create a CLI environment named `new` for accessing the new cluster). 1. Re-deploy your APIs in your new cluster. For example, if the name of your CLI environment for your old cluster is `old`, you can use `cortex get --env old` to list all running APIs in your old cluster, and re-deploy them in the new cluster by changing directories to each API's project folder and running `cortex deploy --env new`. 1. Route requests to your new cluster. - * If you are using a custom domain: update the A record in your Route 53 hosted zone to point to your new cluster's API Gateway (if you are using API Gateway) or API load balancer (if clients connect directly to the API load balancer). + * If you are using a custom domain: update the A record in your Route 53 hosted zone to point to your new cluster's API load balancer. * If you have a backend service which makes requests to Cortex: update your backend service to make requests to the new cluster's endpoints. * If you have a self-managed API Gateway in front of your Cortex cluster: update the routes to use new cluster's endpoints. 1. Spin down your old cluster. If you updated DNS settings, wait 24-48 hours before spinning down your old cluster to allow the DNS cache to be flushed. diff --git a/docs/workloads/realtime/troubleshooting.md b/docs/workloads/realtime/troubleshooting.md index 7f498003e4..184a08e10f 100644 --- a/docs/workloads/realtime/troubleshooting.md +++ b/docs/workloads/realtime/troubleshooting.md @@ -7,7 +7,7 @@ When making prediction requests to your API, it's possible to get a `{"message": 1. It's possible that your API is simply not ready yet. You can check the status of your API with `cortex get API_NAME`, and stream the logs with `cortex logs API_NAME`. 1. Your API may have errored during initialization or while responding to a previous request. `cortex get API_NAME` will show the status of your API, and you can view the logs with `cortex logs API_NAME`. -It is also possible to receive a `{"message":"Service Unavailable"}` error message (with HTTP status code `503`) if you are using an API Gateway endpoint for your API and if your request exceeds API Gateway's 29 second timeout. If the request is exceeding the API Gateway timeout, your client should receive the `{"message":"Service Unavailable"}` response ~29 seconds after making the request. To confirm that this is the issue, you can modify your `predict()` function to immediately return a response (e.g. `return "ok"`), re-deploy your API, wait for the update to complete, and try making a request. If your client successfully receives the "ok" response, it is likely that the API Gateway timeout is occurring. You can either modify your `predict()` implementation to take less time, run on faster hardware (e.g. GPUs), or disable API Gateway. +It is also possible to receive a `{"message":"Service Unavailable"}` error message (with HTTP status code `503`) if you are using API Gateway in front of your API endpoints and if your request exceeds API Gateway's 29 second timeout. If the request is exceeding the API Gateway timeout, your client should receive the `{"message":"Service Unavailable"}` response ~29 seconds after making the request. To confirm that this is the issue, you can modify your `predict()` function to immediately return a response (e.g. `return "ok"`), re-deploy your API, wait for the update to complete, and try making a request. If your client successfully receives the "ok" response, it is likely that the API Gateway timeout is occurring. You can either modify your `predict()` implementation to take less time, run on faster hardware (e.g. GPUs), or don't use API Gateway (there is no timeout when using the API's endpoint). ## API is stuck updating From c9f49d5af12ac2425f19a3a3d9e704f45f0cfed0 Mon Sep 17 00:00:00 2001 From: David Eliahu Date: Tue, 5 Jan 2021 01:40:05 -0800 Subject: [PATCH 20/20] Add back api gateway lib --- pkg/lib/aws/apigateway.go | 373 ++++++++++++++++++++++++++++++++++++++ pkg/lib/aws/clients.go | 9 + 2 files changed, 382 insertions(+) create mode 100644 pkg/lib/aws/apigateway.go diff --git a/pkg/lib/aws/apigateway.go b/pkg/lib/aws/apigateway.go new file mode 100644 index 0000000000..7403fb23f4 --- /dev/null +++ b/pkg/lib/aws/apigateway.go @@ -0,0 +1,373 @@ +/* +Copyright 2020 Cortex Labs, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package aws + +import ( + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/cortexlabs/cortex/pkg/lib/errors" +) + +// CreateAPIGateway Creates a new API Gateway with the default stage +func (c *Client) CreateAPIGateway(name string, tags map[string]string) (string, error) { + createAPIResponse, err := c.APIGatewayV2().CreateApi(&apigatewayv2.CreateApiInput{ + Name: aws.String(name), + ProtocolType: aws.String(apigatewayv2.ProtocolTypeHttp), + Tags: aws.StringMap(tags), + }) + if err != nil { + return "", errors.Wrap(err, "failed to create api gateway") + } + if createAPIResponse.ApiId == nil { + return "", errors.ErrorUnexpected("failed to create api gateway") + } + + _, err = c.APIGatewayV2().CreateStage(&apigatewayv2.CreateStageInput{ + ApiId: createAPIResponse.ApiId, + AutoDeploy: aws.Bool(true), + StageName: aws.String("$default"), + Tags: aws.StringMap(tags), + }) + if err != nil { + c.DeleteAPIGateway(*createAPIResponse.ApiId) // best effort cleanup + return "", errors.Wrap(err, "failed to create $default api gateway stage") + } + + return *createAPIResponse.ApiId, nil +} + +// GetVPCLinkByTag Gets a VPC Link by tag (returns nil if there are no matches) +func (c *Client) GetVPCLinkByTag(tagName string, tagValue string) (*apigatewayv2.VpcLink, error) { + var nextToken *string + + for { + vpcLinks, err := c.APIGatewayV2().GetVpcLinks(&apigatewayv2.GetVpcLinksInput{ + NextToken: nextToken, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to get vpc links") + } + + for _, vpcLink := range vpcLinks.Items { + for tag, value := range vpcLink.Tags { + if tag == tagName && *value == tagValue { + return vpcLink, nil + } + } + } + + nextToken = vpcLinks.NextToken + if nextToken == nil { + break + } + } + + return nil, nil +} + +// GetAPIGatewayByTag Gets an API Gateway by tag (returns nil if there are no matches) +func (c *Client) GetAPIGatewayByTag(tagName string, tagValue string) (*apigatewayv2.Api, error) { + var nextToken *string + + for { + apis, err := c.APIGatewayV2().GetApis(&apigatewayv2.GetApisInput{ + NextToken: nextToken, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to get api gateways") + } + + for _, api := range apis.Items { + for tag, value := range api.Tags { + if tag == tagName && *value == tagValue { + return api, nil + } + } + } + + nextToken = apis.NextToken + if nextToken == nil { + break + } + } + + return nil, nil +} + +// DeleteVPCLinkByTag Deletes a VPC Link by tag (returns the deleted VPC Link, or nil if it was not found) +func (c *Client) DeleteVPCLinkByTag(tagName string, tagValue string) (*apigatewayv2.VpcLink, error) { + vpcLink, err := c.GetVPCLinkByTag(tagName, tagValue) + if err != nil { + return nil, err + } else if vpcLink == nil { + return nil, nil + } + + _, err = c.APIGatewayV2().DeleteVpcLink(&apigatewayv2.DeleteVpcLinkInput{ + VpcLinkId: vpcLink.VpcLinkId, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to delete vpc link "+*vpcLink.VpcLinkId) + } + + return vpcLink, nil +} + +// DeleteAPIGatewayByTag Deletes an API Gateway by tag (returns the deleted API Gateway, or nil if it was not found) +func (c *Client) DeleteAPIGatewayByTag(tagName string, tagValue string) (*apigatewayv2.Api, error) { + apiGateway, err := c.GetAPIGatewayByTag(tagName, tagValue) + if err != nil { + return nil, err + } else if apiGateway == nil { + return nil, nil + } + + err = c.DeleteAPIGateway(*apiGateway.ApiId) + if err != nil { + return nil, err + } + + return apiGateway, nil +} + +// DeleteAPIGateway Deletes an API Gateway by ID (returns an error if the API Gateway does not exist) +func (c *Client) DeleteAPIGateway(apiGatewayID string) error { + // Delete mappings in case user added a custom domain name (otherwise this will block API Gateway deletion) + err := c.DeleteAPIGatewayMappings(apiGatewayID) + if err != nil { + return err + } + + _, err = c.APIGatewayV2().DeleteApi(&apigatewayv2.DeleteApiInput{ + ApiId: aws.String(apiGatewayID), + }) + if err != nil { + return errors.Wrap(err, "failed to delete api gateway "+apiGatewayID) + } + + return nil +} + +// DeleteAPIGatewayMappingsForDomainName deletes all API mappings that point to the provided api gateway from the provided domain name +func (c *Client) DeleteAPIGatewayMappingsForDomainName(apiGatewayID string, domainName string) error { + var nextToken *string + + for { + apiMappings, err := c.APIGatewayV2().GetApiMappings(&apigatewayv2.GetApiMappingsInput{ + DomainName: aws.String(domainName), + NextToken: nextToken, + }) + if err != nil { + return errors.Wrap(err, "failed to get api mappings") + } + + for _, apiMapping := range apiMappings.Items { + if *apiMapping.ApiId != apiGatewayID { + continue + } + + _, err := c.APIGatewayV2().DeleteApiMapping(&apigatewayv2.DeleteApiMappingInput{ + DomainName: aws.String(domainName), + ApiMappingId: apiMapping.ApiMappingId, + }) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("failed to delete api mapping %s in domain %s", *apiMapping.ApiMappingId, domainName)) + } + } + + nextToken = apiMappings.NextToken + if nextToken == nil { + break + } + } + + return nil +} + +// DeleteAPIGatewayMappings deletes all API mappings that point to the provided api gateway +func (c *Client) DeleteAPIGatewayMappings(apiGatewayID string) error { + var nextToken *string + + for { + domainNames, err := c.APIGatewayV2().GetDomainNames(&apigatewayv2.GetDomainNamesInput{ + NextToken: nextToken, + }) + if err != nil { + return errors.Wrap(err, "failed to get domain names") + } + + for _, domainName := range domainNames.Items { + err := c.DeleteAPIGatewayMappingsForDomainName(apiGatewayID, *domainName.DomainName) + if err != nil { + return err + } + } + + nextToken = domainNames.NextToken + if nextToken == nil { + break + } + } + + return nil +} + +// GetVPCLinkIntegration gets the VPC Link integration in an API Gateway, or nil if unable to find it +func (c *Client) GetVPCLinkIntegration(apiGatewayID string, vpcLinkID string) (*apigatewayv2.Integration, error) { + var nextToken *string + + for { + integrations, err := c.APIGatewayV2().GetIntegrations(&apigatewayv2.GetIntegrationsInput{ + ApiId: &apiGatewayID, + NextToken: nextToken, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to get api gateway integrations for api gateway "+apiGatewayID) + } + + // find integration which is connected to the VPC link + for _, integration := range integrations.Items { + if *integration.ConnectionId == vpcLinkID { + return integration, nil + } + } + + nextToken = integrations.NextToken + if nextToken == nil { + break + } + } + + return nil, nil +} + +// GetRouteIntegrationID returns the integration which is attached to a endpoint route, or empty string if unable to find it +func (c *Client) GetRouteIntegrationID(apiGatewayID string, endpoint string) (string, error) { + route, err := c.GetRoute(apiGatewayID, endpoint) + if err != nil { + return "", err + } + if route == nil { + return "", nil + } + + return ExtractRouteIntegrationID(route), nil +} + +// ExtractRouteIntegrationID extracts the integration ID which is attached to a route, or "" if no route is attached +func ExtractRouteIntegrationID(route *apigatewayv2.Route) string { + if route == nil || route.Target == nil { + return "" + } + + // trim of prefix of integrationID. + // Note: Integrations get attached to routes via a target of the format integrations/ + integrationID := strings.TrimPrefix(*route.Target, "integrations/") + return integrationID +} + +// GetRoute retrieves the route matching an endpoint, or nil if unable to find it +func (c *Client) GetRoute(apiGatewayID string, endpoint string) (*apigatewayv2.Route, error) { + var nextToken *string + + for { + routes, err := c.APIGatewayV2().GetRoutes(&apigatewayv2.GetRoutesInput{ + ApiId: &apiGatewayID, + NextToken: nextToken, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to get api gateway routes for api gateway "+apiGatewayID) + } + + // find route which matches the endpoint + for _, route := range routes.Items { + if *route.RouteKey == "ANY "+endpoint { + return route, nil + } + } + + nextToken = routes.NextToken + if nextToken == nil { + break + } + } + + return nil, nil +} + +// CreateRoute creates a new route and attaches the route to the integration +func (c *Client) CreateRoute(apiGatewayID string, integrationID string, endpoint string) error { + _, err := c.APIGatewayV2().CreateRoute(&apigatewayv2.CreateRouteInput{ + ApiId: &apiGatewayID, + RouteKey: aws.String("ANY " + endpoint), + Target: aws.String("integrations/" + integrationID), + }) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("failed to create %s route for api gateway %s with integration %s", endpoint, apiGatewayID, integrationID)) + } + return nil +} + +// CreateHTTPIntegration creates new HTTP integration for API Gateway, returns integration ID +func (c *Client) CreateHTTPIntegration(apiGatewayID string, targetEndpoint string) (string, error) { + integrationResponse, err := c.APIGatewayV2().CreateIntegration(&apigatewayv2.CreateIntegrationInput{ + ApiId: &apiGatewayID, + IntegrationType: aws.String("HTTP_PROXY"), + IntegrationUri: &targetEndpoint, + PayloadFormatVersion: aws.String("1.0"), + IntegrationMethod: aws.String("ANY"), + }) + if err != nil { + return "", errors.Wrap(err, fmt.Sprintf("failed to create api gateway integration for endpoint %s in api gateway %s", targetEndpoint, apiGatewayID)) + } + return *integrationResponse.IntegrationId, nil +} + +// DeleteIntegration deletes an integration from API Gateway +func (c *Client) DeleteIntegration(apiGatewayID string, integrationID string) error { + _, err := c.APIGatewayV2().DeleteIntegration(&apigatewayv2.DeleteIntegrationInput{ + ApiId: &apiGatewayID, + IntegrationId: &integrationID, + }) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("failed to delete api gateway integration %s in api gateway %s", integrationID, apiGatewayID)) + } + return nil +} + +// DeleteRoute deletes a route from API Gateway, and returns the deleted route (or nil if it wasn't found) +func (c *Client) DeleteRoute(apiGatewayID string, endpoint string) (*apigatewayv2.Route, error) { + route, err := c.GetRoute(apiGatewayID, endpoint) + if err != nil { + return nil, err + } else if route == nil { + return nil, nil + } + + _, err = c.APIGatewayV2().DeleteRoute(&apigatewayv2.DeleteRouteInput{ + ApiId: &apiGatewayID, + RouteId: route.RouteId, + }) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("failed to delete api gateway route %s with endpoint %s in api gateway %s", *route.RouteId, endpoint, apiGatewayID)) + } + + return route, nil +} diff --git a/pkg/lib/aws/clients.go b/pkg/lib/aws/clients.go index ed03b6026c..11ff04b5cc 100644 --- a/pkg/lib/aws/clients.go +++ b/pkg/lib/aws/clients.go @@ -18,6 +18,7 @@ package aws import ( "github.com/aws/aws-sdk-go/service/acm" + "github.com/aws/aws-sdk-go/service/apigatewayv2" "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/cloudformation" "github.com/aws/aws-sdk-go/service/cloudwatch" @@ -48,6 +49,7 @@ type clients struct { autoscaling *autoscaling.AutoScaling cloudWatchLogs *cloudwatchlogs.CloudWatchLogs cloudWatch *cloudwatch.CloudWatch + apiGatewayV2 *apigatewayv2.ApiGatewayV2 serviceQuotas *servicequotas.ServiceQuotas cloudFormation *cloudformation.CloudFormation iam *iam.IAM @@ -151,6 +153,13 @@ func (c *Client) CloudWatch() *cloudwatch.CloudWatch { return c.clients.cloudWatch } +func (c *Client) APIGatewayV2() *apigatewayv2.ApiGatewayV2 { + if c.clients.apiGatewayV2 == nil { + c.clients.apiGatewayV2 = apigatewayv2.New(c.sess) + } + return c.clients.apiGatewayV2 +} + func (c *Client) ServiceQuotas() *servicequotas.ServiceQuotas { if c.clients.serviceQuotas == nil { c.clients.serviceQuotas = servicequotas.New(c.sess)