Skip to content

Commit f1f4c29

Browse files
authored
[INFRANG-6860] Only push ECR images to us-west-2 (#186)
* ci now only pushes to us-west-2 for ecr. images are replicated to all other regions. * fix syntax error * only use OIDC auth for docker image push
1 parent ece9a62 commit f1f4c29

File tree

6 files changed

+42
-70
lines changed

6 files changed

+42
-70
lines changed

circleci/docker-publish

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
# Usage:
77
#
8-
# docker-publish
8+
# docker-publish
99
# optional flag "-r private-repos" enables Docker Build Kit to allow ssh socket mounting to pull private modules/repos
1010

1111

@@ -42,17 +42,11 @@ image_exists() {
4242
}
4343

4444
check_ecr_vars() {
45-
# ECR required env vars. If OIDC_ECR_UPLOAD_ROLE is defined via context, then use it to login to aws.
46-
if [[ -z $OIDC_ECR_UPLOAD_ROLE ]]; then
47-
if [[ -z $ECR_ACCOUNT_ID ]]; then echo "Missing var for ECR: ECR_ACCOUNT_ID" && exit 1; fi
48-
if [[ -z $ECR_PUSH_SECRET ]]; then echo "Missing var for ECR: ECR_PUSH_SECRET" && exit 1; fi
49-
else
50-
if [ -z "${CIRCLE_OIDC_TOKEN_V2}" ]; then
51-
echo "OIDC Token cannot be found. A CircleCI context must be specified."
52-
exit 1
53-
fi
54-
echo "Using AWS role defined in \$OIDC_ECR_UPLOAD_ROLE to login to aws ecr"
45+
if [ -z "${CIRCLE_OIDC_TOKEN_V2}" ]; then
46+
echo "OIDC Token cannot be found. A CircleCI context must be specified."
47+
exit 1
5548
fi
49+
echo "Using AWS role defined in \$OIDC_ECR_UPLOAD_ROLE to login to aws ecr"
5650
}
5751

5852
ecr_login(){
@@ -86,9 +80,9 @@ SHORT_SHA=${CIRCLE_SHA1:0:7}
8680

8781
ORG=clever
8882

89-
ECR_REGION_US_WEST_1=us-west-1
83+
# Only push to us-west-2, images are replicated to other regions
9084
ECR_REGION_US_WEST_2=us-west-2
91-
ECR_REGION_US_EAST_1=us-east-1
85+
ECR_REGION_US_WEST_1=us-west-1
9286
AWS_ECR_PROFILE=oidc-ecr-profile
9387

9488
echo "Docker version..."
@@ -99,47 +93,32 @@ check_ecr_vars
9993

10094
install_awscli
10195

102-
# Some Dockerfiles for private repos depend on public images (and vice versa) in us-west-1
103-
echo "If necessary, add the ECR_BUILD_ID and ECR_BUILD_SECRET env vars to circle manually."
104-
echo "They can be found in init-service as CI_ECR_XXX_KEY and CI_ECR_XXX_SECRET."
96+
# Some Dockerfiles for private repos depend on public images (and vice
97+
# versa) in us-west-1. This login allows us to pull the images for the
98+
# final image build.
99+
echo "If necessary, add the ECR_BUILD_ID env var to circle manually."
105100
if [[ -n $ECR_BUILD_ID ]]; then
106-
if [[ -z $OIDC_ECR_UPLOAD_ROLE ]]; then
107-
echo "Logging into ECR in us-west-1 using static credentials..."
108-
ecr_login us-west-1 $ECR_BUILD_ID $ECR_BUILD_SECRET
109-
else
110-
echo "Logging into ECR using role credentials..."
111-
assume_role_with_web_identity $OIDC_ECR_UPLOAD_ROLE $AWS_ECR_PROFILE
112-
ecr_login_with_profile $ECR_REGION_US_WEST_1
113-
fi
101+
echo "Logging into ECR using role credentials..."
102+
assume_role_with_web_identity $OIDC_ECR_UPLOAD_ROLE $AWS_ECR_PROFILE
103+
ecr_login_with_profile $ECR_REGION_US_WEST_1
114104
fi
115105

116-
if [ -z "$(docker images -q $ORG/$REPO:$SHORT_SHA)" ]; then
117-
echo "Building docker image..."
106+
if [ -z "$(docker images -q $ORG/$REPO:$SHORT_SHA)" ]; then
107+
echo "Building docker image..."
118108
if [ $readopt == "private-repos" ]; then
119109
echo "With Private Repos..."
120-
DOCKER_BUILDKIT=1 docker build --ssh default -t $ORG/$REPO:$SHORT_SHA .
110+
DOCKER_BUILDKIT=1 docker build --ssh default -t $ORG/$REPO:$SHORT_SHA .
121111
else
122112
docker build -t $ORG/$REPO:$SHORT_SHA .
123113
fi
124114
else
125115
echo "Image already exists... skipping build"
126116
fi
127117

128-
# ECR login.
129-
if [[ -z $OIDC_ECR_UPLOAD_ROLE ]]; then
130-
echo "Logging into ECR using static credentials..."
131-
ecr_login $ECR_REGION_US_WEST_1 $ECR_PUSH_ID $ECR_PUSH_SECRET
132-
ecr_login $ECR_REGION_US_WEST_2 $ECR_PUSH_ID $ECR_PUSH_SECRET
133-
ecr_login $ECR_REGION_US_EAST_1 $ECR_PUSH_ID $ECR_PUSH_SECRET
134-
else
135-
echo "Logging into ECR using role credentials..."
136-
assume_role_with_web_identity $OIDC_ECR_UPLOAD_ROLE $AWS_ECR_PROFILE
137-
ecr_login_with_profile $ECR_REGION_US_WEST_1
138-
ecr_login_with_profile $ECR_REGION_US_WEST_2
139-
ecr_login_with_profile $ECR_REGION_US_EAST_1
140-
fi
118+
# ECR login. Only push to us-west-2, images are replicated to other regions.
119+
echo "Logging into ECR using role credentials..."
120+
assume_role_with_web_identity $OIDC_ECR_UPLOAD_ROLE $AWS_ECR_PROFILE
121+
ecr_login_with_profile $ECR_REGION_US_WEST_2
141122

142-
echo "Pushing to ECR..."
143-
push_ecr_image $ECR_REGION_US_WEST_1
123+
echo "Pushing to ECR (us-west-2 only, images replicated to other regions)..."
144124
push_ecr_image $ECR_REGION_US_WEST_2
145-
push_ecr_image $ECR_REGION_US_EAST_1

internal/docker/docker.go

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"github.com/Clever/ci-scripts/internal/environment"
2525
)
2626

27+
const ecrRootRegion = "us-west-2"
28+
2729
// Dockers documentation doesn't provide any examples for using their
2830
// daemon client. This blog post is very helpful for reference:
2931
// https://www.loginradius.com/blog/engineering/build-push-docker-images-golang/
@@ -32,12 +34,12 @@ import (
3234
// complexity in a simple API.
3335
type Docker struct {
3436
cli *client.Client
35-
ecrCreds map[string]types.AuthConfig
37+
ecrCreds types.AuthConfig
3638
awsCfg aws.Config
3739
}
3840

3941
// New initializes a new docker daemon client and caches ecr credentials
40-
// for all 4 regions.
42+
// for us-west-2 (images are replicated to other regions).
4143
func New(ctx context.Context, ecrUploadRole string) (*Docker, error) {
4244
cl, err := client.NewClientWithOpts(client.WithAPIVersionNegotiation())
4345
if err != nil {
@@ -48,14 +50,8 @@ func New(ctx context.Context, ecrUploadRole string) (*Docker, error) {
4850
awsCfg: environment.AWSCfg(ctx, ecrUploadRole),
4951
}
5052

51-
grp, ctx := errgroup.WithContext(ctx)
52-
d.ecrCreds = map[string]types.AuthConfig{}
53-
for _, r := range environment.Regions {
54-
r := r
55-
grp.Go(func() error { return d.ecrCredentials(ctx, r) })
56-
}
57-
58-
if err := grp.Wait(); err != nil {
53+
// Only fetch credentials for us-west-2, images are replicated to other regions
54+
if err := d.ecrCredentials(ctx, ecrRootRegion); err != nil {
5955
return nil, err
6056
}
6157

@@ -104,14 +100,12 @@ func (d *Docker) Push(ctx context.Context, tags []string) error {
104100
for _, tag := range tags {
105101
tag := tag
106102
fmt.Println("pushing", tag)
107-
parts := strings.Split(tag, ".")
108-
region := parts[3]
109103

110104
grp.Go(func() error {
111105
// TODO: check if the repository exists, if it doesn't this just
112106
// nondescriptly endlessly retries.
113107
res, err := d.cli.ImagePush(grpCtx, tag, types.ImagePushOptions{
114-
RegistryAuth: encodeCreds(d.ecrCreds[region]),
108+
RegistryAuth: encodeCreds(d.ecrCreds),
115109
})
116110
if err != nil {
117111
return fmt.Errorf("unable to push image: %v", err)
@@ -154,7 +148,7 @@ func (d *Docker) ecrCredentials(ctx context.Context, region string) error {
154148
return fmt.Errorf("invalid token: expected two parts, got %d", len(parts))
155149
}
156150

157-
d.ecrCreds[region] = types.AuthConfig{
151+
d.ecrCreds = types.AuthConfig{
158152
Username: parts[0],
159153
Password: parts[1],
160154
ServerAddress: *auth.ProxyEndpoint,

internal/docker/targets.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,12 @@ func BuildTargets(apps map[string]*models.LaunchConfig) (map[string]DockerTarget
5656
done[artifact] = struct{}{}
5757

5858
tags := []string{}
59-
for _, region := range environment.Regions {
60-
tag := fmt.Sprintf(
61-
"%s.dkr.ecr.%s.amazonaws.com/%s:%s",
62-
environment.ECRAccountID(), region, artifact, environment.ShortSHA1(),
63-
)
64-
tags = append(tags, tag)
65-
}
59+
// Only push to ecrRootRegion, images are replicated to other regions
60+
tag := fmt.Sprintf(
61+
"%s.dkr.ecr.%s.amazonaws.com/%s:%s",
62+
environment.ECRAccountID(), ecrRootRegion, artifact, environment.ShortSHA1(),
63+
)
64+
tags = append(tags, tag)
6665

6766
targets[repo.Dockerfile(launch)] = DockerTarget{
6867
Tags: tags,

internal/environment/environment.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ var (
5656
// upload role.
5757
oidcEcrUploadRole = ""
5858

59-
// Regions is the set of regions this app should perform
60-
// operations in.
61-
Regions = []string{"us-west-1", "us-west-2", "us-east-1"}
59+
// LambdaRegions is the set of regions to upload Lambda artifacts to.
60+
// Lambda artifacts are not replicated and must be uploaded to each region.
61+
LambdaRegions = []string{"us-west-1", "us-west-2", "us-east-1"}
6262

6363
// Local is a boolean which should be set to true when running
6464
// locally on a developers machine.

internal/lambda/lambda.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ func New(ctx context.Context, bucketPrefix string) *Lambda {
2727
}
2828

2929
// Publish an already built lambda artifact archive to s3 using the
30-
// artifact name as the key. The archive is pushed to each of the 4 aws
30+
// artifact name as the key. The archive is pushed to each of the aws
3131
// regions. Each region is pushed in it's own goroutine.
3232
func (l *Lambda) Publish(ctx context.Context, binaryPath, artifactName string) error {
3333
grp, grpCtx := errgroup.WithContext(ctx)
34-
for _, region := range environment.Regions {
34+
for _, region := range environment.LambdaRegions {
3535
region := region
3636
bucket := fmt.Sprintf("%s-%s", l.artifactBucketPrefix, region)
3737
key := s3Key(artifactName)

internal/lambda/targets.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func s3Key(artifactName string) string {
6666

6767
func s3Buckets() string {
6868
out := []string{}
69-
for _, r := range environment.Regions {
69+
for _, r := range environment.LambdaRegions {
7070
out = append(out, fmt.Sprintf("S3Buckets={%[1]s=\"%[2]s-%[1]s", r, environment.LambdaArtifactBucketPrefix()))
7171
}
7272
return strings.Join(out, ",")

0 commit comments

Comments
 (0)