Skip to content

Commit 37503df

Browse files
Update README.md
1 parent 9ebb470 commit 37503df

File tree

1 file changed

+127
-90
lines changed

1 file changed

+127
-90
lines changed

README.md

Lines changed: 127 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
11
# 🚀 Reusable GitHub Workflow: Kubernetes App Deployment with ArgoCD (v2 BETA)
22

3-
This GitHub Actions **reusable workflow** automates Kubernetes application deployment using [Kustomize](https://kubectl.docs.kubernetes.io/references/kustomize/) and [ArgoCD](https://argo-cd.readthedocs.io/en/stable/).
3+
This GitHub Actions **reusable workflow** automates Kubernetes application deployment using [Kustomize](https://kubectl.docs.kubernetes.io/references/kustomize/) and [ArgoCD](https://argo-cd.readthedocs.io/en/stable/).
44
It renders and templates your manifest files, commits the results to your **continuous deployment (CD) repo**, and uses the **ArgoCD REST API** to create and sync applications.
55

66
> **ArgoCD Applications are auto-created if missing**, so first-time deployments work out-of-the-box.
7-
> ⚠️ **v2 is currently in BETA**APIs and inputs may evolve slightly.
7+
> ⚠️ **v2 is currently in BETA**inputs and behavior may evolve slightly.
88
99
---
1010

1111
## ⚙️ Inputs
1212

1313
### Core
14-
| Name | Required | Type | Description |
15-
|---------------|----------|--------|-------------|
16-
| `runner` || string | GitHub runner label (default: `ubuntu-latest`) |
17-
| `cd_repo` || string | Continuous deployment repo where templated manifests are stored |
18-
| `environment` || string | Logical environment name (e.g. `dev`, `prod`) |
19-
| `cluster` || string | Required only when `env_map[environment]` has multiple clusters |
20-
| `namespace` || string | Kubernetes namespace for deployment |
14+
| Name | Required | Type | Description |
15+
|---------------------|----------|--------|-------------|
16+
| `runner` || string | GitHub runner label (default: `ubuntu-latest`) |
17+
| `cd_repo` || string | Continuous deployment repo where templated manifests are stored |
18+
| `github_environment`|| string | **GitHub Environment** name for this job (enables approvals & env-scoped secrets in repo settings) |
19+
| `target` || string | **Logical environment** to deploy to (e.g. `dev`, `qa`, `prod`). If `env_map[target]` has multiple clusters, you **must** also set `target_cluster`. |
20+
| `target_cluster` || string | Specific cluster to use **when** `target` maps to multiple clusters in `env_map` (e.g. `aks-prod-weu`). For single-cluster envs leave empty. |
21+
| `namespace` || string | Kubernetes namespace for deployment |
22+
23+
> 🔎 **`github_environment` vs `target`**
24+
> `github_environment` ties the job to a GitHub Environment (for approvals and env-scoped secrets).
25+
> `target` is your **logical deployment environment** used to look up clusters via `env_map`.
2126
2227
### Source Repo
23-
| Name | Required | Type | Description |
24-
|-----------------|----------|--------|-------------|
25-
| `repo` || string | GitHub repo containing source manifests (e.g. `my-org/my-app`) |
26-
| `deployFilesPath` || string | Path to manifest files inside `repo` |
27-
| `repo_commit_id` || string | Commit SHA to deploy (overrides `branch_name`) |
28-
| `branch_name` || string | Branch to checkout (default: `main`) |
28+
| Name | Required | Type | Description |
29+
|--------------------|----------|--------|-------------|
30+
| `repo` | | string | GitHub repo containing source manifests (e.g. `my-org/my-app`) |
31+
| `deployFilesPath` | | string | Path to manifest files inside `repo` |
32+
| `repo_commit_id` | | string | Commit SHA to deploy (overrides `branch_name`) |
33+
| `branch_name` | | string | Branch to checkout (default: `main`) |
2934

3035
### Deployment Modes
3136
- **Mode A (single app):**
@@ -43,36 +48,53 @@ It renders and templates your manifest files, commits the results to your **cont
4348
{"name":"app2","images":["repo/app2"],"path":"apps/app2/overlays/prod"}
4449
]
4550
```
51+
### Providing `env_map` (input vs. environment variable)
4652

47-
### Environment Map
48-
| Name | Required | Type | Description |
49-
|-----------|----------|--------|-------------|
50-
| `env_map` | ❌ | string | JSON describing environments, clusters, registries, and UAMI mappings |
53+
You can provide the environment map in **two ways**. The workflow will use **`inputs.env_map` first**, and if it’s empty, it will fall back to the **`ENV_MAP` environment variable**.
5154

52-
Example shape:
53-
```json
54-
{
55-
"dev": {
56-
"cluster_count": 1,
57-
"clusters": [
58-
{
59-
"cluster": "aks-west-europe",
60-
"dns_zone": "internal.demo.affinity7software.com",
61-
"container_registry": "ghcr.io/my-org",
62-
"uami_map": [
63-
{"uami_name":"aks-uami","uami_resource_group":"rg-demo","client_id":"1234-5678"}
64-
]
65-
}
66-
]
67-
}
68-
}
55+
**Precedence:**
56+
1. `with: env_map: "<JSON>"` ✅ (preferred)
57+
2. `env: ENV_MAP: "<JSON>"` (fallback)
58+
3. If neither is present → the workflow **fails** with a clear error.
59+
60+
**Examples**
61+
62+
**A) Pass as workflow input (preferred)**
63+
```yaml
64+
jobs:
65+
deploy:
66+
uses: gitopsmanager/k8s-deploy/.github/workflows/deploy.yaml@v2
67+
with:
68+
target: prod
69+
target_cluster: aks-prod-weu
70+
namespace: my-namespace
71+
cd_repo: my-org/continuous-deployment
72+
env_map: ${{ secrets.ENV_MAP_JSON }} # JSON string
73+
```
74+
75+
**B) Provide via environment variable `ENV_MAP` (fallback)**
76+
```yaml
77+
jobs:
78+
deploy:
79+
uses: gitopsmanager/k8s-deploy/.github/workflows/deploy.yaml@v2
80+
with:
81+
target: prod
82+
target_cluster: aks-prod-weu
83+
namespace: my-namespace
84+
cd_repo: my-org/continuous-deployment
85+
env:
86+
ENV_MAP: ${{ secrets.ENV_MAP_JSON }} # JSON string
6987
```
7088
89+
> ℹ️ **Format:** `env_map` must be **valid JSON** (not YAML).
90+
> ❗ If `target` maps to multiple clusters in `env_map` and `target_cluster` is empty, the workflow fails and lists valid cluster options.
91+
92+
7193
---
7294

