Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions mlops-multi-account-cdk/mlops-infra/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,18 @@ aws_session_token = YOUR_SESSION_TOKEN
### Bootstrap AWS Accounts
***Warning:** It is best you setup a python environment to handle all installs for this project and manage python packages. Use your preferred terminal and editor to run the following commands.*

Before you start with the deployment of the solution make sure to bootstrap your accounts. Ensure you add the account details in `mlops_infra/config/constants.py` mainly the target deployment accounts: **DEV**, **PREPROD** and **PROD**. follow the steps below to achieve that:
Before you start with the deployment of the solution make sure to bootstrap your accounts. Ensure you add the account details in `mlops_infra/config/constants.py` mainly the target deployment accounts: **DEV**, **PREPROD** and **PROD**.
```
PIPELINE_ACCOUNT = "" # account to host the pipeline handling updates of this repository

DEV_ACCOUNT = "" # account to setup sagemaker studio and networking stack

PREPROD_ACCOUNT = "" # account to setup networking stack

PROD_ACCOUNT = "" # account to setup networking stack
```

follow the steps below to achieve that:

1. Clone this repository in your work environment (e.g. your laptop)

Expand Down Expand Up @@ -235,12 +246,24 @@ cdk synth

as a stage could include a combination of stacks `--all` flag is included with the `deploy` command

once you are done with testing the new feature that was deployed locally, run the following to clean-up the environment:
### Clean-up

In case you used the local deployment, once you are done with testing the new feature that was deployed locally, run the following to clean-up the environment:

```
cdk --app ./cdk.out/assembly-Personal destroy —all
# destroy stage to target account (make it match your stack name)
cdk --app ./cdk.out/assembly-Personal destroy —all
```
This would only delete the service catalog stack deployed in the target account and not the deployed projects.

Similarly if you used the CI/CD deployment:
```
# destroy deployed stack in target account (make it match your stack name)
cdk destroy
```
This would only delete the pipeline stack and nothing else deployed from the pipeline i.e. stacks deployed to the target accounts and the deployed projects.

**NOTE** deployed stack from the pipeline won't be deleted to delete those you have to manually delete them through CloudFormation Delete stack command.

This command could fail in the following cases:

Expand Down
2 changes: 1 addition & 1 deletion mlops-multi-account-cdk/mlops-infra/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

deployment_env = cdk.Environment(account=PIPELINE_ACCOUNT, region=DEFAULT_DEPLOYMENT_REGION)

PipelineStack(app, "ml-deploy-pipeline", env=deployment_env)
PipelineStack(app, "ml-infra-deploy-pipeline", env=deployment_env)

# Personal Stacks for testing locally, comment out when committing to repository
if not os.getenv("CODEBUILD_BUILD_ARN"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,13 @@
CODE_COMMIT_REPO_NAME = "mlops-infra"
PIPELINE_BRANCH = "main"

PIPELINE_ACCOUNT = ""
PIPELINE_ACCOUNT = "" # account to host the pipeline handling updates of this repository

DEV_ACCOUNT = ""
DEV_REGION = "eu-west-1"
DEV_ACCOUNT = "" # account to setup sagemaker studio and networking stack

PREPROD_ACCOUNT = ""
PREPROD_REGION = "eu-west-1"

PROD_ACCOUNT = ""
PROD_REGION = "eu-west-1"
PREPROD_ACCOUNT = "" # account to setup networking stack

PROD_ACCOUNT = "" # account to setup networking stack

DEFAULT_DEPLOYMENT_REGION = "eu-west-1"
APP_PREFIX = "mlops"
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

VPC_ID = "vpc-0d321f7663affed2d"
VPC_CIDR = "15.0.0.0/16"
VPC_ID = "vpc-"
VPC_CIDR = "10.0.0.0/16"

APP_SUBNETS = ["subnet-051d737bce2a09efe", "subnet-0272fcf9a6c5ad207", "subnet-0b6e3cc901590c35f"]
APP_SUBNETS = ["subnet-", "subnet-", "subnet-"]

BASE_SECURITY_GROUP = "sg-0657dec78ac20a372"
BASE_SECURITY_GROUP = "sg-"
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@
from mlops_infra.config.constants import (
APP_PREFIX,
CODE_COMMIT_REPO_NAME,
DEV_REGION,
DEV_ACCOUNT,
PIPELINE_BRANCH,
PREPROD_ACCOUNT,
PREPROD_REGION,
PROD_ACCOUNT,
PROD_REGION,
DEFAULT_DEPLOYMENT_REGION
)

from mlops_infra.networking_stack import NetworkingStack
Expand Down Expand Up @@ -158,7 +156,7 @@ def __init__(
CoreStage(
self,
"dev",
env=Environment(account=DEV_ACCOUNT, region=DEV_REGION),
env=Environment(account=DEV_ACCOUNT, region=DEFAULT_DEPLOYMENT_REGION),
)
)
# add preprod stage for resources that we want to deploy in this account and potentially in other accounts as well
Expand All @@ -167,7 +165,7 @@ def __init__(
self,
"preprod",
deploy_sm_domain=False,
env=Environment(account=PREPROD_ACCOUNT, region=PREPROD_REGION),
env=Environment(account=PREPROD_ACCOUNT, region=DEFAULT_DEPLOYMENT_REGION),
)
)
# add prod stage for resources that we want to deploy in this account and potentially in other accounts as well
Expand All @@ -176,6 +174,6 @@ def __init__(
self,
"prod",
deploy_sm_domain=False,
env=Environment(account=PROD_ACCOUNT, region=PROD_REGION),
env=Environment(account=PROD_ACCOUNT, region=DEFAULT_DEPLOYMENT_REGION),
)
)
16 changes: 11 additions & 5 deletions mlops-multi-account-cdk/mlops-infra/scripts/cdk-account-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ read -p 'Governance Account: ' gov_account
read -p 'Dev Account: ' dev_account
read -p 'PreProd Account: ' preprod_account
read -p 'Prod Account: ' prod_account

