Skip to content

Commit c975683

Browse files
authored
Merge pull request #17 from ikopas/feature/add-vpc-config
Feature/add vpc config
2 parents d02e979 + c5e6d22 commit c975683

File tree

6 files changed

+95
-10
lines changed

6 files changed

+95
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ manual_dist/**
1111
/build
1212
.idea/
1313
.vscode/
14+
.DS_Store

README.md

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ Any additional arguments supported with `docker build` are supported
2020
sm-docker build . --file /path/to/Dockerfile --build-arg foo=bar
2121
```
2222

23-
By default, the image will be pushed to a repository `sagemakerstudio` with the tag `latest`, and use the Studio App's execution role and the default SageMaker Python SDK S3 bucket
23+
By default, the CodeBuild project will not run within a VPC, the image will be pushed to a repository `sagemakerstudio` with the tag `latest`, and use the Studio App's execution role and the default SageMaker Python SDK S3 bucket
2424

2525
These can be overridden with the relevant CLI options.
2626

2727
```bash
28-
sm-docker build . --repository mynewrepo:1.0 --role MyRoleName
28+
sm-docker build . --repository mynewrepo:1.0 --role SampleDockerBuildRole --bucket sagemaker-us-east-1-326543455535 --vpc-id vpc-0c70e76ef1c603b94 --subnet-ids subnet-0d984f080338960bb,subnet-0ac3e96808c8092f2 --security-group-ids sg-0d31b4042f2902cd0
2929
```
3030

3131
The CLI will take care of packaging the current directory and uploading to S3, creating a CodeBuild project, starting a build with the S3 artifacts, tailing the build logs, and uploading the built image to ECR.
@@ -101,16 +101,38 @@ The following permissions are required in the execution role to execute a build
101101
"ecr:DescribeRepositories",
102102
"ecr:UploadLayerPart",
103103
"ecr:ListImages",
104-
"ecr:InitiateLayerUpload",
104+
"ecr:InitiateLayerUpload",
105105
"ecr:BatchCheckLayerAvailability",
106106
"ecr:PutImage"
107107
],
108108
"Resource": "arn:aws:ecr:*:*:repository/sagemaker-studio*"
109109
},
110110
{
111+
"Sid": "ReadAccessToPrebuiltAwsImages",
111112
"Effect": "Allow",
112-
"Action": "ecr:GetAuthorizationToken",
113-
"Resource": "*"
113+
"Action": [
114+
"ecr:BatchGetImage",
115+
"ecr:GetDownloadUrlForLayer"
116+
],
117+
"Resource": [
118+
"arn:aws:ecr:*:763104351884:repository/*",
119+
"arn:aws:ecr:*:217643126080:repository/*",
120+
"arn:aws:ecr:*:727897471807:repository/*",
121+
"arn:aws:ecr:*:626614931356:repository/*",
122+
"arn:aws:ecr:*:683313688378:repository/*",
123+
"arn:aws:ecr:*:520713654638:repository/*",
124+
"arn:aws:ecr:*:462105765813:repository/*"
125+
]
126+
},
127+
{
128+
"Sid": "EcrAuthorizationTokenRetrieval",
129+
"Effect": "Allow",
130+
"Action": [
131+
"ecr:GetAuthorizationToken"
132+
],
133+
"Resource": [
134+
"*"
135+
]
114136
},
115137
{
116138
"Effect": "Allow",
@@ -151,6 +173,26 @@ The following permissions are required in the execution role to execute a build
151173

152174
```
153175

176+
If you need to run your CodeBuild project within a VPC, please add the following actions to your execution role that the CodeBuild Project will assume:
177+
178+
```json
179+
{
180+
"Sid": "VpcAccessActions",
181+
"Effect": "Allow",
182+
"Action": [
183+
"ec2:CreateNetworkInterface",
184+
"ec2:CreateNetworkInterfacePermission",
185+
"ec2:DescribeDhcpOptions",
186+
"ec2:DescribeNetworkInterfaces",
187+
"ec2:DeleteNetworkInterface",
188+
"ec2:DescribeSubnets",
189+
"ec2:DescribeSecurityGroups",
190+
"ec2:DescribeVpcs"
191+
],
192+
"Resource": "*"
193+
}
194+
```
195+
154196
### Development
155197

156198
Checkout the repository.

sagemaker_studio_image_build/builder.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,13 @@ def delete_zip_file(bucket, key):
6464
s3.delete_object(Bucket=bucket, Key=key)
6565

6666

67-
def build_image(repository, role, bucket, compute_type, extra_args, log=True):
67+
def build_image(repository, role, bucket, compute_type, vpc_config, extra_args, log=True):
6868
bucket, key = upload_zip_file(repository, bucket, " ".join(extra_args))
6969
try:
7070
from sagemaker_studio_image_build.codebuild import TempCodeBuildProject
7171

72-
with TempCodeBuildProject(f"{bucket}/{key}", role, repository=repository, compute_type=compute_type) as p:
72+
with TempCodeBuildProject(f"{bucket}/{key}", role, repository=repository,
73+
compute_type=compute_type, vpc_config=vpc_config) as p:
7374
p.build(log)
7475
finally:
7576
delete_zip_file(bucket, key)

sagemaker_studio_image_build/cli.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ def validate_args(args, extra_args):
1515
f'Error parsing reference: "{args.repository}" is not a valid repository/tag'
1616
)
1717

18+
vpc_config = [args.vpc_id, args.subnet_ids, args.security_group_ids]
19+
none_arg_count = sum(arg is None for arg in [args.vpc_id, args.subnet_ids, args.security_group_ids])
20+
21+
if none_arg_count > 0 and none_arg_count < 3:
22+
raise ValueError(
23+
'Invalid input of the VPC configuration. Please either provide all of the VPC arguments or none of them,'\
24+
'in which case the CodeBuild Project, by default, will not run within a VPC.'
25+
)
26+
1827
# Validate extra_args
1928
for idx, extra_arg in enumerate(extra_args):
2029
# Validate that the path to the Dockerfile is within the PWD.
@@ -46,11 +55,24 @@ def get_role(args):
4655
)
4756

4857

58+
def construct_vpc_config(args):
59+
if args.vpc_id is None:
60+
return None
61+
else:
62+
vpc_config = {
63+
'vpcId': args.vpc_id,
64+
'subnets': args.subnet_ids.split(','),
65+
'securityGroupIds': args.security_group_ids.split(',')
66+
}
67+
return vpc_config
68+
69+
4970
def build_image(args, extra_args):
5071
validate_args(args, extra_args)
5172

5273
builder.build_image(
53-
args.repository, get_role(args), args.bucket, args.compute_type, extra_args, log=not args.no_logs
74+
args.repository, get_role(args), args.bucket, args.compute_type,
75+
construct_vpc_config(args), extra_args, log=not args.no_logs
5476
)
5577

5678

@@ -74,7 +96,7 @@ def main():
7496
"--compute-type",
7597
help="The CodeBuild compute type (default: BUILD_GENERAL1_SMALL)",
7698
choices=["BUILD_GENERAL1_SMALL", "BUILD_GENERAL1_MEDIUM",
77-
"BUILD_GENERAL1_LARGE", "BUILD_GENERAL1_2XLARGE"]
99+
"BUILD_GENERAL1_LARGE", "BUILD_GENERAL1_2XLARGE"],
78100
default="BUILD_GENERAL1_SMALL"
79101
)
80102
build_parser.add_argument(
@@ -85,6 +107,18 @@ def main():
85107
"--bucket",
86108
help="The S3 bucket to use for sending data to CodeBuild (if None, use the SageMaker SDK default bucket).",
87109
)
110+
build_parser.add_argument(
111+
"--vpc-id",
112+
help="The Id of the VPC that will host the CodeBuild Project (such as vpc-05c09f91d48831c8c).",
113+
)
114+
build_parser.add_argument(
115+
"--subnet-ids",
116+
help="The comma-separated list of subnet ids for the CodeBuild Project (such as subnet-0b31f1863e9d31a67)",
117+
)
118+
build_parser.add_argument(
119+
"--security-group-ids",
120+
help="The comma-separated list of security group ids for the CodeBuild Project (such as sg-0ce4ec0d0414d2ddc).",
121+
)
88122
build_parser.add_argument(
89123
"--no-logs",
90124
action="store_true",

sagemaker_studio_image_build/codebuild.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111

1212

1313
class TempCodeBuildProject:
14-
def __init__(self, s3_location, role, repository=None, compute_type=None):
14+
def __init__(self, s3_location, role, repository=None, compute_type=None, vpc_config=None):
1515
self.s3_location = s3_location
1616
self.role = role
1717

1818
self.session = boto3.session.Session()
1919
self.domain_id, self.user_profile_name = self._get_studio_metadata()
2020
self.repo_name = None
2121
self.compute_type = compute_type or "BUILD_GENERAL1_SMALL"
22+
self.vpc_config = vpc_config
2223

2324
if repository:
2425
self.repo_name, self.tag = repository.split(":", maxsplit=1)
@@ -75,6 +76,9 @@ def __enter__(self):
7576
"serviceRole": f"arn:{partition}:iam::{account}:role/{self.role}",
7677
}
7778

79+
if self.vpc_config is not None:
80+
args["vpcConfig"] = self.vpc_config
81+
7882
client.create_project(**args)
7983
return self
8084

sagemaker_studio_image_build/data/buildspec.template.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ phases:
99
- $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION --registry-ids 217643126080)
1010
- $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION --registry-ids 727897471807)
1111
- $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION --registry-ids 626614931356)
12+
- $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION --registry-ids 683313688378)
13+
- $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION --registry-ids 520713654638)
14+
- $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION --registry-ids 462105765813)
1215
build:
1316
commands:
1417
- echo Build started on `date`

0 commit comments

Comments
 (0)