Skip to content

Commit fc8c663

Browse files
authored
Merge pull request #12 from cloudogu/feature/argocd_helm
Feature/argocd helm
2 parents 018330e + 01e7a6a commit fc8c663

36 files changed

+661
-475
lines changed

README.md

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@ working example bundled with the complete infrastructure for a gitops deep dive.
1515
- [Real life examples](#real-life-examples)
1616
- [Usage](#usage)
1717
- [Default Folder Structure](#default-folder-structure)
18-
- [FluxV1](#fluxv1)
19-
- [Plain-k8s](#plain-k8s)
20-
- [Helm](#helm)
21-
- [FluxV2](#fluxv2)
22-
- [ArgoCD](#argocd)
18+
- [Plain-k8s](#plain-k8s)
19+
- [Helm](#helm)
2320
- [GitOps-Config](#gitops-config)
2421
- [SCM-Provider](#scm-provider)
2522
- [Stages](#stages)
@@ -89,6 +86,7 @@ def gitopsConfig = [
8986
repositoryUrl: 'fluxv1/gitops'
9087
],
9188
application: 'spring-petclinic',
89+
gitopsTool: 'FLUX',
9290
stages: [
9391
staging: [
9492
deployDirectly: true
@@ -120,6 +118,7 @@ def gitopsConfig = [
120118
cesBuildLibVersion: <cesBuildLibVersion> /* Default: a recent cesBuildLibVersion see deployViaGitops.groovy */ ,
121119
cesBuildLibCredentialsId: <cesBuildLibCredentialsId> /* Default: '', empty due to default public github repo */,
122120
application: 'spring-petclinic',
121+
gitopsTool: 'FLUX'
123122
mainBranch: 'master' /* Default: 'main' */,
124123
deployments: [
125124
sourcePath: 'k8s' /* Default: 'k8s' */,
@@ -157,9 +156,14 @@ deployViaGitops(gitopsConfig)
157156
### Real life examples
158157

159158
**FluxV1:**
160-
* [using petclinic with helm](https://github.com/cloudogu/k8s-gitops-playground/blob/main/applications/petclinic/fluxv1/helm/Jenkinsfile)
161-
* [using petclinic with plain-k8s](https://github.com/cloudogu/k8s-gitops-playground/blob/main/applications/petclinic/fluxv1/plain-k8s/Jenkinsfile)
162-
* [using helm with nginx and extra resources](https://github.com/cloudogu/k8s-gitops-playground/blob/main/applications/nginx/fluxv1/Jenkinsfile)
159+
* [using petclinic with helm and extra k8s-resources and extra files](https://github.com/cloudogu/k8s-gitops-playground/blob/main/applications/petclinic/fluxv1/helm/Jenkinsfile)
160+
* [using petclinic with plain-k8s and extra files](https://github.com/cloudogu/k8s-gitops-playground/blob/main/applications/petclinic/fluxv1/plain-k8s/Jenkinsfile)
161+
* [using nginx with helm and extra files](https://github.com/cloudogu/k8s-gitops-playground/blob/main/applications/nginx/fluxv1/Jenkinsfile)
162+
163+
**ArgoCD:**
164+
* [using petclinic with helm and extra k8s-resources and extra files](https://github.com/cloudogu/k8s-gitops-playground/blob/main/applications/petclinic/argocd/helm/Jenkinsfile)
165+
* [using petclinic with plain-k8s](https://github.com/cloudogu/k8s-gitops-playground/blob/main/applications/petclinic/argocd/plain-k8s/Jenkinsfile)
166+
163167

164168
---
165169

@@ -201,9 +205,7 @@ A default project structure in your application repo could look like the example
201205
and/or helm resources bundled in a folder. This specific resources folder (here `k8s`) will later be specified by the
202206
`sourcePath` within the deployments section of your `gitopsConfig`.
203207

204-
### FluxV1
205-
206-
#### Plain-k8s
208+
### Plain-k8s
207209
```
208210
├── application
209211
├── config.yamllint.yaml // not necessarily needed
@@ -217,7 +219,7 @@ and/or helm resources bundled in a folder. This specific resources folder (here
217219
└── service.yaml
218220
```
219221

220-
#### Helm
222+
### Helm
221223
```
222224
├── application
223225
├── config.yamllint.yaml // not necessarily needed
@@ -238,14 +240,6 @@ and/or helm resources bundled in a folder. This specific resources folder (here
238240
└── values-staging.yaml
239241
```
240242

241-
### FluxV2
242-
243-
Upcoming
244-
245-
### ArgoCD
246-
247-
Upcoming
248-
249243
---
250244

251245
## GitOps-Config
@@ -254,12 +248,16 @@ You can find a complete yet simple example [here](#examples).
254248

255249
**Properties**
256250

257-
First of all there are some mandatory properties e.g. the information about your gitops repository and the application repository.
251+
First of all there are some mandatory properties e.g. the information about your gitops repository, the application repository and the gitops tool to be used.
258252

259253
```
260254
application: 'spring-petclinic' // Name of the application. Used as a folder in GitOps repo
261255
```
262256

257+
```
258+
gitopsTool: 'ARGO' // Name of the gitops tool. Currently supporting 'FLUX' (for now only fluxV1) and 'ARGO' (for now supporting only helm charts from git repos)
259+
```
260+
263261
and some optional parameters (below are the defaults) for the configuration of the dependency to the ces-build-lib or the default name for the git branch:
264262
```
265263
cesBuildLibRepo: 'https://github.com/cloudogu/ces-build-lib',

src/com/cloudogu/gitopsbuildlib/deployment/Deployment.groovy

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ abstract class Deployment {
1717
def create(String stage) {
1818
createFoldersAndCopyK8sResources(stage)
1919
createFileConfigmaps(stage)
20-
createPreValidation(stage)
20+
preValidation(stage)
2121
validate(stage)
22-
createPostValidation(stage)
22+
postValidation(stage)
2323
}
2424

25-
abstract createPreValidation(String stage)
26-
abstract createPostValidation(String stage)
25+
abstract preValidation(String stage)
26+
abstract postValidation(String stage)
2727

2828
def validate(String stage) {
2929
gitopsConfig.validators.each { validatorConfig ->
@@ -36,11 +36,11 @@ abstract class Deployment {
3636
def sourcePath = gitopsConfig.deployments.sourcePath
3737
def application = gitopsConfig.application
3838

39-
script.sh "mkdir -p ${stage}/${application}/${sourcePath}/"
39+
script.sh "mkdir -p ${stage}/${application}/extraResources/"
4040
script.sh "mkdir -p ${configDir}/"
4141
// copy extra resources like sealed secrets
42-
script.echo "Copying k8s payload from application repo to gitOps Repo: '${sourcePath}/${stage}/*' to '${stage}/${application}/${sourcePath}'"
43-
script.sh "cp -r ${script.env.WORKSPACE}/${sourcePath}/${stage}/* ${stage}/${application}/${sourcePath}/ || true"
42+
script.echo "Copying k8s payload from application repo to gitOps Repo: '${sourcePath}/${stage}/*' to '${stage}/${application}/extraResources/'"
43+
script.sh "cp -r ${script.env.WORKSPACE}/${sourcePath}/${stage}/* ${stage}/${application}/extraResources/ || true"
4444
script.sh "cp ${script.env.WORKSPACE}/*.yamllint.yaml ${configDir}/ || true"
4545
}
4646

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,59 @@
1-
package com.cloudogu.gitopsbuildlib.deployment
1+
package com.cloudogu.gitopsbuildlib.deployment.helm
22

3-
import com.cloudogu.gitopsbuildlib.deployment.repotype.GitRepo
4-
import com.cloudogu.gitopsbuildlib.deployment.repotype.HelmRepo
5-
import com.cloudogu.gitopsbuildlib.deployment.repotype.RepoType
3+
import com.cloudogu.gitopsbuildlib.deployment.Deployment
4+
import com.cloudogu.gitopsbuildlib.deployment.helm.helmrelease.ArgoCDRelease
5+
import com.cloudogu.gitopsbuildlib.deployment.helm.helmrelease.FluxV1Release
6+
import com.cloudogu.gitopsbuildlib.deployment.helm.helmrelease.HelmRelease
7+
import com.cloudogu.gitopsbuildlib.deployment.helm.repotype.GitRepo
8+
import com.cloudogu.gitopsbuildlib.deployment.helm.repotype.HelmRepo
9+
import com.cloudogu.gitopsbuildlib.deployment.helm.repotype.RepoType
610

711
class Helm extends Deployment {
812

9-
protected RepoType helm
13+
protected RepoType chartRepo
14+
protected HelmRelease helmRelease
1015

1116
Helm(def script, def gitopsConfig) {
1217
super(script, gitopsConfig)
1318
if (gitopsConfig.deployments.helm.repoType == 'GIT') {
14-
helm = new GitRepo(script)
19+
chartRepo = new GitRepo(script)
1520
} else if (gitopsConfig.deployments.helm.repoType == 'HELM') {
16-
helm = new HelmRepo(script)
21+
chartRepo = new HelmRepo(script)
22+
}
23+
if(gitopsConfig.gitopsTool == 'FLUX') {
24+
helmRelease = new FluxV1Release(script)
25+
} else if(gitopsConfig.gitopsTool == 'ARGO') {
26+
helmRelease = new ArgoCDRelease(script)
1727
}
1828
}
1929

2030
@Override
21-
def createPreValidation(String stage) {
31+
def preValidation(String stage) {
2232
def helmConfig = gitopsConfig.deployments.helm
2333
def application = gitopsConfig.application
2434
def sourcePath = gitopsConfig.deployments.sourcePath
2535

2636
// writing the merged-values.yaml via writeYaml into a file has the advantage, that it gets formatted as valid yaml
2737
// This makes it easier to read in and indent for the inline use in the helmRelease.
2838
// It enables us to reuse the `fileToInlineYaml` function, without writing a complex formatting logic.
29-
script.writeFile file: "${stage}/${application}/mergedValues.yaml", text: helm.mergeValues(helmConfig, ["${script.env.WORKSPACE}/${sourcePath}/values-${stage}.yaml", "${script.env.WORKSPACE}/${sourcePath}/values-shared.yaml"] as String[])
39+
script.writeFile file: "${stage}/${application}/mergedValues.yaml", text: chartRepo.mergeValues(helmConfig, ["${script.env.WORKSPACE}/${sourcePath}/values-${stage}.yaml", "${script.env.WORKSPACE}/${sourcePath}/values-shared.yaml"] as String[])
3040

3141
updateYamlValue("${stage}/${application}/mergedValues.yaml", helmConfig)
32-
script.writeFile file: "${stage}/${application}/helmRelease.yaml", text: helm.createHelmRelease(helmConfig, application, getNamespace(stage), "${stage}/${application}/mergedValues.yaml")
42+
43+
script.writeFile file: "${stage}/${application}/applicationRelease.yaml", text: helmRelease.create(helmConfig, application, getNamespace(stage), "${stage}/${application}/mergedValues.yaml")
44+
3345
// since the values are already inline (helmRelease.yaml) we do not need to commit them into the gitops repo
3446
script.sh "rm ${stage}/${application}/mergedValues.yaml"
3547
}
3648

3749
@Override
38-
def createPostValidation(String stage) {
50+
def postValidation(String stage) {
51+
def helmConfig = gitopsConfig.deployments.helm
52+
53+
// clean the gitrepo helm chart folder since the helmRelease.yaml ist now created
54+
if (helmConfig.repoType == 'GIT') {
55+
script.sh "rm -rf chart || true"
56+
}
3957
}
4058

4159
private void updateYamlValue(String yamlFilePath, Map helmConfig) {
@@ -53,28 +71,4 @@ class Helm extends Deployment {
5371
}
5472
script.writeYaml file: yamlFilePath, data: data, overwrite: true
5573
}
56-
57-
58-
//TODO helmValuesFromFile not yet implemented
59-
// private String createFromFileValues(String stage, Map gitopsConfig) {
60-
// String values = ""
61-
//
62-
// gitopsConfig.helmValuesFromFile.each {
63-
// if (stage in it['stage']) {
64-
// values = fileToInlineYaml(it['key'], "${script.env.WORKSPACE}/k8s/${it['file']}")
65-
// }
66-
// }
67-
// return values
68-
// }
69-
//
70-
// private String fileToInlineYaml(String key, String filePath) {
71-
// String values = ""
72-
// String indent = " "
73-
//
74-
// def fileContent = readFile filePath
75-
// values += "\n ${key}: |\n${indent}"
76-
// values += fileContent.split("\\n").join("\n" + indent)
77-
//
78-
// return values
79-
// }
8074
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.cloudogu.gitopsbuildlib.deployment.helm.helmrelease
2+
3+
import com.cloudogu.gitopsbuildlib.docker.DockerWrapper
4+
5+
class ArgoCDRelease extends HelmRelease{
6+
7+
protected DockerWrapper dockerWrapper
8+
9+
ArgoCDRelease(def script) {
10+
super(script)
11+
dockerWrapper = new DockerWrapper(script)
12+
}
13+
14+
@Override
15+
String create(Map helmConfig, String application, String namespace, String mergedValuesFile) {
16+
17+
String helmRelease = ""
18+
if (helmConfig.repoType == 'GIT') {
19+
helmRelease = createResourcesFromGitRepo(helmConfig, application, mergedValuesFile)
20+
} else if (helmConfig.repoType == 'HELM') {
21+
// TODO not yet implemented
22+
}
23+
return helmRelease
24+
}
25+
26+
private String createResourcesFromGitRepo(Map helmConfig, String application, String mergedValuesFile) {
27+
String helmRelease = ""
28+
29+
def chartPath = ''
30+
if (helmConfig.containsKey('chartPath')) {
31+
chartPath = helmConfig.chartPath
32+
}
33+
34+
dockerWrapper.withHelm {
35+
String templateScript = "helm template ${application} chart/${chartPath} -f ${mergedValuesFile}"
36+
helmRelease = script.sh returnStdout: true, script: templateScript
37+
}
38+
// this line removes all empty lines since helm template creates some and the helm kubeval validator will throw an error if there are emtpy lines present
39+
helmRelease = helmRelease.replaceAll("(?m)^[ \t]*\r?\n", "")
40+
return helmRelease
41+
}
42+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.cloudogu.gitopsbuildlib.deployment.helm.helmrelease
2+
3+
class FluxV1Release extends HelmRelease{
4+
5+
FluxV1Release(def script) {
6+
super(script)
7+
}
8+
9+
@Override
10+
String create(Map helmConfig, String application, String namespace, String mergedValuesFile) {
11+
def values = fileToInlineYaml(mergedValuesFile)
12+
def chart = getChart(helmConfig)
13+
return """apiVersion: helm.fluxcd.io/v1
14+
kind: HelmRelease
15+
metadata:
16+
name: ${application}
17+
namespace: ${namespace}
18+
annotations:
19+
fluxcd.io/automated: "false"
20+
spec:
21+
releaseName: ${application}
22+
chart:${chart}
23+
values:
24+
${values}
25+
"""
26+
}
27+
28+
private String gitRepoChart(Map helmConfig) {
29+
30+
def chartPath = "."
31+
if (helmConfig.containsKey('chartPath') && helmConfig.chartPath) {
32+
chartPath = helmConfig.chartPath
33+
}
34+
35+
return """
36+
git: ${helmConfig.repoUrl}
37+
ref: ${helmConfig.version}
38+
path: ${chartPath}"""
39+
}
40+
41+
private String helmRepoChart(Map helmConfig) {
42+
return """
43+
repository: ${helmConfig.repoUrl}
44+
name: ${helmConfig.chartName}
45+
version: ${helmConfig.version}"""
46+
}
47+
48+
private String getChart(Map helmConfig) {
49+
if (helmConfig.repoType == 'GIT') {
50+
return gitRepoChart(helmConfig)
51+
} else if (helmConfig.repoType == 'HELM') {
52+
return helmRepoChart(helmConfig)
53+
}
54+
}
55+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.cloudogu.gitopsbuildlib.deployment.helm.helmrelease
2+
3+
abstract class HelmRelease {
4+
5+
protected script
6+
7+
HelmRelease(def script) {
8+
this.script = script
9+
}
10+
11+
abstract String create(Map helmConfig, String application, String namespace, String mergedValuesFile)
12+
13+
String fileToInlineYaml(String fileContents) {
14+
String values = ""
15+
String indent = " "
16+
String fileContent = script.readFile fileContents
17+
fileContent.split("\n").each { line ->
18+
if(line.size() > 0) {
19+
values += indent + line + "\n"
20+
} else {
21+
values += line + "\n"
22+
}
23+
}
24+
// remove unnecessary last blank line
25+
return values.substring(0, values.lastIndexOf('\n'))
26+
}
27+
}

0 commit comments

Comments
 (0)