- Angular Frontend CI/CD
- Table of Content
- Resources Used
- CI/CD Solution Architecture
- Steps
- Repository
- EC2 Instance
- Code Build
- Code Deploy
- Create Application
- Deployment groups
- Deployment groups: Deployment group name
- Deployment groups: Service role
- Deployment groups: Deployment type
- Deployment groups: Environment configuration
- Deployment groups: Agent Configuration with AWS Systems Manager
- Deployment groups: Deployment Configuration
- Deployment groups: Load Balancer
- Deployment groups: Advanced - optional
- AWS CodePipeline
- Conclusion
- Miscellaneous
- EC2 Instance
- AWS CodePipeline
- AWS CodeDeploy
- AWS CodeBuild
- Enterprise GitHub
- IAM Roles
We will be proceeding with the following architecture for the CI/CD for an Angular application.
Setup the repository to manage credentials for automatic deployment.
This is to be created to isolate production and local code development.
export const environment = {
production: true,
APIUrl: "", // To be replaced by deployment instance
};
This will include the typical angular project .gitignore.
.DS_STORE
/dist/
/bazel-out
/integration/bazel/bazel-*
*.log
/node_modules/
# CircleCI temporary file for cache key computation.
# See `save_month_to_file` in `.circleci/config.yml`.
month.txt
# Include when developing application packages.
pubspec.lock
.c9
.idea/
.devcontainer/*
!.devcontainer/README.md
!.devcontainer/recommended-devcontainer.json
!.devcontainer/recommended-Dockerfile
.settings/
.vscode/launch.json
.vscode/settings.json
.vscode/tasks.json
*.swo
*.swp
modules/.settings
modules/.vscode
.vimrc
.nvimrc
# Don't check in secret files
*secret.js
# Ignore npm/yarn debug log
npm-debug.log
yarn-error.log
# build-analytics
.build-analytics
# rollup-test output
/modules/rollup-test/dist/
# User specific bazel settings
.bazelrc.user
# User specific ng-dev settings
.ng-dev.user*
.notes.md
baseline.json
# Ignore .history for the xyz.local-history VSCode extension
.history
# Husky
.husky/_
aio/content/examples/.DS_Store
Things to consider:
- Operating System: Ubuntu-jammy-22.04
- Elastic IP address needs to be assigned
sudo apt update
sudo apt upgrade
Install the CodeDeploy agent for Ubuntu Server - AWS CodeDeploy
sudo apt install ruby-full
sudo apt install wget
cd /home/ubuntu
wget https://bucket-name.s3.region-identifier.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto
sudo service codedeploy-agent start
sudo service codedeploy-agent status
sudo apt install nginx
Create a User policy and assign the following AWS managed policy to it. Then attach it to EC2.
IAM: AmazonEC2RoleforAWSCodeDeploy
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
It is necessary for Code deploy application deployment group to recognize the instance.
Key: Name
Value: unique-name-for-ec2
This step is necessary to generate the artifacts of ng build
of the frontend application. Create a code Build Project from the Code Build in AWS Console.
Give a project name. Optionally Build Badge can be turned on.
Put GitHub Enterprise as the source provider. Configure the GitHub Enterprise personal access token from your enterprise GitHub Developer settings tab. Be sure to provide Repo Full access to the PAT and set the expiration likewise. Provide the
Once the personal token is saved in the code build. Put the Repository URL.
This can be left unchecked. AWS Code Pipeline will take care of that.
This is important consideration since it looks at the codebuild script: buildspec.yml in your source code. To ensure that your build environment will not fail refer to the codebuild environment Docker images for testing.
Docker images provided by CodeBuild - AWS CodeBuild
The following could be an instance of one configuration.
To configure the role for AWS CodeBuild let the CodeBuild create one or refer to the following documentation for creating one. Easier option is to let CodeBuild take care of it.
AWS CodeBuild permissions reference - AWS CodeBuild
Place the buildspec.yml configuration file into root of the project. The typical file will look like this for angular project.
version: 0.2
phases:
install:
runtime-versions:
nodejs: 18
pre_build:
commands:
- echo Installing source NPM dependencies...
- npm install --force
- npm install -g @angular/cli
build:
commands:
- echo Build started on `date`
- ng build --configuration=production
post_build:
commands:
- echo Build completed on `date`
artifacts:
files:
- 'dist/**/*'
- appspec.yml
- 'scripts/**'
- nginx.conf
For reference:
Build specification reference for CodeBuild - AWS CodeBuild
This is where you usually define where to store the generated artifacts from build into. However, since this code build will be used in conjunction with AWS CodePipeline, it will be managed by CodePipeline. We can leave it to No artifacts right now.
Additionally, Logging can be turned on to get information on CodeBuild. However, if you are sure that the script works or alternatively, we can verify it from the AWS CodePipeline console for Code Build errors. This can be left unchecked.
It manages the deployment of artifacts into the EC2 instance. Make sure to do code-deploy agent installation first in EC2 instance. From the AWS Code Deploy Console proceed with create application.
Give an application name and select a compute platform to deploy the code. For this case: EC2/On-premises.
Select the currently created application. and select the Deployment groups tab. Then proceed with the Create Deployment group.
Give a unique deployment group name.
Create a service role for the AWS Code Deploy. For this create a role in AWS IAM console and Attach the following AWS managed Role:
AWSCodeDeployRole
The policy should be like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"autoscaling:CompleteLifecycleAction",
"autoscaling:DeleteLifecycleHook",
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeLifecycleHooks",
"autoscaling:PutLifecycleHook",
"autoscaling:RecordLifecycleActionHeartbeat",
"autoscaling:CreateAutoScalingGroup",
"autoscaling:CreateOrUpdateTags",
"autoscaling:UpdateAutoScalingGroup",
"autoscaling:EnableMetricsCollection",
"autoscaling:DescribePolicies",
"autoscaling:DescribeScheduledActions",
"autoscaling:DescribeNotificationConfigurations",
"autoscaling:SuspendProcesses",
"autoscaling:ResumeProcesses",
"autoscaling:AttachLoadBalancers",
"autoscaling:AttachLoadBalancerTargetGroups",
"autoscaling:PutScalingPolicy",
"autoscaling:PutScheduledUpdateGroupAction",
"autoscaling:PutNotificationConfiguration",
"autoscaling:PutWarmPool",
"autoscaling:DescribeScalingActivities",
"autoscaling:DeleteAutoScalingGroup",
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:TerminateInstances",
"tag:GetResources",
"sns:Publish",
"cloudwatch:DescribeAlarms",
"cloudwatch:PutMetricAlarm",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeInstanceHealth",
"elasticloadbalancing:RegisterInstancesWithLoadBalancer",
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:DeregisterTargets"
],
"Resource": "*"
}
]
}
According to your preference select the deployment strategy. Usually this depends on the requirement of application.
This depends on the solution architecture if you have multiple instance configuration for redundancy purpose. For a single instance deployment select Amazon EC2 instance and select the appropriate tag you created while setting up your instance.
AWS Systems Manager is wonderful tool in managing SysOps work. It can be used to automate installation of code deploy agent in the EC2 instance also. However, for ease of setup, we have manually installed the code deploy agent for more control vectors. So you can proceed with the following option.
We can opt with the one shown below. However, this can be tweaked with your own project requirements usually in the case of Auto Scaling Groups.
If you have implemented the load balancer in your solution, select an appropriate target group. However, in case of single instance uncheck the Enable load balancing option.
Additional settings can be configured to enhance the deployment. Following are additional features that can be enabled with Deployment groups. You can then proceed with Create deployment group option.
AWS CodePipeline helps us to create end to end CI/CD and DevOps cycle for the project. It can integrate the following phases of DevOps Cycle:
Proceed with the Create Pipeline option from the AWS CodePipeline Console.
Give pipeline a unique name. You can let pipeline create a service role for your project which is an easier option. For reference the following is the Service Role for the AWS CodePipeline.
{
"Statement": [
{
"Action": [
"iam:PassRole"
],
"Resource": "*",
"Effect": "Allow",
"Condition": {
"StringEqualsIfExists": {
"iam:PassedToService": [
"cloudformation.amazonaws.com",
"elasticbeanstalk.amazonaws.com",
"ec2.amazonaws.com",
"ecs-tasks.amazonaws.com"
]
}
}
},
{
"Action": [
"codecommit:CancelUploadArchive",
"codecommit:GetBranch",
"codecommit:GetCommit",
"codecommit:GetRepository",
"codecommit:GetUploadArchiveStatus",
"codecommit:UploadArchive"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"codedeploy:CreateDeployment",
"codedeploy:GetApplication",
"codedeploy:GetApplicationRevision",
"codedeploy:GetDeployment",
"codedeploy:GetDeploymentConfig",
"codedeploy:RegisterApplicationRevision"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"codestar-connections:UseConnection"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"elasticbeanstalk:*",
"ec2:*",
"elasticloadbalancing:*",
"autoscaling:*",
"cloudwatch:*",
"s3:*",
"sns:*",
"cloudformation:*",
"rds:*",
"sqs:*",
"ecs:*"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"lambda:InvokeFunction",
"lambda:ListFunctions"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"opsworks:CreateDeployment",
"opsworks:DescribeApps",
"opsworks:DescribeCommands",
"opsworks:DescribeDeployments",
"opsworks:DescribeInstances",
"opsworks:DescribeStacks",
"opsworks:UpdateApp",
"opsworks:UpdateStack"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"cloudformation:CreateStack",
"cloudformation:DeleteStack",
"cloudformation:DescribeStacks",
"cloudformation:UpdateStack",
"cloudformation:CreateChangeSet",
"cloudformation:DeleteChangeSet",
"cloudformation:DescribeChangeSet",
"cloudformation:ExecuteChangeSet",
"cloudformation:SetStackPolicy",
"cloudformation:ValidateTemplate"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"codebuild:BatchGetBuilds",
"codebuild:StartBuild",
"codebuild:BatchGetBuildBatches",
"codebuild:StartBuildBatch"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Effect": "Allow",
"Action": [
"devicefarm:ListProjects",
"devicefarm:ListDevicePools",
"devicefarm:GetRun",
"devicefarm:GetUpload",
"devicefarm:CreateUpload",
"devicefarm:ScheduleRun"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"servicecatalog:ListProvisioningArtifacts",
"servicecatalog:CreateProvisioningArtifact",
"servicecatalog:DescribeProvisioningArtifact",
"servicecatalog:DeleteProvisioningArtifact",
"servicecatalog:UpdateProduct"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"cloudformation:ValidateTemplate"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:DescribeImages"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"states:DescribeExecution",
"states:DescribeStateMachine",
"states:StartExecution"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"appconfig:StartDeployment",
"appconfig:StopDeployment",
"appconfig:GetDeployment"
],
"Resource": "*"
}
],
"Version": "2012-10-17"
}
This is where the Artifact store can be defined and encryption method for it. You can proceed with the following options for ease of access:
Select the source provider. For instance, if you have your repository hosted in Enterprise GitHub Server, there is additional setting to setup connection to GitHub Enterprise Server which can be found in Miscellaneous section of this documentation. Select the connection, the repository name and the branch name and proceed with rest of the settings as follows:
Select the AWS CodeBuild as the Build provider and the project that you created in the earlier section. The Environment variables lets you pass secrets to variables in buildspec.yml. Refer to the documentation for the use case and proceed with rest of configuration.
Proceed with the configuration for the Deploy with the appropriate configuration that you created earlier.
Proceed to the Review stage and select option Create pipeline.
Hence the CI/CD pipeline has successfully been setup. You will see the complete pipeline in AWS CodePipeline and be able to see progression through different stages as shown in the following. Further modification can be done to achieve greater setup for CI/CD with AWS.
This repository contains sample Angular Application created from official tutorial of Angular Documentation.
Angular Tour of Heroes Tutorial Link
This repository can be used as reference to find relevant structure for project, best practices and documentation purposes.
There are few steps to perform before connecting to GitHub Enterprise Server. From the Developer Tools, select Connections option and proceed with Create connection.
Select GitHub Enterprise Server.
Name your connection and provide with URL and select option Connect to GitHub Enterprise Server. This will prompt you to login to Github Enterprise Server using your corporate credentials for GitHub Enterprise. If you are Organization owner where the repository belongs to you can proceed ahead. However, if you are not, you can request the Organization owner for the access to the selected repositories. This Connection is established as GitHub Apps. Once approved your connection is good to go.
After approval you can check the connection status in the Connections console as follows: