I’m trying to build a pipeline that build and push docker images to ECR using buildspec for AWS CodeBuild. My project is multi containers microservices with docker-compose yaml file. I have enable Privileged mode for my CodeBuild, the pipeline is able login to AWS, build and tag the images but it’s failing at docker push command with the following error:
[Container] 2023/02/21 17:45:38 Command did not exit successfully docker push $REPOSITORY_URL/service1:$TAG exit status 1
[Container] 2023/02/21 17:45:38 Phase complete: POST_BUILD State: FAILED
[Container] 2023/02/21 17:45:38 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: docker push $REPOSITORY_URL/service1:$TAG. Reason: exit status 1
My docker-compose.yaml file looks like this:
version: '3.4'
services:
service1:
image: service1
build:
context: .
dockerfile: Service1.API/Dockerfile
service2:
image: service2
build:
context: .
dockerfile: service2.API/Dockerfile
My buildspec file looks like this:
version: 0.2
phases:
install:
runtime-versions:
docker: latest
pre_build:
commands:
# This Docker Image tag will have date, time and Codecommit version
- TAG="$(date +%Y-%m-%d.%H.%M.%S).$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | head -c 8)"
# Check AWS CLI Version
- echo "Checking AWS CLI Version..."
- aws --version
# Login to ECR Registry
- echo "Logging in to Amazon ECR..."
- $(aws ecr get-login --no-include-email --region us-east-1)
build:
commands:
- echo "Docker build started on `date`"
- echo "Building the Docker images..."
- docker-compose -f docker-compose.yml build
- echo Tagging the Docker images...
- docker tag service1:latest $REPOSITORY_URL/service1:$TAG
- docker tag service2:latest $REPOSITORY_URL/service2:$TAG
post_build:
commands:
# Push Docker Image to ECR Repository
- echo "Docker build completed on `date`"
- echo "Pushing the Docker images to Amazon ECR..."
- docker push $REPOSITORY_URL/service1:$TAG
- docker push $REPOSITORY_URL/service2:$TAG
- echo "Docker Push to ECR Repository Completed - $REPOSITORY_URL:$TAG"
# Create Artifacts which we can use if we want to continue our pipeline for other stages
- echo "Writing the image details to a file...""
- echo {"service1":"$REPOSITORY_URL/service1:$TAG","service2":"$REPOSITORY_URL/service2:$TAG"} > build.json
artifacts:
files:
- build.json
- manifests/*
I have attached all necessary policies an permision to my codebuild service role, my policy looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:CompleteLayerUpload",
"ecr:GetDownloadUrlForLayer",
"ecr:InitiateLayerUpload",
"ecr:PutImage",
"ecr:UploadLayerPart",
"ecr:SetRepositoryPolicy",
"ecr:DescribeImages",
"ecr:DescribeRepositories",
"ecr:ListImages",
"ecr:DeleteRepositoryPolicy",
"ecr:GetRepositoryPolicy",
"ecr:GetAuthorizationToken"
],
"Effect": "Allow",
"Resource": "arn:aws:ecr:us-east-1:<ACCOUNT_ID>:repository/dev-repo"
},
{
"Action": [
"ecr:GetAuthorizationToken"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr-public:GetAuthorizationToken",
"sts:GetServiceBearerToken"
],
"Resource": "*"
}
]
}
The log error is not clear enough and does not give head on what could be wrong, I have joined some answers to these similar questions to form my policy but it’s still not working for me.
2
Answers
Because this is a multi container microservices application, I thought I could use a single ECR repository for both images, turned out this was the issue. So I solved this by making sure that each image has separate ECR repository and the image name must match the repository name.
Example:
$REPOSITORY_URL should be:
The error message seems pretty clear to me:
Your command is invalid, you’re trying to push to a destination named $REPOSITORY_URL/service1:$TAG.
You’re setting TAG in the pre-build phase, but this is not the right way to do it, and anyway the correct syntax should be
Follow this guide to write a correct buildspec.
At least, you’re missing the env section with the properly variables setting.