Skip to content

Building a Docker Image using AWS CodeBuild


CodeBuild
For more information on Code Build, visit https://aws.amazon.com/codebuild/


CodeBuild Description


This tutorial will walk through the steps required to build a docker image using AWS CodeBuild, and then pushing that Image to an ECR repository.


CodeBuild Pre-Requisites


1.    Active AWS Account:
You will need to have an active AWS account, as this lab will cover setting up an AWS Code Build Project that pulls code from CodeCommit, and pushes the built Docker Image to ECR.


2.    GIT:
You must have GIT installed on your local workstation. Instructions to install GIT for your local workstation, go to the GIT site, and follow the appropriate instructions for your platform. https://git-scm.com/downloads


Create ECR Repository


Follow the instructions found here, as a reference to build am AWS ECR repository to hold our Docker image. A brief rundown of the steps required to build the ECR repository can be found below.

  • Services --> Elastic Container Service
  • Get Started --> Cancel
  • Repositories from left menu --> Get Started --> Name Repo, -->Next Step
  • Copy Container URI, for example: 012345678910.dkr.ecr.us-east-1.amazonaws.com/simple-api-codebuild:latest
  • Click the Permissions Tab --> Name the SID Public, Choose Effect:Allow, Principal:Everybody, Pull:only Actions from Action section
  • Save All


Create CodeCommit Repository


Now that we have our repository constructed, we need to create our CodeCommit repository and our project code base that will be pushed to that new repository and utilized by the CodeBuild service to build our docker image and push it to the new repository.


1.    Create CodeCommit Repository:
Follow the instructions found here to create a new CodeCommit repository that will store the code that CodeBuild will use to build the Docker Image.


2.    Create Code Base:
Create a project directory that will contain the following 3 files. Once the directory has been created, then we will cd into that directory and initialize a new local git repo in the directory with the git init command. Once complete, then using your editor of choice, create 3 new files, one for each of the following code snippets listed below. Save each file in the directory as these files will be committed to our CodeCommit repository in a future step.


SimpleAPI.py:

A simple API written in python that utilizes Bottle as the web server component.

# *******************************************************************
# Bottle Example API
# Authors/Maintainers: Rich Nason (rnason@awsdocs.com)
# *******************************************************************

# Required Modules:
# =================

# Install Requirements via PIP
from bottle import Bottle, HTTPResponse  # WebServer

# Bottle Parameters:
# ===================

VERSION = '0.0.1'     # API Version
BOTTLEIP = '0.0.0.0'  # The IP that Bottle will listen on to serve the API
BOTTLEPORT = '80'   # The TCP port that bottle will use to serve the API


# Setup the Bottle WebServer Instance:
# ====================================

APP = Bottle(__name__)


# Index Route
@APP.route('/', method=['OPTIONS', 'GET'])
def index():
    try:
        resp_msg = "All systems reporting go for launch!!"
        body = {'version': VERSION, 'message': resp_msg}
        response = HTTPResponse(status=200, body=body)
        return response
    except Exception as err:
        print(err)
        body = {'version': VERSION, 'message': err}
        response = HTTPResponse(status=400, body=body)
        return response


# Start the Web Server
# =====================

if __name__ == '__main__':
    try:
        SERVER = APP.run(host=BOTTLEIP, port=BOTTLEPORT, debug=True)
    except KeyboardInterrupt:
        pass
        print('exiting...')
        SERVER.stop()


Dockerfile:

CodeBuild will utilize this file as a set of instructions on how to build the docker image.

############################################################
# Dockerfile to build an example API endpoint
# Based on: alpine:latest
# DATE: 09/28/2017
# COPYRIGHT: awsdocs.com
############################################################

# Set the base image
FROM alpine:latest

# File Author / Maintainer
MAINTAINER "Rich Nason" <rnason@awsdocs.com>

###################################################################
#***************  OVERRIDE ENABLED ENV VARIABLES  *****************
###################################################################


###################################################################
#*******************  UPDATES & PRE-REQS  *************************
###################################################################

# Install dependencies
RUN apk update && apk add curl python py-pip jq vim

# Install bottle if running the python file directly
RUN pip install bottle

###################################################################
#*******************  APPLICATION INSTALL  ************************
###################################################################


###################################################################
#*****************  CONFIGURE START ITEMS  ************************
###################################################################


###################################################################
#******************  ADD REQUIRED APP FILES  **********************
###################################################################

ADD simpleAPI.py /usr/local/bin

###################################################################
#*************  CMD & EXPOSE APPLICATION PORTS  *******************
###################################################################

CMD [ "sh", "-c", "python /root/api.py" ]

