CI/CD with AWS CodeCommit, AWS CodeBuild and deploy Helm with EKS

Create a Pipeline to deploy an EKS Cluster with Helm

Helm charts for EKS

To Set up AWS code commit

To set up connections to AWS CodeCommit repos, you need to configure Git credentials for CodeCommit in the IAM console and then use those credentials for HTTPS connections. 

You can refer the link below to set up connections.

You can select any protocol on AWS CodeCommit depending upon your use case for pushing and pulling code from CodeCommit repositories by extending Git.

In this Article, We will be creating two different CodeBuild and two different Code pipeline as eks deployment has two different lifecycles.

One for Building the helm charts and pushing as image to ECR and another for pulling the helm charts from ECR and deploy to EKS.

First Code Build - CodeCommit Push images to ECR

Second CodeBuild - Pull helm charts and deploy on EKS cluster

Step 1

Create a role by using codebuild service.

This requires an AWS IAM role that needs to have limited role that is capable of interacting with the EKS cluster and pushing and pulling Images.

Below Policy is for Codebuild service to interact with the EKS cluster:

{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "eks:DescribeNodegroup", "eks:DescribeFargateProfile", "eks:ListTagsForResource", "eks:DescribeIdentityProviderConfig", "eks:DescribeUpdate", "eks:AccessKubernetesApi", "eks:DescribeCluster", "eks:DescribeAddon" ], "Resource": “arn:aws:eks:us-west-2:<ACCOUNT-ID>:cluster/<EKS-CLUSTER-NAME>” }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": "eks:DescribeAddonVersions", "Resource": “*" } ] }

Step 2

Below policy is for push and pull access to ECR

{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "ecr:PutLifecyclePolicy", "ecr:PutImageTagMutability", "ecr:StartImageScan", "ecr:CreateRepository", "ecr:GetDownloadUrlForLayer", "ecr:PutImageScanningConfiguration", "ecr:UploadLayerPart", "ecr:BatchDeleteImage", "ecr:ListImages", "ecr:DeleteLifecyclePolicy", "ecr:DeleteRepository", "ecr:PutImage", "ecr:BatchGetImage", "ecr:CompleteLayerUpload", "ecr:StartLifecyclePolicyPreview", "ecr:InitiateLayerUpload", "ecr:DeleteRepositoryPolicy", "ecr:BatchCheckLayerAvailability", "ecr:GetLifecyclePolicy" ], "Resource": “arn:aws:ecr:us-west-2:<ACCOUNT-ID>:repository/<REPOSITORY-NAME>” }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": "ecr:GetAuthorizationToken", "Resource": "*" }, { "Sid": "VisualEditor2", "Effect": "Allow", "Action": "ecr:BatchCheckLayerAvailability", "Resource": "arn:aws:ecr:us-west-2:<ACCOUNT-ID>:repository/<REPOSITORY-NAME>" } ] }

Step 3

You can add below policy statement in ECR Repo -> Permissions to limit resource level access.

You need to replace the <AWS-CODE-BUILD-ROLE> with your Code Build role name which you have created previously.

{ "Version": "2008-10-17", "Statement": [ { "Sid": "EKS-CodeBuild-ECR-Policy-Statement", "Effect": "Allow", "Principal": { "AWS": “arn:aws:iam::<ACCOUNT-ID>:role/<AWS-CODE-BUILD-ROLE>” }, "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:BatchDeleteImage", "ecr:BatchGetImage", "ecr:CompleteLayerUpload", "ecr:DeleteLifecyclePolicy", "ecr:DeleteRepository", "ecr:DeleteRepositoryPolicy", "ecr:GetDownloadUrlForLayer", "ecr:InitiateLayerUpload", "ecr:PutImage", "ecr:PutLifecyclePolicy", "ecr:StartLifecyclePolicyPreview", "ecr:UploadLayerPart" ] } ] }

Step 4

Before pushing the source code and Helm charts to CodeCommit, you need to have buildspec.yml file.

I have two buildspec files for different lifecycles.

Below example yaml is for pushing the helm charts to ECR. In my case I’m using consul as the repository name, Replace with your environment values accordingly.

You can provide environment variable values either in the buildspec.yml file as seen below or on the runtime environment variable configurations while configuring codebuild and codepipeline.

