-
Notifications
You must be signed in to change notification settings - Fork 162
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add pattern for ArgoCD workloads in AWS CodeCommit
- Loading branch information
Yuriy Bezsonov
committed
Jan 5, 2024
1 parent
5443da3
commit c88e7ac
Showing
8 changed files
with
344 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -254,6 +254,7 @@ Patterns: | |
snyk | ||
starter | ||
gmaestro | ||
workloads-codecommit | ||
``` | ||
- Bootstrap your CDK environment. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import WorkloadsCodeCommitConstruct from '../lib/workloads-codecommit-construct'; | ||
import { configureApp } from '../lib/common/construct-utils'; | ||
|
||
const app = configureApp(); | ||
|
||
new WorkloadsCodeCommitConstruct(app, 'workloads-codecommit'); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
# EKS Cluster with ArgoCD and Workloads in private AWS CodeCommit repository | ||
|
||
## Objective | ||
|
||
This example shows how to provision an EKS cluster with: | ||
|
||
- ArgoCD | ||
- Workloads deployed by ArgoCD | ||
- Private AWS CodeCommit repository to store the configurations of workloads | ||
- Setup to trigger ArgoCD projects sync on git push to AWS CodeCommit repository | ||
|
||
Pattern source: /lib/workloads-codecommit-construct/index.ts | ||
|
||
## Architecture | ||
|
||
![Architectural diagram](./images/argocd-cc.png) | ||
|
||
To better understand how ArgoCD works with EKS Blueprints, read the EKS Blueprints ArgoCD [Documentation](https://aws-quickstart.github.io/cdk-eks-blueprints/addons/argo-cd/) | ||
|
||
- After a push to AWS CodeCommit repository notification trigger calls AWS Lambda | ||
- AWS Lambda calls ArgoCD webhook URL to trigger ArgoCD projects sync | ||
|
||
## Prerequisites | ||
|
||
Ensure that you have installed the following tools on your machine. | ||
|
||
1. [aws cli](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) | ||
2. [kubectl](https://Kubernetes.io/docs/tasks/tools/) | ||
3. [cdk](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_install) | ||
4. [npm](https://docs.npmjs.com/cli/v8/commands/npm-install) | ||
5. [jq](https://jqlang.github.io/jq/) | ||
6. `make` | ||
|
||
## Deploy EKS Cluster with Amazon EKS Blueprints for CDK | ||
|
||
1. Clone the repository | ||
|
||
```sh | ||
git clone https://github.com/aws-samples/cdk-eks-blueprints-patterns.git | ||
cd cdk-eks-blueprints-patterns | ||
``` | ||
|
||
2. Update npm | ||
|
||
```sh | ||
npm install -g npm@latest | ||
``` | ||
|
||
3. View patterns and deploy workloads-codecommit pattern | ||
|
||
```sh | ||
make list | ||
npx cdk bootstrap | ||
make pattern workloads-codecommit deploy | ||
``` | ||
|
||
## Verify the resources | ||
|
||
1. Run the update-kubeconfig command. You should be able to get the command from the CDK output message. More information can be found at https://aws-quickstart.github.io/cdk-eks-blueprints/getting-started/#cluster-access | ||
|
||
```sh | ||
aws eks update-kubeconfig --name workloads-codecommit-blueprint --region <your region> --role-arn arn:aws:iam::xxxxxxxxx:role/workloads-codecommit-blue-workloadscodecommitbluepr-VH6YOKWPAt5H | ||
``` | ||
|
||
2. Verify the resources created from the steps above. | ||
|
||
```bash | ||
$ kubectl get po -n argocd | ||
NAME READY STATUS RESTARTS AGE | ||
blueprints-addon-argocd-application-controller-0 1/1 Running 0 1h | ||
blueprints-addon-argocd-applicationset-controller-7b78c7fc5dmkx 1/1 Running 0 1h | ||
blueprints-addon-argocd-dex-server-6cf94ddc54-p68pl 1/1 Running 0 1h | ||
blueprints-addon-argocd-notifications-controller-6f6b7d95ckhf6p 1/1 Running 0 1h | ||
blueprints-addon-argocd-redis-b8dbc7dc6-dvbkr 1/1 Running 0 1h | ||
blueprints-addon-argocd-repo-server-66df7f448f-kvwmw 1/1 Running 0 1h | ||
blueprints-addon-argocd-server-584db5f545-8xp48 1/1 Running 0 1h | ||
``` | ||
|
||
## Give ArgoCD access to AWS CodeCommit | ||
|
||
```bash | ||
until kubectl get svc blueprints-addon-argocd-server -n argocd -o json | jq --raw-output '.status.loadBalancer.ingress[0].hostname' | grep -m 1 "elb.amazonaws.com"; do sleep 5 ; done; | ||
export ARGOCD_SERVER=`kubectl get svc blueprints-addon-argocd-server -n argocd -o json | jq --raw-output '.status.loadBalancer.ingress[0].hostname'` | ||
|
||
export ARGOCD_USER=argocd-cc | ||
export CC_REPO_NAME=eks-blueprints-workloads-cc | ||
|
||
aws iam create-service-specific-credential --user-name $ARGOCD_USER --service-name codecommit.amazonaws.com --no-cli-pager | ||
export CC_REPO_URL=$(aws codecommit get-repository --repository-name $CC_REPO_NAME --query 'repositoryMetadata.cloneUrlHttp' --output text) | ||
export SSC_ID=$(aws iam list-service-specific-credentials --user-name $ARGOCD_USER --query 'ServiceSpecificCredentials[0].ServiceSpecificCredentialId' --output text) | ||
export SSC_USER=$(aws iam list-service-specific-credentials --user-name $ARGOCD_USER --query 'ServiceSpecificCredentials[0].ServiceUserName' --output text) | ||
export SSC_PWD=$(aws iam reset-service-specific-credential --user-name $ARGOCD_USER --service-specific-credential-id $SSC_ID --query 'ServiceSpecificCredential.ServicePassword' --output text) | ||
|
||
cat > argocd-workloads-repos-creds.yaml <<EOF | ||
apiVersion: v1 | ||
kind: Secret | ||
metadata: | ||
name: repo-creds-platform-https | ||
namespace: argocd | ||
labels: | ||
argocd.argoproj.io/secret-type: repo-creds | ||
stringData: | ||
url: ${CC_REPO_URL} | ||
password: ${SSC_PWD} | ||
username: ${SSC_USER} | ||
EOF | ||
|
||
kubectl apply -f argocd-workloads-repos-creds.yaml | ||
rm argocd-workloads-repos-creds.yaml | ||
|
||
echo Deployment finished. | ||
echo "AWS CodeCommit Blueprint workloads repository URL: $CC_REPO_URL" | ||
echo "ArgoCD URL: https://$ARGOCD_SERVER" | ||
echo "ArgoCD server user: admin" | ||
echo "ArgoCD admin password: $(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)" | ||
``` | ||
|
||
## Create notification trigger | ||
|
||
```bash | ||
export LAMBDA_ARN=$(aws lambda get-function --function-name eks-blueprints-workloads-cc-webhook | jq -r .Configuration.FunctionArn) | ||
|
||
cat > trigger.json <<EOF | ||
[ | ||
{ | ||
"destinationArn": "${LAMBDA_ARN}", | ||
"branches": [], | ||
"name": "${CC_REPO_NAME}-trigger", | ||
"customData": "${ARGOCD_SERVER}", | ||
"events": [ | ||
"all" | ||
] | ||
} | ||
] | ||
EOF | ||
|
||
aws codecommit put-repository-triggers --repository-name $CC_REPO_NAME --triggers file://trigger.json --no-cli-pager | ||
rm trigger.json | ||
``` | ||
|
||
## Populate AWS CodeCommit with Blueprint workloads Sample repository | ||
|
||
```bash | ||
pushd .. | ||
git clone https://github.com/aws-samples/eks-blueprints-workloads.git | ||
git clone codecommit::$AWS_REGION://$CC_REPO_NAME | ||
cd $CC_REPO_NAME | ||
git checkout -b main | ||
cd .. | ||
rsync -av eks-blueprints-workloads/ $CC_REPO_NAME --exclude .git | ||
cd $CC_REPO_NAME | ||
git add . && git commit -m "initial commit" && git push --set-upstream origin main | ||
popd | ||
``` | ||
|
||
ArgoCD will receive notification and will start sync. | ||
|
||
![ArgoCD sync](./images/argocd-cc-workloads.png) | ||
|
||
## Destroy | ||
|
||
To teardown and remove the resources created in this example: | ||
|
||
1. Delete "bootstrap-apps" project in ArgoCD UI and wait until ArgoCD delete workloads | ||
|
||
2. Delete AWS CodeCommit credentials | ||
|
||
```sh | ||
export SSC_ID=$(aws iam list-service-specific-credentials --user-name $ARGOCD_USER --query 'ServiceSpecificCredentials[1].ServiceSpecificCredentialId' --output text) | ||
aws iam delete-service-specific-credential --user-name $ARGOCD_USER --service-specific-credential-id $SSC_ID | ||
export SSC_ID=$(aws iam list-service-specific-credentials --user-name $ARGOCD_USER --query 'ServiceSpecificCredentials[0].ServiceSpecificCredentialId' --output text) | ||
aws iam delete-service-specific-credential --user-name $ARGOCD_USER --service-specific-credential-id $SSC_ID | ||
``` | ||
|
||
3. Delete deployed resources | ||
|
||
```sh | ||
cd cdk-eks-blueprints-patterns | ||
make pattern workloads-codecommit destroy | ||
``` | ||
|
||
4. Delete cloned repositories (`if necessary`) | ||
|
||
```sh | ||
pushd .. | ||
rm -rf eks-blueprints-workloads-cc | ||
rm -rf eks-blueprints-workloads | ||
popd | ||
``` |
40 changes: 40 additions & 0 deletions
40
lib/workloads-codecommit-construct/WorkloadsCodeCommitRepo.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { Construct } from 'constructs'; | ||
import { NestedStack, NestedStackProps } from 'aws-cdk-lib'; | ||
import * as blueprints from '@aws-quickstart/eks-blueprints'; | ||
import * as codecommit from 'aws-cdk-lib/aws-codecommit'; | ||
import * as iam from 'aws-cdk-lib/aws-iam'; | ||
import * as lambda from 'aws-cdk-lib/aws-lambda'; | ||
|
||
export default class WorkloadsCodeCommitRepoStack extends NestedStack { | ||
public static builder(userName: string, repoName: string): blueprints.NestedStackBuilder { | ||
return { | ||
build(scope: Construct, id: string, props: NestedStackProps) { | ||
return new WorkloadsCodeCommitRepoStack(scope, id, props, userName, repoName); | ||
} | ||
}; | ||
} | ||
|
||
constructor(scope: Construct, id: string, props: NestedStackProps, userName: string, repoName: string) { | ||
super(scope, id); | ||
|
||
const repo = new codecommit.Repository(this, repoName + '-codecommit-repo', { | ||
repositoryName: repoName, | ||
}); | ||
|
||
const user = new iam.User(this, userName + '-user-name', { | ||
userName: userName, | ||
}); | ||
repo.grantPull(user); | ||
|
||
const fn = new lambda.Function(this, repoName + '-webhook', { | ||
runtime: lambda.Runtime.NODEJS_20_X, | ||
functionName: repoName + '-webhook', | ||
description: 'Webhook for ArgoCD on commit to AWS CodeCommit', | ||
handler: 'index.handler', | ||
code: lambda.Code.fromAsset("lib/workloads-codecommit-construct/lambda"), | ||
}); | ||
|
||
const principal = new iam.ServicePrincipal('codecommit.amazonaws.com'); | ||
fn.grantInvoke(principal); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import * as blueprints from '@aws-quickstart/eks-blueprints'; | ||
import { Construct } from 'constructs'; | ||
import WorkloadsCodeCommitRepoStack from './WorkloadsCodeCommitRepo'; | ||
|
||
/** | ||
* Demonstrates how to use AWS CodeCommmit as a repository for ArgoCD workloads. | ||
*/ | ||
|
||
export default class WorkloadsCodeCommitConstruct extends Construct { | ||
constructor(scope: Construct, id: string) { | ||
super(scope, id); | ||
|
||
const region = process.env.CDK_DEFAULT_REGION!; | ||
|
||
const userName = 'argocd-cc'; | ||
const repoName = 'eks-blueprints-workloads-cc'; | ||
|
||
const repoUrl = 'https://git-codecommit.' + region + '.amazonaws.com/v1/repos/' + repoName; | ||
|
||
const stackId = `${id}-blueprint`; | ||
|
||
const bootstrapRepo : blueprints.ApplicationRepository = { | ||
repoUrl, | ||
targetRevision: 'main', | ||
}; | ||
|
||
const addOns: Array<blueprints.ClusterAddOn> = [ | ||
new blueprints.NestedStackAddOn({ | ||
builder: WorkloadsCodeCommitRepoStack.builder(userName, repoName), | ||
id: repoName + "-codecommit-repo-nested-stack" | ||
}), | ||
new blueprints.SecretsStoreAddOn, | ||
new blueprints.ArgoCDAddOn({ | ||
bootstrapRepo: { | ||
...bootstrapRepo, | ||
path: 'envs/dev', | ||
}, | ||
values: { | ||
server: { | ||
service: { | ||
type: "LoadBalancer" | ||
} | ||
} | ||
} | ||
}) | ||
]; | ||
|
||
blueprints.EksBlueprint.builder() | ||
.account(process.env.CDK_DEFAULT_ACCOUNT!) | ||
.region(process.env.CDK_DEFAULT_REGION) | ||
.addOns(...addOns) | ||
|
||
.version('auto') | ||
.build(scope, stackId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* eslint-env node */ | ||
const https = require('https'); // eslint-disable-line | ||
|
||
/* webhook payload | ||
{ | ||
"ref": "refs/heads/main", | ||
"repository": { | ||
"html_url": "https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-blueprints-workloads-cc", | ||
"default_branch": "main" | ||
} | ||
} | ||
*/ | ||
|
||
exports.handler = async function(event) { | ||
const eventSourceARNarray = event.Records[0].eventSourceARN.split(':'); | ||
const repoName = eventSourceARNarray[eventSourceARNarray.length - 1]; | ||
const ref = event.Records[0].codecommit.references[0].ref; | ||
const refArray = ref.split('/'); | ||
const branch = refArray[refArray.length - 1]; | ||
const data = JSON.stringify({ | ||
"ref": ref, | ||
"repository": { | ||
"html_url": "https://git-codecommit." + event.Records[0].awsRegion + ".amazonaws.com/v1/repos/" + repoName, | ||
"default_branch": branch | ||
} | ||
}); | ||
console.log(data); | ||
|
||
const options = { | ||
hostname: event.Records[0].customData, | ||
path: '/api/webhook', | ||
method: 'POST', | ||
port: 443, | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'X-GitHub-Event': 'push', | ||
'Content-Length': data.length, | ||
}, | ||
}; | ||
|
||
const promise = new Promise(function(resolve, reject) { | ||
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; | ||
const req = https.request(options, (res) => { | ||
resolve(res.statusCode); | ||
}).on('error', (e) => { | ||
reject(Error(e)); | ||
}); | ||
req.write(data); | ||
req.end(); | ||
}); | ||
return promise; | ||
}; |