Setting up an AWS CodeDeploy Deployment Using PowerShell

AWS CodeDeploy Setup Using PowerShellOne of those important metrics to track as part of a successful DevOps organization is how fast the organization can deliver value to its customers. This value is what separates manual, error-prone, “do whatever it takes to get it done” tasks that some organizations are faced with from fully-automated and standardized workflows that successful DevOps organizations enjoy every day.  In the AWS world, this is where AWS CodeDeploy service comes in.

DevOps value ultimately means delivering reliable, dependable software that solves customers’ problems as quick as possible. Did you notice the key term in that last sentence? Delivering. A software developer’s code that solves all of the world’s problems doesn’t mean anything if it can’t be delivered or deployed to his customers.

CodeDeploy is AWS’s solution for deploying a software package to AWS resources or on-prem. It allows teams to build automated pipelines or self-service functionality to invoke routine, standard deployments to one or more environments.

AWS CodeDeploy First-Timers

If you’re new to AWS CodeDeploy or perhaps automated deployment products in general, you’ll undoubtedly be overwhelmed when just beginning. Layered onto that, if you’re not too familiar with AWS as well, it can seem extremely daunting. But, we’re here to help you over that hurdle.

There are essentially two different ways to set up AWS CodeDeploy. It can all be done via the AWS portal where you’ll find yourself navigating through lots of windows, going back and forth missing a step here and there or you can use a script.

A script allows me to teach you the exact steps needed. There’s no guessing what I mean. If you can copy and paste text, you can build AWS CodeDeploy from scratch.

AWS provides a few different ways to script out a CodeDeploy configuration. We could use Python, the AWS CLI or go straight to the APIs themselves but we can also use PowerShell. For those already using PowerShell, this tutorial will get AWS CodeDeploy up and running with code you understand already. However, even if you don’t know PowerShell, the code we’ll be using will be reasonably simple anyway.

Prerequisites

To get started, we’re going to need a few prerequisites and I’ll be assuming a few things. First, if you’ve never interacted with AWS with PowerShell before, you’re going to need to download and install the AWSPowerShell module. This module can be installed via the PowerShell Gallery by running Install-Module AWSPowerShell in a PowerShell window.

Also, you’ll need to authenticate to AWS. For a full breakdown on how to do this, refer to the Using AWS Credentials article. Since I’ll be using the us-east-1 location for all of my code in this tutorial, I’ve also made it my default by running Initialize-AwsDefaults -Region ‘us-east-1’.

Prep the application for CodeDeploy

An “application” or “package” can be anything for AWS CodeDeploy. To keep this simple, I’m just going to be calling my “application” a single PowerShell script. When deployed, it will execute on my deployment targets.

I’ll first need to “prep” my application to be deployed. I do this by creating a YAML file called appsec.yml. This file will contain all of the instructions I’d like to provide to CodeDeploy when the application is deployed. This file has a ton of options so feel free to take a peek at all of the configuration options if you need to perform a different set of tasks.

This appspec.yml file will need to be in the root of your folder. Below is my example file. This indicates that when this deployment is performed on a Windows server, it will look for files in the path. It will then copy those files to C:. This step is just copying files to the deployment target.

version: 0.0
os: windows
files:
  - source: \AcmeCorp
    destination: C:\FolderOnClientServer
If we wanted to, we could execute a PowerShell script as well using a hook.
hooks:
  AfterInstall:
    - location: C:\FolderOnClientServer\MyAwesomeScript.ps1
      timeout: 300

Create the application
Next step is to create the application. We do this by using the New-CDApplication cmdlet. I’m calling my application AcmeCorpScripts.

$applicationid = New-CDApplication -ApplicationName AcmeCorpScripts

Optionally create the deployment configuration
The application’s deployment routine will have a default, but if you want to change that, you could use the New-CDDeploymentConfig to create your own routine (configuration) or choose an existing one using the Get-CDDeploymentConfigList command.

PS> New-CDDeploymentConfig -DeploymentConfigName AtLeastOnHealthyHost -MinimumHealthyHosts_Type HOST_COUNT -MinimumHealthyHosts_Value 1
1046c8a0-2de5-48fe-ae3e-cd9a33af8b5d

Create the IAM Access Key
CodeDeploy will need to get access to the deployment targets. As part of its authentication routine, it will need an access key, so I’ll go ahead and create that now using an existing IAM user I’ve set up called codedeploytesting.

PS> $iamAccessKey = New-IAMAccessKey -UserName codedeploytesting
AccessKeyId : XXXXXXXXXXXXXXX CreateDate : 2/11/2018 5:18:03 PM SecretAccessKey : XXXXXXXXXXXXXXXXXX Status : Active UserName : powershell

IAM Service Role Setup
Next, we have to setup an IAM service role. I’ll create a text file that looks like the following as C:\CodeDeployRole.json to represent that service role.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "codedeploy.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Once I have the JSON file created, I’ll then run New-IAMRole to assign the policy just created and create a role called CodeDeployRole.

PS> New-IAMRole -RoleName CodeDeployRole -AssumeRolePolicyDocument (Get-Content -Raw C:\CodeDeployRole.json)

Path             RoleName                           RoleId                   CreateDate             Description
----             --------                           ------                   ----------             -----------
/                CodeDeployRole                     AROAJYJUOYSDWOTXRRC5C    2/9/2018 9:03:37 PM

Once the role is created, we’ll then need to register the IAM role policy giving the CodeDeployRole the ability to create a session token.

PS> Register-IAMRolePolicy -RoleName CodeDeployRole -PolicyArn arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole

Create the on-premises configuration file
Since I’d like to use an on-premises deployment target, I need to perform some configuration there as well. I’ll use PowerShell to create a conf.onpremises.yml file located in. This path is mandatory. I will be using the following code to create a new folder and create the file using the IAM access key I created earlier and specifying the region and IAM user’s ARN I created earlier.

$codeDeployDir = "$env:ALLUSERSPROFILE\Amazon\CodeDeploy"
if (-not (Test-Path -Path $codeDeployDir)) {
    New-Item -Path $codeDeployDir -ItemType Directory
}

$Region = 'us-east-1'

## Get the recently created IAM user info
$iamUserName = 'codedeploytesting'
$iamUser = Get-IAMUser -UserName $iamUserName

$iamUser

Arn              : arn:aws:iam::054715970076:user/powershell
CreateDate       : 7/25/2017 6:11:58 PM
PasswordLastUsed : 1/1/0001 12:00:00 AM
Path             : /
UserId           : AIDAJQPYI5W26FAVSZFTG
UserName         : powershell


$confFileContent = @'

---
aws_access_key_id: {0}
aws_secret_access_key: {1}
iam_user_arn: {2}
region: {3}
'@ -f $iamAccessKey.AccessKeyId,$iamAccessKey.SecretAccessKey,$iamUser.Arn,$Region

Set-Content -Path "$codeDeployDir\conf.onpremises.yml" -Value $confFileContent

Register an on-prem instance
Next, I’ll register a new on-prem instance using the same name as my server.
Register-CDOnPremiseInstance -IamUserArn $iamUser.Arn -InstanceName CLIENTSRV1

Install the AWS CodeDeploy Agent
Now it’s time to install the AWS CodeDeploy Agent on my on-prem server. Using the below PowerShell code will expedite this process tremendously.

$Region = 'us-east-1'
$installerFilePath = "$env:TEMP\codedeploy-agent.msi"
Read-S3Object -BucketName  aws-codedeploy-$Region -Key latest/codedeploy-agent.msi -File $installerFilePath

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2/11/2018   4:52 PM       12730368 codedeploy-agent.msi

