Skip to content

Instantly share code, notes, and snippets.

@jlis
Created May 15, 2018 13:16
Show Gist options
  • Star 77 You must be signed in to star a gist
  • Fork 26 You must be signed in to fork a gist
  • Save jlis/4bc528041b9661ae6594c63cd2ef673c to your computer and use it in GitHub Desktop.
Save jlis/4bc528041b9661ae6594c63cd2ef673c to your computer and use it in GitHub Desktop.
AWS ECS and ECR deployment via Docker and Gitlab CI
image: docker:latest
variables:
REPOSITORY_URL: <AWS ACCOUNT ID>.dkr.ecr.eu-central-1.amazonaws.com/<ECS REPOSITORY NAME>
REGION: eu-central-1
TASK_DEFINTION_NAME: <TASK DEFINITION NAME>
CLUSTER_NAME: <CLUSTER NAME>
SERVICE_NAME: <SERVICE NAME>
services:
- docker:dind
before_script:
- apk add --no-cache curl jq python py-pip
- pip install awscli
- $(aws ecr get-login --no-include-email --region "${REGION}")
- IMAGE_TAG="$(echo $CI_COMMIT_SHA | head -c 8)"
stages:
- build
- deploy
build:
stage: build
script:
- echo "Building image..."
- docker build -t $REPOSITORY_URL:latest .
- echo "Tagging image..."
- docker tag $REPOSITORY_URL:latest $REPOSITORY_URL:$IMAGE_TAG
- echo "Pushing image..."
- docker push $REPOSITORY_URL:latest
- docker push $REPOSITORY_URL:$IMAGE_TAG
only:
- master
deploy:
stage: deploy
script:
- echo $REPOSITORY_URL:$IMAGE_TAG
- TASK_DEFINITION=$(aws ecs describe-task-definition --task-definition "$TASK_DEFINTION_NAME" --region "${REGION}")
- NEW_CONTAINER_DEFINTIION=$(echo $TASK_DEFINITION | python $CI_PROJECT_DIR/update_task_definition_image.py $REPOSITORY_URL:$IMAGE_TAG)
- echo "Registering new container definition..."
- aws ecs register-task-definition --region "${REGION}" --family "${TASK_DEFINTION_NAME}" --container-definitions "${NEW_CONTAINER_DEFINTIION}"
- echo "Updating the service..."
- aws ecs update-service --region "${REGION}" --cluster "${CLUSTER_NAME}" --service "${SERVICE_NAME}" --task-definition "${TASK_DEFINTION_NAME}"
only:
- master
import sys, json, argparse
parser = argparse.ArgumentParser('Replaces image in the task definition')
parser.add_argument('image_uri', metavar='I', type=str, nargs='+',
help='The new image URI')
args = parser.parse_args()
definition = json.load(sys.stdin)['taskDefinition']['containerDefinitions']
definition[0]['image'] = args.image_uri[0]
print json.dumps(definition)
@Dascienz
Copy link

Dascienz commented Oct 29, 2021

Note, in Gitlab you can now use $CI_COMMIT_SHORT_SHA instead of "$(echo $CI_COMMIT_SHA | head -c 8)". See: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html#:~:text=is%20built%20for.-,CI_COMMIT_SHORT_SHA,-11.7

@Tushar-Sawdays
Copy link

Anyone here has a solution to pass a container environment used on applications?

Like injecting this Envs in the task definition.

I have used sed command in my pipeline to inject env vars in task definition file.

@Peterragheb
Copy link

    - TASK_DEFINITION=$(aws ecs describe-task-definition --task-definition "$CI_AWS_ECS_TASK_DEFINITION" --region "${AWS_DEFAULT_REGION}")
    - NEW_CONTAINER_DEFINTIION=$(echo $TASK_DEFINITION | jq --arg IMAGE "$DOCKER_REGISTRY/$APP_NAME:latest" '.taskDefinition.containerDefinitions[0].image = $IMAGE | .taskDefinition.containerDefinitions[0]')
    - echo "Registering new container definition..."
    - aws ecs register-task-definition --region "${AWS_DEFAULT_REGION}" --family "${CI_AWS_ECS_TASK_DEFINITION}" --container-definitions "${NEW_CONTAINER_DEFINTIION}"
    - echo "Updating the service..."
    - aws ecs update-service --region "${AWS_DEFAULT_REGION}" --cluster "${CI_AWS_ECS_CLUSTER}" --service "${CI_AWS_ECS_SERVICE}"  --task-definition "${CI_AWS_ECS_TASK_DEFINITION}"