version: 0.2 env: variables: TAG: "1.0" AWS_DEFAULT_REGION: "us-west-2" AWS_ACCOUNT_ID: "092463544305" IMAGE_REPO_NAME: "consul" phases: install: commands: - yum install -y awscli git python3 - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 - chmod 700 get_helm.sh - ./get_helm.sh - rm -rf get_helm.sh pre_build: commands: - echo Entered the pre_build phase... - echo Logging in to Amazon ECR... - export HELM_EXPERIMENTAL_OCI=1 - aws ecr get-login-password --region $AWS_DEFAULT_REGION | helm registry login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com build: commands: - echo Entered the build phase... - echo Building the helm image... - helm chart save . consul - helm chart save . $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$TAG post_build: commands: - echo Entered the post_build phase... - echo Pushing the Docker image... - helm chart push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$TAG

Step 5

Another buildspec2.yml which I have below is for pulling the images from ECR and deploying to EKS.

version: 0.2 env: variables: TAG: "1.0" AWS_DEFAULT_REGION: "us-west-2" AWS_ACCOUNT_ID: "092463544305" IMAGE_REPO_NAME: "consul" AWS_CLUSTER_NAME: "vault-eks-cluster-demo" phases: install: commands: - yum install -y awscli git python3 - wget https://get.helm.sh/helm-v3.5.4-linux-amd64.tar.gz -O helm.tar.gz; tar -xzf helm.tar.gz - chmod +x ./linux-amd64/helm - mv ./linux-amd64/helm /usr/local/bin/helm - curl -o kubectl https://amazon-eks.s3.$AWS_DEFAULT_REGION.amazonaws.com/1.19.6/2021-01-05/bin/linux/amd64/kubectl - chmod +x ./kubectl - mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$PATH:$HOME/bin - echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc - source ~/.bashrc pre_build: commands: - echo Entered the pre_build phase... - echo Logging in to Amazon ECR... - export HELM_EXPERIMENTAL_OCI=1 - aws ecr get-login-password --region $AWS_DEFAULT_REGION | helm registry login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com - echo Logging in to Amazon EKS... - aws eks --region $AWS_DEFAULT_REGION update-kubeconfig --name $AWS_CLUSTER_NAME build: commands: - echo Entered the build phase... - echo helm pull and performing helm install - helm chart pull $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/consul:$TAG - helm chart export $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/consul:$TAG --destination ./consul-charts - helm install hashicorp ./consul-charts/consul/

Now those buildspec files in your source code and push it to CodeCommit.

Step 6

CodeBuild in order to have permission to authenticate EKS cluster and to do deployment, you need to go to aws-auth configmap on your EKS Configurations, and add the following under data.mapRoles

I have added my role which I created for CodeBuild Service "EKS-CodeBuild-Cluster-Access role"  so that it has permission to authenticate to the cluster.

In my case it is like this as seen below.

apiVersion: v1 data: mapRoles: | - groups: - system:bootstrappers - system:nodes rolearn: arn:aws:iam:::role/eksctl-vault-eks-cluster-demo-nod-NodeInstanceRole-TIYSXKH8AF1 username: system:node:{{EC2PrivateDNSName}} - rolearn: arn:aws:iam:::role/EKS-CodeBuild-Cluster-Access username: codebuild-eks groups: - system:masters mapUsers: | [] kind: ConfigMap metadata: creationTimestamp: "2021-02-01T13:33:41Z" name: aws-auth namespace: kube-system resourceVersion: "23749582" selfLink: /api/v1/namespaces/kube-system/configmaps/aws-auth

Step 7

CodeBuild Configurations:

You need to create a two separate CodeBuild Projects

Go to CodeBuild and create build project.

Below are my configurations,

For BuildSpec Configuration, By default, CodeBuild looks for a file named buildspec.yml in the source code root directory.

If you have other names for your buildspec.yml file, you can enter the filename in build specifications in CodeBuild.

You need to repeat the same procedure to create another Code build project for deploying to eks cluster.

Step 8

Once done, Go to CodePipeline

Create two different pipelines,

Click Create new pipeline and add source

Select Build Provider as “AWS CodeBuild” and choose the project which you created previously.

In the deployment stage, click Skip deploy stage and select Create pipeline.

Now whenever there is any change to the code and commits happens in CodeCommit, it will kick starts the pipeline.