4

As the title suggests, the blue/green deployment for ecs never finishes because the install lifecycle event never finishes and timesout.

This is the picture showing that: enter image description here The appspec file:

version: 0.0 
Resources: 
  - TargetService: 
      Type: AWS::ECS::Service 
      Properties: 
        TaskDefinition: <TASK_DEFINITION> 
        LoadBalancerInfo: 
          ContainerName: "WordpressContainer" 
          ContainerPort: 80 

The taskdef file:

{ 
    "executionRoleArn": "arn:aws:iam::336636872471:role/WordpressPipelineExecutionRole", 
    "containerDefinitions": [ 
        { 
            "name": "WordpressContainer", 
            "image": "<IMAGE1_NAME>", 
            "essential": true, 
            "portMappings": [ 
                { 
                    "hostPort": 80, 
                    "protocol": "tcp", 
                    "containerPort": 80 
                } 
            ] 
        } 
    ], 
    "requiresCompatibilities": [ 
        "FARGATE" 
    ], 
    "networkMode": "awsvpc", 
    "cpu": "256", 
    "memory": "512", 
    "family": "wordpress" 
} 

I am pushing a bare-bones wordpress docker image to ECR which triggers a pipeline but it stucks on CodeDeploy.

Any ideas what is happening? How am I even supposed to debug that?

P.S. it timed-out in 60 minutes with the message:

The deployment timed out while waiting for the replacement task set to become healthy. This time out period is 60 minutes.

Laimonas Sutkus
  • 3,247
  • 2
  • 26
  • 47

2 Answers2

0

I would check the target groups's health check since it is waiting for a replacement task to become healthier. Is your current deployment of ECS targets HEALTHY? If they are not, the ALB will be trying to bounce these containers to try and refresh them to have a health check passed. Also, does your CodeDeplot have access to deploy to ECR?

Cloud W.
  • 181
  • 5
  • There may be a number of reasons why your targets are not HEALTHY. Make sure your ALB security group allows egress to your targets, and that your ECS security group allows ingress from the ALB. If you don't already, you may want to enable direct access to the targets, so you can see what response you get for the health check. Can you increase your application's logging? Are you seeing anything relevant in the Cloudwatch logs for the target instances? – Chris Goldman Sep 09 '19 at 17:47
  • Good points @ChrisGoldman. I would check the cluster logging as well or cloud watch logs to see what is happening when it is trying to deploy and see if a command is hanging up – Cloud W. Sep 09 '19 at 18:08
0

I'm running into a similar issue. I looked at the cloud logs and didn't see anything obvious. I based my architecture off of https://pypi.org/project/cloudcomponents.cdk-blue-green-container-deployment/

Below are links to images of the results

Code Deploy Failure

Lifecycle events

Target Group 1

Target Group 2

appspec.yaml

version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: "sample-website"
          ContainerPort: 80

buildspec.yml

version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws --version
      - aws ecr get-login-password | docker login --username AWS --password-stdin $REPOSITORY_URI
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:=latest}
      - echo Setting environment variables...
      - echo $EXECUTION_ROLE_ARN
      - echo $FAMILY
      - sed -i "s|SED_REPLACE_EXECUTION_ROLE_ARN|$EXECUTION_ROLE_ARN|g" taskdef.json
      - sed -i "s|SED_REPLACE_FAMILY|$FAMILY|g" taskdef.json
      - cat taskdef.json
  build:
    commands:
      - echo Docker build and tagging started on `date`
      - docker build -t $REPOSITORY_URI:latest -t $REPOSITORY_URI:$IMAGE_TAG -f Dockerfile .
      - echo Docker build and tagging completed on `date`
  post_build:
    commands:
- echo Pushing the Docker images to container registry...
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - echo Writing image definitions file...
      - printf '{"ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
      - echo Build completed on `date`
artifacts:
  files:
    - "appspec.yaml"
    - "taskdef.json"
  secondary-artifacts:
    ManifestArtifact:
      files:
        - appspec.yaml
        - taskdef.json
    ImageArtifact:
      files:
        - imageDetail.json

taskdef.json