$procParams = @{
  FilePath = 'msiexec.exe'
  ArgumentList = @('/i', "`"$installerFilePath`"", '/quiet', '/l', "`"$env:Temp\awscodedeploy-install.log`"")
  Wait = $true
  NoNewWindow = $true
}
Start-Process @procParams

Once complete, if you can run Get-Service -Name codedeployagent with no errors, it was successful.

Add tags to the instance
Next, I’ll add tags to the on-prem instance so that I can target this tag later.

PS> Add-CDOnPremiseInstanceTag -InstanceName CLIENTSRV1 -Tag @{ 'Key' = 'Name'; 'Value' = 'AcmeCorpServers' } 

Create the deployment group
Next, I’ll create the deployment group using the IAM role’s ARN I created earlier assigning the tag created.

PS> $serviceRoleArn = (Get-IAMRole -RoleName CodeDeployRole).Arn
PS> New-CDDeploymentGroup -ApplicationName AcmeCorpScripts -DeploymentConfigName CodeDeployDefault.AllAtOnce -DeploymentGroupName AcmeCorpServers -OnPremisesInstanceTagFilter @{Key="Name"; Type="KEY_AND_VALUE"; Value="AcmeCorpServers" } -ServiceRoleArn $serviceRoleArn
8137fd07-2d18-4778-8e82-ac0f94fb6002

Perform a deployment
Now it’s finally time to perform the deployment! I’m using a Github repo as a source. This requires a bit of setup which you can find instructions for here.
Once Github is setup, you’ll need to find the commit ID indicating the version of the app you’d like to deploy. Once you’ve found that, you can then create a new CodeDeploy deployment using New-CDDeployment. You can see below I’m using a repo called MyScripts in my adbertram Github account. This command returns the deployment ID.

PS> New-CDDeployment -ApplicationName AcmeCorpScripts -DeploymentGroupName AcmeCorpServers -Revision_GitHubLocation_Repository 'adbertram/MyScripts' -RevisionType Github -Revision_GitHubLocation_CommitId '9f38885ce2c63a01e378df68a0d2c2e6166b21c0'
d-S8WDE6VFR

Track deployment
Once the deployment has been started, you can then either let it go or track it. If you’d like to track progress, this can be done using the Get-CDDeployment cmdlet. You can see below that the Status is succeeded meaning it was complete!

PS> Get-CDDeployment -DeploymentId $depIds

AdditionalDeploymentStatusInfo     :
ApplicationName                    : AcmeCorpScripts
AutoRollbackConfiguration          : Amazon.CodeDeploy.Model.AutoRollbackConfiguration
BlueGreenDeploymentConfiguration   :
CompleteTime                       : 2/11/2018 7:20:23 PM
ComputePlatform                    : Server
CreateTime                         : 2/11/2018 7:20:06 PM
Creator                            : user
DeploymentConfigName               : CodeDeployDefault.AllAtOnce
DeploymentGroupName                : AcmeCorpServers
DeploymentId                       : d-0ZNK2WYFR
DeploymentOverview                 : Amazon.CodeDeploy.Model.DeploymentOverview
DeploymentStatusMessages           : {}
DeploymentStyle                    : Amazon.CodeDeploy.Model.DeploymentStyle
Description                        :
ErrorInformation                   :
FileExistsBehavior                 : DISALLOW
IgnoreApplicationStopFailures      : False
InstanceTerminationWaitTimeStarted : False
LoadBalancerInfo                   :
PreviousRevision                   :
Revision                           : Amazon.CodeDeploy.Model.RevisionLocation
RollbackInfo                       :
StartTime                          : 1/1/0001 12:00:00 AM
Status                             : Succeeded
TargetInstances                    :
UpdateOutdatedInstancesOnly        : False

Summary
There’s quite a bit to setting up your first CodeDeploy deployment, but once you’ve got the Github repo setup, application created, deployment groups, tags set up and the on-prem agents installed, the deployment just needs to be invoked.

Once created this deployment can then be used as part of a larger automated pipeline by perhaps using AWS’s CodePipeline service as well. Once a deployment is set up for an application, that’s a big win for automation. By doing this with a script, you’ll then be able to build more deployments and templatize a lot of this to make the process even easier.

About the Author

Guest author: Adam the AutomatorAdam Bertram is a 20-year veteran of IT. He’s an automation engineer, blogger, consultant, freelance writer, Pluralsight course author and content marketing advisor to multiple technology companies. Adam focuses on DevOps, system management, and automation technologies as well as various cloud platforms. He is a Microsoft Cloud and Datacenter Management MVP who absorbs knowledge from the IT field and explains it in an easy-to-understand fashion.

Catch up on Adam’s articles at adamtheautomator.com, connect on linkedin.com/in/adbertram or follow him on Twitter at @adbertram.

Share this post →

You might also like: