Creating a Code deploy pipeline

Introduction

The manual setup steps taken from the AWS docs on creating a simple pipeline (CodeCommit repository).

Have been automated using the CDK.

Examples follows in Python.

Create a CodeCommit repository

# import packages
from aws_cdk import (
    core,
    aws_codecommit as code_commit
)
# creates a CodeCommit repository
code_commit.Repository(self, "CodeCommitRepository",repository_name="MyDemoRepo")

Create an EC2 Linux instance and install the CodeDeploy agent

from aws_cdk import (
    core,
    aws_ec2 as ec2,
    aws_iam as iam
)

vpcId = "<replace with vpc id>"
instanceName = "MyCodePipelineDemo"
instanceType = "t2.micro"
amiName = "amzn2-ami-hvm-2.0.20200520.1-x86_64-gp2"
keyPair = "<replace with your key pair>"

# pull the values from the props dictionary
roleArn = props["ec2role"]

# get the aws environment details
env = kwargs['env']

# add the custom script to run at instance creation, which installs the code deploy agent
userData = "yum -y update; yum install -y ruby aws-cli; \
cd /home/ec2-user; aws s3 cp s3://aws-codedeploy-{}/latest/install . --region {}; \
chmod +x install; ./install auto".format(
    env.region, env.region
)

# lookup existing vpc
vpc = ec2.Vpc.from_lookup(self, "vpc", vpc_id=vpcId,)

# create a security group
sec_group = ec2.SecurityGroup(
    self, "sec-group",security_group_name="sg_pipelinedemo", vpc=vpc, allow_all_outbound=True,
)

# add ingress rule for ssh, limit to your own ip 
sec_group.add_ingress_rule( 
    peer=ec2.Peer.ipv4("<replace with your ip cidrblock>"),
    description="Allow SSH connection",
    connection=ec2.Port.tcp(22),
)

# add ingress rule to allow HTTP connections, limit to your own ip
sec_group.add_ingress_rule(
        peer=ec2.Peer.ipv4("<replace with your ip cidrblock>"),
    description="Allow HTTP connection",
    connection=ec2.Port.tcp(80),
)

# create the ec2 instance, assign the ec2inst role

ec2_instance = ec2.Instance(
    self,
    "ec2-instance",
    instance_name=instanceName,
    instance_type=ec2.InstanceType(instanceType),
    machine_image=ec2.MachineImage().lookup(name=amiName),
    vpc=vpc,
    security_group=sec_group,
    key_name=keyPair,
    role=iam.Role.from_role_arn(self,"ec2role",role_arn=roleArn),

)

# attach the custom user data
ec2_instance.add_user_data(userData)

# add a tag
core.Tag.add(self, key="Name", value="MyCodePipelineDemo")

Create an application in CodeDeploy

from aws_cdk import (
    core,
    aws_codedeploy as code_deploy,
)
# create a server application
serverApplication = code_deploy.ServerApplication(
    self, "MyDemoApplication", application_name="MyDemoApplication",
)

Create a CodeDeploy service role

from aws_cdk import (
    core,
    aws_iam as iam,
)

import random

# create a role assign an existing service role, using the arn
def createRole(self,policyArn,servicePrincipal,roleName):
    iamRole = iam.Role(
        self,
        "role" + str(random.random()),
        role_name=roleName,
        assumed_by=iam.ServicePrincipal(servicePrincipal,),
    )
    
    iamRole.add_managed_policy(
        iam.ManagedPolicy.from_managed_policy_arn(
            self, "managedpolicy" + str(random.random()), managed_policy_arn=policyArn
        )
    )

    #print(iam.Role.role_arn)
    return iamRole.role_arn

# call the createRole function
deployroleArn = self.createRole(
    "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole",
    "codedeploy",
    "CodeDeployRole"
)

Create an application in CodeDeploy

from aws_cdk import (
    core,
    aws_codedeploy as code_deploy,
)
 # Create a server application (CodeDeploy Application that deploys to EC2/on-premise instances.)
