Golden image creation using Packer and AWS CodePipeline

Hi All, we know that Packer can be used to create Golden images for multiple platforms. Here we will use Packer to create an Golden image of Amazon Linux OS in AWS. The created images are called as AMI which appear in AWS dashboard. The image creation is necessarry in situations when we want the OS to have pre set of packages installed to support our application. The custom created AMI can be used to spin up EC2 instances when we need to build large infrastructure frequently to support the applications.

In this tutorial I will be using AWS CodeCommit, CodeBuild and create a CodePipeline with these. The CodePipeline will automatically get triggered when a commit happens to the CodeCommit repo. The pipeline will run the CodeBuild which will trigger the buildspec.yml and use the packer build command mentioned in it to build the Golden image (AMI)

I will be commiting 2 files to CodeCommit – buildspec.yml and CreateAMI.json file

Below is the content of buildspec.yml

version: 0.2

      - echo "Installing HashiCorp Packer..."
      - curl -qL -o && unzip
      - echo "Installing jq..."
      - curl -qL -o jq && chmod +x ./jq
      - echo "Validating CreateAMI.json"
      - ./packer validate CreateAMI.json
      ### HashiCorp Packer cannot currently obtain the AWS CodeBuild-assigned role and its credentials
      ### Manually capture and configure the AWS CLI to provide HashiCorp Packer with AWS credentials
      ### More info here:
      - echo "Configuring AWS credentials"
      - curl -qL -o aws_credentials.json$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI > aws_credentials.json
      - aws configure set region $AWS_REGION
      - echo "AWS region set is:" $AWS_REGION
      - aws configure set aws_access_key_id `./jq -r '.AccessKeyId' aws_credentials.json`
      - aws configure set aws_secret_access_key `./jq -r '.SecretAccessKey' aws_credentials.json`
      - aws configure set aws_session_token `./jq -r '.Token' aws_credentials.json`
      - echo "Building HashiCorp Packer template, CreateAMI.json"
      - ./packer build CreateAMI.json
      - echo "HashiCorp Packer build completed on `date`"

Below is the content of CreateAMI.json

    "variables": {
        "aws_region": "{{env `AWS_REGION`}}"
  "builders": [
      "type": "amazon-ebs",
      "region": "{{user `aws_region`}}",
      "instance_type": "t2.micro",
      "source_ami": "ami-0080e4c5bc078760e",
      "ssh_username": "ec2-user",
      "ami_name": "custom-Dev1",
      "ami_description": "Amazon Linux Image OS with pre-installed packages",
      "run_tags": {
        "Name": "custom-Dev1",
	"Env": "dev",
	"Project": "DevOps"
  "provisioners": [
      "type": "shell",
      "inline": [
        "sudo yum install java python wget -y",
	"sudo yum install tomcat -y"

1. Create an AWS CodeCommit Repository and add these 2 files into it.
2. Create AWS CodeBuild project and select CodeCommit repo and master branch
3. Create CodePipeline by selecting CodeCommit repo and CodeBuild project as stages.
Screenshot from 2018-12-19 12-06-05

Screenshot from 2018-12-19 12-07-56

Screenshot from 2018-12-19 12-08-52

Skip Deploy stage and create the pipleine.

4. Select the created CodePipeline and click on Release changes which will start running the pipeline.

5. After the pipeline finishes successfully, go to the EC2 dashboard and click on AMI in left side and you should see the created Golden image.


Azure Kubernetes Cluster (AKS) – Creation steps

Microsoft Azure is an open, flexible, enterprise-grade cloud computing platform. Azure Kubernetes Service (AKS) brings these two solutions together, allowing users to quickly and easily create fully managed Kubernetes clusters.

Here we will create Azure Kubernetes cluster (AKS) using Azure cli.
The master server of the Kubernetes cluster will be managed by Azure (this is free) and only the worker nodes will be created in Virtual machine section of the Azure. We can use the kubectl to interact with the pods.

Sign up for Microsoft Azure account with a subscription or create a new free account.

The first step is to provision a new Kubernetes cluster using the Microsoft Azure CLI. Follow these steps:

Install AZ using below command

curl -L | bash

Install Kubectl using below commands on RHEL or CentOS

sudo cat < /etc/yum.repos.d/kubernetes.repo

sudo yum install -y kubectl

Log in to Microsoft Azure using below command.
This will generate a url and unique code. Open the url in the browser and copy the code for login successfully.

az login

Create a resource group by mentioning the resource group name and location

az group create --name Dev-AKS --location eastus

Create a cluster by specifying the cluster name and node count as 3 nodes

az aks create --resource-group Dev-AKS --name Dev-AKS-1 --node-count 3 --enable-addons monitoring --generate-ssh-keys

Get the Credetials for the cluster which will allow to communicate with the created cluster.

az aks get-credentials --name Dev-AKS-1 --resource-group Dev-AKS

Next use kubectl commands to check cluster resources

kubectl describe cluster
kubectl get services
kubectl get pods

AWS Cloudformation – cfn-init and UserData

We use AWS Cloudformation to provision resources in AWS. There are lot of examples available in internet on different use cases.
The Cloudformation scripts can be written using yaml or json language.

Using AWS CloudFormation we can automatically install, configure, and start applications on Amazon EC2 instances. Doing so enables you to easily duplicate deployments and update existing installations without connecting directly to the instance, which can save you a lot of time and effort.

For installing packages automatically on EC2 instance upon boot up we need to use cfn-init and metadata in Cloudformation.

Below is an example on how cfn-init and metadata is defined in the Cloudformation script and how they work.Understanding of this is very important if you want to have packages installed on to EC2 instance upon boot up.

The cfn-init helper script reads template metadata from the AWS::CloudFormation::Init key and acts accordingly to:
Fetch and parse metadata from AWS CloudFormation
Install packages
Write files to disk
Enable/disable and start/stop services

cfn-init does not require credentials, so you do not need to use the –access-key, –secret-key, –role, or –credential-file options.
In this case we are connecting to S3 to download the scripts. So we need to create a role which allows access to get objects in S3 bucket, and then attach this role to EC2 instance.

Put your commands and scripts to be run on EC2 instance in the commands section under AWS::CloudFormation::Init

This will be invoked in the UserData section
/opt/aws/bin/cfn-init –verbose –stack –region us-east-1 –resource Create_Instance

We also have to install cfn as give in UserData section and start cfn service before invoking the AWS::CloudFormation::Init

Note: Please use json editor to format the below code before using it.

“Resources”: {
“Create_Instance”: {
“Type”: “AWS::EC2::Instance”,
“Metadata”: {
“AWS::CloudFormation::Init”: {
“config”: {
“commands”: {
“01_mkdir_scripts”: {
“command”: “if [ ! -d \”/home/ec2-user/scripts \” ] ; then mkdir -p \”/home/ec2-user/scripts\” ; fi;”
“02_copy_scripts_from_s3”: {
“command”: “/usr/bin/aws s3 cp s3://testBucket19/installScripts /home/ec2-user/scripts –recursive”
“03_Install_java”: {
“command”: “/bin/bash -x /home/ec2-user/scripts/”,
“waitAfterCompletion”: “50”
“04_Install_Tomcat”: {
“command”: “/bin/bash -x /home/ec2-user/scripts/”,
“waitAfterCompletion”: “50”

“Properties”: {
“UserData”: {
“Fn::Base64”: {
“Fn::Join”: [
“yum install -y python-pip\n”,
“pip install awscli\n”,
“/usr/bin/easy_install –script-dir /opt/aws/bin\n”,
“cp -v /usr/lib/python2*/site-packages/aws_cfn_bootstrap*/init/redhat/cfn-hup /etc/init.d \n”,
“chmod +x /etc/init.d/cfn-hup \n”,
“/etc/init.d/cfn-hup start \n”,
“/opt/aws/bin/cfn-init –verbose –stack “,
“Ref”: “AWS::StackId”
” –resource Create_Instance –region “,
“Ref”: “AWS::Region”
“/opt/aws/bin/cfn-signal -e 0 –stack “,
“Ref”: “AWS::StackName”
” –resource Create_Instance “,
” –region “,
“Ref”: “AWS::Region”

Jenkinsfile example to publish into Artifactory

Here is a Jenkinsfile to upload and download artifacts from the Jfrog Artifactory. I really like to share this post as it took me few hours to get this working as I couldn’t find proper example on the internet.

You can install standalone Jfrog Artifactory in an EC2 Linux VM.

Next you will need to have the Artifactory plugin installed in the Jenkins. Go to Manage Jenkins->Configure System –> In server_id field mention name as Artifac_dev_server1 and provide the artifactory url, username and password.

Screenshot from 2018-09-20 11-15-24

You can fork and use the sample application source code from my github repo –

Below is the Jenkinsfile file in groovy language syntax.

pipeline {
    agent any
    environment {
    def uploadSpec = """{
     "files": [
          "pattern": "classes/abc/*",
          "target": "generic-local/"
    def downloadSpec = """{
     "files": [
          "pattern": "generic-local/*",
          "target": "/home/ec2-user/.jenkins/workspace/testpipeline-1/downloads/"
    stages {
        stage('Build') {
            steps {
                echo 'Building..'
                sh 'ant -f build.xml run'
        stage('Test') {
            steps {
                echo 'Publish the artifacts..'
                sh 'mkdir -p downloads'
                        //def server = Artifactory.newServer('', 'admin', 'art@123')
                        def server = Artifactory.server 'Artifac_dev_server1'
                        server.bypassProxy = true
                        echo 'Uploaded the file to Jfrog Artifactory successfully'
                        echo 'Downloaded the file from Jfrog Artifactory successfully'
        stage('Notify') {
            steps {
                echo 'Mail Notification...'
                mail body: 'Project build successful for job named testpipeline-1',
                from: '',
                subject: 'project build successful',
                to: ''

There are 2 functions defined as uploadSpec and downloadSpec which contains the path and details about files/artifacts which needs to uploaded and downloaded. In the stage ‘Test’ the connection to the Artifactory happens and file gets uploaded using server.upload(uploadSpec). Similarly we can excute the download function by using

The ‘Notify’ stage contains simple syntax to send mail with message as success or failure state of the job.

Deployment into Kubernetes on Google Cloud

Let’s Deploy an application into Kubernetes on GCP (Google Cloud Platform).

Install the Google Cloud SDK, which includes the gcloud command-line tool.

Install the Kubernetes command-line tool. kubectl is used to communicate with Kubernetes, which is the cluster orchestration system of Kubernetes Engine clusters

Create a project in your GCP console and retrieve the Project ID of it

Next set your project and zone with below commands

gcloud config set project [PROJECT_ID]
gcloud config set compute/zone us-central1-b

export PROJECT_ID="$(gcloud config get-value project -q)"

Download sample applications
git clone

Switch to the directory

cd kubernetes-engine-samples/hello-app

Install the Docker using below commands

sudo yum install docker -y
docker --version
sudo service docker status
sudo service docker start
sudo docker images
sudo docker ps

The value of PROJECT_ID will be used to tag the container image for pushing it to your private Container Registry.

docker build -t${PROJECT_ID}/my-app:v1 .

The prefix refers to Google Container Registry, where the image will be stored. Let’s push the docker image to GCR (If you not enabled GCR then enable it from your console)

docker images
gcloud docker -- push${PROJECT_ID}/my-app:v1

Create a container cluster

Now that the container image is stored in a registry, you need to create a container cluster to run the container image. A cluster consists of a pool of Compute Engine VM instances running Kubernetes, the open source cluster orchestration system that powers Kubernetes Engine.

Run the following command to create a four-node cluster named myapp-cluster:

gcloud container clusters create myapp-cluster --num-nodes=4
gcloud compute instances list

Let’s Deploy application to Kubernetes

To deploy and manage applications on a Kubernetes Engine cluster, you must communicate with the Kubernetes cluster management system. You typically do this by using the kubectl command-line tool.

The kubectl run command below causes Kubernetes to create a Deployment named myapp-web on your cluster. The Deployment manages multiple copies of your application, called replicas, and schedules them to run on the individual nodes in your cluster.

Run the following command to deploy your application, listening on port 8090:

kubectl run hello-web${PROJECT_ID}/my-app:v1 --port 8090
kubectl get deployment myapp-web
kubectl get pods

Expose your application to the Internet

kubectl expose deployment myapp-web --type=LoadBalancer --port 80 --target-port 8090

The kubectl expose command above creates a Service resource, which provides networking and IP support to your application’s Pods. Kubernetes Engine creates an external IP and a Load Balancer for your application.

The –port flag specifies the port number configured on the Load Balancer, and the –target-port flag specifies the port number that is used by the Pod created by the kubectl run command from the previous step.

Get your service IP address by using below command

kubectl get service

Scale up your application using below commands

kubectl scale deployment myapp-web --replicas=2
kubectl get deployment myapp-web
kubectl get pods

To Deploy a new version of your app use below commands

docker build -t${PROJECT_ID}/my-app:v2 .
gcloud docker -- push${PROJECT_ID}/my-app:v2
kubectl set image deployment/myapp-web${PROJECT_ID}/my-app:v2

Clean up the things using below commands

kubectl delete service myapp-web
gcloud compute forwarding-rules list
gcloud container clusters delete myapp-cluster

Delete file in sub-directory of S3 using Python

Hi All,
We use boto3 libraries to connect to S3 and do actions on bucket for objects to¬† upload, download, copy, delete. But let’s say if you want to download a specific object which is under a sub directory in the bucket then it becomes difficult to its less known on how to do this.

Below are few python script examples on using prefix of the subdirectory with boto and boto3 libraries

Example 1: Copy a file/object which is residing in a subdiretory of Bucket1 to Bucket2

import boto
conn = boto.connect_s3()

srcBucket = conn.get_bucket('testProjBucket-1') #Source Bucket name
dstBucket = conn.get_bucket('testProjBucket-2') #Destination Bucket name


Example 2: Downloads the test.txt from bucket ‘testProjBucket-1’ to the local system path /home/ec2-user/mydownloads/
Here the downloaded file name will be as hai.txt

import boto3
s3 = boto3.resource('s3')


s3.meta.client.download_file('testProjBucket-1', prefix1, '/home/ec2-user/mydownloads/hai.txt')

Example 3: Delete a specific object from a specific sub-directory inside a bucket (Using boto libraries)

import boto
conn = boto.connect_s3(region_name='', aws_access_key_id = '', aws_secret_access_key = '')

fileName = ""

srcBucket = conn.get_bucket('testProjBucket-1')

Example 4: Delete a specific object from a specific sub-directory inside a bucket (Using boto3 libraries)

import boto3
client = boto3.client('s3', region_name='us-east-1', aws_access_key_id = '', aws_secret_access_key = '')


response = client.delete_object(

Note: There is no move command for object in boto3 library. We can only use copy command. But we can use move in the aws-cli

How to upload and run Nodejs package using AWS Lambda

Hey guys.. If you have tried using Nodejs code to run in AWS Lambda you know how painful it is to package the node modules with needed libraries to make it work in Lambda function. Yes it is difficult in begining but once you start exploring and understanding it becomes so much interesting as what all you can achieve using nodejs.

Here I will using nodejs UUID module to generate a unique id which can be used in application or in database. The AWS documentation tells that “You can create a deployment package yourself or write your code directly in the Lambda console, in which case the console creates the deployment package for you and uploads it, creating your Lambda function.” but there is no step-by-step instructions and screenshots to show how to do it. And also you won’t get much information in other blogs as I have tried exploring and ended up without proper steps. So, I like to show you here how to do.

The best way is to install nodejs and test the code on your local linux or windows environment and then package and upload the zip file to Lambda function.

Install nodejs using this command (the OS is RedHat)

curl --silent --location | sudo bash -
sudo yum -y install nodejs

You can verify the installation by checking the node version (node -v) and npm version (npm -v)


Install the UUID module using below command

npm install uuid


You will get node_modules directory under /home/ec2-user

Navigate to directory /home/ec2-user/node_modules/uuid

and zip the all the files under this
zip -r *

Go to AWS Lambda and create a function
Select nodejs



Upload the zip file to Lambda function

Next copy the below code to the “edit code inline”

exports.handler = (event, context, callback) => {
var uuid = require('uuid');

Next save and test the function by creating a event


Then you should see new random UniqueID generated every time when you test this function.