apiVersion: v1 kind: ConfigMap metadata: name: auto-cd-templates data: functions.sh: |- added=0 copy() { local src=${TEMPLATE_ROOT}/$1 dest=$2 if [ ! -f $dest ];then cp "$src" "$dest" git add "$dest" added=$(($added+1)) fi } template() { local src=${TEMPLATE_ROOT}/$1 dest=$2 if [ ! -f $dest ];then envsubst '$ARTIFACTORY_URL,$DOMAIN_NAME,$ISSUER_NAME,$PROJECT_NAME,$PROJECT_PATH,$GIT_REPOSITORY_URL,$DEPLOY_URL,$STAGE,$ORG_NAME,$NAMESPACE' <"$src" >"$dest" git add "$dest" added=$(($added+1)) fi } git_push() { local message=$1 if [ $added -ne 0 ];then git commit -am "$message" git push fi } cleanup() { rm -rf .* * || true } del_resources() { local ress="$1" file="$2" yq -i 'del(.resources[]|select(.=="'"$ress"'"))' "$file" git add "$file" added=$(($added+1)) } add_resources() { local ress="$1" file="$2" del_resources "$@" yq -i '.resources += "'"$ress"'"' "$file" git add "$file" added=$(($added+1)) } git_prepare() { local url="$1" username="$2" email="$3" mkdir -p "${HOME}/.ssh" cp -v "${WORKSPACE_SSH_DIRECTORY_PATH}"/* "${HOME}/.ssh" chmod 700 "${HOME}/.ssh" chmod 400 "${HOME}/.ssh"/* git config --global user.name "$username" git config --global user.email "$email" git clone "$url" --branch main --depth 1 . } install_base() { mkdir -p bases/project bases/install bases/deploy bases/images bases/trigger-push bases/trigger-tag ci copy empty-kusto.yaml "ci/kustomization.yaml" copy yamllint.yaml .yamllint.yaml copy base-repo.yaml bases/images/repo.yaml copy images-kusto.yaml bases/images/kustomization.yaml copy base-deploy.yaml bases/project/deploy.yaml copy base-secret.yaml bases/project/secret.yaml copy base-config.yaml bases/project/config.yaml copy base-service.yaml bases/project/service.yaml copy base-kusto.yaml bases/project/kustomization.yaml copy install-install.yaml bases/install/install.yaml copy install-kusto.yaml bases/install/kustomization.yaml copy deploy-kusto.yaml bases/deploy/kustomization.yaml copy trigger-kusto.yaml bases/trigger-tag/kustomization.yaml copy trigger-tag.yaml bases/trigger-tag/trigger.yaml copy trigger-kusto.yaml bases/trigger-push/kustomization.yaml copy trigger-push.yaml bases/trigger-push/trigger.yaml template base-update.yaml.tmpl bases/images/update.yaml template base-cert.yaml.tmpl bases/project/cert.yaml template deploy-repo.yaml.tmpl bases/deploy/repo.yaml if [ -f README.md ] && [ $(wc -l < README.md) -eq 2 ];then rm README.md fi copy README.md README.md } create_prj() { export ORG_NAME=$(echo ${PROJECT_PATH}|sed 's#/.*##') mkdir -p "projects/${PROJECT_NAME}" "ci/${PROJECT_NAME}" template ci-kusto.yaml.tmpl "ci/${PROJECT_NAME}/kustomization.yaml" add_resources "${PROJECT_NAME}" "ci/kustomization.yaml" template project-kusto.yaml.tmpl "projects/${PROJECT_NAME}/kustomization.yaml" while [ $# -gt 0 ];do export STAGE=$1 mkdir -p "stages/${STAGE}/${PROJECT_NAME}" "stages/${STAGE}/deploy/${PROJECT_NAME}" template deploy-project-kusto.yaml.tmpl "stages/${STAGE}/deploy/${PROJECT_NAME}/kustomization.yaml" if [ "${STAGE}" == "prod" ] || [ "${STAGE}" == "production" ];then template deploy-policy-tag.yaml.tmpl "stages/${STAGE}/deploy/${PROJECT_NAME}/policy.yaml" else template deploy-policy-default.yaml.tmpl "stages/${STAGE}/deploy/${PROJECT_NAME}/policy.yaml" fi copy empty-kusto.yaml "stages/${STAGE}/deploy/kustomization.yaml" del_resources "../../../bases/deploy" "stages/${STAGE}/deploy/kustomization.yaml" template stage-kusto.yaml.tmpl "stages/${STAGE}/${PROJECT_NAME}/kustomization.yaml" template stage-ingress.yaml.tmpl "stages/${STAGE}/${PROJECT_NAME}/ingress.yaml" template stage-cert.yaml.tmpl "stages/${STAGE}/${PROJECT_NAME}/cert.yaml" template stage-config.yaml.tmpl "stages/${STAGE}/${PROJECT_NAME}/config.yaml" shift done } activate_prj() { export ORG_NAME=$(echo ${PROJECT_PATH}|sed 's#/.*##') while [ $# -gt 0 ];do export STAGE=$1 add_resources "${PROJECT_NAME}" "stages/${STAGE}/deploy/kustomization.yaml" shift done } delete_prj() { rm -rf "projects/${PROJECT_NAME}" while [ $# -gt 0 ];do export STAGE=$1 rm -rf "stages/${STAGE}/${PROJECT_NAME}" "stages/${STAGE}/deploy/${PROJECT_NAME}" del_resources "${PROJECT_NAME}" "stages/${STAGE}/deploy/kustomization.yaml" del_resources "${PROJECT_NAME}" "ci/kustomization.yaml" shift done } ci-kusto.yaml.tmpl: |- --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namePrefix: ${PROJECT_NAME}- resources: - ../../bases/trigger-push - ../../bases/trigger-tag patches: - target: kind: Trigger name: push patch: |- - op: replace path: /spec/template/spec/resourcetemplates/0/spec/pipelineRef/name value: auto-ci-push - target: kind: Trigger name: push patch: |- apiVersion: triggers.tekton.dev/v1beta1 kind: Trigger metadata: name: "push" spec: interceptors: - name: project-name ref: kind: ClusterInterceptor name: cel params: - name: filter value: body.repository.name == '${PROJECT_NAME}' - target: kind: Trigger name: push patch: |- - op: replace path: /spec/template/spec/resourcetemplates/0/spec/pipelineRef/name value: auto-ci-tag - target: kind: Trigger name: tag patch: |- apiVersion: triggers.tekton.dev/v1beta1 kind: Trigger metadata: name: "tag" spec: interceptors: - name: project-name ref: kind: ClusterInterceptor name: cel params: - name: filter value: body.repository.name == '${PROJECT_NAME}' deploy-project-kusto.yaml.tmpl: |- --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namePrefix: ${PROJECT_NAME}- commonLabels: app.kubernetes.io/name: ${ORG_NAME} app.kubernetes.io/component: ${PROJECT_NAME} component: ${PROJECT_NAME} resources: - ../../../../bases/install - ../../../../bases/images - policy.yaml patches: - target: kind: ImageRepository name: repo patch: |- apiVersion: image.toolkit.fluxcd.io/v1beta2 kind: ImageRepository metadata: name: repo spec: image: ${ARTIFACTORY_URL}/${PROJECT_PATH} - target: kind: Kustomization name: install patch: |- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: install spec: path: "./stages/${STAGE}/${PROJECT_NAME}" targetNamespace: "${DOMAIN_NAME}-org-${ORG_NAME}-${STAGE}" - target: kind: ImageUpdateAutomation name: update patch: |- apiVersion: image.toolkit.fluxcd.io/v1beta1 kind: ImageUpdateAutomation metadata: name: update spec: update: path: ./stages/${STAGE}/${PROJECT_NAME} deploy-policy-tag.yaml.tmpl: |- apiVersion: image.toolkit.fluxcd.io/v1beta2 kind: ImagePolicy metadata: name: ${PROJECT_NAME}-policy labels: app.kubernetes.io/component: ${PROJECT_NAME} app.kubernetes.io/name: ${ORG_NAME} component: ${PROJECT_NAME} spec: imageRepositoryRef: name: ${PROJECT_NAME}-repo filterTags: pattern: '^v(?P.*)$' extract: '$semver' policy: semver: range: '>=0.1.0' deploy-policy-default.yaml.tmpl: |- apiVersion: image.toolkit.fluxcd.io/v1beta2 kind: ImagePolicy metadata: name: ${PROJECT_NAME}-policy labels: app.kubernetes.io/component: ${PROJECT_NAME} app.kubernetes.io/name: ${ORG_NAME} component: ${PROJECT_NAME} spec: imageRepositoryRef: name: ${PROJECT_NAME}-repo filterTags: pattern: '^main-(?P.*)$' extract: '$semver' policy: semver: range: '>=0.1.0' README.md: |- # Deployment configuration Only valid if FluxCD is activated in the cluster ## File structure - `ci/`: Configuration for Tekton pipeline for . Should contain triggers and pipelines. - `projects/`: Global configuration for deployment, affect every stages - `stages//`: Configuration for deployment in the plateform - `stages//deploy`: FluxCD configuration for , should be deployed on that stage namespace as it deploy everything needed to deploy the projects trigger-kusto.yaml: |- --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - trigger.yaml trigger-push.yaml: |- apiVersion: triggers.tekton.dev/v1beta1 kind: Trigger metadata: name: "push" labels: type: branch-push spec: bindings: - name: artifactory-url value: "$(extensions.artifactory-url)" - name: project-name value: "$(extensions.project-name)" - name: project-path value: "$(extensions.project-path)" - name: git-repository-url value: "$(extensions.git-repository-url)" - name: git-revision value: "$(extensions.git-revision)" - name: branch-name value: "$(extensions.branch-name)" - name: git-default-branch value: "$(extensions.git-default-branch)" - name: generate-name value: "$(extensions.generate-name)" template: spec: params: - name: artifactory-url description: The url of the current artifactory - name: project-name description: The git repository name - name: project-path description: The path of the current project - name: git-repository-url description: The git repository url - name: git-revision description: The git revision default: main - name: git-default-branch description: The git revision default: main - name: branch-name description: The git branch default: main - name: generate-name resourcetemplates: - apiVersion: tekton.dev/v1beta1 kind: PipelineRun metadata: generateName: $(tt.params.generate-name)- annotations: "mayfly.cloud.namecheap.com/expire": "336h" # 2 weeks spec: pipelineRef: name: "auto-ci-push" params: - name: artifactory-url value: $(tt.params.artifactory-url) - name: project-name value: $(tt.params.project-name) - name: project-path value: $(tt.params.project-path) - name: git-url value: $(tt.params.git-repository-url) - name: git-revision value: $(tt.params.git-revision) - name: git-default-branch value: $(tt.params.git-default-branch) - name: branch-name value: $(tt.params.branch-name) workspaces: - name: source persistentVolumeClaim: claimName: source subPath: $(tt.params.git-revision) - name: dockerconfig secret: secretName: gitea-docker items: - key: ".dockerconfigjson" path: "config.json" - name: sslcertdir secret: secretName: gitea items: - key: "ca.crt" path: "ca.crt" - name: ssh secret: secretName: ssh-credentials items: - key: "known_hosts" path: "known_hosts" - key: "ssh-privatekey" path: "id_rsa" - key: "ssh-publickey" path: "id_rsa.pub" trigger-tag.yaml: |- apiVersion: triggers.tekton.dev/v1beta1 kind: Trigger metadata: name: "tag" labels: type: tag-push spec: bindings: - name: artifactory-url value: "$(extensions.artifactory-url)" - name: project-name value: "$(extensions.project-name)" - name: project-path value: "$(extensions.project-path)" - name: git-repository-url value: "$(extensions.git-repository-url)" - name: git-revision value: "$(extensions.git-revision)" - name: tag-name value: $(extensions.tag-name) - name: generate-name value: "$(extensions.generate-name)" template: spec: params: - name: artifactory-url description: The url of the current artifactory - name: project-name description: The git repository name - name: project-path description: The path of the current project - name: git-repository-url description: The git repository url - name: git-revision description: The git revision default: main - name: tag-name description: The git tag - name: generate-name resourcetemplates: - apiVersion: tekton.dev/v1beta1 kind: PipelineRun metadata: generateName: $(tt.params.generate-name)- annotations: "mayfly.cloud.namecheap.com/expire": "1440h" # 2 months spec: pipelineRef: name: "auto-ci-tag" params: - name: artifactory-url value: $(tt.params.artifactory-url) - name: project-name value: $(tt.params.project-name) - name: project-path value: $(tt.params.project-path) - name: git-url value: $(tt.params.git-repository-url) - name: git-revision value: $(tt.params.git-revision) - name: tag-name value: $(tt.params.tag-name) workspaces: - name: source persistentVolumeClaim: claimName: source subPath: $(tt.params.git-revision) - name: dockerconfig secret: secretName: gitea-docker items: - key: ".dockerconfigjson" path: "config.json" - name: sslcertdir secret: secretName: gitea items: - key: "ca.crt" path: "ca.crt" - name: ssh secret: secretName: ssh-credentials items: - key: "known_hosts" path: "known_hosts" - key: "ssh-privatekey" path: "id_rsa" - key: "ssh-publickey" path: "id_rsa.pub" empty-kusto.yaml: |- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: images-kusto.yaml: |- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - repo.yaml - update.yaml stage-kusto.yaml.tmpl: |- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ../../../projects/${PROJECT_NAME} - ingress.yaml commonLabels: app.kubernetes.io/instance: ${STAGE} images: - name: appli newName: ${ARTIFACTORY_URL}/${ORG_NAME}/${PROJECT_NAME} newTag: latest # {"$imagepolicy": "${NAMESPACE}:${PROJECT_NAME}-policy:tag"} patches: - target: kind: ConfigMap name: ${PROJECT_NAME}-config path: config.yaml - target: kind: Certificate name: ${PROJECT_NAME}-web path: cert.yaml stage-ingress.yaml.tmpl: |- --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ${PROJECT_NAME}-web labels: app.kubernetes.io/component: ${PROJECT_NAME} app.kubernetes.io/name: ${ORG_NAME} component: ${PROJECT_NAME} spec: tls: - hosts: - ${PROJECT_NAME}.${STAGE}.${ORG_NAME}.${DOMAIN_NAME} secretName: cert rules: - host: ${PROJECT_NAME}.${STAGE}.${ORG_NAME}.${DOMAIN_NAME} http: paths: - backend: service: name: svc port: number: 80 path: / pathType: Prefix stage-cert.yaml.tmpl: |- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: ${PROJECT_NAME}-web spec: secretName: ${PROJECT_NAME}-cert dnsNames: - ${PROJECT_NAME}.${STAGE}.${ORG_NAME}.${DOMAIN_NAME} stage-config.yaml.tmpl: |- apiVersion: v1 kind: ConfigMap metadata: name: ${PROJECT_NAME}-config data: ENV_VAR_NAME: env_var_value yamllint.yaml: |- --- extends: default rules: document-start: present: true empty-lines: max-end: 1 indentation: spaces: 2 indent-sequences: false line-length: disable colons: max-spaces-after: -1 base-kusto.yaml: |- --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - cert.yaml - deploy.yaml - service.yaml - config.yaml - secret.yaml base-update.yaml.tmpl: |- --- apiVersion: image.toolkit.fluxcd.io/v1beta1 kind: ImageUpdateAutomation metadata: name: update spec: interval: 5m sourceRef: kind: GitRepository name: deploy-git git: checkout: ref: branch: main commit: author: email: fluxcd.automation@${ARTIFACTORY_URL} name: fluxcd messageTemplate: | Automated image update: {{ .AutomationObject }} Files: {{ range $filename, $_ := .Updated.Files -}} - {{ $filename }} {{ end -}} Objects: {{ range $resource, $_ := .Updated.Objects -}} - {{ $resource.Kind }} {{ $resource.Name }} {{ end -}} Images: {{ range .Updated.Images -}} - {{.}} {{ end -}} {{- $ChangeId := .AutomationObject -}} {{- $ChangeId = printf "%s-%s" $ChangeId ( .Updated.Files | toString ) -}} {{- $ChangeId = printf "%s-%s" $ChangeId ( .Updated.Objects | toString ) -}} {{- $ChangeId = printf "%s-%s" $ChangeId ( .Updated.Images | toString ) }} Change-Name: {{ $ChangeId }} Change-Id: {{ printf "I%s" ( sha256sum $ChangeId | trunc 40 ) }} push: branch: main update: strategy: Setters base-repo.yaml: |- --- apiVersion: image.toolkit.fluxcd.io/v1beta2 kind: ImageRepository metadata: name: repo spec: interval: 5m provider: generic secretRef: name: gitea base-cert.yaml.tmpl: |- --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: web spec: issuerRef: group: cert-manager.io kind: ClusterIssuer name: ${ISSUER_NAME} base-deploy.yaml: |- --- apiVersion: apps/v1 kind: Deployment metadata: name: app spec: replicas: 1 selector: template: spec: securityContext: runAsGroup: 1000 runAsUser: 1000 fsGroup: 1000 containers: - name: app image: appli imagePullPolicy: IfNotPresent envFrom: - configMapRef: name: "config" - secretRef: name: "secret" base-secret.yaml: |- --- apiVersion: v1 kind: Secret metadata: name: "secret" annotations: gramo.solidite.fr/no-parent: "true" labels: k8up.io/backup: "true" type: Opaque base-config.yaml: |- --- apiVersion: v1 kind: ConfigMap metadata: name: "config" labels: k8up.io/backup: "true" data: base-service.yaml: |- --- apiVersion: v1 kind: Service metadata: name: svc spec: ports: - name: app port: 80 protocol: TCP targetPort: app type: ClusterIP install-install.yaml: |- --- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: install spec: interval: 5m sourceRef: kind: GitRepository name: deploy-git prune: true timeout: 1m install-kusto.yaml: |- --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - install.yaml deploy-repo.yaml.tmpl: |- --- apiVersion: source.toolkit.fluxcd.io/v1 kind: GitRepository metadata: name: git spec: interval: 5m0s url: ${DEPLOY_URL} ref: branch: main secretRef: name: ssh-credentials deploy-kusto.yaml: |- --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namePrefix: deploy- resources: - repo.yaml - ../install project-kusto.yaml.tmpl: |- --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namePrefix: ${PROJECT_NAME}- commonLabels: app.kubernetes.io/name: ${ORG_NAME} app.kubernetes.io/component: ${PROJECT_NAME} component: ${PROJECT_NAME} resources: - ../../bases/project patches: - target: kind: Deployment name: app patch: |- apiVersion: apps/v1 kind: Deployment metadata: name: app annotations: configmap.reloader.stakater.com/reload: "${PROJECT_NAME}-config" secret.reloader.stakater.com/reload: "${PROJECT_NAME}-secret" spec: selector: template: spec: securityContext: runAsGroup: 1000 runAsUser: 1000 fsGroup: 1000 containers: - name: app ports: - name: app containerPort: 8080 protocol: TCP