Merge 498264f409 into 2b12c4d710
1
cicd/README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
# kub308-workshop
|
||||
21
cicd/argo-events.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: argo-events
|
||||
namespace: argocd
|
||||
labels:
|
||||
env: dev
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://argoproj.github.io/argo-helm
|
||||
targetRevision: 2.4.8
|
||||
chart: argo-events
|
||||
destination:
|
||||
server: "https://kubernetes.default.svc"
|
||||
namespace: argo-events
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
automated:
|
||||
selfHeal: true
|
||||
23
cicd/argo-workflows.yaml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: argo-workflows
|
||||
namespace: argocd
|
||||
labels:
|
||||
env: dev
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: cnoe://argo-workflows/manifests
|
||||
targetRevision: HEAD
|
||||
path: "dev"
|
||||
destination:
|
||||
server: "https://kubernetes.default.svc"
|
||||
namespace: argo
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
automated:
|
||||
selfHeal: true
|
||||
1352
cicd/argo-workflows/manifests/base/install.yaml
Normal file
2
cicd/argo-workflows/manifests/base/kustomization.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
resources:
|
||||
- install.yaml
|
||||
20
cicd/argo-workflows/manifests/dev/external-secret.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: keycloak-oidc
|
||||
namespace: argo
|
||||
spec:
|
||||
secretStoreRef:
|
||||
name: keycloak
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: keycloak-oidc
|
||||
data:
|
||||
- secretKey: client-id
|
||||
remoteRef:
|
||||
key: keycloak-clients
|
||||
property: ARGO_WORKFLOWS_CLIENT_ID
|
||||
- secretKey: secret-key
|
||||
remoteRef:
|
||||
key: keycloak-clients
|
||||
property: ARGO_WORKFLOWS_CLIENT_SECRET
|
||||
31
cicd/argo-workflows/manifests/dev/ingress.yaml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: argo-workflows-ingress
|
||||
namespace: argo
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||
spec:
|
||||
ingressClassName: "nginx"
|
||||
rules:
|
||||
- host: localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /argo-workflows(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: argo-server
|
||||
port:
|
||||
name: web
|
||||
- host: cnoe.localtest.me
|
||||
http:
|
||||
paths:
|
||||
- path: /argo-workflows(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: argo-server
|
||||
port:
|
||||
name: web
|
||||
8
cicd/argo-workflows/manifests/dev/kustomization.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
resources:
|
||||
- ../base
|
||||
- external-secret.yaml
|
||||
- ingress.yaml
|
||||
- sa-admin.yaml
|
||||
patches:
|
||||
- path: patches/cm-argo-workflows.yaml
|
||||
- path: patches/deployment-argo-server.yaml
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: workflow-controller-configmap
|
||||
namespace: argo
|
||||
data:
|
||||
config: |
|
||||
sso:
|
||||
insecureSkipVerify: true
|
||||
issuer: https://cnoe.localtest.me:8443/keycloak/realms/cnoe
|
||||
clientId:
|
||||
name: keycloak-oidc
|
||||
key: client-id
|
||||
clientSecret:
|
||||
name: keycloak-oidc
|
||||
key: secret-key
|
||||
redirectUrl: https://cnoe.localtest.me:8443/argo-workflows/oauth2/callback
|
||||
rbac:
|
||||
enabled: true
|
||||
scopes:
|
||||
- openid
|
||||
- profile
|
||||
- email
|
||||
- groups
|
||||
nodeEvents:
|
||||
enabled: false
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: argo-server
|
||||
namespace: argo
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "20"
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: argo-server
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 2746
|
||||
scheme: HTTP
|
||||
env:
|
||||
- name: BASE_HREF
|
||||
value: "/argo-workflows/"
|
||||
args:
|
||||
- server
|
||||
- --configmap=workflow-controller-configmap
|
||||
- --auth-mode=client
|
||||
- --auth-mode=sso
|
||||
- "--secure=false"
|
||||
- "--loglevel"
|
||||
- "info"
|
||||
- "--log-format"
|
||||
- "text"
|
||||
32
cicd/argo-workflows/manifests/dev/sa-admin.yaml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Used by users in the admin group
|
||||
# TODO Need to tighten up permissions.
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: admin
|
||||
namespace: argo
|
||||
annotations:
|
||||
workflows.argoproj.io/rbac-rule: "'admin' in groups"
|
||||
workflows.argoproj.io/rbac-rule-precedence: "10"
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: argo-admin
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: admin
|
||||
namespace: argo
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: admin.service-account-token
|
||||
annotations:
|
||||
kubernetes.io/service-account.name: admin
|
||||
namespace: argo
|
||||
type: kubernetes.io/service-account-token
|
||||
23
cicd/backstage-templates.yaml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: backstage-templates
|
||||
namespace: argocd
|
||||
labels:
|
||||
env: dev
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: cnoe://backstage-templates/entities
|
||||
targetRevision: HEAD
|
||||
path: "."
|
||||
directory:
|
||||
exclude: 'catalog-info.yaml'
|
||||
destination:
|
||||
server: "https://kubernetes.default.svc"
|
||||
namespace: backstage
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
automated:
|
||||
selfHeal: true
|
||||
BIN
cicd/backstage-templates/.DS_Store
vendored
Normal file
BIN
cicd/backstage-templates/entities/.DS_Store
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
site_name: 'Argo Sample Example'
|
||||
nav:
|
||||
- Home: index.md
|
||||
- idpBuilder: idpbuilder.md
|
||||
plugins:
|
||||
- techdocs-core
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
namespace: argocd
|
||||
labels:
|
||||
example: basic
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: ${{values.repoUrl}}
|
||||
targetRevision: HEAD
|
||||
path: manifests
|
||||
destination:
|
||||
name: workshop
|
||||
namespace: ${{values.name}}
|
||||
syncPolicy:
|
||||
automated:
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
description: This is a basic example application
|
||||
annotations:
|
||||
backstage.io/techdocs-ref: dir:.
|
||||
backstage.io/kubernetes-label-selector: 'entity-id=${{values.name}}'
|
||||
backstage.io/kubernetes-namespace: default
|
||||
argocd/app-name: ${{values.name | dump}}
|
||||
links:
|
||||
- url: https://cnoe.localtest.me:8443/gitea
|
||||
title: Repo URL
|
||||
icon: github
|
||||
spec:
|
||||
owner: guest
|
||||
lifecycle: experimental
|
||||
type: service
|
||||
system: ${{values.name | dump}}
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: System
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
description: An example system for demonstration purposes
|
||||
annotations:
|
||||
backstage.io/techdocs-ref: dir:.
|
||||
links:
|
||||
- url: https://github.com/cnoe-io/stacks/tree/main/ref-implementation
|
||||
title: CNOE Repo
|
||||
icon: github
|
||||
spec:
|
||||
owner: guest
|
||||
lifecycle: experimental
|
||||
type: service
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
[![Codespell][codespell-badge]][codespell-link]
|
||||
[![E2E][e2e-badge]][e2e-link]
|
||||
[![Go Report Card][report-badge]][report-link]
|
||||
[![Commit Activity][commit-activity-badge]][commit-activity-link]
|
||||
|
||||
# IDP Builder
|
||||
|
||||
Internal development platform binary launcher.
|
||||
|
||||
> **WORK IN PROGRESS**: This tool is in a pre-release stage and is under active development.
|
||||
|
||||
## About
|
||||
|
||||
Spin up a complete internal developer platform using industry standard technologies like Kubernetes, Argo, and backstage with only Docker required as a dependency.
|
||||
|
||||
This can be useful in several ways:
|
||||
* Create a single binary which can demonstrate an IDP reference implementation.
|
||||
* Use within CI to perform integration testing.
|
||||
* Use as a local development environment for platform engineers.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Checkout our [documentation website](https://cnoe.io/docs/reference-implementation/installations/idpbuilder) for getting started with idpbuilder.
|
||||
|
||||
## Community
|
||||
|
||||
- If you have questions or concerns about this tool, please feel free to reach out to us on the [CNCF Slack Channel](https://cloud-native.slack.com/archives/C05TN9WFN5S).
|
||||
- You can also join our community meetings to meet the team and ask any questions. Checkout [this calendar](https://calendar.google.com/calendar/embed?src=064a2adfce866ccb02e61663a09f99147f22f06374e7a8994066bdc81e066986%40group.calendar.google.com&ctz=America%2FLos_Angeles) for more information.
|
||||
|
||||
## Contribution
|
||||
|
||||
Checkout the [contribution doc](./CONTRIBUTING.md) for contribution guidelines and more information on how to set up your local environment.
|
||||
|
||||
|
||||
<!-- JUST BADGES & LINKS -->
|
||||
[codespell-badge]: https://github.com/cnoe-io/idpbuilder/actions/workflows/codespell.yaml/badge.svg
|
||||
[codespell-link]: https://github.com/cnoe-io/idpbuilder/actions/workflows/codespell.yaml
|
||||
|
||||
[e2e-badge]: https://github.com/cnoe-io/idpbuilder/actions/workflows/e2e.yaml/badge.svg
|
||||
[e2e-link]: https://github.com/cnoe-io/idpbuilder/actions/workflows/e2e.yaml
|
||||
|
||||
[report-badge]: https://goreportcard.com/badge/github.com/cnoe-io/idpbuilder
|
||||
[report-link]: https://goreportcard.com/report/github.com/cnoe-io/idpbuilder
|
||||
|
||||
[commit-activity-badge]: https://img.shields.io/github/commit-activity/m/cnoe-io/idpbuilder
|
||||
[commit-activity-link]: https://github.com/cnoe-io/idpbuilder/pulse
|
||||
|
After Width: | Height: | Size: 57 KiB |
|
|
@ -0,0 +1,11 @@
|
|||

|
||||
|
||||
# Example Basic Application
|
||||
|
||||
Thanks for trying out this demo! In this example, we deployed a simple guestbook application to a remote cluster using Backstage.
|
||||
|
||||
### idpbuilder
|
||||
|
||||
Checkout idpbuilder website: https://cnoe.io/docs/reference-implementation/installations/idpbuilder
|
||||
|
||||
Checkout idpbuilder repository: https://github.com/cnoe-io/idpbuilder
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
labels:
|
||||
entity-id: ${{values.name}}
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
entity-id: ${{values.name}}
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
ports:
|
||||
- containerPort: 80
|
||||
55
cicd/backstage-templates/entities/basic-remote/template.yaml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
apiVersion: scaffolder.backstage.io/v1beta3
|
||||
kind: Template
|
||||
metadata:
|
||||
description: Creates a Simple Kubernetes Deployment to Remote EKS
|
||||
name: basic-remote
|
||||
title: Deploy an Application to EKS
|
||||
spec:
|
||||
owner: guest
|
||||
type: service
|
||||
parameters:
|
||||
- title: Configuration Options
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
default: demo
|
||||
description: name of this application
|
||||
|
||||
steps:
|
||||
- id: template
|
||||
name: Generating component
|
||||
action: fetch:template
|
||||
input:
|
||||
url: ./skeleton
|
||||
values:
|
||||
name: ${{parameters.name}}
|
||||
repoUrl: https://cnoe.localtest.me:8443/gitea/giteaAdmin/${{parameters.name}}.git
|
||||
|
||||
- id: publish
|
||||
name: Publishing to a gitea git repository
|
||||
action: publish:gitea
|
||||
input:
|
||||
description: This is an example app
|
||||
# Hard coded value for this demo purposes only.
|
||||
repoUrl: cnoe.localtest.me:8443/gitea?repo=${{parameters.name}}
|
||||
defaultBranch: main
|
||||
- id: create-argocd-app
|
||||
name: Create ArgoCD App
|
||||
action: cnoe:kubernetes:apply
|
||||
input:
|
||||
manifestPath: argo-cd/app.yaml
|
||||
namespaced: true
|
||||
clusterName: local
|
||||
- id: register
|
||||
name: Register
|
||||
action: catalog:register
|
||||
input:
|
||||
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
|
||||
catalogInfoPath: 'catalog-info.yaml'
|
||||
output:
|
||||
links:
|
||||
- title: Open in catalog
|
||||
icon: catalog
|
||||
entityRef: ${{ steps['register'].output.entityRef }}
|
||||
6
cicd/backstage-templates/entities/basic/mkdocs.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
site_name: 'Simple Example'
|
||||
nav:
|
||||
- Home: index.md
|
||||
- idpBuilder: idpbuilder.md
|
||||
plugins:
|
||||
- techdocs-core
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
description: This is for testing purposes
|
||||
annotations:
|
||||
backstage.io/kubernetes-label-selector: 'entity-id=${{values.name}}'
|
||||
backstage.io/kubernetes-namespace: default
|
||||
argocd/app-name: ${{values.name | dump}}
|
||||
links:
|
||||
- url: https://cnoe.localtest.me:8443/gitea
|
||||
title: Repo URL
|
||||
icon: github
|
||||
spec:
|
||||
owner: guest
|
||||
lifecycle: experimental
|
||||
type: service
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
[![Codespell][codespell-badge]][codespell-link]
|
||||
[![E2E][e2e-badge]][e2e-link]
|
||||
[![Go Report Card][report-badge]][report-link]
|
||||
[![Commit Activity][commit-activity-badge]][commit-activity-link]
|
||||
|
||||
# IDP Builder
|
||||
|
||||
Internal development platform binary launcher.
|
||||
|
||||
> **WORK IN PROGRESS**: This tool is in a pre-release stage and is under active development.
|
||||
|
||||
## About
|
||||
|
||||
Spin up a complete internal developer platform using industry standard technologies like Kubernetes, Argo, and backstage with only Docker required as a dependency.
|
||||
|
||||
This can be useful in several ways:
|
||||
* Create a single binary which can demonstrate an IDP reference implementation.
|
||||
* Use within CI to perform integration testing.
|
||||
* Use as a local development environment for platform engineers.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Checkout our [documentation website](https://cnoe.io/docs/reference-implementation/installations/idpbuilder) for getting started with idpbuilder.
|
||||
|
||||
## Community
|
||||
|
||||
- If you have questions or concerns about this tool, please feel free to reach out to us on the [CNCF Slack Channel](https://cloud-native.slack.com/archives/C05TN9WFN5S).
|
||||
- You can also join our community meetings to meet the team and ask any questions. Checkout [this calendar](https://calendar.google.com/calendar/embed?src=064a2adfce866ccb02e61663a09f99147f22f06374e7a8994066bdc81e066986%40group.calendar.google.com&ctz=America%2FLos_Angeles) for more information.
|
||||
|
||||
## Contribution
|
||||
|
||||
Checkout the [contribution doc](./CONTRIBUTING.md) for contribution guidelines and more information on how to set up your local environment.
|
||||
|
||||
|
||||
<!-- JUST BADGES & LINKS -->
|
||||
[codespell-badge]: https://github.com/cnoe-io/idpbuilder/actions/workflows/codespell.yaml/badge.svg
|
||||
[codespell-link]: https://github.com/cnoe-io/idpbuilder/actions/workflows/codespell.yaml
|
||||
|
||||
[e2e-badge]: https://github.com/cnoe-io/idpbuilder/actions/workflows/e2e.yaml/badge.svg
|
||||
[e2e-link]: https://github.com/cnoe-io/idpbuilder/actions/workflows/e2e.yaml
|
||||
|
||||
[report-badge]: https://goreportcard.com/badge/github.com/cnoe-io/idpbuilder
|
||||
[report-link]: https://goreportcard.com/report/github.com/cnoe-io/idpbuilder
|
||||
|
||||
[commit-activity-badge]: https://img.shields.io/github/commit-activity/m/cnoe-io/idpbuilder
|
||||
[commit-activity-link]: https://github.com/cnoe-io/idpbuilder/pulse
|
||||
|
After Width: | Height: | Size: 57 KiB |
|
|
@ -0,0 +1,11 @@
|
|||

|
||||
|
||||
# Example Basic Application
|
||||
|
||||
Thanks for trying out this demo! In this example, we deployed a simple application.
|
||||
|
||||
### idpbuilder
|
||||
|
||||
Checkout idpbuilder website: https://cnoe.io/docs/reference-implementation/installations/idpbuilder
|
||||
|
||||
Checkout idpbuilder repository: https://github.com/cnoe-io/idpbuilder
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
namespace: default
|
||||
labels:
|
||||
entity-id: ${{values.name}}
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
entity-id: ${{values.name}}
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
ports:
|
||||
- containerPort: 80
|
||||
58
cicd/backstage-templates/entities/basic/template.yaml
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
apiVersion: scaffolder.backstage.io/v1beta3
|
||||
kind: Template
|
||||
metadata:
|
||||
description: Creates a Simple Kubernetes Deployment on Remote EKS
|
||||
name: basic
|
||||
title: Deploy an Application on EKS
|
||||
spec:
|
||||
owner: guest
|
||||
type: service
|
||||
parameters:
|
||||
- title: Configuration Options
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: name of this application
|
||||
|
||||
steps:
|
||||
- id: template
|
||||
name: Generating component
|
||||
action: fetch:template
|
||||
input:
|
||||
url: ./skeleton
|
||||
values:
|
||||
name: ${{parameters.name}}
|
||||
|
||||
- id: publish
|
||||
name: Publishing to a gitea git repository
|
||||
action: publish:gitea
|
||||
input:
|
||||
description: This is an example app
|
||||
# Hard coded value for this demo purposes only.
|
||||
repoUrl: cnoe.localtest.me:8443/gitea?repo=${{parameters.name}}
|
||||
defaultBranch: main
|
||||
- id: create-argocd-app
|
||||
name: Create ArgoCD App
|
||||
action: cnoe:create-argocd-app
|
||||
input:
|
||||
appName: ${{parameters.name}}
|
||||
appNamespace: ${{parameters.name}}
|
||||
argoInstance: workshop-cluster
|
||||
projectName: default
|
||||
# necessary until we generate our own cert
|
||||
repoUrl: https://cnoe.localtest.me:8443/gitea/giteaAdmin/${{parameters.name}}
|
||||
path: "manifests"
|
||||
- id: register
|
||||
name: Register
|
||||
action: catalog:register
|
||||
input:
|
||||
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
|
||||
catalogInfoPath: 'catalog-info.yaml'
|
||||
|
||||
output:
|
||||
links:
|
||||
- title: Open in catalog
|
||||
icon: catalog
|
||||
entityRef: ${{ steps['register'].output.entityRef }}
|
||||
9
cicd/backstage-templates/entities/catalog-info.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Location
|
||||
metadata:
|
||||
name: basic-example-templates
|
||||
description: A collection of example templates
|
||||
spec:
|
||||
targets:
|
||||
- ./basic-remote/template.yaml
|
||||
- ./ci-cd/template.yaml
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: v2
|
||||
name: workflowTemplates
|
||||
description: A Helm chart for Workflow Templates
|
||||
|
||||
type: application
|
||||
|
||||
version: 0.1.0
|
||||
|
||||
appVersion: "0.1.0"
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: EventSource
|
||||
metadata:
|
||||
name: "{{ .Values.serviceName }}-deploy"
|
||||
namespace: {{ .Values.namespace }}
|
||||
spec:
|
||||
service:
|
||||
ports:
|
||||
- port: 12000
|
||||
targetPort: 12000
|
||||
webhook:
|
||||
github:
|
||||
port: "12000"
|
||||
endpoint: /
|
||||
method: POST
|
||||
---
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Sensor
|
||||
metadata:
|
||||
name: "{{ .Values.serviceName }}-deploy"
|
||||
namespace: {{ .Values.namespace }}
|
||||
spec:
|
||||
template:
|
||||
serviceAccountName: operate-workflow-sa
|
||||
dependencies:
|
||||
- name: test-dep
|
||||
eventSourceName: "{{ .Values.serviceName }}-deploy"
|
||||
eventName: github
|
||||
triggers:
|
||||
- template:
|
||||
name: "{{ .Values.serviceName }}-deploy-argo-workflow-trigger"
|
||||
argoWorkflow:
|
||||
operation: submit
|
||||
source:
|
||||
resource:
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Workflow
|
||||
metadata:
|
||||
generateName: "cd-{{ .Values.serviceName }}-"
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
env: dev
|
||||
entity-id: "{{ .Values.serviceName }}"
|
||||
spec:
|
||||
serviceAccountName: admin
|
||||
entrypoint: deploy-workflow
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deployrepo
|
||||
value: "{{ .Values.giteaBaseUrl }}/{{ .Values.serviceName}}-deploy"
|
||||
- name: image-tag
|
||||
value: "0.0.1"
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: workdir
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 256Mi
|
||||
templates:
|
||||
- name: deploy-workflow
|
||||
dag:
|
||||
tasks:
|
||||
{{- range $v := .Values.envs }}
|
||||
- name: {{ $v.name | upper }}
|
||||
template: deployment-workflow
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deployrepo
|
||||
value: "{{`{{workflow.parameters.deployrepo}}`}}"
|
||||
- name: image-tag
|
||||
value: "{{`{{workflow.parameters.image-tag}}`}}"
|
||||
- name: envname
|
||||
value: {{ $v.name }}
|
||||
{{- if not (eq $v.depends "None") }}
|
||||
depends: {{ $v.depends | upper}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
- name: deployment-workflow
|
||||
inputs:
|
||||
parameters:
|
||||
- name: deployrepo
|
||||
- name: image-tag
|
||||
- name: envname
|
||||
dag:
|
||||
tasks:
|
||||
- name: clone-deploy-repo
|
||||
template: clonerepo
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deployrepo
|
||||
value: "https://{{`{{inputs.parameters.deployrepo}}`}}"
|
||||
- name: branch
|
||||
value: "main"
|
||||
- name: envname
|
||||
value: "{{`{{inputs.parameters.envname}}`}}"
|
||||
- name: update-image-version
|
||||
template: update-manifest
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deployrepo
|
||||
value: "{{`{{inputs.parameters.deployrepo}}`}}"
|
||||
- name: tag-version
|
||||
value: "{{`{{inputs.parameters.image-tag}}`}}"
|
||||
- name: envname
|
||||
value: "{{`{{inputs.parameters.envname}}`}}"
|
||||
depends: "clone-deploy-repo"
|
||||
- name: sync-argocd-app
|
||||
template: sync-argocd-app
|
||||
when: "'{{`{{tasks.update-image-version.outputs.parameters.argocd_flag}}`}}' == 'execute_cd'"
|
||||
arguments:
|
||||
parameters:
|
||||
- name: appname
|
||||
value: "{{`{{inputs.parameters.envname}}`}}-{{ .Values.serviceName }}"
|
||||
- name: envname
|
||||
value: "{{`{{inputs.parameters.envname}}`}}"
|
||||
depends: "update-image-version"
|
||||
|
||||
- name: wait-for-app-sync
|
||||
template: wait-for-sync
|
||||
when: "'{{`{{tasks.update-image-version.outputs.parameters.argocd_flag}}`}}' == 'execute_cd'"
|
||||
arguments:
|
||||
parameters:
|
||||
- name: appname
|
||||
value: "{{`{{inputs.parameters.envname}}`}}-{{ .Values.serviceName }}"
|
||||
- name: envname
|
||||
value: "{{`{{inputs.parameters.envname}}`}}"
|
||||
depends: "sync-argocd-app"
|
||||
- name: clonerepo
|
||||
inputs:
|
||||
parameters:
|
||||
- name: deployrepo
|
||||
- name: branch
|
||||
- name: envname
|
||||
container:
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
image: alpine/git:v2.45.1
|
||||
workingDir: /workdir/{{`{{inputs.parameters.envname}}`}}
|
||||
args:
|
||||
- clone
|
||||
- --depth
|
||||
- "1"
|
||||
- --branch
|
||||
- "{{`{{inputs.parameters.branch}}`}}"
|
||||
- --single-branch
|
||||
- "{{`{{inputs.parameters.deployrepo}}`}}"
|
||||
- -c
|
||||
- http.sslVerify=false
|
||||
- .
|
||||
|
||||
- name: update-manifest
|
||||
inputs:
|
||||
parameters:
|
||||
- name: deployrepo
|
||||
- name: tag-version
|
||||
- name: envname
|
||||
container:
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
image: alpine/git:v2.45.1
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: gitea-credentials
|
||||
workingDir: /workdir/{{`{{inputs.parameters.envname}}`}}
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
set -x &&
|
||||
mkdir deploy-repo && cd deploy-repo &&
|
||||
git clone https://{{`{{inputs.parameters.deployrepo}}`}}.git -c http.sslVerify=false &&
|
||||
repo={{`{{inputs.parameters.deployrepo}}`}} &&
|
||||
repo_name=`echo -n $repo | awk -F/ '{print $NF}'` &&
|
||||
env_name={{`{{inputs.parameters.envname}}`}} &&
|
||||
cd $repo_name/environments/$env_name &&
|
||||
image_version={{`{{inputs.parameters.tag-version}}`}} &&
|
||||
sed -i "s/ tag: .*/ tag: $image_version/g" values.yaml &&
|
||||
cat values.yaml &&
|
||||
git status &&
|
||||
echo -n "execute_cd" > /workdir/cd_argo_flag.txt &&
|
||||
m_count=$(git status -s | wc -l) &&
|
||||
if [ $m_count == 1 ]; then
|
||||
git config --global user.email "noreply@aws.com"
|
||||
git config --global user.name ARGO
|
||||
git remote set-url origin https://$GITEA_USERNAME:$GITEA_TOKEN@{{`{{inputs.parameters.deployrepo}}`}}.git
|
||||
git add values.yaml
|
||||
git commit -m "Updated image version to $image_version"
|
||||
git push --set-upstream origin main
|
||||
else
|
||||
echo "No updates to values file, skipping git push"
|
||||
echo -n "skip_cd" > /workdir/cd_argo_flag.txt
|
||||
fi
|
||||
outputs:
|
||||
parameters:
|
||||
- name: argocd_flag
|
||||
valueFrom:
|
||||
path: /workdir/cd_argo_flag.txt
|
||||
- name: sync-argocd-app
|
||||
inputs:
|
||||
parameters:
|
||||
- name: appname
|
||||
- name: envname
|
||||
container:
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
workingDir: /workdir/{{`{{inputs.parameters.envname}}`}}
|
||||
image: argoproj/argocd:v2.6.15
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
argocd login argocd-server.argocd --plaintext --username $ARGOCD_USERNAME --password $ARGOCD_PASSWORD &&
|
||||
argocd app sync "{{`{{inputs.parameters.appname}}`}}" --force --prune
|
||||
env:
|
||||
- name: ARGOCD_USERNAME
|
||||
value: admin
|
||||
- name: ARGOCD_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: argocd-credentials
|
||||
key: ARGOCD_ADMIN_PASSWORD
|
||||
|
||||
- name: wait-for-sync
|
||||
inputs:
|
||||
parameters:
|
||||
- name: appname
|
||||
- name: envname
|
||||
container:
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
workingDir: /workdir/{{`{{inputs.parameters.envname}}`}}
|
||||
image: argoproj/argocd:v2.6.15
|
||||
command: ["/bin/bash"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
argocd login argocd-server.argocd --plaintext --username $ARGOCD_USERNAME --password $ARGOCD_PASSWORD &&
|
||||
health_status=$(argocd app get "{{`{{inputs.parameters.appname}}`}}" --refresh | grep "Health Status:" | awk '{print $3}') &&
|
||||
for i in {1..10};
|
||||
do
|
||||
if [ "${health_status}" = "Healthy" ]; then
|
||||
echo "App is Healthy"
|
||||
exit 0
|
||||
fi
|
||||
echo "App Health: $health_status"
|
||||
health_status=$(argocd app get "{{`{{inputs.parameters.appname}}`}}" --refresh | grep "Health Status:" | awk '{print $3}')
|
||||
sleep 10
|
||||
done &&
|
||||
echo "App Health: $health_status" &&
|
||||
exit 1
|
||||
env:
|
||||
- name: ARGOCD_USERNAME
|
||||
value: admin
|
||||
- name: ARGOCD_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: argocd-credentials
|
||||
key: ARGOCD_ADMIN_PASSWORD
|
||||
parameters:
|
||||
- src:
|
||||
dependencyName: test-dep
|
||||
dataTemplate: "{{`{{ .Input.body.image_version }}`}}"
|
||||
dest: spec.arguments.parameters.1.value
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: "{{ .Values.serviceName }}-deploy-webhook-es-svc"
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
app: argo-events
|
||||
app.kubernetes.io/name: argo-events
|
||||
app.kubernetes.io/instance: my-argo-events
|
||||
spec:
|
||||
ports:
|
||||
- port: 12000
|
||||
protocol: TCP
|
||||
targetPort: 12000
|
||||
selector:
|
||||
eventsource-name: "{{ .Values.serviceName }}-deploy"
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: "{{ .Values.serviceName }}-deploy-webhook-es-ing"
|
||||
namespace: {{ .Values.namespace }}
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: 512m
|
||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: {{ .Values.hostName }}
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: "{{ .Values.serviceName }}-deploy-webhook-es-svc"
|
||||
port:
|
||||
number: 12000
|
||||
path: /argo-events/{{ .Values.serviceName }}-deploy(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
- host: localhost
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: "{{ .Values.serviceName }}-deploy-webhook-es-svc"
|
||||
port:
|
||||
number: 12000
|
||||
path: /argo-events/{{ .Values.serviceName }}-deploy(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
serviceName: ${{values.name}}
|
||||
|
||||
namespace: ${{values.name}}
|
||||
|
||||
hostName: ${{values.repoHost}}
|
||||
|
||||
giteaBaseUrl: ${{values.repoHost}}:443/gitea/giteaAdmin
|
||||
|
||||
imageBase: ${{values.repoHost}}:443/gitea/giteaadmin
|
||||
|
||||
envs:
|
||||
{%- if (values.envConfig.length) %}
|
||||
{%- set depends = 'None' %}
|
||||
{%- for envDetails in values.envConfig %}
|
||||
- name: ${{ envDetails.environment }}
|
||||
depends: ${{ depends }}
|
||||
cluster: ${{ envDetails.clusterName }}
|
||||
{%- set depends = envDetails.environment %}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
serviceName: ${{values.name}}
|
||||
|
||||
envs:
|
||||
{%- if (values.envConfig.length) %}
|
||||
{%- set depends = 'None' %}
|
||||
{%- for envDetails in values.envConfig %}
|
||||
- name: ${{ envDetails.environment }}
|
||||
depends: ${{ depends }}
|
||||
cluster: ${{ envDetails.clusterName }}
|
||||
{%- set depends = envDetails.environment %}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
31
cicd/backstage-templates/entities/ci-cd/go-api/Dockerfile
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Use the official Golang image as the base image
|
||||
FROM golang:1.22 as builder
|
||||
|
||||
# Set the Current Working Directory inside the container
|
||||
WORKDIR /app
|
||||
|
||||
# Copy go mod files if they exist
|
||||
COPY go.mod ./
|
||||
|
||||
# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
|
||||
RUN go mod download
|
||||
|
||||
# Copy the source code into the container
|
||||
COPY main.go .
|
||||
|
||||
# Build the Go app
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o myapp .
|
||||
|
||||
# Command to run the executable
|
||||
CMD ["./myapp"]
|
||||
|
||||
# # Start a new stage from scratch
|
||||
# FROM alpine:latest
|
||||
|
||||
# WORKDIR /root/
|
||||
|
||||
# # Copy the Pre-built binary file from the previous stage
|
||||
# COPY --from=builder /app/myapp .
|
||||
|
||||
# # Command to run the executable
|
||||
# CMD ["./myapp"]
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
description: This is CICD Application Deployment on Remote EKS Cluster
|
||||
annotations:
|
||||
backstage.io/kubernetes-label-selector: 'entity-id=${{values.name}}'
|
||||
argocd/app-selector: 'entity-id=${{values.name}}'
|
||||
argo-workflows.cnoe.io/cluster-name: local
|
||||
argo-workflows.cnoe.io/namespace: ${{values.name}}
|
||||
argo-workflows.cnoe.io/label-selector: 'entity-id=${{values.name}}'
|
||||
links:
|
||||
- url: https://${{values.repoHost}}:443/gitea/giteaAdmin/${{values.name}}
|
||||
title: App Repo URL
|
||||
icon: github
|
||||
- url: https://${{values.repoHost}}:443/gitea/giteaAdmin/${{values.name}}-deploy
|
||||
title: Deploy Repo URL
|
||||
icon: github
|
||||
spec:
|
||||
owner: guest
|
||||
lifecycle: experimental
|
||||
type: service
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: v2
|
||||
name: workflowTemplates
|
||||
description: A Helm chart for Workflow Templates
|
||||
|
||||
type: application
|
||||
|
||||
version: 0.1.0
|
||||
|
||||
appVersion: "0.1.0"
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: EventSource
|
||||
metadata:
|
||||
name: "{{ .Values.serviceName }}"
|
||||
namespace: {{ .Values.namespace }}
|
||||
spec:
|
||||
service:
|
||||
ports:
|
||||
- port: 12000
|
||||
targetPort: 12000
|
||||
webhook:
|
||||
github:
|
||||
port: "12000"
|
||||
endpoint: /
|
||||
method: POST
|
||||
---
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Sensor
|
||||
metadata:
|
||||
name: "{{ .Values.serviceName }}-ci"
|
||||
namespace: {{ .Values.namespace }}
|
||||
spec:
|
||||
template:
|
||||
serviceAccountName: operate-workflow-sa
|
||||
dependencies:
|
||||
- name: test-dep
|
||||
eventSourceName: "{{ .Values.serviceName }}"
|
||||
eventName: github
|
||||
triggers:
|
||||
- template:
|
||||
name: "{{ .Values.serviceName }}-argo-workflow-trigger"
|
||||
argoWorkflow:
|
||||
operation: submit
|
||||
source:
|
||||
resource:
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Workflow
|
||||
metadata:
|
||||
generateName: "ci-{{ .Values.serviceName }}-"
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
env: dev
|
||||
entity-id: "{{ .Values.serviceName }}"
|
||||
spec:
|
||||
serviceAccountName: admin
|
||||
entrypoint: ci-build
|
||||
arguments:
|
||||
parameters:
|
||||
- name: apprepo
|
||||
value: "https://{{ .Values.giteaBaseUrl }}/{{ .Values.serviceName}}"
|
||||
- name: branch
|
||||
value: main
|
||||
- name: deployrepo
|
||||
value: "{{ .Values.giteaBaseUrl }}/{{ .Values.serviceName}}-deploy"
|
||||
- name: image
|
||||
value: "{{ .Values.imageBase }}/{{ .Values.serviceName}}"
|
||||
- name: tag-version
|
||||
value: 0.0.1
|
||||
- name: hostname
|
||||
value: {{ .Values.hostName }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: workdir
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 256Mi
|
||||
templates:
|
||||
- name: ci-build
|
||||
dag:
|
||||
tasks:
|
||||
- name: clone
|
||||
template: clonerepo
|
||||
arguments:
|
||||
parameters:
|
||||
- name: apprepo
|
||||
value: "{{`{{workflow.parameters.apprepo}}`}}"
|
||||
- name: branch
|
||||
value: "{{`{{workflow.parameters.branch}}`}}"
|
||||
|
||||
- name: build-and-push-image
|
||||
template: build-image-kaniko
|
||||
arguments:
|
||||
parameters:
|
||||
- name: image
|
||||
value: "{{`{{workflow.parameters.image}}`}}"
|
||||
- name: tag-version
|
||||
value: "{{`{{workflow.parameters.tag-version}}`}}"
|
||||
depends: "clone"
|
||||
|
||||
- name: invoke-cd-workflow
|
||||
template: invoke-cd-workflow
|
||||
arguments:
|
||||
parameters:
|
||||
- name: hostname
|
||||
value: "{{`{{workflow.parameters.hostname}}`}}"
|
||||
- name: cdpath
|
||||
value: "{{ .Values.serviceName}}-deploy"
|
||||
- name: imageversion
|
||||
value: "{{`{{workflow.parameters.tag-version}}`}}"
|
||||
depends: "build-and-push-image"
|
||||
|
||||
- name: clonerepo
|
||||
inputs:
|
||||
parameters:
|
||||
- name: apprepo
|
||||
- name: branch
|
||||
container:
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
image: alpine/git:v2.45.1
|
||||
workingDir: /workdir
|
||||
args:
|
||||
- clone
|
||||
- --depth
|
||||
- "1"
|
||||
- --branch
|
||||
- "{{`{{inputs.parameters.branch}}`}}"
|
||||
- --single-branch
|
||||
- "{{`{{inputs.parameters.apprepo}}`}}"
|
||||
- -c
|
||||
- http.sslVerify=false
|
||||
- .
|
||||
|
||||
- name: go-build
|
||||
container:
|
||||
image: golang:1.22
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
workingDir: /workdir
|
||||
command:
|
||||
- go
|
||||
args:
|
||||
- build
|
||||
- -v
|
||||
- -o
|
||||
- myapp
|
||||
|
||||
- name: build-image-kaniko
|
||||
inputs:
|
||||
parameters:
|
||||
- name: image
|
||||
- name: tag-version
|
||||
volumes:
|
||||
- name: docker-config
|
||||
configMap:
|
||||
name: docker-config
|
||||
container:
|
||||
image: gcr.io/kaniko-project/executor:latest
|
||||
volumeMounts:
|
||||
- name: workdir
|
||||
mountPath: /workdir
|
||||
- name: docker-config
|
||||
mountPath: /kaniko/.docker
|
||||
workingDir: /workdir
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1
|
||||
memory: 2Gi
|
||||
env:
|
||||
- name: DOCKER_CONFIG
|
||||
value: /kaniko/.docker
|
||||
args:
|
||||
- --dockerfile=Dockerfile
|
||||
- --context=.
|
||||
- --destination={{`{{inputs.parameters.image}}`}}:{{`{{inputs.parameters.tag-version}}`}}
|
||||
- --skip-tls-verify
|
||||
- --cache=false
|
||||
|
||||
- name: invoke-cd-workflow
|
||||
inputs:
|
||||
parameters:
|
||||
- name: hostname
|
||||
- name: cdpath
|
||||
- name: imageversion
|
||||
container:
|
||||
image: alpine:3.20
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: gitea-credentials
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
workingDir: "/workdir"
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
set -x &&
|
||||
apk add curl jq &&
|
||||
cd_workflow_url=https://{{`{{inputs.parameters.hostname}}`}}:443/argo-events/{{`{{inputs.parameters.cdpath}}`}} &&
|
||||
image_version={{`{{inputs.parameters.imageversion}}`}} &&
|
||||
curl -k -s -d '{"image_version":"'${image_version}'"}' -H "Content-Type: application/json" -X POST ${cd_workflow_url}
|
||||
parameters:
|
||||
- src:
|
||||
dependencyName: test-dep
|
||||
dataTemplate: "{{`{{ .Input.body.head_commit.id }}`}}"
|
||||
dest: spec.arguments.parameters.4.value
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: "{{ .Values.serviceName }}-webhook-es-svc"
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
app: argo-events
|
||||
app.kubernetes.io/name: argo-events
|
||||
app.kubernetes.io/instance: my-argo-events
|
||||
spec:
|
||||
ports:
|
||||
- port: 12000
|
||||
protocol: TCP
|
||||
targetPort: 12000
|
||||
selector:
|
||||
eventsource-name: "{{ .Values.serviceName }}"
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: "{{ .Values.serviceName }}-webhook-es-ing"
|
||||
namespace: {{ .Values.namespace }}
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: 512m
|
||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: {{ .Values.hostName }}
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: "{{ .Values.serviceName }}-webhook-es-svc"
|
||||
port:
|
||||
number: 12000
|
||||
path: /argo-events/{{ .Values.serviceName }}(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
- host: localhost
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: "{{ .Values.serviceName }}-webhook-es-svc"
|
||||
port:
|
||||
number: 12000
|
||||
path: /argo-events/{{ .Values.serviceName }}(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# apiVersion: external-secrets.io/v1beta1
|
||||
# kind: ExternalSecret
|
||||
# metadata:
|
||||
# name: gitea-credentials
|
||||
# namespace: {{ .Values.namespace }}
|
||||
# spec:
|
||||
# secretStoreRef:
|
||||
# name: gitea
|
||||
# kind: ClusterSecretStore
|
||||
# refreshInterval: "0"
|
||||
# target:
|
||||
# name: gitea-credentials
|
||||
# data:
|
||||
# - secretKey: GITEA_USERNAME
|
||||
# remoteRef:
|
||||
# key: gitea-credential
|
||||
# property: username
|
||||
# - secretKey: GITEA_PASSWORD
|
||||
# remoteRef:
|
||||
# key: gitea-credential
|
||||
# property: password
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: argocd-credentials
|
||||
namespace: {{ .Values.namespace }}
|
||||
spec:
|
||||
secretStoreRef:
|
||||
name: argocd
|
||||
kind: ClusterSecretStore
|
||||
refreshInterval: "0"
|
||||
target:
|
||||
name: argocd-credentials
|
||||
data:
|
||||
- secretKey: ARGOCD_ADMIN_PASSWORD
|
||||
remoteRef:
|
||||
key: argocd-initial-admin-secret
|
||||
property: password
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: admin-binding
|
||||
namespace: {{ .Values.namespace }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: admin
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: admin
|
||||
namespace: {{ .Values.namespace }}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
serviceName: ${{values.name}}
|
||||
|
||||
namespace: ${{values.name}}
|
||||
|
||||
hostName: ${{values.repoHost}}
|
||||
|
||||
giteaBaseUrl: ${{values.repoHost}}:443/gitea/giteaAdmin
|
||||
|
||||
imageBase: ${{values.repoHost}}:443/gitea/giteaadmin
|
||||
3
cicd/backstage-templates/entities/ci-cd/go-api/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module goapi
|
||||
|
||||
go 1.22
|
||||
36
cicd/backstage-templates/entities/ci-cd/go-api/main.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// ping handler
|
||||
func pingHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
log.Println("Error : %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
response := Response{Message: "pong from server : "+hostname}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
func main(){
|
||||
http.HandleFunc("/ping", pingHandler)
|
||||
log.Println("Server started on 8080")
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,565 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: ${{values.name}}
|
||||
labels:
|
||||
name: ${{values.name}}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: ${{values.name}}
|
||||
namespace: ${{values.name}}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: operate-workflow-sa
|
||||
namespace: ${{values.name}}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: operate-workflow-sa-binding
|
||||
namespace: ${{values.name}}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: operate-workflow-sa
|
||||
namespace: ${{values.name}}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: argo-server-cluster-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: ${{values.name}}-cluster-binding
|
||||
namespace: ${{values.name}}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: ${{values.name}}
|
||||
namespace: ${{values.name}}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: gitea-credentials
|
||||
namespace: ${{values.name}}
|
||||
spec:
|
||||
secretStoreRef:
|
||||
name: gitea
|
||||
kind: ClusterSecretStore
|
||||
refreshInterval: "0"
|
||||
target:
|
||||
name: gitea-credentials
|
||||
data:
|
||||
- secretKey: GITEA_USERNAME
|
||||
remoteRef:
|
||||
key: gitea-credential
|
||||
property: username
|
||||
- secretKey: GITEA_PASSWORD
|
||||
remoteRef:
|
||||
key: gitea-credential
|
||||
property: password
|
||||
- secretKey: GITEA_TOKEN
|
||||
remoteRef:
|
||||
key: gitea-token
|
||||
property: token
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: k8s-config
|
||||
namespace: ${{values.name}}
|
||||
stringData:
|
||||
k8s-config.yaml: "type: 'config'\nclusters:\n - url: https://kubernetes.default.svc.cluster.local\n
|
||||
\ name: local\n authProvider: 'serviceAccount'\n skipTLSVerify: true\n
|
||||
\ skipMetricsLookup: true\n serviceAccountToken: \n $file: /var/run/secrets/kubernetes.io/serviceaccount/token\n
|
||||
\ caData: \n $file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n"
|
||||
---
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: EventBus
|
||||
metadata:
|
||||
name: default
|
||||
namespace: ${{values.name}}
|
||||
spec:
|
||||
nats:
|
||||
native:
|
||||
auth: token
|
||||
replicas: 3
|
||||
---
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: EventSource
|
||||
metadata:
|
||||
name: "${{values.name}}-provisioner"
|
||||
namespace: ${{values.name}}
|
||||
spec:
|
||||
service:
|
||||
ports:
|
||||
- port: 12000
|
||||
targetPort: 12000
|
||||
webhook:
|
||||
github:
|
||||
port: "12000"
|
||||
endpoint: /
|
||||
method: POST
|
||||
---
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Sensor
|
||||
metadata:
|
||||
name: "${{values.name}}-provisioner"
|
||||
namespace: ${{values.name}}
|
||||
spec:
|
||||
template:
|
||||
serviceAccountName: operate-workflow-sa
|
||||
dependencies:
|
||||
- name: test-dep
|
||||
eventSourceName: "${{values.name}}-provisioner"
|
||||
eventName: github
|
||||
filters:
|
||||
data:
|
||||
- path: "[body.commits.#.modified.#()#]"
|
||||
type: string
|
||||
value:
|
||||
- 'provisioner.yaml'
|
||||
triggers:
|
||||
- template:
|
||||
name: "${{values.name}}-provisioner-argo-workflow-trigger"
|
||||
argoWorkflow:
|
||||
operation: submit
|
||||
source:
|
||||
resource:
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Workflow
|
||||
metadata:
|
||||
generateName: "provisioner-${{values.name}}-"
|
||||
namespace: ${{values.name}}
|
||||
labels:
|
||||
env: dev
|
||||
entity-id: "${{values.name}}"
|
||||
spec:
|
||||
serviceAccountName: ${{values.name}}
|
||||
entrypoint: instantiate-provisioner
|
||||
volumes:
|
||||
- name: k8s-config
|
||||
secret:
|
||||
secretName: k8s-config
|
||||
arguments:
|
||||
parameters:
|
||||
- name: service-name
|
||||
value: ${{values.name}}
|
||||
- name: repobaseurl
|
||||
value: ${{values.repoHost}}:443/gitea
|
||||
- name: argoeventsBaseUrl
|
||||
value: ${{values.repoHost}}:443/argo-events
|
||||
- name: repoHostName
|
||||
value: ${{values.repoHost}}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: workdir
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 256Mi
|
||||
templates:
|
||||
- name: instantiate-provisioner
|
||||
dag:
|
||||
tasks:
|
||||
- name: clone-shared-helm-repo
|
||||
template: clone-repo
|
||||
arguments:
|
||||
parameters:
|
||||
- name: repo-name
|
||||
value: "https://{{workflow.parameters.repobaseurl}}/giteaAdmin/idpbuilder-localdev-shared-helm-charts-entities"
|
||||
- name: target-dir
|
||||
value: shared-repo
|
||||
- name: service-name
|
||||
value: "{{workflow.parameters.service-name}}"
|
||||
- name: cicd-argocd-apps
|
||||
template: cicd-argocd-apps
|
||||
arguments:
|
||||
parameters:
|
||||
- name: app-repo
|
||||
value: "https://{{workflow.parameters.repobaseurl}}/giteaAdmin/{{workflow.parameters.service-name}}"
|
||||
- name: deploy-repo
|
||||
value: "https://{{workflow.parameters.repobaseurl}}/giteaAdmin/{{workflow.parameters.service-name}}-deploy"
|
||||
- name: service-name
|
||||
value: "{{workflow.parameters.service-name}}"
|
||||
depends: "clone-shared-helm-repo"
|
||||
- name: create-dockerconfig
|
||||
template: create-dockerconfig
|
||||
arguments:
|
||||
parameters:
|
||||
- name: gitea-url
|
||||
value: "https://{{workflow.parameters.repobaseurl}}"
|
||||
- name: service-name
|
||||
value: "{{workflow.parameters.service-name}}"
|
||||
depends: "cicd-argocd-apps"
|
||||
- name: clone-deploy-repo
|
||||
template: clone-repo
|
||||
arguments:
|
||||
parameters:
|
||||
- name: repo-name
|
||||
value: "https://{{workflow.parameters.repobaseurl}}/giteaAdmin/{{workflow.parameters.service-name}}-deploy"
|
||||
- name: target-dir
|
||||
value: "{{workflow.parameters.service-name}}-deploy"
|
||||
- name: service-name
|
||||
value: "{{workflow.parameters.service-name}}"
|
||||
depends: "create-dockerconfig"
|
||||
- name: helm-folders-create
|
||||
template: create-helm-env-directories
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deploy-repo
|
||||
value: "https://{{workflow.parameters.repobaseurl}}/giteaAdmin/{{workflow.parameters.service-name}}-deploy"
|
||||
- name: service-name
|
||||
value: "{{workflow.parameters.service-name}}"
|
||||
- name: host-name
|
||||
value: "{{workflow.parameters.repoHostName}}"
|
||||
depends: "clone-deploy-repo"
|
||||
- name: push-to-deploy-repo
|
||||
template: push-to-repo
|
||||
when: "'{{tasks.helm-folders-create.outputs.parameters.commit-flag}}' == 'commit'"
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deploy-repo
|
||||
value: "{{workflow.parameters.repobaseurl}}/giteaAdmin/{{workflow.parameters.service-name}}-deploy"
|
||||
- name: service-name
|
||||
value: "{{workflow.parameters.service-name}}"
|
||||
depends: "helm-folders-create"
|
||||
- name: create-argocd-apps-for-services
|
||||
template: argo-cd-apps-for-services
|
||||
arguments:
|
||||
parameters:
|
||||
- name: deploy-repo
|
||||
value: https://"{{workflow.parameters.repobaseurl}}/giteaAdmin/{{workflow.parameters.service-name}}-deploy"
|
||||
- name: service-name
|
||||
value: "{{workflow.parameters.service-name}}"
|
||||
depends: "push-to-deploy-repo || push-to-deploy-repo.Skipped"
|
||||
- name: add-webhook-to-apprepo
|
||||
template: gitea-webhook-creation
|
||||
arguments:
|
||||
parameters:
|
||||
- name: gitea-url
|
||||
value: "https://{{workflow.parameters.repobaseurl}}"
|
||||
- name: repo-name
|
||||
value: "{{workflow.parameters.service-name}}"
|
||||
- name: webhook-url
|
||||
value: "https://{{workflow.parameters.argoeventsBaseUrl}}/{{workflow.parameters.service-name}}"
|
||||
depends: "create-argocd-apps-for-services"
|
||||
- name: add-webhook-to-provisioner
|
||||
template: gitea-webhook-creation
|
||||
arguments:
|
||||
parameters:
|
||||
- name: gitea-url
|
||||
value: "https://{{workflow.parameters.repobaseurl}}"
|
||||
- name: repo-name
|
||||
value: "{{workflow.parameters.service-name}}-deploy"
|
||||
- name: webhook-url
|
||||
value: "https://{{workflow.parameters.argoeventsBaseUrl}}/{{workflow.parameters.service-name}}-provisioner"
|
||||
depends: "create-argocd-apps-for-services"
|
||||
- name: clone-repo
|
||||
inputs:
|
||||
parameters:
|
||||
- name: repo-name
|
||||
- name: target-dir
|
||||
container:
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
image: alpine/git:v2.45.1
|
||||
workingDir: "/workdir/{{inputs.parameters.target-dir}}"
|
||||
args:
|
||||
- clone
|
||||
- --depth
|
||||
- "1"
|
||||
- --branch
|
||||
- "main"
|
||||
- --single-branch
|
||||
- "{{inputs.parameters.repo-name}}.git"
|
||||
- -c
|
||||
- http.sslVerify=false
|
||||
- .
|
||||
- name: cicd-argocd-apps
|
||||
inputs:
|
||||
parameters:
|
||||
- name: app-repo
|
||||
- name: deploy-repo
|
||||
- name: service-name
|
||||
container:
|
||||
image: alpine/k8s:1.31.0
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
- mountPath: "/.kube/"
|
||||
name: k8s-config
|
||||
workingDir: /workdir
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
set -x &&
|
||||
ls -lrt &&
|
||||
cd shared-repo/argocd-apps &&
|
||||
app_repo={{inputs.parameters.app-repo}} &&
|
||||
deploy_repo={{inputs.parameters.deploy-repo}} &&
|
||||
service_name={{inputs.parameters.service-name}} &&
|
||||
kubectl get ns &&
|
||||
echo "serviceName: $service_name" > test.yaml &&
|
||||
echo "envList: " >> test.yaml &&
|
||||
echo " ci:" >> test.yaml &&
|
||||
echo " repo: $app_repo" >> test.yaml &&
|
||||
echo " path: ci " >> test.yaml &&
|
||||
echo " namespace: $service_name " >> test.yaml &&
|
||||
echo " cd:" >> test.yaml &&
|
||||
echo " repo: $deploy_repo" >> test.yaml &&
|
||||
echo " path: cd " >> test.yaml &&
|
||||
echo " namespace: $service_name " >> test.yaml &&
|
||||
helm template . -f test.yaml &&
|
||||
helm template . -f test.yaml | kubectl apply -f -
|
||||
- name: create-dockerconfig
|
||||
inputs:
|
||||
parameters:
|
||||
- name: gitea-url
|
||||
- name: service-name
|
||||
container:
|
||||
image: alpine/k8s:1.31.0
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: gitea-credentials
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
- mountPath: "/.kube/"
|
||||
name: k8s-config
|
||||
workingDir: /workdir
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
apk add yq &&
|
||||
echo "Creating Configmap for docker config" &&
|
||||
gitea_auth=$(echo -n $GITEA_USERNAME:$GITEA_PASSWORD | base64) &&
|
||||
echo "apiVersion: v1
|
||||
|
||||
kind: ConfigMap
|
||||
|
||||
metadata:
|
||||
name: docker-config
|
||||
namespace: {{inputs.parameters.service-name}}
|
||||
data:
|
||||
config.json: |
|
||||
{
|
||||
\"auths\": {
|
||||
\"{{inputs.parameters.gitea-url}}\": {
|
||||
\"auth\": \"$gitea_auth\"
|
||||
}
|
||||
}
|
||||
}
|
||||
" > docker_config.yaml &&
|
||||
kubectl apply -f docker_config.yaml
|
||||
- name: create-helm-env-directories
|
||||
inputs:
|
||||
parameters:
|
||||
- name: deploy-repo
|
||||
- name: service-name
|
||||
- name: host-name
|
||||
container:
|
||||
image: alpine:3.20
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
workingDir: "/workdir/{{ inputs.parameters.service-name }}-deploy"
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
set -x &&
|
||||
apk add yq &&
|
||||
ls -lrt && pwd &&
|
||||
sed -i "s/appName: .*/appName: {{ inputs.parameters.service-name }}/g" /workdir/shared-repo/app-deploy/values.yaml &&
|
||||
sed -i "s/REGISTRY_HOST/{{ inputs.parameters.host-name }}/g" /workdir/shared-repo/app-deploy/values.yaml &&
|
||||
sed -i "s/INGRESS_HOST/{{ inputs.parameters.host-name }}/g" /workdir/shared-repo/app-deploy/values.yaml &&
|
||||
echo "Check all environment specific helm templates exists or not" &&
|
||||
echo -n "flag" > /workdir/commit_flag.txt &&
|
||||
if [ ! -d environments ]; then
|
||||
mkdir environments
|
||||
fi &&
|
||||
cd environments/ &&
|
||||
image_tag="0.0.0" &&
|
||||
for env in $(yq -r '.envs[].name' ../provisioner.yaml); do
|
||||
echo "*** Processing ${env} Env ***"
|
||||
if [ -d $env ]; then
|
||||
echo "$env env helm chart exists, skipping helm directory creation"
|
||||
image_tag=$(yq -r '.image.tag' $env/values.yaml)
|
||||
else
|
||||
echo "Creating $env env helm skelton structure"
|
||||
echo -n "commit" > /workdir/commit_flag.txt
|
||||
mkdir $env
|
||||
# cp -pR ../helm ${env}/
|
||||
cp -pR /workdir/shared-repo/app-deploy/* ${env}/
|
||||
ls -lrt ${env}/
|
||||
sed -i "s/envName: .*/envName: $env/" ${env}/values.yaml
|
||||
sed -i "s/tag: .*/tag: $image_tag/" ${env}/values.yaml
|
||||
fi
|
||||
done &&
|
||||
if grep -q "commit" "/workdir/commit_flag.txt"; then
|
||||
echo "Adding new environment to CD helm chart"
|
||||
yq -i '.envs = (load("../provisioner.yaml") | .envs)' ../cd/values.yaml
|
||||
fi
|
||||
|
||||
outputs:
|
||||
parameters:
|
||||
- name: commit-flag
|
||||
valueFrom:
|
||||
path: /workdir/commit_flag.txt
|
||||
- name: push-to-repo
|
||||
inputs:
|
||||
parameters:
|
||||
- name: deploy-repo
|
||||
- name: service-name
|
||||
container:
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
image: alpine/git:v2.45.1
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: gitea-credentials
|
||||
workingDir: /workdir/{{ inputs.parameters.service-name }}-deploy
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
set -x &&
|
||||
ls -lrt && pwd &&
|
||||
git status &&
|
||||
git config --global user.email "noreply@aws.com" &&
|
||||
git config --global user.name ARGO &&
|
||||
git remote set-url origin https://$GITEA_USERNAME:$GITEA_TOKEN@{{inputs.parameters.deploy-repo}}.git &&
|
||||
git add . &&
|
||||
git commit -m "Adding helm charts" &&
|
||||
git push --set-upstream origin main
|
||||
- name: argo-cd-apps-for-services
|
||||
inputs:
|
||||
parameters:
|
||||
- name: deploy-repo
|
||||
- name: service-name
|
||||
container:
|
||||
image: alpine/k8s:1.31.0
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
- mountPath: "/.kube/"
|
||||
name: k8s-config
|
||||
workingDir: /workdir
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
set -x &&
|
||||
ls -lrt &&
|
||||
apk add yq &&
|
||||
cd shared-repo/argocd-apps &&
|
||||
deploy_repo={{inputs.parameters.deploy-repo}} &&
|
||||
service_name={{inputs.parameters.service-name}} &&
|
||||
echo "serviceName: $service_name" > cd-test.yaml &&
|
||||
echo "k8sServer: workshop" >> cd-test.yaml &&
|
||||
echo "envList: " >> cd-test.yaml &&
|
||||
for env in $(yq -r '.envs[].name' /workdir/$service_name-deploy/provisioner.yaml); do
|
||||
echo "*** Creating ${env} Argo CD App ***"
|
||||
echo " $env:" >> cd-test.yaml
|
||||
echo " repo: $deploy_repo" >> cd-test.yaml
|
||||
echo " path: environments/$env " >> cd-test.yaml
|
||||
echo " namespace: $service_name-$env " >> cd-test.yaml
|
||||
done &&
|
||||
helm template . -f cd-test.yaml &&
|
||||
helm template . -f cd-test.yaml | kubectl apply -f -
|
||||
- name: gitea-webhook-creation
|
||||
inputs:
|
||||
parameters:
|
||||
- name: gitea-url
|
||||
- name: repo-name
|
||||
- name: webhook-url
|
||||
container:
|
||||
image: alpine:3.20
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: gitea-credentials
|
||||
volumeMounts:
|
||||
- mountPath: /workdir
|
||||
name: workdir
|
||||
workingDir: "/workdir"
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- >-
|
||||
set -x &&
|
||||
apk add curl jq &&
|
||||
hooks_api_url={{inputs.parameters.gitea-url}}/api/v1/repos/giteaAdmin/{{inputs.parameters.repo-name}}/hooks &&
|
||||
webhook_url={{inputs.parameters.webhook-url}} &&
|
||||
webhook_details=`curl -k -X 'GET' "${hooks_api_url}" -H "accept: application/json" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" | jq '.[].config.url'` &&
|
||||
if [ -z "$webhook_details" ]; then
|
||||
echo "Webhook is not found, creating webhook with $webhook_url"
|
||||
curl -k -X 'POST' "${hooks_api_url}" -H "accept: application/json" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d '{"branch_filter": "main","type": "gitea", "events":["push"], "config": {"url": "'${webhook_url}'", "content_type": "json"}, "active": true}'
|
||||
else
|
||||
echo "Webhook is already exists"
|
||||
fi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: "${{values.name}}-provisioner-webhook-es-svc"
|
||||
namespace: ${{values.name}}
|
||||
labels:
|
||||
app: argo-events
|
||||
app.kubernetes.io/name: argo-events
|
||||
app.kubernetes.io/instance: my-argo-events
|
||||
spec:
|
||||
ports:
|
||||
- port: 12000
|
||||
protocol: TCP
|
||||
targetPort: 12000
|
||||
selector:
|
||||
eventsource-name: "${{values.name}}-provisioner"
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: "${{values.name}}-provisioner-webhook-es-ing"
|
||||
namespace: ${{values.name}}
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: 512m
|
||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: ${{values.repoHost}}
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: "${{values.name}}-provisioner-webhook-es-svc"
|
||||
port:
|
||||
number: 12000
|
||||
path: /argo-events/${{values.name}}-provisioner(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
- host: localhost
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: "${{values.name}}-provisioner-webhook-es-svc"
|
||||
port:
|
||||
number: 12000
|
||||
path: /argo-events/${{values.name}}-provisioner(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
220
cicd/backstage-templates/entities/ci-cd/template.yaml
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
apiVersion: scaffolder.backstage.io/v1beta3
|
||||
kind: Template
|
||||
metadata:
|
||||
description: Creates CI and CD Workflows and Deploy Apps to Remote EKS
|
||||
name: eks-ci-cd
|
||||
title: Deploy an Application with CICD to EKS
|
||||
tags:
|
||||
- go
|
||||
spec:
|
||||
owner: user:guest
|
||||
type: service
|
||||
parameters:
|
||||
- title: Service Info
|
||||
required:
|
||||
- serviceName
|
||||
properties:
|
||||
serviceName:
|
||||
title: Service Name
|
||||
type: string
|
||||
default: riv2024demo
|
||||
pattern: ^[a-z\d]{1,64}$
|
||||
description: Provide service name
|
||||
costCenter:
|
||||
type: string
|
||||
title: Cost Center
|
||||
default: C0001
|
||||
description: Provide CostCenter ID for finance management
|
||||
language:
|
||||
title: Language
|
||||
type: string
|
||||
default: go
|
||||
enum:
|
||||
- go
|
||||
readOnlyGroup:
|
||||
type: string
|
||||
title: Access Group Name (ReadOnly)
|
||||
default: cnoe-ro-ad@cnoe.io
|
||||
description: AD Group Name to provide read only access
|
||||
readWriteGroup:
|
||||
type: string
|
||||
title: Access Group Name (ReadWrite)
|
||||
default: cnoe-rw-ad@cnoe.io
|
||||
description: AD Group Name to provide read & write only access
|
||||
|
||||
- title: Source Control Configuration
|
||||
required:
|
||||
- repoHost
|
||||
properties:
|
||||
repoHost:
|
||||
title: Repository Host
|
||||
type: string
|
||||
default: cnoe.localtest.me
|
||||
enum:
|
||||
- cnoe.localtest.me
|
||||
owner:
|
||||
type: string
|
||||
title: Owner
|
||||
default: cnoe.io
|
||||
description: Repo Owner Name
|
||||
isNewAppRepo:
|
||||
title: Would you like us to create the application repository for you?
|
||||
type: string
|
||||
default: Yes
|
||||
enum:
|
||||
- Yes
|
||||
isNewDeployRepo:
|
||||
title: Would you like us to create the deploy repository for you?
|
||||
type: string
|
||||
default: Yes
|
||||
enum:
|
||||
- Yes
|
||||
- title: Artifact and Credentials Management
|
||||
required:
|
||||
- artifactStore
|
||||
properties:
|
||||
artifactStore:
|
||||
title: Select Artifact Store
|
||||
type: string
|
||||
default: gitea
|
||||
enum:
|
||||
- gitea
|
||||
artifactStoreCredentialsPath:
|
||||
title: Artifact Store Credentials Path
|
||||
type: string
|
||||
default: /team1/artifact-store
|
||||
sourceControlCredentialsPath:
|
||||
title: Source Control Credentials Path
|
||||
default: /team1/source-control
|
||||
type: string
|
||||
notificationChannelCredentialsPath:
|
||||
title: Notification Channel Credentials Path
|
||||
type: string
|
||||
default: /team1/notification-channel
|
||||
|
||||
- title: Environment Configuration
|
||||
properties:
|
||||
envConfig:
|
||||
title: Environments
|
||||
type: array
|
||||
minItems: 1
|
||||
ui:options:
|
||||
addable: true
|
||||
orderable: true
|
||||
removable: true
|
||||
items:
|
||||
title: ''
|
||||
type: object
|
||||
required:
|
||||
- environment
|
||||
- clusterName
|
||||
properties:
|
||||
environment:
|
||||
title: Environment Name
|
||||
type: string
|
||||
default: dev
|
||||
description: Allowed values ci, dev, qa, stage, production, prod, preprod
|
||||
pattern: '^(|dev|test|ci|qa|stage|production|prod|preprod)[0-9]*$'
|
||||
clusterName:
|
||||
title: Cluster Name
|
||||
type: string
|
||||
default: workshop
|
||||
enum:
|
||||
- 'workshop'
|
||||
|
||||
steps:
|
||||
- id: deploy-template
|
||||
name: Generating application deployment template
|
||||
action: fetch:template
|
||||
input:
|
||||
url: ./deploy
|
||||
targetPath: ./app-deploy
|
||||
values:
|
||||
name: ${{parameters.serviceName}}
|
||||
repoHost: ${{parameters.repoHost}}
|
||||
envConfig: ${{parameters.envConfig}}
|
||||
|
||||
- id: app-template
|
||||
name: Generating application code template
|
||||
action: fetch:template
|
||||
input:
|
||||
url: ./go-api
|
||||
targetPath: ./app
|
||||
values:
|
||||
name: ${{parameters.serviceName}}
|
||||
repoHost: ${{parameters.repoHost}}
|
||||
|
||||
- id: provisioner-template
|
||||
name: Generating application code template
|
||||
action: fetch:template
|
||||
input:
|
||||
url: ./provisioner
|
||||
targetPath: ./provisioner
|
||||
values:
|
||||
name: ${{parameters.serviceName}}
|
||||
repoHost: ${{parameters.repoHost}}
|
||||
|
||||
- id: publish-deploy-repo
|
||||
name: Publishing to a gitea deploy git repository
|
||||
action: publish:gitea
|
||||
input:
|
||||
description: This is an example app
|
||||
sourcePath: ./app-deploy
|
||||
repoUrl: ${{parameters.repoHost}}:443/gitea?repo=${{parameters.serviceName}}-deploy
|
||||
defaultBranch: main
|
||||
|
||||
- id: publish-app-repo
|
||||
name: Publishing to a gitea application git repository
|
||||
action: publish:gitea
|
||||
input:
|
||||
description: This is an example app
|
||||
sourcePath: ./app
|
||||
repoUrl: ${{parameters.repoHost}}:443/gitea?repo=${{parameters.serviceName}}
|
||||
defaultBranch: main
|
||||
|
||||
- id: create-provisioner-workflow
|
||||
name: Create Provisioner Workflow
|
||||
action: cnoe:kubernetes:apply
|
||||
input:
|
||||
namespaced: true
|
||||
manifestPath: ./provisioner/workflow.yaml
|
||||
clusterName: local
|
||||
values:
|
||||
name: ${{parameters.serviceName}}
|
||||
repoHost: ${{parameters.repoHost}}
|
||||
|
||||
- id: wait-for-provisioner
|
||||
name: Wait for provisioner workflow to be available
|
||||
action: debug:wait
|
||||
input:
|
||||
seconds: 70
|
||||
|
||||
- id: run-provisioner-workflow
|
||||
name: Invoke Provisioner Workflow
|
||||
action: http:backstage:request
|
||||
input:
|
||||
path: '/proxy/provisioner/argo-events/${{parameters.serviceName}}-provisioner'
|
||||
method: POST
|
||||
headers:
|
||||
content-type: 'application/json'
|
||||
body:
|
||||
{
|
||||
"commits": [
|
||||
{
|
||||
"modified": ["provisioner.yaml"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
- id: register
|
||||
name: Register
|
||||
action: catalog:register
|
||||
input:
|
||||
repoContentsUrl: ${{ steps['publish-app-repo'].output.repoContentsUrl }}
|
||||
catalogInfoPath: 'catalog-info.yaml'
|
||||
|
||||
output:
|
||||
links:
|
||||
- title: Open in catalog
|
||||
icon: catalog
|
||||
entityRef: ${{ steps['register'].output.entityRef }}
|
||||
21
cicd/backstage.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: backstage
|
||||
namespace: argocd
|
||||
labels:
|
||||
env: dev
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: cnoe://backstage/manifests
|
||||
targetRevision: HEAD
|
||||
path: "."
|
||||
destination:
|
||||
server: "https://kubernetes.default.svc"
|
||||
namespace: backstage
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
automated:
|
||||
selfHeal: true
|
||||
77
cicd/backstage/manifests/argocd-secrets.yaml
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: eso-store
|
||||
namespace: argocd
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: eso-store
|
||||
namespace: argocd
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- selfsubjectrulesreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: eso-store
|
||||
namespace: argocd
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: eso-store
|
||||
namespace: argocd
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: eso-store
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ClusterSecretStore
|
||||
metadata:
|
||||
name: argocd
|
||||
spec:
|
||||
provider:
|
||||
kubernetes:
|
||||
remoteNamespace: argocd
|
||||
server:
|
||||
caProvider:
|
||||
type: ConfigMap
|
||||
name: kube-root-ca.crt
|
||||
namespace: argocd
|
||||
key: ca.crt
|
||||
auth:
|
||||
serviceAccount:
|
||||
name: eso-store
|
||||
namespace: argocd
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: argocd-credentials
|
||||
namespace: backstage
|
||||
spec:
|
||||
secretStoreRef:
|
||||
name: argocd
|
||||
kind: ClusterSecretStore
|
||||
refreshInterval: "0"
|
||||
target:
|
||||
name: argocd-credentials
|
||||
data:
|
||||
- secretKey: ARGOCD_ADMIN_PASSWORD
|
||||
remoteRef:
|
||||
key: argocd-initial-admin-secret
|
||||
property: password
|
||||
465
cicd/backstage/manifests/install.yaml
Normal file
|
|
@ -0,0 +1,465 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: backstage
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: backstage
|
||||
namespace: backstage
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: backstage-argo-worfklows
|
||||
rules:
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
- workflows
|
||||
- applications
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: read-all
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: backstage-argo-worfklows
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: backstage-argo-worfklows
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: backstage
|
||||
namespace: backstage
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: backstage-read-all
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: read-all
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: backstage
|
||||
namespace: backstage
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: backstage-config
|
||||
namespace: backstage
|
||||
data:
|
||||
app-config.yaml: |
|
||||
app:
|
||||
title: CNOE Backstage
|
||||
baseUrl: https://cnoe.localtest.me:8443
|
||||
organization:
|
||||
name: CNOE
|
||||
backend:
|
||||
# Used for enabling authentication, secret is shared by all backend plugins
|
||||
# See https://backstage.io/docs/tutorials/backend-to-backend-auth for
|
||||
# information on the format
|
||||
# auth:
|
||||
# keys:
|
||||
# - secret: ${BACKEND_SECRET}
|
||||
baseUrl: https://cnoe.localtest.me:8443
|
||||
listen:
|
||||
port: 7007
|
||||
# Uncomment the following host directive to bind to specific interfaces
|
||||
# host: 127.0.0.1
|
||||
csp:
|
||||
connect-src: ["'self'", 'http:', 'https:']
|
||||
# Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference
|
||||
# Default Helmet Content-Security-Policy values can be removed by setting the key to false
|
||||
cors:
|
||||
origin: https://cnoe.localtest.me:8443
|
||||
methods: [GET, HEAD, PATCH, POST, PUT, DELETE]
|
||||
credentials: true
|
||||
database:
|
||||
client: pg
|
||||
connection:
|
||||
host: ${POSTGRES_HOST}
|
||||
port: ${POSTGRES_PORT}
|
||||
user: ${POSTGRES_USER}
|
||||
password: ${POSTGRES_PASSWORD}
|
||||
cache:
|
||||
store: memory
|
||||
# workingDirectory: /tmp # Use this to configure a working directory for the scaffolder, defaults to the OS temp-dir
|
||||
|
||||
integrations:
|
||||
gitea:
|
||||
- baseUrl: https://cnoe.localtest.me:8443/gitea
|
||||
host: cnoe.localtest.me:8443
|
||||
username: ${GITEA_USERNAME}
|
||||
password: ${GITEA_PASSWORD}
|
||||
- baseUrl: https://cnoe.localtest.me/gitea
|
||||
host: cnoe.localtest.me
|
||||
username: ${GITEA_USERNAME}
|
||||
password: ${GITEA_PASSWORD}
|
||||
# github:
|
||||
# - host: github.com
|
||||
# apps:
|
||||
# - $include: github-integration.yaml
|
||||
# - host: github.com
|
||||
# # This is a Personal Access Token or PAT from GitHub. You can find out how to generate this token, and more information
|
||||
# # about setting up the GitHub integration here: https://backstage.io/docs/getting-started/configuration#setting-up-a-github-integration
|
||||
# token: ${GITHUB_TOKEN}
|
||||
### Example for how to add your GitHub Enterprise instance using the API:
|
||||
# - host: ghe.example.net
|
||||
# apiBaseUrl: https://ghe.example.net/api/v3
|
||||
# token: ${GHE_TOKEN}
|
||||
|
||||
proxy:
|
||||
### Example for how to add a proxy endpoint for the frontend.
|
||||
### A typical reason to do this is to handle HTTPS and CORS for internal services.
|
||||
endpoints:
|
||||
'/provisioner': https://cnoe.localtest.me/
|
||||
|
||||
# Reference documentation http://backstage.io/docs/features/techdocs/configuration
|
||||
# Note: After experimenting with basic setup, use CI/CD to generate docs
|
||||
# and an external cloud storage when deploying TechDocs for production use-case.
|
||||
# https://backstage.io/docs/features/techdocs/how-to-guides#how-to-migrate-from-techdocs-basic-to-recommended-deployment-approach
|
||||
techdocs:
|
||||
builder: 'local' # Alternatives - 'external'
|
||||
generator:
|
||||
runIn: 'local'
|
||||
publisher:
|
||||
type: 'local' # Alternatives - 'googleGcs' or 'awsS3'. Read documentation for using alternatives.
|
||||
|
||||
auth:
|
||||
environment: development
|
||||
session:
|
||||
secret: MW2sV-sIPngEl26vAzatV-6VqfsgAx4bPIz7PuE_2Lk=
|
||||
providers:
|
||||
keycloak-oidc:
|
||||
development:
|
||||
metadataUrl: ${KEYCLOAK_NAME_METADATA}
|
||||
clientId: backstage
|
||||
clientSecret: ${KEYCLOAK_CLIENT_SECRET}
|
||||
prompt: auto
|
||||
|
||||
scaffolder:
|
||||
# see https://backstage.io/docs/features/software-templates/configuration for software template options
|
||||
defaultAuthor:
|
||||
name: backstage-scaffolder
|
||||
email: noreply
|
||||
defaultCommitMessage: "backstage scaffolder"
|
||||
catalog:
|
||||
import:
|
||||
entityFilename: catalog-info.yaml
|
||||
pullRequestBranchName: backstage-integration
|
||||
rules:
|
||||
- allow: [Component, System, API, Resource, Location, Template]
|
||||
locations:
|
||||
# Examples from a public GitHub repository.
|
||||
- type: url
|
||||
target: https://cnoe.localtest.me/gitea/giteaAdmin/idpbuilder-localdev-backstage-templates-entities/raw/branch/main/catalog-info.yaml
|
||||
## Uncomment these lines to add an example org
|
||||
# - type: url
|
||||
# target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml
|
||||
# rules:
|
||||
# - allow: [User, Group]
|
||||
kubernetes:
|
||||
serviceLocatorMethod:
|
||||
type: 'multiTenant'
|
||||
clusterLocatorMethods:
|
||||
- $include: k8s-config.yaml
|
||||
argocd:
|
||||
username: admin
|
||||
password: ${ARGOCD_ADMIN_PASSWORD}
|
||||
appLocatorMethods:
|
||||
- type: 'config'
|
||||
instances:
|
||||
- name: in-cluster
|
||||
url: https://cnoe.localtest.me:8443/argocd
|
||||
username: admin
|
||||
password: ${ARGOCD_ADMIN_PASSWORD}
|
||||
argoWorkflows:
|
||||
baseUrl: ${ARGO_WORKFLOWS_URL}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: k8s-config
|
||||
namespace: backstage
|
||||
stringData:
|
||||
k8s-config.yaml: "type: 'config'\nclusters:\n - url: https://kubernetes.default.svc.cluster.local\n
|
||||
\ name: local\n authProvider: 'serviceAccount'\n skipTLSVerify: true\n
|
||||
\ skipMetricsLookup: true\n serviceAccountToken: \n $file: /var/run/secrets/kubernetes.io/serviceaccount/token\n
|
||||
\ caData: \n $file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: backstage
|
||||
namespace: backstage
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 7007
|
||||
targetPort: http
|
||||
selector:
|
||||
app: backstage
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: postgresql
|
||||
name: postgresql
|
||||
namespace: backstage
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: postgres
|
||||
port: 5432
|
||||
selector:
|
||||
app: postgresql
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: backstage
|
||||
namespace: backstage
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "20"
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: backstage
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: backstage
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- node
|
||||
- packages/backend
|
||||
- --config
|
||||
- config/app-config.yaml
|
||||
env:
|
||||
- name: LOG_LEVEL
|
||||
value: debug
|
||||
- name: NODE_TLS_REJECT_UNAUTHORIZED
|
||||
value: "0"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: backstage-env-vars
|
||||
- secretRef:
|
||||
name: gitea-credentials
|
||||
- secretRef:
|
||||
name: argocd-credentials
|
||||
image: ghcr.io/cnoe-io/backstage-app:135c0cb26f3e004a27a11edb6a4779035aff9805
|
||||
name: backstage
|
||||
ports:
|
||||
- containerPort: 7007
|
||||
name: http
|
||||
volumeMounts:
|
||||
- mountPath: /app/config
|
||||
name: backstage-config
|
||||
readOnly: true
|
||||
serviceAccountName: backstage
|
||||
volumes:
|
||||
- name: backstage-config
|
||||
projected:
|
||||
sources:
|
||||
- configMap:
|
||||
items:
|
||||
- key: app-config.yaml
|
||||
path: app-config.yaml
|
||||
name: backstage-config
|
||||
- secret:
|
||||
items:
|
||||
- key: k8s-config.yaml
|
||||
path: k8s-config.yaml
|
||||
name: k8s-config
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
labels:
|
||||
app: postgresql
|
||||
name: postgresql
|
||||
namespace: backstage
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "10"
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: postgresql
|
||||
serviceName: service-postgresql
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: postgresql
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: POSTGRES_DB
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: backstage-env-vars
|
||||
key: POSTGRES_DB
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: backstage-env-vars
|
||||
key: POSTGRES_USER
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: backstage-env-vars
|
||||
key: POSTGRES_PASSWORD
|
||||
image: docker.io/library/postgres:15.3-alpine3.18
|
||||
name: postgres
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgresdb
|
||||
resources:
|
||||
limits:
|
||||
memory: 500Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 300Mi
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: "500Mi"
|
||||
---
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: Password
|
||||
metadata:
|
||||
name: backstage
|
||||
namespace: backstage
|
||||
spec:
|
||||
length: 36
|
||||
digits: 5
|
||||
symbols: 5
|
||||
symbolCharacters: "/-+"
|
||||
noUpper: false
|
||||
allowRepeat: true
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: backstage-oidc
|
||||
namespace: backstage
|
||||
spec:
|
||||
secretStoreRef:
|
||||
name: keycloak
|
||||
kind: ClusterSecretStore
|
||||
refreshInterval: "0"
|
||||
target:
|
||||
name: backstage-env-vars
|
||||
template:
|
||||
engineVersion: v2
|
||||
data:
|
||||
BACKSTAGE_FRONTEND_URL: https://cnoe.localtest.me:8443/backstage
|
||||
POSTGRES_HOST: postgresql.backstage.svc.cluster.local
|
||||
POSTGRES_PORT: '5432'
|
||||
POSTGRES_DB: backstage
|
||||
POSTGRES_USER: backstage
|
||||
POSTGRES_PASSWORD: "{{.POSTGRES_PASSWORD}}"
|
||||
ARGO_WORKFLOWS_URL: https://cnoe.localtest.me:8443/argo-workflows
|
||||
KEYCLOAK_NAME_METADATA: https://cnoe.localtest.me:8443/keycloak/realms/cnoe/.well-known/openid-configuration
|
||||
KEYCLOAK_CLIENT_SECRET: "{{.BACKSTAGE_CLIENT_SECRET}}"
|
||||
ARGOCD_AUTH_TOKEN: "argocd.token={{.ARGOCD_SESSION_TOKEN}}"
|
||||
ARGO_CD_URL: 'https://argocd-server.argocd.svc.cluster.local/api/v1/'
|
||||
data:
|
||||
- secretKey: ARGOCD_SESSION_TOKEN
|
||||
remoteRef:
|
||||
key: keycloak-clients
|
||||
property: ARGOCD_SESSION_TOKEN
|
||||
- secretKey: BACKSTAGE_CLIENT_SECRET
|
||||
remoteRef:
|
||||
key: keycloak-clients
|
||||
property: BACKSTAGE_CLIENT_SECRET
|
||||
dataFrom:
|
||||
- sourceRef:
|
||||
generatorRef:
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: Password
|
||||
name: backstage
|
||||
rewrite:
|
||||
- transform:
|
||||
template: "POSTGRES_PASSWORD"
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: gitea-credentials
|
||||
namespace: backstage
|
||||
spec:
|
||||
secretStoreRef:
|
||||
name: gitea
|
||||
kind: ClusterSecretStore
|
||||
refreshInterval: "0"
|
||||
target:
|
||||
name: gitea-credentials
|
||||
data:
|
||||
- secretKey: GITEA_USERNAME
|
||||
remoteRef:
|
||||
key: gitea-credential
|
||||
property: username
|
||||
- secretKey: GITEA_PASSWORD
|
||||
remoteRef:
|
||||
key: gitea-credential
|
||||
property: password
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: backstage
|
||||
namespace: backstage
|
||||
spec:
|
||||
ingressClassName: "nginx"
|
||||
rules:
|
||||
- host: localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: backstage
|
||||
port:
|
||||
name: http
|
||||
- host: cnoe.localtest.me
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: backstage
|
||||
port:
|
||||
name: http
|
||||
64
cicd/backstage/manifests/job.yaml
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: gitea-token
|
||||
namespace: backstage
|
||||
annotations:
|
||||
argocd.argoproj.io/hook: PostSync
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
generateName: gitea-token
|
||||
spec:
|
||||
serviceAccountName: backstage
|
||||
restartPolicy: Never
|
||||
volumes:
|
||||
- name: k8s-config
|
||||
secret:
|
||||
secretName: k8s-config
|
||||
containers:
|
||||
- name: kubectl
|
||||
image: alpine/k8s:1.31.0
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: gitea-credentials
|
||||
volumeMounts:
|
||||
- name: k8s-config
|
||||
readOnly: true
|
||||
mountPath: "/.kube/"
|
||||
command: ["/bin/bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
#! /bin/bash
|
||||
|
||||
apt -qq update && apt -qq install curl jq -y
|
||||
|
||||
GITEA_URL=http://my-gitea-http.gitea.svc.cluster.local:3000
|
||||
GITEA_TOKENS_URL="${GITEA_URL}/api/v1/users/giteaAdmin/tokens"
|
||||
|
||||
TOKENS_COUNT=$(curl -k -s -X 'GET' "${GITEA_TOKENS_URL}" -H "accept: application/json" -H "Content-Type: application/json" -u $GITEA_USERNAME:$GITEA_PASSWORD | jq '. | length')
|
||||
|
||||
curl -sS -LO "https://dl.k8s.io/release/v1.31.0/bin/linux/amd64/kubectl"
|
||||
chmod +x kubectl
|
||||
|
||||
if [ ${TOKENS_COUNT} -eq 0 ]; then
|
||||
echo "No tokens found, creating token and k8s secret"
|
||||
NEW_TOKEN=$(curl -k -X POST "${GITEA_TOKENS_URL}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name": "token1", "scopes": ["write:repository", "read:issue", "read:organization", "read:misc"]}' \
|
||||
-u $GITEA_USERNAME:$GITEA_PASSWORD | jq -r '.sha1')
|
||||
TOKEN=$(echo -n $NEW_TOKEN | base64)
|
||||
echo \
|
||||
"apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-token
|
||||
namespace: gitea
|
||||
type: Opaque
|
||||
data:
|
||||
token: ${TOKEN}
|
||||
" > /tmp/gitea_secret.yaml
|
||||
./kubectl apply -f /tmp/gitea_secret.yaml
|
||||
else
|
||||
echo "$TOKENS_COUNT tokens found, skipping secret creation"
|
||||
fi
|
||||
12
cicd/backstage/manifests/role.yaml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: backstage-cluster-admin
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: backstage
|
||||
namespace: backstage
|
||||
73
cicd/codespaces.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
## Running idpbuilder in Codespaces in Browser
|
||||
|
||||
**_NOTE:_**: __Steps described below applies to running this implementation in Codespaces in **web browsers** (e.g. Firefox and Chrome).
|
||||
If you are using Codespaces with GitHub CLI, steps described here do not apply to you.__
|
||||
|
||||
|
||||
Let's create an instance of Codespaces.
|
||||
|
||||

|
||||
|
||||
It may take a few minutes for it to be ready. Once it's ready, you can either get the latest release of idpbuilder or build from the main branch.
|
||||
Build the idpbuilder binary.
|
||||
|
||||
|
||||
- Get the latest release:
|
||||
```bash
|
||||
version=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/cnoe-io/idpbuilder/releases/latest)
|
||||
version=${version##*/}
|
||||
wget https://github.com/cnoe-io/idpbuilder/releases/download/${version}/idpbuilder-linux-amd64.tar.gz
|
||||
tar xzf idpbuilder-linux-amd64.tar.gz
|
||||
sudo mv ./idpbuilder /usr/local/bin/
|
||||
```
|
||||
- Alternatively, build from the main branch
|
||||
```bash
|
||||
make build
|
||||
sudo mv ./idpbuilder /usr/local/bin/
|
||||
```
|
||||
|
||||
Codespaces assigns random hostname to your specific instance. You need to make sure they are reflected correctly.
|
||||
Instance host name is available as an environment variable (`CODESPACE_NAME`). Let's use it to setup our host names.
|
||||
Run the following commands to update host name and ports. Port is set to 443 because this is the port used by the browser to access your instance.
|
||||
|
||||
Clone the [stacks](https://github.com/cnoe-io/stacks) repo.
|
||||
|
||||
|
||||
```bash
|
||||
cd ref-implementation
|
||||
|
||||
./replace.sh ${CODESPACE_NAME}-8080.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN} 443
|
||||
|
||||
cd -
|
||||
```
|
||||
|
||||
Now you are ready to run idpbuilder with reference implementation.
|
||||
|
||||
```bash
|
||||
idpbuilder create --protocol http \
|
||||
--host ${CODESPACE_NAME}-8080.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN} \
|
||||
--port 8080 --use-path-routing --package ref-implementation
|
||||
```
|
||||
Once idpbuilder finishes bootstrapping, you should have port 8080 forward in the port tab within Codespaces.
|
||||
|
||||

|
||||
|
||||
You may get a 404 page after clicking the port 8080 forwarded address. This is completely normal because Backstage may not be ready yet.
|
||||
Give it a few more minutes and it should redirect you to a Backstage page.
|
||||
|
||||
### Accessing UIs
|
||||
|
||||
If you'd like to track progress of deployment, go to `/argocd` path and login with your ArgoCD credentials.
|
||||
For example run this command to get the URL for Argo CD:
|
||||
```bash
|
||||
echo https://${CODESPACE_NAME}-8080.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}/argocd
|
||||
```
|
||||
|
||||
From here on, you can follow the instructions in the [README](./README.md) file. The only difference is that the URL to access UIs is given by:
|
||||
|
||||
```echo
|
||||
echo https://${CODESPACE_NAME}-8080.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}
|
||||
```
|
||||
|
||||
For example, if you need to access Argo Workflows UI, instead of going to `https://cnoe.localtest.me:8443/argo`,
|
||||
you go to `https://${CODESPACE_NAME}-8080.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}/argo`
|
||||
23
cicd/external-secrets.yaml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: external-secrets
|
||||
namespace: argocd
|
||||
labels:
|
||||
env: dev
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
destination:
|
||||
namespace: external-secrets
|
||||
server: "https://kubernetes.default.svc"
|
||||
source:
|
||||
repoURL: cnoe://external-secrets/manifests
|
||||
targetRevision: HEAD
|
||||
path: "."
|
||||
project: default
|
||||
syncPolicy:
|
||||
automated:
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
12
cicd/external-secrets/generate-manifests.sh
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
INSTALL_YAML="manifests/install.yaml"
|
||||
CHART_VERSION="0.9.11"
|
||||
|
||||
echo "# EXTERNAL SECRETS INSTALL RESOURCES" >${INSTALL_YAML}
|
||||
echo "# This file is auto-generated with 'ref-impelmentation/external-secrets/generate-manifests.sh'" >>${INSTALL_YAML}
|
||||
|
||||
helm repo add external-secrets --force-update https://charts.external-secrets.io
|
||||
helm repo update
|
||||
helm template --namespace external-secrets external-secrets external-secrets/external-secrets -f values.yaml --version ${CHART_VERSION} >>${INSTALL_YAML}
|
||||
9277
cicd/external-secrets/manifests/install.yaml
Normal file
0
cicd/external-secrets/values.yaml
Normal file
45
cicd/get-credentials.sh
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
#!/bin/bash
|
||||
# Execute the idpbuilder command and store the output in a variable
|
||||
output=$(idpbuilder get secrets)
|
||||
# Extract the ArgoCD password using grep and awk
|
||||
argocd_password=$(echo "$output" | grep -A 3 "argocd-initial-admin-secret" | grep "password" | awk '{print $3}')
|
||||
gitea_password=$(echo "$output" | grep -A 3 "gitea-credential" | grep "password" | awk '{print $3}')
|
||||
keycloak_password=$(echo "$output" | grep -A 9 "keycloak-config" | grep "USER_PASSWORD" | awk '{print $3}')
|
||||
# Create the credentials.txt file with the required ArgoCD details
|
||||
cat <<EOF > ~/environment/credentials.txt
|
||||
ArgoCD
|
||||
URL : https://${IDE_DOMAIN}/argocd
|
||||
Username: admin
|
||||
Password: ${argocd_password}
|
||||
ArgoWorkflows
|
||||
URL: https://${IDE_DOMAIN}/argo-workflows
|
||||
Username: user1
|
||||
Password: ${keycloak_password}
|
||||
BackStage
|
||||
URL: https://${IDE_DOMAIN}/
|
||||
Username: user1
|
||||
Password: ${keycloak_password}
|
||||
Gitea
|
||||
URL: https://${IDE_DOMAIN}/gitea
|
||||
Username: giteaAdmin
|
||||
Password: ${gitea_password}
|
||||
EOF
|
||||
|
||||
echo "credentials.txt file created with ArgoCD details."
|
||||
|
||||
# Hack : Removing internal svc resolution for backstage
|
||||
kubectl patch configmap coredns-conf-default --patch '{"data":{"default.conf":""}}' -n kube-system
|
||||
|
||||
# Setting up gitconfig
|
||||
git config --global user.name "CNOE"
|
||||
git config --global user.email "cnoe@io"
|
||||
|
||||
GITEA_PAT=$(kubectl get secret gitea-token -n gitea -o jsonpath='{.data.token}' | base64 -d)
|
||||
GIT_CREDS="$HOME/.git-credentials"
|
||||
cat > $GIT_CREDS << EOT
|
||||
https://giteaAdmin:${GITEA_PAT}@${IDE_DOMAIN}/gitea
|
||||
EOT
|
||||
|
||||
git config --global credential.helper 'store'
|
||||
|
||||
echo "Git config update completed."
|
||||
BIN
cicd/images/backstage-templates-spark.png
Normal file
|
After Width: | Height: | Size: 437 KiB |
BIN
cicd/images/backstage-templates.png
Normal file
|
After Width: | Height: | Size: 436 KiB |
BIN
cicd/images/basic-deployment.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
cicd/images/basic-template-flow.png
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
cicd/images/codespaces-create.png
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
cicd/images/demo-entity.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
cicd/images/demo2-entity.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
BIN
cicd/images/port.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
688
cicd/images/src/basic-deployment.excalidraw
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
{
|
||||
"type": "excalidraw",
|
||||
"version": 2,
|
||||
"source": "https://excalidraw.com",
|
||||
"elements": [
|
||||
{
|
||||
"id": "yozZorioSE1OUkpHktzVP",
|
||||
"type": "rectangle",
|
||||
"x": 727,
|
||||
"y": 454,
|
||||
"width": 138,
|
||||
"height": 68.00000000000001,
|
||||
"angle": 0,
|
||||
"strokeColor": "#e03131",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 1193746031,
|
||||
"version": 164,
|
||||
"versionNonce": 917424207,
|
||||
"isDeleted": false,
|
||||
"boundElements": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "Qn0U1j1w19_hNzfHMrEHQ"
|
||||
},
|
||||
{
|
||||
"id": "Um8DNgdEeXUjERYx_0rtv",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "qJj5wVYIiRzV91y3h6Xbi",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "cE_ucOKJBcWQXtcgaSoPF",
|
||||
"type": "arrow"
|
||||
}
|
||||
],
|
||||
"updated": 1707246661988,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "Qn0U1j1w19_hNzfHMrEHQ",
|
||||
"type": "text",
|
||||
"x": 760.3499984741211,
|
||||
"y": 475.5,
|
||||
"width": 71.30000305175781,
|
||||
"height": 25,
|
||||
"angle": 0,
|
||||
"strokeColor": "#e03131",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": null,
|
||||
"seed": 1937750799,
|
||||
"version": 157,
|
||||
"versionNonce": 397238721,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1707246500158,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"text": "ArgoCD",
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"baseline": 18,
|
||||
"containerId": "yozZorioSE1OUkpHktzVP",
|
||||
"originalText": "ArgoCD",
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 183,
|
||||
"versionNonce": 512282671,
|
||||
"isDeleted": false,
|
||||
"id": "z1vPsJxFaPRhe0i1Ck0Je",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 418,
|
||||
"y": 351,
|
||||
"strokeColor": "#f08c00",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 138,
|
||||
"height": 68.00000000000001,
|
||||
"seed": 1492127791,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"boundElements": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "DyaGAvMwuxh_cnuhL8d3P"
|
||||
},
|
||||
{
|
||||
"id": "ahkUXt0AQa8URVqUCdwu5",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "Um8DNgdEeXUjERYx_0rtv",
|
||||
"type": "arrow"
|
||||
}
|
||||
],
|
||||
"updated": 1707246694929,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 186,
|
||||
"versionNonce": 1954345551,
|
||||
"isDeleted": false,
|
||||
"id": "DyaGAvMwuxh_cnuhL8d3P",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 434.9583320617676,
|
||||
"y": 372.5,
|
||||
"strokeColor": "#f08c00",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 104.08333587646484,
|
||||
"height": 25,
|
||||
"seed": 1610363471,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": null,
|
||||
"boundElements": [],
|
||||
"updated": 1707246694929,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Backstage",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "z1vPsJxFaPRhe0i1Ck0Je",
|
||||
"originalText": "Backstage",
|
||||
"lineHeight": 1.25,
|
||||
"baseline": 18
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 205,
|
||||
"versionNonce": 1736977089,
|
||||
"isDeleted": false,
|
||||
"id": "hKolk3HE8f7p7kku0fuAR",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 722,
|
||||
"y": 251,
|
||||
"strokeColor": "#2f9e44",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 138,
|
||||
"height": 68.00000000000001,
|
||||
"seed": 1171434639,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"boundElements": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "DpYp_SU3PTt5pGMJEYXeQ"
|
||||
},
|
||||
{
|
||||
"id": "ahkUXt0AQa8URVqUCdwu5",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "cE_ucOKJBcWQXtcgaSoPF",
|
||||
"type": "arrow"
|
||||
}
|
||||
],
|
||||
"updated": 1707246657028,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 212,
|
||||
"versionNonce": 420957761,
|
||||
"isDeleted": false,
|
||||
"id": "DpYp_SU3PTt5pGMJEYXeQ",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 763.1333332061768,
|
||||
"y": 272.5,
|
||||
"strokeColor": "#2f9e44",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 55.733333587646484,
|
||||
"height": 25,
|
||||
"seed": 1661747887,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": null,
|
||||
"boundElements": [],
|
||||
"updated": 1707246497718,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Gitea",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "hKolk3HE8f7p7kku0fuAR",
|
||||
"originalText": "Gitea",
|
||||
"lineHeight": 1.25,
|
||||
"baseline": 18
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 192,
|
||||
"versionNonce": 567119311,
|
||||
"isDeleted": false,
|
||||
"id": "A_LZS0mn561UWD01SaaNw",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 932,
|
||||
"y": 353,
|
||||
"strokeColor": "#9c36b5",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 138,
|
||||
"height": 68.00000000000001,
|
||||
"seed": 639538113,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"boundElements": [
|
||||
{
|
||||
"type": "text",
|
||||
"id": "pFG3mG67d8W-gP9a7l27j"
|
||||
},
|
||||
{
|
||||
"id": "qJj5wVYIiRzV91y3h6Xbi",
|
||||
"type": "arrow"
|
||||
}
|
||||
],
|
||||
"updated": 1707246620246,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 210,
|
||||
"versionNonce": 1183409057,
|
||||
"isDeleted": false,
|
||||
"id": "pFG3mG67d8W-gP9a7l27j",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 947.6500015258789,
|
||||
"y": 374.5,
|
||||
"strokeColor": "#9c36b5",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 106.69999694824219,
|
||||
"height": 25,
|
||||
"seed": 1601729441,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": null,
|
||||
"boundElements": [],
|
||||
"updated": 1707246498719,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Kubernetes",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "A_LZS0mn561UWD01SaaNw",
|
||||
"originalText": "Kubernetes",
|
||||
"lineHeight": 1.25,
|
||||
"baseline": 18
|
||||
},
|
||||
{
|
||||
"id": "ahkUXt0AQa8URVqUCdwu5",
|
||||
"type": "arrow",
|
||||
"x": 561,
|
||||
"y": 389.03022718221666,
|
||||
"width": 154,
|
||||
"height": 102.11103654737104,
|
||||
"angle": 0,
|
||||
"strokeColor": "#f08c00",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": {
|
||||
"type": 2
|
||||
},
|
||||
"seed": 1646169281,
|
||||
"version": 238,
|
||||
"versionNonce": 1284654255,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1707246701910,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
81,
|
||||
-32.03022718221666
|
||||
],
|
||||
[
|
||||
154,
|
||||
-102.11103654737104
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "z1vPsJxFaPRhe0i1Ck0Je",
|
||||
"focus": 0.5432390553840177,
|
||||
"gap": 5
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "hKolk3HE8f7p7kku0fuAR",
|
||||
"focus": 0.7087101937049524,
|
||||
"gap": 7
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
},
|
||||
{
|
||||
"type": "arrow",
|
||||
"version": 337,
|
||||
"versionNonce": 2107204335,
|
||||
"isDeleted": false,
|
||||
"id": "Um8DNgdEeXUjERYx_0rtv",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 565.0411501895638,
|
||||
"y": 389.1698221307173,
|
||||
"strokeColor": "#f08c00",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 153.9999999999999,
|
||||
"height": 103.34207184944046,
|
||||
"seed": 1365398817,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": {
|
||||
"type": 2
|
||||
},
|
||||
"boundElements": [],
|
||||
"updated": 1707246699212,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"startBinding": {
|
||||
"elementId": "z1vPsJxFaPRhe0i1Ck0Je",
|
||||
"focus": -0.45382037830581345,
|
||||
"gap": 9.041150189563837
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "yozZorioSE1OUkpHktzVP",
|
||||
"focus": -0.8066378321183331,
|
||||
"gap": 7.958849810436277
|
||||
},
|
||||
"lastCommittedPoint": null,
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow",
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
94.95884981043616,
|
||||
39.83017786928269
|
||||
],
|
||||
[
|
||||
153.9999999999999,
|
||||
103.34207184944046
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "XAiE7TdBFNjm7rN5XwJO2",
|
||||
"type": "text",
|
||||
"x": 508,
|
||||
"y": 297,
|
||||
"width": 164.89999389648438,
|
||||
"height": 25,
|
||||
"angle": 0,
|
||||
"strokeColor": "#f08c00",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": null,
|
||||
"seed": 1475743759,
|
||||
"version": 54,
|
||||
"versionNonce": 201561807,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1707246643630,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"text": "Create Git Repo",
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"textAlign": "left",
|
||||
"verticalAlign": "top",
|
||||
"baseline": 18,
|
||||
"containerId": null,
|
||||
"originalText": "Create Git Repo",
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "Wtfg9wiBcJ8qgM5sJ1Rgy",
|
||||
"type": "text",
|
||||
"x": 522,
|
||||
"y": 444,
|
||||
"width": 159.28334045410156,
|
||||
"height": 50,
|
||||
"angle": 0,
|
||||
"strokeColor": "#f08c00",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": null,
|
||||
"seed": 1002133263,
|
||||
"version": 60,
|
||||
"versionNonce": 1766483329,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1707246645667,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"text": "Create ArgoCD \nApplication",
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"textAlign": "left",
|
||||
"verticalAlign": "top",
|
||||
"baseline": 43,
|
||||
"containerId": null,
|
||||
"originalText": "Create ArgoCD \nApplication",
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "qJj5wVYIiRzV91y3h6Xbi",
|
||||
"type": "arrow",
|
||||
"x": 873,
|
||||
"y": 489,
|
||||
"width": 114,
|
||||
"height": 66,
|
||||
"angle": 0,
|
||||
"strokeColor": "#e03131",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": {
|
||||
"type": 2
|
||||
},
|
||||
"seed": 630215073,
|
||||
"version": 118,
|
||||
"versionNonce": 1585297729,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1707246649748,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
78,
|
||||
-6
|
||||
],
|
||||
[
|
||||
114,
|
||||
-66
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "yozZorioSE1OUkpHktzVP",
|
||||
"focus": 0.17612524461839527,
|
||||
"gap": 8
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "A_LZS0mn561UWD01SaaNw",
|
||||
"focus": -0.08501118568232663,
|
||||
"gap": 2
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "cE_ucOKJBcWQXtcgaSoPF",
|
||||
"type": "arrow",
|
||||
"x": 794,
|
||||
"y": 449,
|
||||
"width": 2,
|
||||
"height": 127,
|
||||
"angle": 0,
|
||||
"strokeColor": "#e03131",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": {
|
||||
"type": 2
|
||||
},
|
||||
"seed": 1514085633,
|
||||
"version": 138,
|
||||
"versionNonce": 842839791,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1707246662294,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
2,
|
||||
-127
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "yozZorioSE1OUkpHktzVP",
|
||||
"focus": -0.037594836371871804,
|
||||
"gap": 5
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "hKolk3HE8f7p7kku0fuAR",
|
||||
"focus": -0.08028535839655757,
|
||||
"gap": 3
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "8nULB38EPuEIAjdNdyYp0",
|
||||
"type": "text",
|
||||
"x": 991,
|
||||
"y": 479,
|
||||
"width": 62.13333511352539,
|
||||
"height": 25,
|
||||
"angle": 0,
|
||||
"strokeColor": "#e03131",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": null,
|
||||
"seed": 1148815169,
|
||||
"version": 7,
|
||||
"versionNonce": 1706607119,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1707246674659,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"text": "Deploy",
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"textAlign": "left",
|
||||
"verticalAlign": "top",
|
||||
"baseline": 18,
|
||||
"containerId": null,
|
||||
"originalText": "Deploy",
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "dxtUjQKSuIlFaCv7spFWr",
|
||||
"type": "text",
|
||||
"x": 809,
|
||||
"y": 377,
|
||||
"width": 35.11666488647461,
|
||||
"height": 25,
|
||||
"angle": 0,
|
||||
"strokeColor": "#e03131",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"roundness": null,
|
||||
"seed": 393005647,
|
||||
"version": 29,
|
||||
"versionNonce": 1356449295,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1707246685968,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"text": "Pull",
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"textAlign": "left",
|
||||
"verticalAlign": "top",
|
||||
"baseline": 18,
|
||||
"containerId": null,
|
||||
"originalText": "Pull",
|
||||
"lineHeight": 1.25
|
||||
}
|
||||
],
|
||||
"appState": {
|
||||
"gridSize": null,
|
||||
"viewBackgroundColor": "#ffffff"
|
||||
},
|
||||
"files": {}
|
||||
}
|
||||
21
cicd/keycloak.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: keycloak
|
||||
namespace: argocd
|
||||
labels:
|
||||
example: ref-implementation
|
||||
spec:
|
||||
destination:
|
||||
namespace: keycloak
|
||||
server: "https://kubernetes.default.svc"
|
||||
source:
|
||||
repoURL: cnoe://keycloak/manifests
|
||||
targetRevision: HEAD
|
||||
path: "."
|
||||
project: default
|
||||
syncPolicy:
|
||||
automated:
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
30
cicd/keycloak/manifests/ingress.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: keycloak-ingress-localhost
|
||||
namespace: keycloak
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "100"
|
||||
spec:
|
||||
ingressClassName: "nginx"
|
||||
rules:
|
||||
- host: localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /keycloak
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: keycloak
|
||||
port:
|
||||
name: http
|
||||
- host: cnoe.localtest.me
|
||||
http:
|
||||
paths:
|
||||
- path: /keycloak
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: keycloak
|
||||
port:
|
||||
name: http
|
||||
164
cicd/keycloak/manifests/install.yaml
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: keycloak
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: keycloak
|
||||
labels:
|
||||
app: keycloak
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: keycloak
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: keycloak
|
||||
name: keycloak
|
||||
namespace: keycloak
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "10"
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: keycloak
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: keycloak
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- start-dev
|
||||
env:
|
||||
- name: KEYCLOAK_ADMIN
|
||||
value: cnoe-admin
|
||||
- name: KEYCLOAK_LOGLEVEL
|
||||
value: ALL
|
||||
- name: QUARKUS_TRANSACTION_MANAGER_ENABLE_RECOVERY
|
||||
value: 'true'
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: keycloak-config
|
||||
image: quay.io/keycloak/keycloak:22.0.3
|
||||
name: keycloak
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /keycloak/realms/master
|
||||
port: 8080
|
||||
volumeMounts:
|
||||
- mountPath: /opt/keycloak/conf
|
||||
name: keycloak-config
|
||||
readOnly: true
|
||||
volumes:
|
||||
- configMap:
|
||||
name: keycloak-config
|
||||
name: keycloak-config
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
keycloak.conf: |
|
||||
# Database
|
||||
# The database vendor.
|
||||
db=postgres
|
||||
|
||||
# The username of the database user.
|
||||
db-url=jdbc:postgresql://postgresql.keycloak.svc.cluster.local:5432/postgres
|
||||
|
||||
# The proxy address forwarding mode if the server is behind a reverse proxy.
|
||||
proxy=edge
|
||||
|
||||
# hostname configuration
|
||||
hostname=cnoe.localtest.me
|
||||
hostname-port=8443
|
||||
http-relative-path=keycloak
|
||||
|
||||
# the admin url requires its own configuration to reflect correct url
|
||||
hostname-admin=cnoe.localtest.me:8443
|
||||
|
||||
hostname-debug=true
|
||||
|
||||
# this should only be allowed in development. NEVER in production.
|
||||
hostname-strict=false
|
||||
hostname-strict-backchannel=false
|
||||
|
||||
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: keycloak-config
|
||||
namespace: keycloak
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: postgresql
|
||||
name: postgresql
|
||||
namespace: keycloak
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: postgres
|
||||
port: 5432
|
||||
selector:
|
||||
app: postgresql
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
labels:
|
||||
app: postgresql
|
||||
name: postgresql
|
||||
namespace: keycloak
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: postgresql
|
||||
serviceName: service-postgresql
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: postgresql
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- secretRef:
|
||||
name: keycloak-config
|
||||
image: docker.io/library/postgres:15.3-alpine3.18
|
||||
name: postgres
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgresdb
|
||||
resources:
|
||||
limits:
|
||||
memory: 500Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 300Mi
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: "500Mi"
|
||||
|
||||
366
cicd/keycloak/manifests/keycloak-config.yaml
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
# resources here are used to configure keycloak instance for SSO
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: keycloak-config
|
||||
namespace: keycloak
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: keycloak-config
|
||||
namespace: keycloak
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get", "create", "update", "patch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: keycloak-config
|
||||
namespace: keycloak
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: keycloak-config
|
||||
namespace: keycloak
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: keycloak-config
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: keycloak-config
|
||||
namespace: argocd
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: keycloak-config
|
||||
namespace: argocd
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: keycloak-config
|
||||
namespace: keycloak
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: keycloak-config
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: config-job
|
||||
namespace: keycloak
|
||||
data:
|
||||
client-scope-groups-payload.json: |
|
||||
{
|
||||
"name": "groups",
|
||||
"description": "groups a user belongs to",
|
||||
"attributes": {
|
||||
"consent.screen.text": "Access to groups a user belongs to.",
|
||||
"display.on.consent.screen": "true",
|
||||
"include.in.token.scope": "true",
|
||||
"gui.order": ""
|
||||
},
|
||||
"type": "default",
|
||||
"protocol": "openid-connect"
|
||||
}
|
||||
group-admin-payload.json: |
|
||||
{"name":"admin"}
|
||||
group-base-user-payload.json: |
|
||||
{"name":"base-user"}
|
||||
group-mapper-payload.json: |
|
||||
{
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-group-membership-mapper",
|
||||
"name": "groups",
|
||||
"config": {
|
||||
"claim.name": "groups",
|
||||
"full.path": "false",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
}
|
||||
realm-payload.json: |
|
||||
{"realm":"cnoe","enabled":true}
|
||||
user-password.json: |
|
||||
{
|
||||
"temporary": false,
|
||||
"type": "password",
|
||||
"value": "${USER1_PASSWORD}"
|
||||
}
|
||||
user-user1.json: |
|
||||
{
|
||||
"username": "user1",
|
||||
"email": "",
|
||||
"firstName": "user",
|
||||
"lastName": "one",
|
||||
"requiredActions": [],
|
||||
"emailVerified": false,
|
||||
"groups": [
|
||||
"/admin"
|
||||
],
|
||||
"enabled": true
|
||||
}
|
||||
user-user2.json: |
|
||||
{
|
||||
"username": "user2",
|
||||
"email": "",
|
||||
"firstName": "user",
|
||||
"lastName": "two",
|
||||
"requiredActions": [],
|
||||
"emailVerified": false,
|
||||
"groups": [
|
||||
"/base-user"
|
||||
],
|
||||
"enabled": true
|
||||
}
|
||||
argo-client-payload.json: |
|
||||
{
|
||||
"protocol": "openid-connect",
|
||||
"clientId": "argo-workflows",
|
||||
"name": "Argo Workflows Client",
|
||||
"description": "Used for Argo Workflows SSO",
|
||||
"publicClient": false,
|
||||
"authorizationServicesEnabled": false,
|
||||
"serviceAccountsEnabled": false,
|
||||
"implicitFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": true,
|
||||
"standardFlowEnabled": true,
|
||||
"frontchannelLogout": true,
|
||||
"attributes": {
|
||||
"saml_idp_initiated_sso_url_name": "",
|
||||
"oauth2.device.authorization.grant.enabled": false,
|
||||
"oidc.ciba.grant.enabled": false
|
||||
},
|
||||
"alwaysDisplayInConsole": false,
|
||||
"rootUrl": "",
|
||||
"baseUrl": "",
|
||||
"redirectUris": [
|
||||
"https://cnoe.localtest.me:8443/argo-workflows/oauth2/callback"
|
||||
],
|
||||
"webOrigins": [
|
||||
"/*"
|
||||
]
|
||||
}
|
||||
|
||||
backstage-client-payload.json: |
|
||||
{
|
||||
"protocol": "openid-connect",
|
||||
"clientId": "backstage",
|
||||
"name": "Backstage Client",
|
||||
"description": "Used for Backstage SSO",
|
||||
"publicClient": false,
|
||||
"authorizationServicesEnabled": false,
|
||||
"serviceAccountsEnabled": false,
|
||||
"implicitFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": true,
|
||||
"standardFlowEnabled": true,
|
||||
"frontchannelLogout": true,
|
||||
"attributes": {
|
||||
"saml_idp_initiated_sso_url_name": "",
|
||||
"oauth2.device.authorization.grant.enabled": false,
|
||||
"oidc.ciba.grant.enabled": false
|
||||
},
|
||||
"alwaysDisplayInConsole": false,
|
||||
"rootUrl": "",
|
||||
"baseUrl": "",
|
||||
"redirectUris": [
|
||||
"https://cnoe.localtest.me:8443/api/auth/keycloak-oidc/handler/frame"
|
||||
],
|
||||
"webOrigins": [
|
||||
"/*"
|
||||
]
|
||||
}
|
||||
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: config
|
||||
namespace: keycloak
|
||||
annotations:
|
||||
argocd.argoproj.io/hook: PostSync
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
generateName: config
|
||||
spec:
|
||||
serviceAccountName: keycloak-config
|
||||
restartPolicy: Never
|
||||
volumes:
|
||||
- name: keycloak-config
|
||||
secret:
|
||||
secretName: keycloak-config
|
||||
- name: config-payloads
|
||||
configMap:
|
||||
name: config-job
|
||||
containers:
|
||||
- name: kubectl
|
||||
image: docker.io/library/ubuntu:22.04
|
||||
volumeMounts:
|
||||
- name: keycloak-config
|
||||
readOnly: true
|
||||
mountPath: "/var/secrets/"
|
||||
- name: config-payloads
|
||||
readOnly: true
|
||||
mountPath: "/var/config/"
|
||||
command: ["/bin/bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
#! /bin/bash
|
||||
|
||||
set -ex -o pipefail
|
||||
|
||||
apt -qq update && apt -qq install curl jq -y
|
||||
|
||||
ADMIN_PASSWORD=$(cat /var/secrets/KEYCLOAK_ADMIN_PASSWORD)
|
||||
USER1_PASSWORD=$(cat /var/secrets/USER_PASSWORD)
|
||||
|
||||
KEYCLOAK_URL=http://keycloak.keycloak.svc.cluster.local:8080/keycloak
|
||||
|
||||
KEYCLOAK_TOKEN=$(curl -sS --fail-with-body -X POST -H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "username=cnoe-admin" \
|
||||
--data-urlencode "password=${ADMIN_PASSWORD}" \
|
||||
--data-urlencode "grant_type=password" \
|
||||
--data-urlencode "client_id=admin-cli" \
|
||||
${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token | jq -e -r '.access_token')
|
||||
|
||||
set +e
|
||||
|
||||
curl --fail-with-body -H "Authorization: bearer ${KEYCLOAK_TOKEN}" "${KEYCLOAK_URL}/admin/realms/cnoe" &> /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
exit 0
|
||||
fi
|
||||
set -e
|
||||
|
||||
curl -sS -LO "https://dl.k8s.io/release/v1.28.3//bin/linux/amd64/kubectl"
|
||||
chmod +x kubectl
|
||||
|
||||
echo "creating cnoe realm and groups"
|
||||
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X POST --data @/var/config/realm-payload.json \
|
||||
${KEYCLOAK_URL}/admin/realms
|
||||
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X POST --data @/var/config/client-scope-groups-payload.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/client-scopes
|
||||
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X POST --data @/var/config/group-admin-payload.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/groups
|
||||
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X POST --data @/var/config/group-base-user-payload.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/groups
|
||||
|
||||
# Create scope mapper
|
||||
echo 'adding group claim to tokens'
|
||||
CLIENT_SCOPE_GROUPS_ID=$(curl -sS -H "Content-Type: application/json" -H "Authorization: bearer ${KEYCLOAK_TOKEN}" -X GET ${KEYCLOAK_URL}/admin/realms/cnoe/client-scopes | jq -e -r '.[] | select(.name == "groups") | .id')
|
||||
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X POST --data @/var/config/group-mapper-payload.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/client-scopes/${CLIENT_SCOPE_GROUPS_ID}/protocol-mappers/models
|
||||
|
||||
echo "creating test users"
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X POST --data @/var/config/user-user1.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/users
|
||||
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X POST --data @/var/config/user-user2.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/users
|
||||
|
||||
USER1ID=$(curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" "${KEYCLOAK_URL}/admin/realms/cnoe/users?lastName=one" | jq -r '.[0].id')
|
||||
USER2ID=$(curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" "${KEYCLOAK_URL}/admin/realms/cnoe/users?lastName=two" | jq -r '.[0].id')
|
||||
|
||||
echo "setting user passwords"
|
||||
jq -r --arg pass ${USER1_PASSWORD} '.value = $pass' /var/config/user-password.json > /tmp/user-password-to-be-applied.json
|
||||
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X PUT --data @/tmp/user-password-to-be-applied.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/users/${USER1ID}/reset-password
|
||||
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X PUT --data @/tmp/user-password-to-be-applied.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/users/${USER2ID}/reset-password
|
||||
|
||||
echo "creating Argo Workflows client"
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X POST --data @/var/config/argo-client-payload.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/clients
|
||||
|
||||
CLIENT_ID=$(curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X GET ${KEYCLOAK_URL}/admin/realms/cnoe/clients | jq -e -r '.[] | select(.clientId == "argo-workflows") | .id')
|
||||
CLIENT_SCOPE_GROUPS_ID=$(curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X GET ${KEYCLOAK_URL}/admin/realms/cnoe/client-scopes | jq -e -r '.[] | select(.name == "groups") | .id')
|
||||
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X PUT ${KEYCLOAK_URL}/admin/realms/cnoe/clients/${CLIENT_ID}/default-client-scopes/${CLIENT_SCOPE_GROUPS_ID}
|
||||
|
||||
ARGO_WORKFLOWS_CLIENT_SECRET=$(curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X GET ${KEYCLOAK_URL}/admin/realms/cnoe/clients/${CLIENT_ID} | jq -e -r '.secret')
|
||||
|
||||
echo "creating Backstage client"
|
||||
curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X POST --data @/var/config/backstage-client-payload.json \
|
||||
${KEYCLOAK_URL}/admin/realms/cnoe/clients
|
||||
|
||||
CLIENT_ID=$(curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X GET ${KEYCLOAK_URL}/admin/realms/cnoe/clients | jq -e -r '.[] | select(.clientId == "backstage") | .id')
|
||||
|
||||
CLIENT_SCOPE_GROUPS_ID=$(curl -sS -H "Content-Type: application/json" -H "Authorization: bearer ${KEYCLOAK_TOKEN}" -X GET ${KEYCLOAK_URL}/admin/realms/cnoe/client-scopes | jq -e -r '.[] | select(.name == "groups") | .id')
|
||||
curl -sS -H "Content-Type: application/json" -H "Authorization: bearer ${KEYCLOAK_TOKEN}" -X PUT ${KEYCLOAK_URL}/admin/realms/cnoe/clients/${CLIENT_ID}/default-client-scopes/${CLIENT_SCOPE_GROUPS_ID}
|
||||
|
||||
BACKSTAGE_CLIENT_SECRET=$(curl -sS -H "Content-Type: application/json" \
|
||||
-H "Authorization: bearer ${KEYCLOAK_TOKEN}" \
|
||||
-X GET ${KEYCLOAK_URL}/admin/realms/cnoe/clients/${CLIENT_ID} | jq -e -r '.secret')
|
||||
|
||||
ARGOCD_PASSWORD=$(./kubectl -n argocd get secret argocd-initial-admin-secret -o go-template='{{.data.password | base64decode }}')
|
||||
|
||||
ARGOCD_SESSION_TOKEN=$(curl -k -sS http://argocd-server.argocd.svc.cluster.local:443/api/v1/session -H 'Content-Type: application/json' -d "{\"username\":\"admin\",\"password\":\"${ARGOCD_PASSWORD}\"}" | jq -r .token)
|
||||
|
||||
echo \
|
||||
"apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: keycloak-clients
|
||||
namespace: keycloak
|
||||
type: Opaque
|
||||
stringData:
|
||||
ARGO_WORKFLOWS_CLIENT_SECRET: ${ARGO_WORKFLOWS_CLIENT_SECRET}
|
||||
ARGO_WORKFLOWS_CLIENT_ID: argo-workflows
|
||||
ARGOCD_SESSION_TOKEN: ${ARGOCD_SESSION_TOKEN}
|
||||
BACKSTAGE_CLIENT_SECRET: ${BACKSTAGE_CLIENT_SECRET}
|
||||
BACKSTAGE_CLIENT_ID: backstage
|
||||
" > /tmp/secret.yaml
|
||||
|
||||
./kubectl apply -f /tmp/secret.yaml
|
||||
|
||||
179
cicd/keycloak/manifests/secret-gen.yaml
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: Password
|
||||
metadata:
|
||||
name: keycloak
|
||||
namespace: keycloak
|
||||
spec:
|
||||
length: 36
|
||||
digits: 5
|
||||
symbols: 5
|
||||
symbolCharacters: "/-+"
|
||||
noUpper: false
|
||||
allowRepeat: true
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: keycloak-config
|
||||
namespace: keycloak
|
||||
spec:
|
||||
refreshInterval: "0"
|
||||
target:
|
||||
name: keycloak-config
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
cnoe.io/cli-secret: "true"
|
||||
cnoe.io/package-name: keycloak
|
||||
engineVersion: v2
|
||||
data:
|
||||
KEYCLOAK_ADMIN_PASSWORD: "{{.KEYCLOAK_ADMIN_PASSWORD}}"
|
||||
KC_DB_USERNAME: keycloak
|
||||
KC_DB_PASSWORD: "{{.KC_DB_PASSWORD}}"
|
||||
POSTGRES_DB: keycloak
|
||||
POSTGRES_USER: keycloak
|
||||
POSTGRES_PASSWORD: "{{.KC_DB_PASSWORD}}"
|
||||
USER_PASSWORD: "{{.USER_PASSWORD}}"
|
||||
dataFrom:
|
||||
- sourceRef:
|
||||
generatorRef:
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: Password
|
||||
name: keycloak
|
||||
rewrite:
|
||||
- transform:
|
||||
template: "KEYCLOAK_ADMIN_PASSWORD"
|
||||
- sourceRef:
|
||||
generatorRef:
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: Password
|
||||
name: keycloak
|
||||
rewrite:
|
||||
- transform:
|
||||
template: "KC_DB_PASSWORD"
|
||||
- sourceRef:
|
||||
generatorRef:
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: Password
|
||||
name: keycloak
|
||||
rewrite:
|
||||
- transform:
|
||||
template: "USER_PASSWORD"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: eso-store
|
||||
namespace: keycloak
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
namespace: keycloak
|
||||
name: eso-store
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- selfsubjectrulesreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: eso-store
|
||||
namespace: keycloak
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: eso-store
|
||||
namespace: keycloak
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: eso-store
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ClusterSecretStore
|
||||
metadata:
|
||||
name: keycloak
|
||||
spec:
|
||||
provider:
|
||||
kubernetes:
|
||||
remoteNamespace: keycloak
|
||||
server:
|
||||
caProvider:
|
||||
type: ConfigMap
|
||||
name: kube-root-ca.crt
|
||||
namespace: keycloak
|
||||
key: ca.crt
|
||||
auth:
|
||||
serviceAccount:
|
||||
name: eso-store
|
||||
namespace: keycloak
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: eso-store
|
||||
namespace: gitea
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: eso-store
|
||||
namespace: gitea
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- selfsubjectrulesreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: eso-store
|
||||
namespace: gitea
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: eso-store
|
||||
namespace: gitea
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: eso-store
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ClusterSecretStore
|
||||
metadata:
|
||||
name: gitea
|
||||
spec:
|
||||
provider:
|
||||
kubernetes:
|
||||
remoteNamespace: gitea
|
||||
server:
|
||||
caProvider:
|
||||
type: ConfigMap
|
||||
name: kube-root-ca.crt
|
||||
namespace: gitea
|
||||
key: ca.crt
|
||||
auth:
|
||||
serviceAccount:
|
||||
name: eso-store
|
||||
namespace: gitea
|
||||
29
cicd/metric-server.yaml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: metric-server
|
||||
namespace: argocd
|
||||
labels:
|
||||
env: dev
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://kubernetes-sigs.github.io/metrics-server
|
||||
targetRevision: 3.12.1
|
||||
helm:
|
||||
releaseName: metrics-server
|
||||
values: |
|
||||
args:
|
||||
- --kubelet-insecure-tls #required for kind/minikube
|
||||
chart: metrics-server
|
||||
destination:
|
||||
server: 'https://kubernetes.default.svc'
|
||||
namespace: kube-system
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
36
cicd/replace.sh
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
# this script replaces hostname and port used by this implementation.
|
||||
# intended for use in environments such as Codespaces where external host and port need to be updated to access in-cluster resources.
|
||||
|
||||
#!/bin/bash
|
||||
set -e
|
||||
# Check if the new port number is provided as an argument
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "Usage: NEW_HOST NEW_PORT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Assign the first script argument to NEW_PORT
|
||||
NEW_HOST="$1"
|
||||
NEW_PORT="$2"
|
||||
|
||||
# Base directory to start from, "." means the current directory
|
||||
CURRENT_DIR=$(echo "${PWD##*/}")
|
||||
if [[ ${CURRENT_DIR} != "cicd" ]]; then
|
||||
echo "please run this script from the ref-implementation directory"
|
||||
exit 10
|
||||
fi
|
||||
BASE_DIRECTORY="."
|
||||
|
||||
# Find all .yaml files recursively starting from the base directory
|
||||
# and perform an in-place search and replace from 8443 to the new port
|
||||
find "$BASE_DIRECTORY" -type f -name "*.yaml" -exec sed -i "s/8443/${NEW_PORT}/g" {} +
|
||||
find "$BASE_DIRECTORY" -type f -name "*.yaml" -exec sed -i "s/cnoe\.localtest\.me/${NEW_HOST}/g" {} +
|
||||
|
||||
# Remove hostname-port configuration if the new port is 443. Browsers strip 443 but keycloak still expects 443 in url.
|
||||
if [[ ${NEW_PORT} == "443" ]]; then
|
||||
sed -i "/hostname-port/d" keycloak/manifests/install.yaml
|
||||
sed -i "/hostname-admin/d" keycloak/manifests/install.yaml
|
||||
sed -i '0,/:443/{s/:443//}' argo-workflows/manifests/dev/patches/cm-argo-workflows.yaml
|
||||
fi
|
||||
|
||||
echo "Replacement complete."
|
||||
19
cicd/shared-helm-charts.yaml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: shared-helm-charts
|
||||
namespace: argocd
|
||||
labels:
|
||||
env: dev
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: cnoe://shared-helm-charts/entities
|
||||
targetRevision: HEAD
|
||||
path: "."
|
||||
destination:
|
||||
server: "https://kubernetes.default.svc"
|
||||
namespace: default
|
||||
syncPolicy:
|
||||
automated:
|
||||
selfHeal: true
|
||||
9
cicd/shared-helm-charts/entities/app-deploy/Chart.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: v2
|
||||
name: simple-go
|
||||
description: A Helm chart for Kubernetes
|
||||
|
||||
type: application
|
||||
|
||||
version: 0.0.0
|
||||
|
||||
appVersion: "0.1.0"
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Values.appName }}
|
||||
namespace: "{{ .Values.appName }}-{{ .Values.envName }}"
|
||||
labels:
|
||||
entity-id: {{ .Values.appName }}
|
||||
app: {{ .Values.appName }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ .Values.appName }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ .Values.appName }}
|
||||
entity-id: {{ .Values.appName }}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.registry }}/{{ .Values.appName }}:{{ .Values.image.tag }}"
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{{ if .Values.ingress.enable }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ .Values.appName }}
|
||||
namespace: "{{ .Values.appName }}-{{ .Values.envName }}"
|
||||
labels:
|
||||
entity-id: {{ .Values.appName }}
|
||||
app: {{ .Values.appName }}
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: {{ .Values.ingress.host }}
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: {{ .Values.appName }}
|
||||
port:
|
||||
number: {{ .Values.service.port }}
|
||||
path: /{{ .Values.appName }}/{{ .Values.envName }}(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
{{ end }}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: "{{ .Values.appName }}-{{ .Values.envName }}"
|
||||
labels:
|
||||
name: "{{ .Values.appName }}-{{ .Values.envName }}"
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Values.appName }}
|
||||
namespace: "{{ .Values.appName }}-{{ .Values.envName }}"
|
||||
labels:
|
||||
entity-id: {{ .Values.appName }}
|
||||
app: {{ .Values.appName }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: 8080
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ .Values.appName }}
|
||||
17
cicd/shared-helm-charts/entities/app-deploy/values.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
appName: demoapp
|
||||
envName: dev
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
registry: REGISTRY_HOST:443/gitea/giteaadmin
|
||||
tag: 0.0.0
|
||||
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
|
||||
ingress:
|
||||
enable: false
|
||||
host: INGRESS_HOST
|
||||
9
cicd/shared-helm-charts/entities/argocd-apps/Chart.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: v2
|
||||
name: provisioner
|
||||
description: A Helm chart for provisioner
|
||||
|
||||
type: application
|
||||
|
||||
version: 0.1.0
|
||||
|
||||
appVersion: "0.1.0"
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{{- range $env, $config := .Values.envList }}
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: "{{ $env }}-{{ $.Values.serviceName }}"
|
||||
namespace: {{ $.Values.namespace }}
|
||||
labels:
|
||||
entity-id: {{ $.Values.serviceName }}
|
||||
spec:
|
||||
project: {{ $.Values.project }}
|
||||
source:
|
||||
path: {{ $config.path }}
|
||||
repoURL: "{{ $config.repo }}"
|
||||
destination:
|
||||
name: {{ $.Values.k8sServer }}
|
||||
namespace: {{ $config.namespace }}
|
||||
syncPolicy:
|
||||
automated:
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
---
|
||||
{{- end }}
|
||||
15
cicd/shared-helm-charts/entities/argocd-apps/values.yaml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
serviceName: demo-app01
|
||||
project: default
|
||||
namespace: argocd
|
||||
|
||||
k8sServer: in-cluster
|
||||
|
||||
# envList:
|
||||
# dev:
|
||||
# repo: dev
|
||||
# path: "abc"
|
||||
# namespace: demo-app01-dev
|
||||
# test:
|
||||
# repo: test
|
||||
# path: "abc"
|
||||
# namespace: demo-app01-test
|
||||
14
cicd/shared-helm-charts/entities/pod.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: busybox
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- image: busybox
|
||||
command:
|
||||
- sleep
|
||||
- "3600"
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: busybox
|
||||
restartPolicy: Always
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
site_name: 'Argo Spark Example'
|
||||
nav:
|
||||
- Home: index.md
|
||||
- idpBuilder: idpbuilder.md
|
||||
plugins:
|
||||
- techdocs-core
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
description: This is a basic example application
|
||||
annotations:
|
||||
backstage.io/techdocs-ref: dir:.
|
||||
backstage.io/kubernetes-label-selector: 'entity-id=${{values.name}}'
|
||||
backstage.io/kubernetes-namespace: default
|
||||
argocd/app-name: ${{values.name | dump}}
|
||||
links:
|
||||
- url: https://cnoe.localtest.me:8443/gitea
|
||||
title: Repo URL
|
||||
icon: github
|
||||
spec:
|
||||
owner: guest
|
||||
lifecycle: experimental
|
||||
type: service
|
||||
system: ${{values.name | dump}}
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: System
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
description: An example system for demonstration purposes
|
||||
annotations:
|
||||
backstage.io/techdocs-ref: dir:.
|
||||
links:
|
||||
- url: https://github.com/cnoe-io/stacks/tree/main/ref-implementation
|
||||
title: CNOE Repo
|
||||
icon: github
|
||||
spec:
|
||||
owner: guest
|
||||
lifecycle: experimental
|
||||
type: service
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
[![Codespell][codespell-badge]][codespell-link]
|
||||
[![E2E][e2e-badge]][e2e-link]
|
||||
[![Go Report Card][report-badge]][report-link]
|
||||
[![Commit Activity][commit-activity-badge]][commit-activity-link]
|
||||
|
||||
# IDP Builder
|
||||
|
||||
Internal development platform binary launcher.
|
||||
|
||||
> **WORK IN PROGRESS**: This tool is in a pre-release stage and is under active development.
|
||||
|
||||
## About
|
||||
|
||||
Spin up a complete internal developer platform using industry standard technologies like Kubernetes, Argo, and backstage with only Docker required as a dependency.
|
||||
|
||||
This can be useful in several ways:
|
||||
* Create a single binary which can demonstrate an IDP reference implementation.
|
||||
* Use within CI to perform integration testing.
|
||||
* Use as a local development environment for platform engineers.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Checkout our [documentation website](https://cnoe.io/docs/reference-implementation/installations/idpbuilder) for getting started with idpbuilder.
|
||||
|
||||
## Community
|
||||
|
||||
- If you have questions or concerns about this tool, please feel free to reach out to us on the [CNCF Slack Channel](https://cloud-native.slack.com/archives/C05TN9WFN5S).
|
||||
- You can also join our community meetings to meet the team and ask any questions. Checkout [this calendar](https://calendar.google.com/calendar/embed?src=064a2adfce866ccb02e61663a09f99147f22f06374e7a8994066bdc81e066986%40group.calendar.google.com&ctz=America%2FLos_Angeles) for more information.
|
||||
|
||||
## Contribution
|
||||
|
||||
Checkout the [contribution doc](./CONTRIBUTING.md) for contribution guidelines and more information on how to set up your local environment.
|
||||
|
||||
|
||||
<!-- JUST BADGES & LINKS -->
|
||||
[codespell-badge]: https://github.com/cnoe-io/idpbuilder/actions/workflows/codespell.yaml/badge.svg
|
||||
[codespell-link]: https://github.com/cnoe-io/idpbuilder/actions/workflows/codespell.yaml
|
||||
|
||||
[e2e-badge]: https://github.com/cnoe-io/idpbuilder/actions/workflows/e2e.yaml/badge.svg
|
||||
[e2e-link]: https://github.com/cnoe-io/idpbuilder/actions/workflows/e2e.yaml
|
||||
|
||||
[report-badge]: https://goreportcard.com/badge/github.com/cnoe-io/idpbuilder
|
||||
[report-link]: https://goreportcard.com/report/github.com/cnoe-io/idpbuilder
|
||||
|
||||
[commit-activity-badge]: https://img.shields.io/github/commit-activity/m/cnoe-io/idpbuilder
|
||||
[commit-activity-link]: https://github.com/cnoe-io/idpbuilder/pulse
|
||||
|
After Width: | Height: | Size: 57 KiB |
|
|
@ -0,0 +1,11 @@
|
|||

|
||||
|
||||
# Example Basic Application
|
||||
|
||||
Thanks for trying out this demo! In this example, we deployed a simple guestbook application to a remote cluster using Backstage.
|
||||
|
||||
### idpbuilder
|
||||
|
||||
Checkout idpbuilder website: https://cnoe.io/docs/reference-implementation/installations/idpbuilder
|
||||
|
||||
Checkout idpbuilder repository: https://github.com/cnoe-io/idpbuilder
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: ${{values.name | dump}}
|
||||
namespace: argocd
|
||||
labels:
|
||||
example: basic
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps.git
|
||||
targetRevision: HEAD
|
||||
path: guestbook
|
||||
destination:
|
||||
name: workshop
|
||||
namespace: guestbook
|
||||
syncPolicy:
|
||||
automated:
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
apiVersion: scaffolder.backstage.io/v1beta3
|
||||
kind: Template
|
||||
metadata:
|
||||
description: Creates a Basic Kubernetes Deployment
|
||||
name: basic-remote
|
||||
title: Create a Basic Deployment in a Remote Cluster
|
||||
spec:
|
||||
owner: guest
|
||||
type: service
|
||||
parameters:
|
||||
- title: Configuration Options
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: name of this application
|
||||
|
||||
steps:
|
||||
- id: template
|
||||
name: Generating component
|
||||
action: fetch:template
|
||||
input:
|
||||
url: ./skeleton
|
||||
values:
|
||||
name: ${{parameters.name}}
|
||||
|
||||
- id: publish
|
||||
name: Publishing to a gitea git repository
|
||||
action: publish:gitea
|
||||
input:
|
||||
description: This is an example app
|
||||
# Hard coded value for this demo purposes only.
|
||||
repoUrl: cnoe.localtest.me:8443/gitea?repo=${{parameters.name}}
|
||||
defaultBranch: main
|
||||
- id: create-argocd-app
|
||||
name: Create ArgoCD App
|
||||
action: cnoe:kubernetes:apply
|
||||
input:
|
||||
manifestPath: manifests/argocd-app.yaml
|
||||
namespaced: true
|
||||
clusterName: local
|
||||
- id: register
|
||||
name: Register
|
||||
action: catalog:register
|
||||
input:
|
||||
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
|
||||
catalogInfoPath: 'catalog-info.yaml'
|
||||
output:
|
||||
links:
|
||||
- title: Open in catalog
|
||||
icon: catalog
|
||||
entityRef: ${{ steps['register'].output.entityRef }}
|
||||
|
|
@ -8,3 +8,4 @@ spec:
|
|||
- ./basic/template.yaml
|
||||
- ./argo-workflows/template.yaml
|
||||
- ./app-with-bucket/template.yaml
|
||||
- ./basic-remote/template.yaml
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ rules:
|
|||
- argoproj.io
|
||||
resources:
|
||||
- workflows
|
||||
- applications
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
|
|
|
|||