7395
## 🔑 UAMI Mapping for Azure Workload Identity
7496

75-
When deploying to **Azure AKS**, this workflow supports exporting **User Assigned Managed Identity (UAMI)** client IDs as environment variables for templating.
97+
When deploying to **Azure AKS**, this workflow exports **User Assigned Managed Identity (UAMI)** client IDs as environment variables for templating.
7698

7799
### How it works
78100
- Each `uami_map` entry from `env_map` is processed.
@@ -82,12 +104,11 @@ When deploying to **Azure AKS**, this workflow supports exporting **User Assigne
82104
2. All `-` characters are replaced with `_`.
83105
- Example: `sidecar-uami` → `sidecar_uami`
84106
3. If the resulting name doesn’t start with `[A-Za-z_]`, an `_` is prepended.
85-
86-
- The transformed name is exported into the workflow environment and set to the UAMI’s `client_id`.
107+
- The transformed name is exported and set to the UAMI’s `client_id`.
108+
- All exported variables are logged for visibility.
87109

88110
### Example
89111
Given this `env_map` cluster entry:
90-
91112
```json
92113
{
93114
"cluster": "devcluster",
@@ -100,16 +121,13 @@ Given this `env_map` cluster entry:
100121
}
101122
```
102123

103-
The following environment variables will be exported for templating:
104-
124+
Exports:
105125
```
106126
app_uami=1111-aaaa
107127
sidecar_uami=2222-bbbb
108128
```
109129