region='eu-west-1'

read -p 'Deployment region: ' region

echo 'Updating constants.py file with accounts and region details'
pattern="[0-9a-zA-Z\-]*"
sed -i '' -e "s/PIPELINE_ACCOUNT = \"$pattern\"/PIPELINE_ACCOUNT = \"$gov_account\"/" \
-e "s/DEV_ACCOUNT = \"$pattern\"/DEV_ACCOUNT = \"$dev_account\"/" \
-e "s/PREPROD_ACCOUNT = \"$pattern\"/PREPROD_ACCOUNT = \"$preprod_account\"/" \
-e "s/PROD_ACCOUNT = \"$pattern\"/PROD_ACCOUNT = \"$prod_account\"/" \
-e "s/DEFAULT_DEPLOYMENT_REGION = \"$pattern\"/DEFAULT_DEPLOYMENT_REGION = \"$region\"/" \
mlops_infra/config/constants.py

echo 'AWS profiles to be used for each account'
read -p 'Governance Account AWS Profile: ' gov_profile
read -p 'Dev Account AWS Profile: ' dev_profile
Expand All @@ -23,6 +29,6 @@ cdk bootstrap aws://$gov_account/$region --profile $gov_profile

cdk bootstrap aws://$dev_account/$region --trust $gov_account --cloudformation-execution-policies 'arn:aws:iam::aws:policy/AdministratorAccess' --profile $dev_profile

cdk bootstrap aws://$preprod_account/$region --trust $dev_account $gov_account --cloudformation-execution-policies 'arn:aws:iam::aws:policy/AdministratorAccess' --profile $preprod_profile
cdk bootstrap aws://$preprod_account/$region --trust $dev_account,$gov_account --cloudformation-execution-policies 'arn:aws:iam::aws:policy/AdministratorAccess' --profile $preprod_profile

cdk bootstrap aws://$prod_account/$region --trust $dev_account $gov_account --cloudformation-execution-policies 'arn:aws:iam::aws:policy/AdministratorAccess' --profile $prod_profile
cdk bootstrap aws://$prod_account/$region --trust $dev_account,$gov_account --cloudformation-execution-policies 'arn:aws:iam::aws:policy/AdministratorAccess' --profile $prod_profile
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ This is an AWS CDK project written in Python 3.8. Here's what you need to have o
│   │   └── ssm_construct.py <--- construct to deploy ssm parameter for the project template to use
│   ├── pipeline_stack.py <--- stack for CICD with code pipeline setup for the repo
│   ├── service_catalog_stack.py <--- stack for service catalog setup and template deployment
│   └── sm_project_stack.py <--- stack for sagemaker project template setup
│   ├── basic_project_stack.py <--- stack for basic sagemaker project template setup - DEV/PREPROD/PROD Accounts provided in constants.py
│   └── dynamic_accounts_project_stack.py <--- stack for sagemaker project template setup - DEV/PREPROD/PROD Accounts provided as parameters during project creation
├── requirements-dev.txt
├── requirements.txt <--- cdk packages used in the stacks (must be installed)
├── scripts <--- shell scripts to automate part of the deployments
Expand Down Expand Up @@ -193,7 +194,18 @@ aws_session_token = YOUR_SESSION_TOKEN
### Bootstrap AWS Accounts
***Warning:** It is best you setup a python environment to handle all installs for this project and manage python packages. Use your preferred terminal and editor to run the following commands.*

