Description: Toolchain template which provides the resources needed to represent infrastructure as code. The template creates 2 source control repositories in GitLab and creates a CI/CD pipeline using GitLab Pipeline to build a model using a SageMaker Pipeline and deploy the resulting trained ML Model from Model Registry to two stages in CD -- staging and production. Parameters: SageMakerProjectName: Type: String Description: Name of the project NoEcho: true MinLength: 1 MaxLength: 32 AllowedPattern: ^[a-zA-Z](-*[a-zA-Z0-9])* SageMakerProjectId: Type: String NoEcho: true Description: Service generated ID of the project. GitLabServer: Type: String MaxLength: 1024 Description: The path to the GitLab Server, e.g. https://gitlab.com, https://test.gitlab.com, http://10.0.0.1 RepositoryBaseUrl: Type: String MaxLength: 1024 Description: The base path to the GitLab account to create the repository within. e.g. https://gitlab.com/ ModelBuildCodeRepositoryName: Type: String MaxLength: 1024 Description: Repository name of the Model Building and Training Code Repository ModelDeployCodeRepositoryName: Type: String MaxLength: 1024 Description: Repository name of the Model Deplyment Code Repository GitLabGroupID: Type: String MaxLength: 1024 Description: The ID of the group in GitLab to create the repositories in. Enter "None" if using the root group. Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Code Repository Info" Parameters: - GitLabServer - RepositoryBaseUrl - ModelBuildCodeRepositoryName - ModelDeployCodeRepositoryName - GitLabGroupID ParameterLabels: GitLabServer: default: "GitLab Server URI. e.g. https://gitlab.com" RepositoryBaseUrl: default: "Base URL for your GitLab Repositories. e.g. https://gitlab.com/" ModelBuildCodeRepositoryName: default: "Model Build Repository Name" ModelDeployCodeRepositoryName: default: "Model Deploy Repository Name" GitLabGroupID: default: "GitLab Group ID. 'None' if using root group" Resources: MlOpsArtifactsBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub sagemaker-project-${SageMakerProjectId} # 58 chars max/ 64 allowed GitSeedCodeCheckinLambda: Type: 'AWS::Lambda::Function' Properties: Description: To trigger the codebuild project for the seedcode checkin Handler: lambda_function.lambda_handler Runtime: python3.9 FunctionName: !Sub sagemaker-${SageMakerProjectId}-git-seedcodecheckin # max: 10+15+19=44 out of 64 max Timeout: 900 Role: AWSDEFAULT___USE_ROLE___ Code: S3Bucket: AWSDEFAULT___CODE_STAGING_BUCKET___ S3Key: AWSDEFAULT___PROJECT_NAME___/seedcode/lambda-seedcode-checkin-gitlab.zip Environment: Variables: GitLabServer: !Sub ${GitLabServer} DeployProjectName: !Sub ${ModelDeployCodeRepositoryName} BuildProjectName: !Sub ${ModelBuildCodeRepositoryName} SageMakerProjectName: !Sub ${SageMakerProjectName} SageMakerProjectId: !Sub ${SageMakerProjectId} GitLabTokenSecretName: AWSDEFAULT___GITLAB_TOKEN_SECRET_NAME___ IAMAccessKeySecretName: AWSDEFAULT___IAM_ACCESS_KEY_SECRET_NAME___ IAMSecretKeySecretName: AWSDEFAULT___IAM_SECRET_KEY_SECRET_NAME___ SeedCodeBucket: AWSDEFAULT___CODE_STAGING_BUCKET___ ModelBuildSeedCode: AWSDEFAULT___PROJECT_NAME___/seedcode/mlops-gitlab-project-seedcode-model-build.zip ModelDeploySeedCode: AWSDEFAULT___PROJECT_NAME___/seedcode/mlops-gitlab-project-seedcode-model-deploy.zip Region: !Ref AWS::Region AccountId: !Ref AWS::AccountId Role: AWSDEFAULT___USE_ROLE___ GroupId: !Sub ${GitLabGroupID} SageMakerSeedCodeCheckinLambdaInvoker: Type: 'AWS::CloudFormation::CustomResource' Properties: ServiceToken: !GetAtt GitSeedCodeCheckinLambda.Arn ### Lambda function to start GitLab CI/CD Pipeline GitLabPipelineTriggerLambda: Type: 'AWS::Lambda::Function' Properties: Description: To trigger the GitLab Pipeline Handler: lambda_function.lambda_handler Runtime: python3.8 FunctionName: !Sub sagemaker-${SageMakerProjectId}-gitlab-trigger # max: 10+15+19=44 out of 64 max Timeout: 900 Role: AWSDEFAULT___USE_ROLE___ Code: S3Bucket: AWSDEFAULT___CODE_STAGING_BUCKET___ S3Key: AWSDEFAULT___PROJECT_NAME___/seedcode/lambda-gitlab-pipeline-trigger.zip Environment: Variables: GitLabServer: !Sub ${GitLabServer} DeployProjectName: !Sub ${ModelDeployCodeRepositoryName} BuildProjectName: !Sub ${ModelBuildCodeRepositoryName} SageMakerProjectName: !Sub ${SageMakerProjectName} SageMakerProjectId: !Sub ${SageMakerProjectId} GitLabTokenSecretName: AWSDEFAULT___GITLAB_TOKEN_SECRET_NAME___ Region: !Ref AWS::Region GroupId: !Sub ${GitLabGroupID} ModelDeploySageMakerEventRule: Type: AWS::Events::Rule Properties: # Max length allowed: 64 Name: !Sub sagemaker-${SageMakerProjectName}-${SageMakerProjectId}-event-rule # max: 10+33+15+5=63 chars Description: "Rule to trigger a deployment when SageMaker Model registry is updated with a new model package. For example, a new model package is registered with Registry" EventPattern: source: - "aws.sagemaker" detail-type: - "SageMaker Model Package State Change" detail: ModelPackageGroupName: - !Sub ${SageMakerProjectName}-${SageMakerProjectId} ModelApprovalStatus: - Approved State: "ENABLED" Targets: - Arn: !GetAtt GitLabPipelineTriggerLambda.Arn Id: !Sub sagemaker-${SageMakerProjectName}-trigger PermissionForEventsToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !GetAtt GitLabPipelineTriggerLambda.Arn Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt ModelDeploySageMakerEventRule.Arn ModelDeploySagemakerCodeRepository: Type: 'AWS::SageMaker::CodeRepository' DependsOn: SageMakerSeedCodeCheckinLambdaInvoker Properties: CodeRepositoryName: !Sub ${ModelDeployCodeRepositoryName}-${SageMakerProjectId} GitConfig: Branch: main RepositoryUrl: !Sub ${RepositoryBaseUrl}/${ModelDeployCodeRepositoryName}-${SageMakerProjectId} Tags: - Key: "sagemaker:project-id" Value: !Sub ${SageMakerProjectId} - Key: "sagemaker:project-name" Value: !Sub ${SageMakerProjectName} ModelBuildSagemakerCodeRepository: Type: 'AWS::SageMaker::CodeRepository' DependsOn: SageMakerSeedCodeCheckinLambdaInvoker Properties: CodeRepositoryName: !Sub ${ModelBuildCodeRepositoryName}-${SageMakerProjectId} GitConfig: Branch: main RepositoryUrl: !Sub ${RepositoryBaseUrl}/${ModelBuildCodeRepositoryName}-${SageMakerProjectId} Tags: - Key: "sagemaker:project-id" Value: !Sub ${SageMakerProjectId} - Key: "sagemaker:project-name" Value: !Sub ${SageMakerProjectName}