110-
### Usage in Manifests
111-
You can now reference these UAMIs in your Kubernetes manifests with `envsubst`:
112-
130+
Use in manifests:
113131
```yaml
114132
env:
115133
- name: APP_UAMI_CLIENT_ID
@@ -118,24 +136,20 @@ env:
118136
value: ${sidecar_uami}
119137
```
120138

121-
### Notes
122-
- All exported variables are printed in the workflow logs for debugging.
123-
- Duplicate names (after transformation) are skipped with a warning.
124-
- This ensures UAMI variables are **safe for shell substitution** and consistent across clusters.
125-
126-
139+
---
127140

128-
### ArgoCD / Misc
141+
## ArgoCD / Misc
129142
| Name | Required | Type | Default | Description |
130143
|--------------------|----------|--------|---------|-------------|
131-
| `argocd_auth_token`| ❌ | string | – | Direct token for ArgoCD auth |
132-
| `argocd_username` | ❌ | string | – | Username (basic auth fallback) |
133-
| `argocd_password` | ❌ | string | – | Password (basic auth fallback) |
134-
| `kustomize_version`| ❌ | string | `5.0.1` | Kustomize version |
135-
| `skip_status_check`| ❌ | string | `false` | Skip waiting for ArgoCD sync |
136-
| `insecure_argo` | ❌ | boolean | `false` | Skip TLS verification |
137-
| `convert_jinja` | ❌ | boolean | `false` | Convert `{{ var }}` → `${var}` before templating |
138-
| `debug` | ❌ | boolean | `false` | Print debug structure |
144+
| `argocd_auth_token`| ❌ | string | – | Direct token for ArgoCD auth |
145+
| `argocd_username` | ❌ | string | – | Username (basic auth fallback) |
146+
| `argocd_password` | ❌ | string | – | Password (basic auth fallback) |
147+
| `kustomize_version`| ❌ | string | `5.0.1` | Kustomize version |
148+
| `skip_status_check`| ❌ | string | `false` | Skip waiting for ArgoCD sync |
149+
| `insecure_argo` | ❌ | boolean| `false` | Skip TLS verification |
150+
| `convert_jinja` | ❌ | boolean| `false` | Convert `{{ var }}` → `${var}` before templating |
151+
| `overlay_dir` | ❌ | string | `""` | Optional overlay subdir (used for image patching & build) |
152+
| `debug` | ❌ | boolean| `false` | Print debug structure |
139153

140154
---
141155

@@ -150,36 +164,36 @@ env:
150164
| Name | Description |
151165
|--------------------|-------------|
152166
| `ARGOCD_CA_CERT` | PEM CA cert to verify ArgoCD endpoint |
153-
| `ARGOCD_USERNAME` | Fallback ArgoCD username |
154-
| `ARGOCD_PASSWORD` | Fallback ArgoCD password |
167+
| `ARGOCD_USERNAME` | Fallback ArgoCD username (if not passing as input) |
168+
| `ARGOCD_PASSWORD` | Fallback ArgoCD password (if not passing as input) |
155169

156170
---
157171

158172
## 📦 Artifact Uploads
159173

160-
| Artifact Name | Description |
161-
|-----------------------------|-------------|
174+
| Artifact Name | Description |
175+
|------------------------------|-------------|
162176
| `templated-source-manifests` | All files after envsubst templating |
163177
| `built-kustomize-manifest` | Final rendered output of `kustomize build` |
164178

165179
---
166180

167181
## 🔄 Deployment Flow Summary
168182

169-
1. Checkout **source** and **CD repos**
170-
2. Parse **env_map JSON** and select cluster
171-
3. Export **UAMI env vars** if provided
172-
4. Convert Jinja → envsubst (if enabled)
173-
5. Template manifests (`envsubst`)
183+
1. Checkout **source** and **CD repos**
184+
2. Parse **env_map JSON** and resolve the cluster from `target` + optional `target_cluster`
185+
3. Export **UAMI env vars** (normalized) if provided
186+
4. Optional: Convert Jinja → envsubst placeholders
187+
5. Template manifests with `envsubst`
174188
6. Copy to CD repo path:
175189
```
176190
continuous-deployment/<cluster>/<namespace>/<application>/
177191
```
178-
7. Patch image tags (if provided)
179-
8. Run `kustomize build`
180-
9. Commit & push to CD repo
181-
10. Create ArgoCD app if missing
182-
11. Trigger ArgoCD sync
192+
7. Patch image tags (if provided)
193+
8. Run `kustomize build` and upload artifact
194+
9. Commit & push to CD repo
195+
10. Create ArgoCD app if missing
196+
11. Trigger ArgoCD sync
183197
12. Wait for sync (unless skipped)
184198