{
  "executionRoleArn": "SED_REPLACE_EXECUTION_ROLE_ARN",
  "containerDefinitions": [
    {
      "name": "sample-website",
      "image": "<IMAGE1_NAME>",
      "essential": true,
      "portMappings": [
        {
          "hostPort": 80,
          "protocol": "tcp",
          "containerPort": 80
        }
      ]
    }
  ],
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "256",
  "memory": "512",
  "family": "SED_REPLACE_FAMILY"
}
from aws_cdk import (
    aws_ec2 as ec2,
    Stack,
    aws_ecs as ecs,
    aws_ecs_patterns as ecs_patterns,
    aws_codecommit as codecommit,
    aws_ecr as ecr,
    aws_codepipeline as codepipeline,
    aws_codepipeline_actions as pipeline_actions,
    aws_codebuild as codebuild,
    aws_codedeploy as codedeploy,
    aws_elasticloadbalancingv2 as ecb,
    Duration
)

from cloudcomponents.cdk_blue_green_container_deployment import (
    EcsDeploymentGroup,
    EcsService,
    DummyTaskDefinition
)
from os import path
from constructs import Construct

class Ab3ArchitectureStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        source_artifact = codepipeline.Artifact(artifact_name='SourceArtifact')
        image_artifact = codepipeline.Artifact(artifact_name='ImageArtifact')
        manifest_artifact = codepipeline.Artifact(artifact_name='ManifestArtifact')

        ab3_code_repo = codecommit.Repository(self, 'AB3_Code_Repository',
            repository_name="AB3_NginxApp", #this name is what's seen in CodeCommit
            #code=codecommit.Code.from_directory(path.abspath( "/home/ec2-user/environment/AB3_NginxApp"))
        )

        ab3_ecr_repo = ecr.Repository(self, 'AB3_ECR_Repository',
            image_scan_on_push=True
        )

        #Ran into a build error so created a policy(AB3ElasticContainerRegistry) and attached it to Ab3ArchitectureStack-AB3CodeBuildRole
        #Fixed token issue, but then neded to attach policy to Ab3ArchitectureStack-AB3PipelineBuildAB3BuildCode
        ab3_build = codebuild.Project(self, 'AB3_Code_Build',
            source=codebuild.Source.code_commit(
                repository=ab3_code_repo
            ),
            environment=codebuild.BuildEnvironment(
                build_image=codebuild.LinuxBuildImage.STANDARD_5_0,
                compute_type=codebuild.ComputeType.SMALL,
                privileged=True,
                environment_variables={
                    'REPOSITORY_URI' : codebuild.BuildEnvironmentVariable(value=ab3_ecr_repo.repository_uri),
                    'FAMILY' : codebuild.BuildEnvironmentVariable(value='AB3-blue-green-family'),
                    #The below is a temporary fix and won't work in other enivronments
                    'EXECUTION_ROLE_ARN' : codebuild.BuildEnvironmentVariable(value='arn:aws:iam::460994089204:role/Admin')
                }
            )
        )

        ab3_vpc = ec2.Vpc(self, 'AB3Vpc', max_azs=2)     # default is all AZs in region

        ab3_cluster = ecs.Cluster(self, 'AB3Cluster', vpc=ab3_vpc)

        ab3_load_balancer = ecb.ApplicationLoadBalancer(self, 'AB3LoadBalancer',
            vpc=ab3_vpc,
            internet_facing=True
        )

        ab3_prod_listener = ab3_load_balancer.add_listener('ProductionListener',
            port=80
        )

        ab3_test_listener = ab3_load_balancer.add_listener('TestListener',
            port=8080
        )

        ab3_prod_tgt_group = ecb.ApplicationTargetGroup(self, 'ProdTargetGoup',
            port=80,
            target_type= ecb.TargetType.IP,
            vpc=ab3_vpc
        )

        ab3_prod_listener.add_target_groups('AddProdTgtGroup',
            target_groups=[ab3_prod_tgt_group]
        )

        ab3_test_tgt_group = ecb.ApplicationTargetGroup(self, 'TestTargetGoup',
            port=8080,
            target_type= ecb.TargetType.IP,
            vpc=ab3_vpc
        )

        ab3_test_listener.add_target_groups('AddTestTgtGroup',
            target_groups=[ab3_test_tgt_group]
        )

        ab3_ecs_service = EcsService(self, "AB3ECSService",
            cluster=ab3_cluster,
            service_name='AB3-Service',
            desired_count=2,
            task_definition= DummyTaskDefinition(self, 'DummyTaskDef', #should be replaced by CodeDeploy in CodePipeline
                image='nginx',
                family='AB3-blue-green-family'
            ),
            test_target_group=ab3_test_tgt_group,
            prod_target_group=ab3_prod_tgt_group
        )

        ab3_ecs_service.connections.allow_from(ab3_load_balancer, ec2.Port.tcp(80))
        ab3_ecs_service.connections.allow_from(ab3_load_balancer, ec2.Port.tcp(8080))

        #ab3_deployment_group = codedeploy.IEcsDeploymentGroup() TypeError Protocols can't be instantiated
        ab3_deployment_group = EcsDeploymentGroup(self, "AB3DeployGroup",
            application_name='AB3-Application',
            deployment_group_name='AB3-Deployment-Group',
            ecs_services=[ab3_ecs_service],
            target_groups=[ab3_prod_tgt_group,ab3_test_tgt_group],
            prod_traffic_listener= ab3_prod_listener,
            test_traffic_listener=ab3_test_listener,
            termination_wait_time=Duration.minutes(15)
        )

        pipeline = codepipeline.Pipeline(self, "AB3Pipeline",
        stages=[
            codepipeline.StageProps(
                stage_name="Source",
                actions=[
                    pipeline_actions.CodeCommitSourceAction(
                        repository=ab3_code_repo,
                        branch='main',
                        output=source_artifact,
                        action_name='AB3Source'
                    )
                ] 
            ),
            codepipeline.StageProps(
                stage_name="Build",
                actions=[
                    pipeline_actions.CodeBuildAction(
                        input=source_artifact,
                        project=ab3_build,
                        action_name='AB3Build',
                        outputs=[image_artifact, manifest_artifact] #second output needs to be specified in buildspec
                        #outputs=[image_artifact]
                    )
                ]
            ),
            codepipeline.StageProps(
                stage_name="Deploy",
                actions=[
                    pipeline_actions.CodeDeployEcsDeployAction(
                        action_name="AB3Deploy",
                        deployment_group=ab3_deployment_group,
                        #app_spec_template_input=image_artifact,
                        #task_definition_template_input=image_artifact
                        app_spec_template_input=manifest_artifact,
                        task_definition_template_input=manifest_artifact,
                        container_image_inputs=[pipeline_actions.CodeDeployEcsContainerImageInput(
                            input=image_artifact,
                            task_definition_placeholder='IMAGE1_NAME'
                        )]
                    )
                ]
            )
        ]
        ) 

        '''
        ab3_ecs_application = codedeploy.EcsApplication(self, "AB3_Application",
            application_name="AB3_NGINX_Application"
        )

        ab3

        ab3_task_definition = ecs.FargateTaskDefinition(self, 'AB3_Task_Definition',
            cpu=256,
            memory_limit_mib=1024
            #task_role= ???,
            #execution_role= ????
        )

        ab3_task_definition.add_container('AB3_Container', 
            image= ecs.ContainerImage.from_ecr_repository(ab3_ecr_repo)

        )

        # Provide a Stage when creating a pipeline

        ecs_patterns.ApplicationLoadBalancedFargateService(self, "AB3Service",
            cluster=ab3_cluster,            # Required
            cpu=512,                    # Default is 256
            desired_count=6,            # Default is 1
            task_image_options=ecs_patterns.ApplicationLoadBalancedTaskImageOptions(
                image=ecs.ContainerImage.from_registry("amazon/amazon-ecs-sample")),
                #image=ecs.ContainerImage.from_ecr_repository(ab3_ecr_repo)),
            memory_limit_mib=2048,      # Default is 512
            public_load_balancer=True  # Default is True
        )
'''
wsa225
  • 9
  • 2
  • This is more of a comment than an answer. Considering moving it to a comment. If you like the question and want it to get more attention, you can upvote instead. – Register Sole Jan 04 '23 at 05:27
  • looks like i lack reputation points to make a comment in other people's answers unfortunately. – wsa225 Jan 04 '23 at 15:50