Skip to content

Commit f6ea18c

Browse files
first commit
0 parents  commit f6ea18c

23 files changed

+735
-0
lines changed

.github/workflows/main.yml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# This is a basic workflow to help you get started with Actions
2+
3+
name: CI
4+
5+
on:
6+
push:
7+
branches: [ main ]
8+
env:
9+
# Update the line below to reflect your appropriate AWS_REGION
10+
AWS_REGION : "us-west-2"
11+
# Permission can be added at job level or workflow level
12+
permissions:
13+
id-token: write # This is required for requesting the JWT
14+
contents: write # This is required for actions/checkout
15+
jobs:
16+
build:
17+
name: Building and Pushing the Image
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v2
23+
24+
- name: Configure AWS credentials
25+
uses: aws-actions/configure-aws-credentials@v1
26+
with:
27+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
28+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
29+
aws-region: ${{ env.AWS_REGION }}
30+
31+
# Hello from AWS: WhoAmI
32+
- name: Sts GetCallerIdentity
33+
run: |
34+
aws sts get-caller-identity
35+
36+
- name: Login to Amazon ECR
37+
id: login-ecr
38+
uses: aws-actions/amazon-ecr-login@v1
39+
40+
- name: Build, tag, and push image to Amazon ECR
41+
id: build-image
42+
env:
43+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
44+
ECR_REPOSITORY: eks-gitops-argocd
45+
46+
run: |
47+
# Build a docker container and push it to ECR
48+
git_hash=$(git rev-parse --short "$GITHUB_SHA")
49+
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:${GITHUB_REF##*/}-$git_hash docker/.
50+
echo "Pushing image to ECR..."
51+
docker push $ECR_REGISTRY/$ECR_REPOSITORY:${GITHUB_REF##*/}-$git_hash
52+
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:${GITHUB_REF##*/}-$git_hash"
53+
54+
- name: Update Version
55+
env:
56+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
57+
ECR_REPOSITORY: eks-gitops-argocd
58+
run: |
59+
git_hash=$(git rev-parse --short "$GITHUB_SHA")
60+
version=$(cat ./charts/eks-gitops-argocd/values.yaml | grep version: | awk '{print $2}')
61+
sed -i "s/$version/${GITHUB_REF##*/}-$git_hash/" ./charts/eks-gitops-argocd/values.yaml
62+
OLD_REPO=`grep 1234567890 ./charts/eks-gitops-argocd/values.yaml | cut -d ':' -f2`
63+
NEW_REPO="${ECR_REGISTRY}/${ECR_REPOSITORY}"
64+
sed -i "s|$OLD_REPO| $NEW_REPO|" ./charts/eks-gitops-argocd/values.yaml
65+
66+
# Update chart version, package, and push
67+
- name : Update helm chart version
68+
env:
69+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
70+
ECR_REPOSITORY: eks-gitops-argocd
71+
run: |
72+
VER=`grep version: ./charts/eks-gitops-argocd/Chart.yaml | cut -d ':' -f2 | tr -d '\n\t\r '`
73+
helm package charts/eks-gitops-argocd
74+
helm push eks-gitops-argocd-${VER}.tgz oci://$ECR_REGISTRY/
75+

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.DS_Store

README.md

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# eks-gitops-argocd
2+
3+
This repository walks through implementing GitOps with GitHub Actions and ArgoCD to deploy applications via helm to EKS
4+
5+
## High Level Architecture
6+
![Alt text](images/eks-gitops-argocd.png?raw=true "GitOps on EKS with GitHub Actions and ArgoCD")
7+
8+
## Build EKS Cluster
9+
For this demo, we will create the EKS cluster using EKSCTL. Before that, some housekeeping
10+
```
11+
export ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
12+
export AWS_REGION=$(aws ec2 describe-availability-zones --query 'AvailabilityZones[0].[RegionName]' --output text)
13+
export AZ1=$(aws ec2 describe-availability-zones --query 'AvailabilityZones[0].ZoneName' --region $AWS_REGION --output text)
14+
export AZ2=$(aws ec2 describe-availability-zones --query 'AvailabilityZones[1].ZoneName' --region $AWS_REGION --output text)
15+
export AZ3=$(aws ec2 describe-availability-zones --query 'AvailabilityZones[2].ZoneName' --region $AWS_REGION --output text)
16+
export K8S_VERSION=1.25
17+
```
18+
19+
If you do not have eksctl installed, install it.
20+
```
21+
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
22+
23+
sudo mv -v /tmp/eksctl /usr/local/bin
24+
eksctl completion bash >> ~/.bash_completion
25+
. /etc/profile.d/bash_completion.sh
26+
. ~/.bash_completion
27+
```
28+
29+
Create a CMK for the EKS cluster to use when encrypting your Kubernetes secrets:
30+
```
31+
aws kms create-alias --alias-name alias/eksworkshop --target-key-id $(aws kms create-key --query KeyMetadata.Arn --output text)
32+
```
33+
34+
Let’s retrieve the ARN of the CMK to input into the create cluster command.
35+
```
36+
export KEY_ARN=$(aws kms describe-key --key-id alias/eksworkshop --query KeyMetadata.Arn --output text)
37+
```
38+
39+
We set the KEY_ARN environment variable to make it easier to refer to the KMS key later.
40+
41+
Now, let’s save the KEY_ARN environment variable into the bash_profile
42+
```
43+
echo "export KEY_ARN=${KEY_ARN}" | tee -a ~/.bash_profile
44+
```
45+
46+
47+
Now let's create the cluster
48+
```
49+
eksctl create cluster -f config/cluster.yaml
50+
```
51+
52+
Test the cluster
53+
```
54+
kubectl get nodes
55+
# if we see our 3 nodes, we know we have authenticated correctly
56+
```
57+
58+
Update kubeconfig file to interact with the EKS cluster
59+
```
60+
aws eks update-kubeconfig --name eks-gitops --region ${AWS_REGION}
61+
```
62+
63+
## Create an ECR Repository
64+
... In the same region, and call it `eks-gitops-argocd`. This is because the files/ configurations in this demo use that name.
65+
66+
## Setup GitHub Actions
67+
68+
Use IAM roles for GitHub Actions to connect to Amazon ECR. Follow [this blog](https://aws.amazon.com/blogs/security/use-iam-roles-to-connect-github-actions-to-actions-in-aws/) to set it up.
69+
70+
Use the contents below for `.github/main.yml`
71+
```
72+
# This is a basic workflow to help you get started with Actions
73+
74+
name: CI
75+
76+
on:
77+
push:
78+
branches: [ main ]
79+
pull_request:
80+
branches: [ main ]
81+
env:
82+
AWS_REGION : "<AWS_REGION>"
83+
# Permission can be added at job level or workflow level
84+
permissions:
85+
id-token: write # This is required for requesting the JWT
86+
contents: write # This is required for actions/checkout
87+
jobs:
88+
build:
89+
name: Building and Pushing the Image
90+
runs-on: ubuntu-latest
91+
92+
steps:
93+
- name: Checkout
94+
uses: actions/checkout@v2
95+
96+
- name: configure aws credentials
97+
uses: aws-actions/configure-aws-credentials@v1.7.0
98+
with:
99+
role-to-assume: arn:aws:iam::<AWS_ACCOUNT_ID>:role/<IAM_ROLE_NAME>
100+
role-session-name: GitHub_to_AWS_via_FederatedOIDC
101+
aws-region: ${{ env.AWS_REGION }}
102+
# Hello from AWS: WhoAmI
103+
- name: Sts GetCallerIdentity
104+
run: |
105+
aws sts get-caller-identity
106+
107+
- name: Login to Amazon ECR
108+
id: login-ecr
109+
uses: aws-actions/amazon-ecr-login@v1
110+
111+
- name: Build, tag, and push image to Amazon ECR
112+
id: build-image
113+
env:
114+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
115+
ECR_REPOSITORY: eks-gitops-argocd
116+
117+
run: |
118+
# Build a docker container and push it to ECR
119+
git_hash=$(git rev-parse --short "$GITHUB_SHA")
120+
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:${GITHUB_REF##*/}-$git_hash docker/.
121+
echo "Pushing image to ECR..."
122+
docker push $ECR_REGISTRY/$ECR_REPOSITORY:${GITHUB_REF##*/}-$git_hash
123+
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:${GITHUB_REF##*/}-$git_hash"
124+
125+
- name: Update Version
126+
run: |
127+
git_hash=$(git rev-parse --short "$GITHUB_SHA")
128+
version=$(cat ./charts/helm-example/values.yaml | grep version: | awk '{print $2}')
129+
sed -i "s/$version/${GITHUB_REF##*/}-$git_hash/" ./charts/helm-example/values.yaml
130+
131+
- name: Commit and push changes
132+
uses: devops-infra/action-commit-push@v0.3
133+
with:
134+
github_token: ${{ secrets.GITHUB_TOKEN }}
135+
commit_message: Version updated
136+
137+
```
138+
139+
## Install ArgoCD on EKS
140+
141+
Install helm
142+
```
143+
curl -sSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
144+
helm version --short
145+
146+
```
147+
148+
Install ArgoCD
149+
```
150+
helm repo add argo https://argoproj.github.io/argo-helm
151+
helm install argocd argo/argo-cd --set server.service.type=LoadBalancer
152+
```
153+
154+
Access the UI which is sitting behing an ELB. To get the password:
155+
```
156+
kubectl get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo
157+
```
158+
159+
Connect to the Repo -> Add/Create an application
160+
```
161+
sudo curl --silent --location -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v2.4.7/argocd-linux-amd64
162+
163+
sudo chmod +x /usr/local/bin/argocd
164+
165+
export ARGOCD_SERVER=`kubectl get svc argocd-server -o json | jq --raw-output '.status.loadBalancer.ingress[0].hostname'`
166+
167+
export ARGO_PWD=`kubectl get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d`
168+
169+
argocd login $ARGOCD_SERVER --username admin --password $ARGO_PWD --insecure
170+
```
171+
172+
Add ECR helm repo
173+
```
174+
argocd repo add XXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com --type helm --name eks-gitops-argocd --enable-oci --username AWS --password $(aws ecr get-login-password --region us-west-2)
175+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: v2
2+
name: eks-gitops-argocd
3+
description: A Helm chart for Kubernetes
4+
5+
# A chart can be either an 'application' or a 'library' chart.
6+
#
7+
# Application charts are a collection of templates that can be packaged into versioned archives
8+
# to be deployed.
9+
#
10+
# Library charts provide useful utilities or functions for the chart developer. They're included as
11+
# a dependency of application charts to inject those utilities and functions into the rendering
12+
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
13+
type: application
14+
15+
# This is the chart version. This version number should be incremented each time you make changes
16+
# to the chart and its templates, including the app version.
17+
version: 0.1.1
18+
19+
# This is the version number of the application being deployed. This version number should be
20+
# incremented each time you make changes to the application.
21+
appVersion: 2.0.0
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
1. Get the application URL by running these commands:
2+
{{- if .Values.ingress.enabled }}
3+
{{- range $host := .Values.ingress.hosts }}
4+
{{- range .paths }}
5+
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
6+
{{- end }}
7+
{{- end }}
8+
{{- else if contains "NodePort" .Values.service.type }}
9+
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "helm-example.fullname" . }})
10+
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
11+
echo http://$NODE_IP:$NODE_PORT
12+
{{- else if contains "LoadBalancer" .Values.service.type }}
13+
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
14+
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "helm-example.fullname" . }}'
15+
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "helm-example.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
16+
echo http://$SERVICE_IP:{{ .Values.service.port }}
17+
{{- else if contains "ClusterIP" .Values.service.type }}
18+
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "helm-example.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
19+
echo "Visit http://127.0.0.1:8080 to use your application"
20+
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
21+
{{- end }}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{{/* vim: set filetype=mustache: */}}
2+
{{/*
3+
Expand the name of the chart.
4+
*/}}
5+
{{- define "helm-example.name" -}}
6+
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
7+
{{- end -}}
8+
9+
{{/*
10+
Create a default fully qualified app name.
11+
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
12+
If release name contains chart name it will be used as a full name.
13+
*/}}
14+
{{- define "helm-example.fullname" -}}
15+
{{- if .Values.fullnameOverride -}}
16+
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
17+
{{- else -}}
18+
{{- $name := default .Chart.Name .Values.nameOverride -}}
19+
{{- if contains $name .Release.Name -}}
20+
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
21+
{{- else -}}
22+
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
23+
{{- end -}}
24+
{{- end -}}
25+
{{- end -}}
26+
27+
{{/*
28+
Create chart name and version as used by the chart label.
29+
*/}}
30+
{{- define "helm-example.chart" -}}
31+
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
32+
{{- end -}}
33+
34+
{{/*
35+
Common labels
36+
*/}}
37+
{{- define "helm-example.labels" -}}
38+
helm.sh/chart: {{ include "helm-example.chart" . }}
39+
{{ include "helm-example.selectorLabels" . }}
40+
{{- if .Chart.AppVersion }}
41+
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
42+
{{- end }}
43+
app.kubernetes.io/managed-by: {{ .Release.Service }}
44+
{{- end -}}
45+
46+
{{/*
47+
Selector labels
48+
*/}}
49+
{{- define "helm-example.selectorLabels" -}}
50+
app.kubernetes.io/name: {{ include "helm-example.name" . }}
51+
app.kubernetes.io/instance: {{ .Release.Name }}
52+
{{- end -}}
53+
54+
{{/*
55+
Create the name of the service account to use
56+
*/}}
57+
{{- define "helm-example.serviceAccountName" -}}
58+
{{- if .Values.serviceAccount.create -}}
59+
{{ default (include "helm-example.fullname" .) .Values.serviceAccount.name }}
60+
{{- else -}}
61+
{{ default "default" .Values.serviceAccount.name }}
62+
{{- end -}}
63+
{{- end -}}

0 commit comments

Comments
 (0)