serverApplication = code_deploy.ServerApplication(
    self, "MyDemoApplication", application_name="MyDemoApplication",
)

Create a deployment group in CodeDeploy

from aws_cdk import (
    core,
    aws_codedeploy as code_deploy,
)
# ServerDeploymentGroup = A CodeDeploy Deployment Group that deploys to EC2/on-premise instances.
# This group uses the ec2 tag assigned earlier to limit deployments on those instances
code_deploy.ServerDeploymentGroup(
    self,
    "CodeDeploymentGroup",
    application=serverApplication,
    deployment_group_name="MyDemoDeploymentGroup",
    role=iam.Role.from_role_arn(self, "role", role_arn=roleArn),
    deployment_config=code_deploy.ServerDeploymentConfig.ONE_AT_A_TIME,
    ec2_instance_tags=code_deploy.InstanceTagSet(
        # any instance with tags satisfying
        # key1=v1 or key1=v2 or key2 (any value) or value v3 (any key)
        # will match this group
        {"Name": ["MyCodePipelineDemo"],},
    ),
)

Create your first pipeline in CodePipeline

Each pipeline must have 2 stages.

In this case.

  • Stage 1 = Source, which is the CodeCommit repository.

  • Stage 2 = Deploy, which is where the deployment happens on the EC2 instance.


# define the pipeline
# the artifact_bucket is the s3 bucket where the pipeline will store code revisions
pipeline = codepipeline.Pipeline(
        self, "code-pipeline",
        pipeline_name="MyFirstPipeline",
        artifact_bucket=artifact_bucket,
)

source_stage = pipeline.add_stage(stage_name="Source")
deploy_stage = pipeline.add_stage(stage_name="Deploy")

source_output = codepipeline.Artifact(artifact_name='source')

source_stage.add_action(
    codepipeline_actions.CodeCommitSourceAction(
        action_name="Source",
        repository=code_commit.Repository.from_repository_name(self,"code_repo",repository_name="MyDemoRepo"),
        run_order=1,
        output=source_output,
    )
)

deploy_stage.add_action(
    codepipeline_actions.CodeDeployServerDeployAction(
        deployment_group=code_deploy.ServerDeploymentGroup.from_server_deployment_group_attributes(
            self,
            "server_code_deploy_group",
            application=code_deploy.ServerApplication.from_server_application_name(self,"server_app",server_application_name="MyDemoApplication"),
            deployment_group_name="MyDemoDeploymentGroup",
        ),
        action_name="Deploy",
        input=source_output
    )
)

CDK deployment

run

cdk deploy [stack-name]

Trigger deployment

To trigger a deployment, add code into your new CodeCommit repository.

Follow steps 1 and 2 from here.

Validate deployment

To verify that your pipeline ran successfully.

View the initial progress of the pipeline.

The status of each stage changes from No executions yet to In Progress, and then to either Succeeded or Failed.

The pipeline should complete the first run within a few minutes.

After Succeeded is displayed for the pipeline status, in the status area for the Deploy stage, choose AWS CodeDeploy.

This opens the CodeDeploy console.

If Succeeded is not displayed see Troubleshooting CodePipeline.

On the Deployments tab, choose the deployment ID.

On the page for the deployment, under Deployment lifecycle events, choose the instance ID.

This opens the EC2 console.

On the Description tab, in Public DNS, copy the address (for example, ec2-192-0-2-1.us-west-2.compute.amazonaws.com), and then paste it into the address bar of your web browser.

This is the sample application you downloaded and pushed to your CodeCommit repository.

You should see “Congratulations This application was deployed using AWS CodeDeploy.”

Destroying the AWS components

Once you are finished call the destroy cdk function to remove the infrastructure to avoid any costs.

cdk destroy [stack]

Further reading

Python CDK Latest docs

Last updated on 30 Jun 2020
Published on 30 Jun 2020