185199
---
@@ -191,25 +205,51 @@ jobs:
191205
deploy:
192206
uses: gitopsmanager/k8s-deploy/.github/workflows/deploy.yaml@v2
193207
with:
194-
environment: dev
195-
application: my-app
208+
# Core
209+
cd_repo: my-org/continuous-deployment
210+
github_environment: prod
211+
target: prod # logical environment
212+
target_cluster: aks-prod-weu # REQUIRED here because prod has >1 clusters
196213
namespace: my-namespace
214+
215+
# Source
197216
repo: my-org/my-app
198-
deployFilesPath: manifests/overlays/dev
199-
overlay_dir: dev
217+
deployFilesPath: manifests/overlays/prod
218+
branch_name: main
219+
220+
# App mode A
221+
application: my-app
222+
overlay_dir: prod
200223
image_tag: abc123
224+
225+
# Env map (JSON string)
226+
env_map: ${{ secrets.ENV_MAP_JSON }} # or pass inline JSON
227+
201228
secrets:
202229
CONTINUOUS_DEPLOYMENT_GH_APP_ID: ${{ secrets.CD_GH_APP_ID }}
203230
CONTINUOUS_DEPLOYMENT_GH_APP_PRIVATE_KEY: ${{ secrets.CD_GH_APP_KEY }}
204231
ARGOCD_CA_CERT: ${{ secrets.ARGOCD_CA_CERT }}
205232
```
206233

234+
**Single-cluster example (no `target_cluster` needed):**
235+
```yaml
236+
with:
237+
cd_repo: my-org/continuous-deployment
238+
github_environment: dev
239+
target: dev
240+
target_cluster: ""
241+
namespace: my-namespace
242+
repo: my-org/my-app
243+
deployFilesPath: manifests/overlays/dev
244+
application: my-app
245+
overlay_dir: dev
246+
```
247+
207248
---
208249

209250
## 🏗 ArgoCD Requirements
210251

211252
ArgoCD ingress must match:
212-
213253
```
214254
https://${cluster}-argocd-argocd-web-ui.${dns_zone}
215255
```
@@ -223,14 +263,14 @@ https://aks-west-europe-argocd-argocd-web-ui.internal.demo.affinity7software.com
223263

224264
## 📦 ArgoCD App Details
225265

226-
| Field | Value |
227-
|--------------|-------|
228-
| `project` | `default` |
229-
| `name` | `${namespace}-${application}` |
230-
| `source.repoURL` | `https://github.com/${cd_repo}` |
231-
| `source.path` | `${cluster}/${namespace}/${application}/...` |
232-
| `destination.server` | `https://kubernetes.default.svc` |
233-
| `destination.namespace` | `${namespace}` |
266+
| Field | Value |
267+
|------------------------|-------|
268+
| `project` | `default` |
269+
| `name` | `${namespace}-${application}` |
270+
| `source.repoURL` | `https://github.com/${cd_repo}` |
271+
| `source.path` | `${cluster}/${namespace}/${application}/...` |
272+
| `destination.server` | `https://kubernetes.default.svc` |
273+
| `destination.namespace`| `${namespace}` |
234274

235275
---
236276

@@ -245,6 +285,3 @@ https://aks-west-europe-argocd-argocd-web-ui.internal.demo.affinity7software.com
245285

246286
Licensed under MIT. See [LICENSE](./LICENSE).
247287
Third-party actions are listed in [THIRD-PARTY-ACTIONS-AND-TOOLS.md](./THIRD-PARTY-ACTIONS-AND-TOOLS.md).
248-
249-
250-

0 commit comments

Comments
 (0)