this is the script i'm using however the service deployment does not start the desired task count is 1 however it does not create any
Screen Shot 2021-11-16 at 4 27 04 PM

@rmpt
Copy link

rmpt commented Nov 17, 2021

or you can use sed to set the new image tag, in my case, the CI_PIPELINE_IID and then use jq to extract the container definition:

NEW_CONTAINER_DEFINITION=$(echo $TASK_DEFINITION | sed -e "s/ecr-image:.*/ecr-image:$CI_PIPELINE_IID\",/g")
NEW_CONTAINER_DEFINITION=$(echo $NEW_CONTAINER_DEFINITION | jq '.taskDefinition.containerDefinitions[0]')

@Peterragheb
Copy link

Actually there was nothing wrong with the script, it was failing to bind a port to the new container because I was using a static port binding.
Later I switched to using gitlab's ecs deployment script

@elfadl
Copy link

elfadl commented Dec 29, 2022

    - TASK_DEFINITION=$(aws ecs describe-task-definition --task-definition "$CI_AWS_ECS_TASK_DEFINITION" --region "${AWS_DEFAULT_REGION}")
    - NEW_CONTAINER_DEFINTIION=$(echo $TASK_DEFINITION | jq --arg IMAGE "$DOCKER_REGISTRY/$APP_NAME:latest" '.taskDefinition.containerDefinitions[0].image = $IMAGE | .taskDefinition.containerDefinitions[0]')
    - echo "Registering new container definition..."
    - aws ecs register-task-definition --region "${AWS_DEFAULT_REGION}" --family "${CI_AWS_ECS_TASK_DEFINITION}" --container-definitions "${NEW_CONTAINER_DEFINTIION}"
    - echo "Updating the service..."
    - aws ecs update-service --region "${AWS_DEFAULT_REGION}" --cluster "${CI_AWS_ECS_CLUSTER}" --service "${CI_AWS_ECS_SERVICE}"  --task-definition "${CI_AWS_ECS_TASK_DEFINITION}"

this is the script i'm using however the service deployment does not start the desired task count is 1 however it does not create any
Screen Shot 2021-11-16 at 4 27 04 PM

you can set minimum healthy percent to 0 and maximum percent to 100 if you want only one container running on your ecs.

@vijayrvk
Copy link

vijayrvk commented Feb 1, 2023

Screenshot 2023-02-01 at 4 12 50 PM

Getting an error while using was ecr login. Any idea? I'm passing secret key and access ID from CI/CD in variables

@nholuongut
Copy link

Hi Guys,

I have done with my gitlab pipeline one branh (master) and now i have fail with two branh both master, develop branh.

Please help me to wrire into .gitlab-ci.yml one
build:
stage: build
deploy:
stage: deploy

all develop, master branh?

Thank for help and hope see rely soon.

@SergiyVasylenko
Copy link

SergiyVasylenko commented Jul 6, 2023

Hi there!
Just finished with ECS FARGATE deployment step at the GitLab CI. Want to share the result.
Hopefully, this would be helpful and save time for someone ;)