EXPOSE 80


buildspec.yaml:

Contains the instructions CodeBuild will need to login to ECR, build the Docker image, and then push the image to ECR.

version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...          
      - docker build -t simpleapi:latest .
      - docker tag simpleapi:latest 012345678910.dkr.ecr.us-east-1.amazonaws.com/simple-api-codebuild:latest    
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push 012345678910.dkr.ecr.us-east-1.amazonaws.com/simple-api-codebuild:latest


3.    Commit and Push:
Once the files have been saved, then push the code to the new code commit repository


Tip

Make sure to replace the origin URL in the command set below with the URL given by your own CodeCommit repository.


Commit Command Syntax:

git remote add origin {{GIT_URL}}
git add --all; git commit -m "{{COMMIT_MESSAGE}}"
git push origin master


Commit Command Example:

git remote add origin ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/simpleAPI-CodeBuild
git add --all; git commit -m "Initial CodeBuild Project Commmit"
git push origin master


Setup Private Subnet with NAT Gateway


CodeBuild requires a private subnet with a configured NAT gateway as CodeBuild is not given a Public IP address like EC2 instances. Create a new subnet in your VPC that can be used for CodeBuild, and attach a NAT gateway to the subnet.


1.    Navigate to VPC Console:
From the top left side of the navigational menu bar, click on the Services menu, and then choose VPC by either navigating to the Networking & Content Delivery section of the listed services, or by typing the first few letters of the service name in the search box, and then choosing it from the filtered list.


VPC


2.    Navigate to Subnets:
Next from within the VPC console, Click on VPC's and select the VPC in which you want to create the new subnet. Take note of the VPC ID, as you will need it when creating our new subnet.


Your VPCs


Select VPC


Next, once the proper VPC has been selected, click on the Subnets section in the left hand menu. Click on the Create subnet button to create a new subnet.


Create Subnet


3.    Create new Subnet:
In the Create Subnet dialog box, Name the subnet, choose the proper VPC, from the VPC drop list, and then fill in a IPv4 CIDR block to be used with the new subnet. Ensure that the IPv4 CIDR block that you choose is not already being used by any of your other existing subnets. Once you have filled in the details, Click the Create button.


Subnet Details


4.    Navigate to NAT Gateways:
Once the subnet has been created, you will be returned to the main Subnets console, where you can verify that the new subnet was created succesfully. Take note of the new Subnet ID as you will need it in the next step. Next, we need to create a NAT gateway. Click on the NAT Gateways link in the left side menu.


NAT Gateways


5.    Create NAT Gateway:
Next, from the NAT Gateways console, click the Create NAT Gateway button.


Create NAT Gateway


In the Create NAT Gateway dialog box, choose the Subnet that will be associated with this NAT Gateway. Next, in the Elastic IP Allocation ID choose an existing EIP, or if one doesn't already exist, then click the Create New EIP button to generate a new one. Once both fields are populated, click the Create a NAT Gateway buttton. Once complete, Click the Close button to be returned to the NAT Gateways console.


Subnet Selection:

When choosing the subnet that the NAT Gateway will be associated with, Choose one of the existing subnets, NOT the new subnet that we just created. The NAT Gateway must be configured to sit in a subnet that is attached to a route out to the IGW in order to access the internet.


NAT Gateway Details


NAT Gateway Created


6.    Navigate to Route Tables:
Once the NAT Gateway has been created, you will be returned to the main NAT Gateways console, where you can verify that the new NAT Gateway was created successfully. Take note of the new NAT Gateway ID as you will need it in the next step. Next, we need to create a new Routing Table, that will route traffic to the NAT gateway, instead of the default IGW. Click on the Route Tables link in the left side menu.


NAT Gateways


7.    Create Route Table:
Next, from the Route Tables console, click the Create Route Table button.


Create Route Table


In the Create Route Table dialog box, choose a name for the Route Table, along with the VPC that it will be attached to from the VPC drop list. Once both fields are populated, click the Yes, Create buttton. Once complete, you will be returned to the Route Table console.


NAT Gateway Details


8.    Attach NAT Gateway to the Route:
Next, we need to attach the NAT Gateway that we created to the new route table. In order to do this. Select the new Route Table from the list in the Route Table console, and click on the Routes tab in the botton section of the conosle. Once on the Routes Section, click on Edit, then Click the Add another route button. A new line item will appear, type in 0.0.0.0/0 for the Destination field, and then in the Target field, choose the new NAT Gateway from the drop list. Once complete, Hit the Save button to save the new route.


Add Route