Before you start with the deployment of the solution make sure to bootstrap your accounts. Ensure you add the account details in `mlops_sm_project_template_rt/config/constants.py` mainly the target deployment accounts: **DEV**, **PREPROD** and **PROD**. follow the steps below to achieve that:
Before you start with the deployment of the solution make sure to bootstrap your accounts. Ensure you add the account details in `mlops_sm_project_template_rt/config/constants.py` mainly the target deployment accounts: **DEV**, **PREPROD** and **PROD**.
```
PIPELINE_ACCOUNT = "" # account to host the pipeline handling updates of this repository

DEV_ACCOUNT = "" # account to host the service catalog template and then build sagemaker project

PREPROD_ACCOUNT = "" # account to deploy the sagemaker endpoint

PROD_ACCOUNT = "" # account to deploy the sagemaker endpoint
```

follow the steps below to achieve that:

1. Clone this repository in your work environment (e.g. your laptop)

Expand Down Expand Up @@ -284,12 +296,22 @@ cdk --app ./cdk.out/assembly-Personal deploy —all

as a stage could include a combination of stacks `--all` flag is included with the `deploy` command

once you are done with testing the new feature that was deployed locally, run the following to clean-up the environment:

### Clean-up

In case you used the local deployment, once you are done with testing the new feature that was deployed locally, run the following to clean-up the environment:
```
# destroy stage to target account (make it match your stack name)
cdk --app ./cdk.out/assembly-Personal destroy —all
```
This would only delete the service catalog stack deployed in the target account and not the deployed projects.

Similarly if you used the CI/CD deployment:
```
# destroy deployed stack in target account (make it match your stack name)
cdk destroy
```
This would only delete the pipeline stack and nothing else deployed from the pipeline i.e. stacks deployed to the target accounts and the deployed projects.

This command could fail in the following cases:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
pipeline_env = cdk.Environment(account=PIPELINE_ACCOUNT, region=DEFAULT_DEPLOYMENT_REGION)
deployment_env = cdk.Environment(account=DEV_ACCOUNT, region=DEFAULT_DEPLOYMENT_REGION)

PipelineStack(app, "ml-deploy-pipeline", env=pipeline_env)
PipelineStack(app, "ml-sg-deploy-pipeline", env=pipeline_env)

# Personal Stacks for testing locally, comment out when committing to repository
if not os.getenv("CODEBUILD_BUILD_ARN"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@
DeployPipelineConstruct,
)

from mlops_sm_project_template_rt.config.constants import PREPROD_ACCOUNT, PROD_ACCOUNT

from mlops_sm_project_template_rt.config.constants import PREPROD_ACCOUNT, PROD_ACCOUNT, DEFAULT_DEPLOYMENT_REGION

class MLOpsStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
Expand Down Expand Up @@ -260,4 +259,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
model_package_group_name,
seed_bucket,
deploy_app_key,
)
PREPROD_ACCOUNT,
PROD_ACCOUNT,
DEFAULT_DEPLOYMENT_REGION
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,13 @@
CODE_COMMIT_REPO_NAME = "mlops-sm-project-template-rt"
PIPELINE_BRANCH = "main"

PIPELINE_ACCOUNT = ""
PIPELINE_ACCOUNT = "" # account used to host the pipeline handling updates of this repository

DEV_ACCOUNT = ""
DEV_REGION = "eu-west-1"
DEV_ACCOUNT = "" # account to host the service catalog template

PREPROD_ACCOUNT = ""
PREPROD_REGION = "eu-west-1"

PROD_ACCOUNT = ""
PROD_REGION = "eu-west-1"
PREPROD_ACCOUNT = "" # account used to deploy the endpoint

PROD_ACCOUNT = "" # account used to deploy the endpoint