- TASK_DEFINITION_CURRENT=$(aws ecs describe-services --services "${ECS_SERVICE_NAME}" --cluster "${ECS_CLUSTER_NAME}" | jq -r .services[].taskDefinition | cut -d "/" -f 2)
- TASK_DEFINTION_NAME=$(echo $TASK_DEFINITION_CURRENT | cut -d ":" -f 1 )
- TASK_DEFINITION=$(aws ecs describe-task-definition --task-definition "$TASK_DEFINTION_NAME")
- NEW_CONTAINER_DEFINTIION=$(echo $TASK_DEFINITION | jq --arg IMAGE "${CI_REGISTRY_IMAGE}/${CI_COMMIT_REF_SLUG}:${DEPLOY_CONTAINER_TAG}" '.taskDefinition.containerDefinitions[0].image = $IMAGE | .taskDefinition.containerDefinitions[0]')
- EXECUTION_ROLE_ARN=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.executionRoleArn')
- TASK_ROLE_ARN=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.taskRoleArn')
- CONTAINER_MEMORY=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.memory')
- CONTAINER_CPU=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.cpu')
- REQUIRE_COMPATABILITIES=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.requiresCompatibilities[]')
- NETWORK_MODE=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.networkMode')
- echo "Registering new container definition..."
- aws ecs register-task-definition --family "${TASK_DEFINTION_NAME}" --container-definitions "${NEW_CONTAINER_DEFINTIION}" --execution-role-arn "${EXECUTION_ROLE_ARN}" --memory "${CONTAINER_MEMORY}" --requires-compatibilities "${REQUIRE_COMPATABILITIES}" --network-mode "${NETWORK_MODE}" --cpu "${CONTAINER_CPU}"  --task-role-arn "${TASK_ROLE_ARN}"
- echo "Updating the service..."
- aws ecs update-service --cluster "${ECS_CLUSTER_NAME}" --service "${ECS_SERVICE_NAME}"  --task-definition "${TASK_DEFINTION_NAME}"

@bilalmeccai
Copy link

to avoid python you can use jq

- NEW_CONTAINER_DEFINTIION=$(echo $TASK_DEFINITION | jq --arg IMAGE "$REPOSITORY_URL:$IMAGE_TAG" '.taskDefinition.containerDefinitions[0].image = $IMAGE | .taskDefinition.containerDefinitions[0]')

Hi,
Is there anyway we can pass two container images with this? I have been trying to work around this and could not find any solutions.

@shamimhan
Copy link

Hi Team ,

ia m getting below vunrability how to fix any one pls help

Improper access control in the Intel(R) Ethernet Controller RDMA driver for linux before version 1.9.30 may allow an unauthenticated user to potentially enable escalation of privilege via network access.

@shamimhan
Copy link

Hi Team ,

i am using for deployment below script

scripts:

  • $(aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ECR_REGISTRY | tr -d '\r')
    • TASK_DEFINITION_CURRENT=$(aws ecs describe-services --services "${SERVICE_NAME}" --cluster "${CLUSTER_NAME}" | jq -r .services[].taskDefinition | cut -d "/" -f 2)
    • TASK_DEFINTION_NAME=$(echo $TASK_DEFINITION_CURRENT | cut -d ":" -f 1 )
    • TASK_DEFINITION=$(aws ecs describe-task-definition --task-definition "$TASK_DEFINTION_NAME")
    • NEW_CONTAINER_DEFINTIION=$(echo $TASK_DEFINITION | jq --arg IMAGE "${AWS_ECR_REGISTRY}/${APP_NAME}/${CI_COMMIT_REF_SLUG}:${SEMVER}" '.taskDefinition.containerDefinitions[0].image = $IMAGE | .taskDefinition.containerDefinitions[0]')
    • EXECUTION_ROLE_ARN=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.executionRoleArn')
    • TASK_ROLE_ARN=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.taskRoleArn')
    • CONTAINER_MEMORY=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.memory')
    • CONTAINER_CPU=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.cpu')
    • REQUIRE_COMPATABILITIES=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.requiresCompatibilities[]')
    • NETWORK_MODE=$(echo $TASK_DEFINITION | jq -r '.taskDefinition.networkMode')
    • echo "Registering new container definition..."
    • aws ecs register-task-definition --family "${TASK_DEFINTION_NAME}" --container-definitions "${NEW_CONTAINER_DEFINTIION}" --execution-role-arn "${EXECUTION_ROLE_ARN}" --memory "${CONTAINER_MEMORY}" --requires-compatibilities "${REQUIRE_COMPATABILITIES}" --network-mode "${NETWORK_MODE}" --cpu "${CONTAINER_CPU}" --task-role-arn "${TASK_ROLE_ARN}"
    • echo "Updating the service..."
    • aws ecs update-service --cluster "${CLUSTER_NAME}" --service "${SERVICE_NAME}" --task-definition "${TASK_DEFINTION_NAME}"

but i am getting below error

“message”: “(service crm-api-secured) failed to launch a task with (error ECS was unable to assume the role ‘arn:aws:iam::XXXXXXXXX:role/null’ that was provided for this task. Please verify that the role being passed has the proper trust relationship and permissions and that your IAM user has permissions to pass this role.).”
any one pls help for the same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment