Skip to content

Commit 9521491

Browse files
author
Abhishek Choudhary
committed
Initial commit for the sample gitops repository
0 parents  commit 9521491

File tree

9 files changed

+372
-0
lines changed

9 files changed

+372
-0
lines changed

.github/workflows/apply_on_merge.yaml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: Apply Cluster Configuration
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'clusters/**/*.yaml'
9+
10+
jobs:
11+
apply-cluster-config:
12+
runs-on: ubuntu-latest
13+
env:
14+
TFY_API_KEY: ${{ secrets.TFY_API_KEY }}
15+
TFY_HOST: ${{ secrets.TFY_HOST }}
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 2 # Need to fetch at least 2 commits to compare changes
21+
22+
- name: Get changed files
23+
id: changed-files
24+
run: |
25+
# Get list of all changed yaml files (including deleted) in clusters directory
26+
added_modified=$(git diff --name-status HEAD^ HEAD | grep "^[AM].*\.yaml$" | grep "^[AM].*clusters/.*/" | awk '{print $2}' | tr '\n' ' ')
27+
deleted=$(git diff --name-status HEAD^ HEAD | grep "^D.*\.yaml$" | grep "^D.*clusters/.*/" | awk '{print $2}' | tr '\n' ' ')
28+
echo "added_modified=${added_modified}" >> "$GITHUB_OUTPUT"
29+
echo "deleted=${deleted}" >> "$GITHUB_OUTPUT"
30+
echo "Changed files:"
31+
echo "${added_modified}"
32+
echo "Deleted files:"
33+
echo "${deleted}"
34+
35+
- name: Install yq
36+
run: |
37+
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq
38+
chmod +x /usr/local/bin/yq
39+
40+
- name: Validate YAML files
41+
run: |
42+
# Function to validate yaml name matches filename
43+
validate_yaml_name() {
44+
local file=$1
45+
local filename=$(basename "$file" .yaml)
46+
local yaml_name=$(yq '.name' "$file")
47+
48+
if [[ "$yaml_name" != "$filename" ]]; then
49+
echo "Error: YAML name field '$yaml_name' does not match filename '$filename' in $file"
50+
exit 1
51+
fi
52+
}
53+
54+
# Split the space-separated string into array and validate each file
55+
for file in ${{ steps.changed-files.outputs.added_modified }}; do
56+
if [[ -n "$file" && -f "$file" ]]; then
57+
echo "Validating $file"
58+
validate_yaml_name "$file"
59+
fi
60+
done
61+
62+
- name: Setup TFY CLI
63+
run: |
64+
echo "Installing TFY CLI..."
65+
pip install -U "truefoundry"
66+
67+
- name: Apply configurations
68+
run: |
69+
# Process deleted files first
70+
for file in ${{ steps.changed-files.outputs.deleted }}; do
71+
if [[ -n "$file" && -f "$file" ]]; then
72+
echo "Deleting configuration for $file"
73+
# tfy delete -f "$file"
74+
fi
75+
done
76+
77+
# Process added/modified files
78+
for file in ${{ steps.changed-files.outputs.added_modified }}; do
79+
if [[ -n "$file" && -f "$file" ]]; then
80+
# Check if file is in applications folder
81+
if [[ "$file" == *"/applications/"* ]]; then
82+
echo "Applying application configuration for $file"
83+
tfy deploy -f "$file"
84+
else
85+
echo "Applying non-application configuration for $file"
86+
tfy apply -f "$file"
87+
fi
88+
fi
89+
done

.github/workflows/dry_run_on_pr.yaml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: TFY Dry Run on PR
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize]
6+
paths:
7+
- 'clusters/**/*.yaml'
8+
9+
jobs:
10+
dry-run:
11+
runs-on: ubuntu-latest
12+
env:
13+
TFY_API_KEY: ${{ secrets.TFY_API_KEY }}
14+
TFY_HOST: ${{ secrets.TFY_HOST }}
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Get changed files
20+
id: changed-files
21+
uses: tj-actions/changed-files@v42
22+
with:
23+
files: |
24+
clusters/**/*.yaml
25+
26+
- name: Install yq
27+
run: |
28+
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq
29+
chmod +x /usr/local/bin/yq
30+
31+
- name: Validate YAML files
32+
run: |
33+
# Function to validate yaml name matches filename
34+
validate_yaml_name() {
35+
local file=$1
36+
local filename=$(basename "$file" .yaml)
37+
38+
# First check if the file is valid YAML
39+
if ! yq eval '.' "$file" > /dev/null 2>&1; then
40+
echo "Error: Invalid YAML syntax in file $file"
41+
exit 1
42+
fi
43+
44+
local yaml_name=$(yq eval '.name' "$file")
45+
46+
if [[ "$yaml_name" != "$filename" ]]; then
47+
echo "Error: YAML name field '$yaml_name' does not match filename '$filename'"
48+
echo "File: $file"
49+
exit 1
50+
fi
51+
}
52+
53+
# Get the changed files as an array
54+
IFS=' ' read -r -a changed_files <<< "${{ steps.changed-files.outputs.all_changed_files }}"
55+
56+
# Validate each changed file
57+
for file in "${changed_files[@]}"; do
58+
if [[ -n "$file" && -f "$file" ]]; then
59+
echo "Validating $file"
60+
validate_yaml_name "$file"
61+
fi
62+
done
63+
64+
- name: Setup TFY CLI
65+
run: |
66+
echo "Installing TFY CLI..."
67+
pip install -U "truefoundry"
68+
69+
- name: Run TFY dry-run for changed files
70+
run: |
71+
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
72+
if [[ $file == */applications/* ]]; then
73+
echo "Running dry-run deploy for application file: $file"
74+
# tfy deploy -f "$file" --dry-run
75+
else
76+
echo "Running dry-run apply for file: $file"
77+
tfy apply -f "$file" --dry-run
78+
fi
79+
done

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Truefoundry Sample Gitops Repo
2+
3+
This is a sample repo for Truefoundry's Gitops workflow. It comprises of the folder structure to keep the cluster, workspace and application configurations in a single repository. It also includes github actions to validate the configuration files on every PR and apply the changes on merge to the main branch.
4+
5+
## Folder Structure
6+
7+
The folder structure is as follows:
8+
9+
```
10+
clusters/
11+
├── cluster1/
12+
│ ├── cluster1.yaml
13+
│ └── workspaces/
14+
│ └── workspace1/
15+
│ ├── workspace1.yaml
16+
│ └── applications/
17+
│ └── app1.yaml
18+
└── cluster2/
19+
├── cluster2.yaml
20+
└── workspaces/
21+
└── workspace1/
22+
├── workspace1.yaml
23+
└── applications/
24+
└── sample-app.yaml
25+
```
26+
27+
We have a top level folder for each cluster. Inside the cluster folder, we have the cluster configuration file and a folder for workspaces. The workspaces folder contains the workspace configuration files and the applications folder which contains the application configuration files.
28+
29+
## File Naming Convention
30+
31+
Each file in the clusters folder should follow the naming convention of `<cluster-name>.yaml`. The cluster name should be the same as the folder name.
32+
33+
The workspaces folder should contain a folder for each workspace. The folder name should be the same as the workspace name. The workspace configuration file should follow the naming convention of `<workspace-name>.yaml`.
34+
35+
The applications folder contains the spec of all the applications. Each application should be in a separate file and follow the naming convention of `<application-name>.yaml`.
36+
37+
## Github actions
38+
39+
We will use Github actions to validate the configuration files and also apply them on every push. To set up the actions, we will need to create a Github repository secret with the name `TFY_API_KEY` and the value of the API key which you can generate from the Truefoundry dashboard.
40+
41+
Before running the actions, please
42+
43+
There are primarily 2 Github actions in the .github/workflows folder:
44+
45+
1. **dry_run_on_pr.yaml** - This action is triggered on every pull request and subsequent changed to the PR. It validated the following things on every PR:
46+
47+
- The filename matches the name field in the yaml file
48+
- It executes apply in dry-run mode for the changed file.
49+
50+
2. **apply_on_merge.yaml** - This action is triggered on every merge to the main branch. It applied all the changed filed in the commit and deleted the configurations for the deleted files.

clusters/cluster1/cluster1.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: cluster1
2+
cluster_type: gcp-gke-standard
3+
environment_names:
4+
- dev
5+
- prod
6+
- staging
7+
collaborators:
8+
- role_id: cluster-admin
9+
subject: user:[email protected]
10+
- role_id: cluster-viewer
11+
subject: user:[email protected]
12+
- role_id: cluster-member
13+
subject: user:[email protected]
14+
- role_id: cluster-admin
15+
subject: user:[email protected]
16+
type: cluster
17+
base_domains:
18+
- '*.cluster1.dev.example.com'
19+
- '*.internal.cluster1.dev.example.com'
20+
monitoring:
21+
loki_url: http://loki.monitoring.svc.cluster.local:3100
22+
prometheus_url: http://prometheus.monitoring.svc.cluster.local:9090
23+
default_registry_fqn: registry:example:docker-registry:dev-images
24+
workbench_config:
25+
ssh_server_config:
26+
base_domain: ssh.cluster1.dev.example.com
27+
port: 80
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
type: service
2+
name: app1
3+
workspace_fqn: cluster1:workspace1
4+
image:
5+
type: build
6+
build_source:
7+
type: git
8+
branch_name: main
9+
ref: abc123def456gh789ijklmnop0123456789abcd
10+
repo_url: https://github.com/example/sample-fastapi-app
11+
build_spec:
12+
type: tfy-python-buildpack
13+
build_context_path: ./
14+
python_version: '3.10'
15+
command: uvicorn app:app --host 0.0.0.0 --port 8000
16+
requirements_path: requirements.txt
17+
ports:
18+
- host: sample-app-service-8000.example-cluster.example.com
19+
port: 8000
20+
expose: true
21+
protocol: TCP
22+
app_protocol: http
23+
replicas: 1
24+
labels:
25+
tfy_openapi_path: openapi.json
26+
allow_interception: false
27+
resources:
28+
node:
29+
type: node_selector
30+
capacity_type: spot_fallback_on_demand
31+
cpu_request: 0.5
32+
cpu_limit: 0.5
33+
memory_request: 1000
34+
memory_limit: 1000
35+
ephemeral_storage_request: 500
36+
ephemeral_storage_limit: 500
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
cluster_fqn: cluster1
2+
name: workspace1
3+
environment_name: devtest
4+
collaborators:
5+
- role_id: workspace-admin
6+
subject: user:[email protected]
7+
type: workspace

clusters/cluster2/cluster2.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: cluster2
2+
cluster_type: aws-eks
3+
environment_names:
4+
- prod
5+
collaborators:
6+
- role_id: cluster-admin
7+
subject: user:[email protected]
8+
- role_id: cluster-admin
9+
subject: user:[email protected]
10+
- role_id: cluster-viewer
11+
subject: team:developers
12+
type: cluster
13+
base_domains:
14+
- '*.example.com'
15+
- '*.production.example.com'
16+
- '*.cluster2-prod.production.example.com'
17+
- '*.example.cloud'
18+
monitoring:
19+
kubecost_url: http://kubecost-cost-analyzer.kubecost.svc.cluster.local:9090
20+
loki_url: http://loki.loki.svc.cluster.local:3100
21+
prometheus_url: >-
22+
http://prometheus-kube-prometheus-prometheus.prometheus.svc.cluster.local:9090
23+
workbench_config:
24+
notebook_config:
25+
base_domain: nb.cluster2-prod.production.example.com
26+
ssh_server_config:
27+
base_domain: ssh.cluster2-prod.production.example.com
28+
port: 80
29+
supported_nodepools:
30+
- name: test-np
31+
- name: test-np2
32+
default_registry_fqn: internal:registry:example-registry:docker-registry:internal-images
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
type: service
2+
workspace_fqn: cluster2:workspace1
3+
name: sample-app
4+
image:
5+
type: build
6+
build_source:
7+
type: git
8+
branch_name: main
9+
ref: abc123def456gh789ijklmnop0123456789abcd
10+
repo_url: https://github.com/example-org/sample-app
11+
build_spec:
12+
type: dockerfile
13+
dockerfile_path: ./Dockerfile
14+
build_context_path: ./
15+
ports:
16+
- host: sample-app.example-domain.com
17+
port: 8080
18+
expose: true
19+
protocol: TCP
20+
app_protocol: http
21+
rollout_strategy:
22+
type: rolling_update
23+
max_surge_percentage: 0
24+
max_unavailable_percentage: 25
25+
allow_interception: false
26+
replicas:
27+
min_replicas: 1
28+
max_replicas: 10
29+
metrics:
30+
type: cpu_utilization
31+
value: 80
32+
resources:
33+
node:
34+
type: node_selector
35+
capacity_type: spot_fallback_on_demand
36+
cpu_request: 2
37+
cpu_limit: 4
38+
memory_request: 200
39+
memory_limit: 500
40+
ephemeral_storage_request: 1000
41+
ephemeral_storage_limit: 2000
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
cluster_fqn: cluster2
2+
name: qa-test-ws
3+
environment_name: prod
4+
collaborators:
5+
- role_id: workspace-admin
6+
subject: user:[email protected]
7+
- role_id: workspace-viewer
8+
subject: user:[email protected]
9+
- role_id: workspace-editor
10+
subject: user:[email protected]
11+
type: workspace

0 commit comments

Comments
 (0)