DEFAULT_DEPLOYMENT_REGION = "eu-west-1"
APP_PREFIX = "mlops-cdk"
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,6 @@
)
import aws_cdk
from constructs import Construct
from mlops_sm_project_template_rt.config.constants import (
PROD_ACCOUNT,
PROD_REGION,
PREPROD_ACCOUNT,
PREPROD_REGION,
)


class DeployPipelineConstruct(Construct):
def __init__(
Expand All @@ -48,6 +41,9 @@ def __init__(
model_package_group_name: str,
repo_s3_bucket_name: str,
repo_s3_object_key: str,
preprod_account: int,
prod_account: int,
deployment_region: str,
**kwargs,
) -> None:
super().__init__(scope, construct_id, **kwargs)
Expand Down Expand Up @@ -267,32 +263,32 @@ def __init__(
],
),
codepipeline_actions.ManualApprovalAction(
action_name="Approve_Staging",
action_name="Approve_PreProd",
run_order=2,
additional_information="Approving deployment for staging",
additional_information="Approving deployment for preprod",
),
],
)

deploy_code_pipeline.add_stage(
stage_name="DeployStaging",
stage_name="DeployPreProd",
actions=[
codepipeline_actions.CloudFormationCreateUpdateStackAction(
action_name="Deploy_CFN_Staging",
action_name="Deploy_CFN_PreProd",
run_order=1,
template_path=cdk_synth_artifact.at_path("staging.template.json"),
stack_name=f"{project_name}-{construct_id}-staging",
template_path=cdk_synth_artifact.at_path("preprod.template.json"),
stack_name=f"{project_name}-{construct_id}-preprod",
admin_permissions=False,
replace_on_failure=True,
role=iam.Role.from_role_arn(
self,
"StagingActionRole",
f"arn:{Aws.PARTITION}:iam::{PREPROD_ACCOUNT}:role/cdk-hnb659fds-deploy-role-{PREPROD_ACCOUNT}-{PREPROD_REGION}",
"PreProdActionRole",
f"arn:{Aws.PARTITION}:iam::{preprod_account}:role/cdk-hnb659fds-deploy-role-{preprod_account}-{deployment_region}",
),
deployment_role=iam.Role.from_role_arn(
self,
"StagingDeploymentRole",
f"arn:{Aws.PARTITION}:iam::{PREPROD_ACCOUNT}:role/cdk-hnb659fds-cfn-exec-role-{PREPROD_ACCOUNT}-{PREPROD_REGION}",
"PreProdDeploymentRole",
f"arn:{Aws.PARTITION}:iam::{preprod_account}:role/cdk-hnb659fds-cfn-exec-role-{preprod_account}-{deployment_region}",
),
cfn_capabilities=[
CfnCapabilities.AUTO_EXPAND,
Expand Down Expand Up @@ -320,12 +316,12 @@ def __init__(
role=iam.Role.from_role_arn(
self,
"ProdActionRole",
f"arn:{Aws.PARTITION}:iam::{PROD_ACCOUNT}:role/cdk-hnb659fds-deploy-role-{PROD_ACCOUNT}-{PROD_REGION}",
f"arn:{Aws.PARTITION}:iam::{prod_account}:role/cdk-hnb659fds-deploy-role-{prod_account}-{deployment_region}",
),
deployment_role=iam.Role.from_role_arn(
self,
"ProdDeploymentRole",
f"arn:{Aws.PARTITION}:iam::{PROD_ACCOUNT}:role/cdk-hnb659fds-cfn-exec-role-{PROD_ACCOUNT}-{PROD_REGION}",
f"arn:{Aws.PARTITION}:iam::{prod_account}:role/cdk-hnb659fds-cfn-exec-role-{prod_account}-{deployment_region}",
),
cfn_capabilities=[
CfnCapabilities.AUTO_EXPAND,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
string_value=DEV_ACCOUNT,
)

# STAGING parameters
# PREPROD parameters
PREPROD_ACCOUNT_id_param = ssm.StringParameter(
self,
"StagingAccountIDParameter",
parameter_name="/mlops/staging/account_id",
"PreProdAccountIDParameter",
parameter_name="/mlops/preprod/account_id",
string_value=PREPROD_ACCOUNT,
)

PREPROD_REGION_param = ssm.StringParameter(
self,
"StagingRegionParameter",
parameter_name="/mlops/staging/region",
"PreProdRegionParameter",
parameter_name="/mlops/preprod/region",
string_value=PREPROD_REGION,
)

Expand Down
Loading