9.    Route Associations:
Lastly, we need to associate the new route table with the new subnet that we created previously. To do this, from the Route Tables console, click on the Subnet Associations tab and click Edit. From the list of available subnets, check the new subnet that we created earlier and click the Save button.


Set Subnet Associations


Create CodeBuild Job


Now that we have our networking all setup, we should be able to start buidling our CodeBuild job. To get started, From the top left side of the navigational menu bar, click on the Services menu, and then choose Code Build by either navigating to the Developer Tools section of the listed services, or by typing the first few letters of the service name in the search box, and then choosing it from the filtered list.


CodeBuild


1.    Create Project:
From the CodeBuild console menu, Click on Create Project to get started building a new CodeBuild project.


Create Project



2.    Fill in Project Details:
Now we need to construct our CodeBuild Project. Give the Project a Project Name, and add a brief Description of the project. Next, Under the Source: What to build section, choose AWS CodeCommit as the Source Provider, then from the drop lists, choose the Repository that CodeBuild will pull from. Next in the Environment: How to build section, set the Environment Image to Use an image managed by AWS CodeBuild, Choose Ubuntu as the Operating System, choose Docker as the Runtime and pick the newest runtime available from the Runtime version. Next, in the Artifacts section, choose No Artifacts under the Type field, ensure that **No cache is also selected. Lastly, from the VPC section, choose the VPC, Subnet, and Security Group to be used for the CodeBuild Projects. Leave the rest of the fields as their default values. Once all of your information is correct, then click the *Continue Button


CodeBuild Subnet Selection:

The subnet that you choose, should be the subnet created in earlier steps of this tutorial. We need to use the subnet that specifically is using a NAT Gateway as opposed to our IGW.


CodeBuild Job 1 CodeBuild Job 2 CodeBuild Job 3


3.    Review the Project:
Once the details of the project have all been filled in, next, review the details of the project on the Review and Build console page, and click the Save button.


CodeBuild Job Review


Add ECR Policy to CodeBuild Execution Role


During the job creation process, CodeBuild created a new role called codebuild-simpleapi-codebuild-service-role. In order to allow CodeBuild access to log into the ECR registry to push our built docker image, we must add an inline policy to the new role, to allow access to ECR.


1.    Open IAM:
To get started modifying the new role, from the top left side of the navigational menu bar, click on the Services menu, and then choose IAM by either navigating to the Security, Identity, and Compliance section of the listed services, or by typing the first few letters of the service name in the search box, and then choosing it from the filtered list.


IAM


2.    Locate CodeBuild Role:
From the IAM console window, click the link to Roles from the left navigation options, and in the search box type codebuild to filter the roles list down. From the filtered list, choose the role that was created for the project, and click the role in order to add a new policy to the role.


IAM Locate Role


3.    Add Inline Policy to the Role:
Next, from the role view, click on the Add inline policy button in order to add a new policy document to the existing list of inline policies already attached to the role.


Add InLine Policy


4.    Inline Policy Statement:
When the Create policy window opens, click on the JSON tab.


IAM Policy JSON


Next, paste the following statement into the Statement [] bracket in the policy and then click Review policy:


{
    "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:CompleteLayerUpload",
        "ecr:GetAuthorizationToken",
        "ecr:InitiateLayerUpload",
        "ecr:PutImage",
        "ecr:UploadLayerPart"
    ],
    "Resource": "*",
    "Effect": "Allow"
}


IAM Policy Statement


5.    Review the Policy:
Once we have submitted the policy, we must Name the policy, and then click the Create policy button to finalize our new inline policy.


IAM Policy Review


6.    Verify the attached Policy:
Last, once we are returned back to the Role console, Verify that the new inline policy is attached to the role as expected. This should complete our role configuration!


Verify IAM Policies


Run the Job


Now that all of our environment setups have been complete, we are now ready to run the job. To start we must navigate back to the CodeBuild console by going to the top navigation, clicking services, and choosing CodeBuild from the list of avilable services:


CodeBuild


1.    Run the Job:
Select the job that you want to run, and then click the Start build button from the console window to run our job for the first time.


CodeBuild Job Run


Next, we need to specify the branch that we are going to build from. In the Start new build dialog box, from the Branch drop selection, choose master. The Source version and Git clone depth will auto populate. Keep the default values and click the Start build button to start the job build.


CodeBuild Job Branch


Lastly, wait for the job to be completed, and if all is successful, then we should be able to navigate over to our ECS repository and see the docker image waiting for us in the repository.


CodeBuild Job Success


Check ECR


CodeBuild Additional Resources


No Additional Resources.


CodeBuild Site/Information References


CodeBuild User Guide


Comments