feat: V1 ?

This commit is contained in:
Max batleforc 2024-06-28 01:12:45 +02:00
parent 1840bf771c
commit 90238e000a
No known key found for this signature in database
GPG Key ID: 25D243AB4B6AC9E7
27 changed files with 1434 additions and 0 deletions

33
Dockerfile Normal file
View File

@ -0,0 +1,33 @@
FROM rust:latest AS builder
WORKDIR /app
# Copy the Cargo.toml and build the project to cache dependencies
COPY Cargo.toml .
RUN mkdir src &&\
echo "fn main() {}" > src/main.rs
RUN cargo build --release
# Copy the rest of the source code then build the project
COPY src src
RUN touch src/main.rs
RUN cargo build --release
# Strip the binaries to reduce size
RUN strip target/release/botdiscord
#FROM alpine:latest as release
FROM gcr.io/distroless/cc-debian12
WORKDIR /app
# Copy each binary from the builder stage, all needed for different stages
COPY --from=builder /app/target/release/server .
# Copy the resource folder that containt default configuration files
COPY ./resource ./resource
ENV PORT 5437
EXPOSE 5437
CMD ["./botdiscord"]

24
chart/Chart.yaml Normal file
View File

@ -0,0 +1,24 @@
apiVersion: v2
name: bu-teammaker
description: A helm to deploy the app
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.2
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.1"

View File

@ -0,0 +1,82 @@
{{- $host_dev := printf "%s-bu-teammaker.dev.%s" .Values.image.tag .Values.ingress.host -}}
{{- $host_prod := printf "%s.%s" "bu-teammaker" .Values.ingress.host -}}
{{- $host := regexMatch "^v[0-9]+\\.[0-9]+\\.[0-9]+$" .Values.image.tag | ternary $host_prod $host_dev -}}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
labels:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
{{- include "mychart.labels" . | nindent 2 }}
annotations:
deployment.kubernetes.io/revision: "{{ .Release.Revision }}-surrealdb"
deployment.git-branch: "{{ .Values.image.tag }}"
rollme: {{ randAlphaNum 5 | quote }}
spec:
replicas: 1
selector:
matchLabels:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
template:
metadata:
labels:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
annotations:
rollme: {{ randAlphaNum 5 | quote }}
spec:
imagePullSecrets:
- name: harbor-pull
volumes:
- name: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
persistentVolumeClaim:
claimName: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
containers:
- name: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
image: "surrealdb/surrealdb:latest"
imagePullPolicy: Always
command:
- start
ports:
- containerPort: 8000
name: http
env:
{{- range $env := .Values.env }}
- name: "{{ $env.name }}"
value: "{{ $env.value }}"
{{- end }}
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: SURREAL_AUTH
value: "true"
- name: SURREAL_USER
envFrom:
secretRef:
name: "bot-discord-db"
key: "username"
- name: SURREAL_PASS
envFrom:
secretRef:
name: "bot-discord-db"
key: "password"
- name: SURREAL_PATH
value: "file:/appdata/bot.db"
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
mountPath: /appdata
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 10

View File

@ -0,0 +1,118 @@
{{- $host_dev := printf "%s-bu-teammaker.dev.%s" .Values.image.tag .Values.ingress.host -}}
{{- $host_prod := printf "%s.%s" "bu-teammaker" .Values.ingress.host -}}
{{- $host := regexMatch "^v[0-9]+\\.[0-9]+\\.[0-9]+$" .Values.image.tag | ternary $host_prod $host_dev -}}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}"
labels:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}"
{{- include "mychart.labels" . | nindent 2 }}
annotations:
deployment.kubernetes.io/revision: "{{ .Release.Revision }}"
deployment.git-branch: "{{ .Values.image.tag }}"
rollme: {{ randAlphaNum 5 | quote }}
spec:
replicas: 1
selector:
matchLabels:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}"
template:
metadata:
labels:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}"
annotations:
rollme: {{ randAlphaNum 5 | quote }}
spec:
imagePullSecrets:
- name: harbor-pull
volumes:
- name: "base_image"
emptyDir: {}
- name: "ssh-key"
secret:
secretName: "bot-discord-pull"
initContainers:
- name: "init"
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: Always
command: ["sh", "-c", "cd /appdata && git clone git@git.weebo.fr:sandbox/base-image.git ."]
env:
- name: "GIT_SSH_COMMAND"
value: "ssh -o StrictHostKeyChecking=no"
volumeMounts:
- name: "base_image"
mountPath: "/appdata"
- name: "ssh-key"
mountPath: "/root/.ssh"
containers:
- name: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}"
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: Always
ports:
- containerPort: 5437
name: http
env:
{{- range $env := .Values.env }}
- name: "{{ $env.name }}"
value: "{{ $env.value }}"
{{- end }}
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: RUST_BACKTRACE
value: "1"
- name: PORT
value: "5437"
- name: IMAGE_PATH
value: "/appdata/"
- name: "DB_NAME"
envFrom:
secretRef:
name: "bot-discord-db"
key: "db_name"
- name: "DB_PASSWORD"
envFrom:
secretRef:
name: "bot-discord-db"
key: "password"
- name: "DB_USER"
envFrom:
secretRef:
name: "bot-discord-db"
key: "username"
- name: "DB_NAMESPACE"
envFrom:
secretRef:
name: "bot-discord-db"
key: "db_namespace"
- name: "BOT_TOKEN"
envFrom:
secretRef:
name: "botdiscord"
key: "token"
- name: RUST_ENV
{{- if regexMatch "^[0-9]+\\.[0-9]+\\.[0-9]+$" .Values.image.tag }}
value: "prod"
{{- else }}
value: "dev-{{ .Values.image.tag }}"
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: "base_image"
mountPath: "/appdata"
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 10

View File

@ -0,0 +1,19 @@
---
apiVersion: v1
kind: Service
metadata:
name: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
labels:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
{{- include "mychart.labels" . | nindent 2 }}
annotations:
deployment.kubernetes.io/revision: "{{ .Release.Revision }}"
deployment.git-branch: "{{ .Values.image.tag }}"
spec:
ports:
- port: 8000
targetPort: 8000
name: http
selector:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
type: ClusterIP

View File

@ -0,0 +1,19 @@
---
apiVersion: v1
kind: Service
metadata:
name: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}"
labels:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}"
{{- include "mychart.labels" . | nindent 2 }}
annotations:
deployment.kubernetes.io/revision: "{{ .Release.Revision }}"
deployment.git-branch: "{{ .Values.image.tag }}"
spec:
ports:
- port: 5437
targetPort: 5437
name: http
selector:
app: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}"
type: ClusterIP

View File

@ -0,0 +1,13 @@
{{/* Generate object name */}}
{{- define "mychart.name" }}
{{- regexMatch "^v[0-9]+\\.[0-9]+\\.[0-9]+$" .Values.image.tag | ternary "prod" (regexReplaceAll "\\W+" .Values.image.tag "_") -}}
{{- end }}
{{/* Generate labels */}}
{{- define "mychart.labels" -}}
{{- with .Values.labels }}
{{- range $key, $value := . }}
{{ $key }}: {{ tpl $value $ | quote }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,10 @@
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: "{{ .Chart.Name }}-{{- template "mychart.name" . -}}-surrealdb"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi

32
chart/values.yaml Normal file
View File

@ -0,0 +1,32 @@
resources: # Need to be fine tunned in the futur
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 20m
memory: 16Mi
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://tempo.monitoring.svc.cluster.local:4317"
- name: RUST_LOG
value: "debug"
- name: APP_NAME
value: "BotDiscord"
ingress:
annotations:
kubernetes.io/ingress.class: "haproxy"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
host: weebo.fr
image:
repository: harbor.weebo.fr/bu_teammaker/botdiscord
pullPolicy: Always
tag: "v1.17.8"
labels:
app.kubernetes.io/name: botdiscord
app.kubernetes.io/component: botdiscord
app.kubernetes.io/instance: "botdiscord-{{ .Release.Name }}"
app.kubernetes.io/part-of: "bot-discord"

23
cicd/.helmignore Normal file
View File

@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

24
cicd/Chart.yaml Normal file
View File

@ -0,0 +1,24 @@
apiVersion: v2
name: cicdv2
description: A CICD pipeline for Kubernetes Tekton
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.53
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"

View File

@ -0,0 +1,238 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: git-clone
labels:
app.kubernetes.io/version: "0.8"
annotations:
tekton.dev/pipelines.minVersion: "0.29.0"
tekton.dev/categories: Git
tekton.dev/tags: git
tekton.dev/displayName: "git clone"
tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64"
spec:
description: >-
These Tasks are Git tasks to work with repositories used by other tasks
in your Pipeline.
The git-clone Task will clone a repo from the provided url into the
output Workspace. By default the repo will be cloned into the root of
your Workspace. You can clone into a subdirectory by setting this Task's
subdirectory param. This Task also supports sparse checkouts. To perform
a sparse checkout, pass a list of comma separated directory patterns to
this Task's sparseCheckoutDirectories param.
workspaces:
- name: output
description: The git repo will be cloned onto the volume backing this Workspace.
- name: ssh-directory
optional: true
description: |
A .ssh directory with private key, known_hosts, config, etc. Copied to
the user's home before git commands are executed. Used to authenticate
with the git remote when performing the clone. Binding a Secret to this
Workspace is strongly recommended over other volume types.
- name: basic-auth
optional: true
description: |
A Workspace containing a .gitconfig and .git-credentials file. These
will be copied to the user's home before any git commands are run. Any
other files in this Workspace are ignored. It is strongly recommended
to use ssh-directory over basic-auth whenever possible and to bind a
Secret to this Workspace over other volume types.
- name: ssl-ca-directory
optional: true
description: |
A workspace containing CA certificates, this will be used by Git to
verify the peer with when fetching or pushing over HTTPS.
params:
- name: url
description: Repository URL to clone from.
type: string
- name: revision
description: Revision to checkout. (branch, tag, sha, ref, etc...)
type: string
default: ""
- name: refspec
description: Refspec to fetch before checking out revision.
default: ""
- name: submodules
description: Initialize and fetch git submodules.
type: string
default: "true"
- name: depth
description: Perform a shallow clone, fetching only the most recent N commits.
type: string
default: "1"
- name: sslVerify
description: Set the `http.sslVerify` global git config. Setting this to `false` is not advised unless you are sure that you trust your git remote.
type: string
default: "true"
- name: crtFileName
description: file name of mounted crt using ssl-ca-directory workspace. default value is ca-bundle.crt.
type: string
default: "ca-bundle.crt"
- name: subdirectory
description: Subdirectory inside the `output` Workspace to clone the repo into.
type: string
default: ""
- name: sparseCheckoutDirectories
description: Define the directory patterns to match or exclude when performing a sparse checkout.
type: string
default: ""
- name: deleteExisting
description: Clean out the contents of the destination directory if it already exists before cloning.
type: string
default: "true"
- name: httpProxy
description: HTTP proxy server for non-SSL requests.
type: string
default: ""
- name: httpsProxy
description: HTTPS proxy server for SSL requests.
type: string
default: ""
- name: noProxy
description: Opt out of proxying HTTP/HTTPS requests.
type: string
default: ""
- name: verbose
description: Log the commands that are executed during `git-clone`'s operation.
type: string
default: "true"
- name: gitInitImage
description: The image providing the git-init binary that this Task runs.
type: string
default: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.29.0"
- name: userHome
description: |
Absolute path to the user's home directory.
type: string
default: "/tekton/home"
results:
- name: commit
description: The precise commit SHA that was fetched by this Task.
- name: url
description: The precise URL that was fetched by this Task.
steps:
- name: clone
image: "$(params.gitInitImage)"
env:
- name: HOME
value: "$(params.userHome)"
- name: PARAM_URL
value: $(params.url)
- name: PARAM_REVISION
value: $(params.revision)
- name: PARAM_REFSPEC
value: $(params.refspec)
- name: PARAM_SUBMODULES
value: $(params.submodules)
- name: PARAM_DEPTH
value: $(params.depth)
- name: PARAM_SSL_VERIFY
value: $(params.sslVerify)
- name: PARAM_CRT_FILENAME
value: $(params.crtFileName)
- name: PARAM_SUBDIRECTORY
value: $(params.subdirectory)
- name: PARAM_DELETE_EXISTING
value: $(params.deleteExisting)
- name: PARAM_HTTP_PROXY
value: $(params.httpProxy)
- name: PARAM_HTTPS_PROXY
value: $(params.httpsProxy)
- name: PARAM_NO_PROXY
value: $(params.noProxy)
- name: PARAM_VERBOSE
value: $(params.verbose)
- name: PARAM_SPARSE_CHECKOUT_DIRECTORIES
value: $(params.sparseCheckoutDirectories)
- name: PARAM_USER_HOME
value: $(params.userHome)
- name: WORKSPACE_OUTPUT_PATH
value: $(workspaces.output.path)
- name: WORKSPACE_SSH_DIRECTORY_BOUND
value: $(workspaces.ssh-directory.bound)
- name: WORKSPACE_SSH_DIRECTORY_PATH
value: $(workspaces.ssh-directory.path)
- name: WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND
value: $(workspaces.basic-auth.bound)
- name: WORKSPACE_BASIC_AUTH_DIRECTORY_PATH
value: $(workspaces.basic-auth.path)
- name: WORKSPACE_SSL_CA_DIRECTORY_BOUND
value: $(workspaces.ssl-ca-directory.bound)
- name: WORKSPACE_SSL_CA_DIRECTORY_PATH
value: $(workspaces.ssl-ca-directory.path)
securityContext:
runAsNonRoot: true
runAsUser: 65532
script: |
#!/usr/bin/env sh
set -eu
if [ "${PARAM_VERBOSE}" = "true" ] ; then
set -x
fi
if [ "${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}" = "true" ] ; then
cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" "${PARAM_USER_HOME}/.git-credentials"
cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" "${PARAM_USER_HOME}/.gitconfig"
chmod 400 "${PARAM_USER_HOME}/.git-credentials"
chmod 400 "${PARAM_USER_HOME}/.gitconfig"
fi
if [ "${WORKSPACE_SSH_DIRECTORY_BOUND}" = "true" ] ; then
cp -R "${WORKSPACE_SSH_DIRECTORY_PATH}" "${PARAM_USER_HOME}"/.ssh
chmod 700 "${PARAM_USER_HOME}"/.ssh
chmod -R 400 "${PARAM_USER_HOME}"/.ssh/*
fi
if [ "${WORKSPACE_SSL_CA_DIRECTORY_BOUND}" = "true" ] ; then
export GIT_SSL_CAPATH="${WORKSPACE_SSL_CA_DIRECTORY_PATH}"
if [ "${PARAM_CRT_FILENAME}" != "" ] ; then
export GIT_SSL_CAINFO="${WORKSPACE_SSL_CA_DIRECTORY_PATH}/${PARAM_CRT_FILENAME}"
fi
fi
CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}"
cleandir() {
# Delete any existing contents of the repo directory if it exists.
#
# We don't just "rm -rf ${CHECKOUT_DIR}" because ${CHECKOUT_DIR} might be "/"
# or the root of a mounted volume.
if [ -d "${CHECKOUT_DIR}" ] ; then
# Delete non-hidden files and directories
rm -rf "${CHECKOUT_DIR:?}"/*
# Delete files and directories starting with . but excluding ..
rm -rf "${CHECKOUT_DIR}"/.[!.]*
# Delete files and directories starting with .. plus any other character
rm -rf "${CHECKOUT_DIR}"/..?*
fi
}
if [ "${PARAM_DELETE_EXISTING}" = "true" ] ; then
cleandir
fi
test -z "${PARAM_HTTP_PROXY}" || export HTTP_PROXY="${PARAM_HTTP_PROXY}"
test -z "${PARAM_HTTPS_PROXY}" || export HTTPS_PROXY="${PARAM_HTTPS_PROXY}"
test -z "${PARAM_NO_PROXY}" || export NO_PROXY="${PARAM_NO_PROXY}"
/ko-app/git-init \
-url="${PARAM_URL}" \
-revision="${PARAM_REVISION}" \
-refspec="${PARAM_REFSPEC}" \
-path="${CHECKOUT_DIR}" \
-sslVerify="${PARAM_SSL_VERIFY}" \
-submodules="${PARAM_SUBMODULES}" \
-depth="${PARAM_DEPTH}" \
-sparseCheckoutDirectories="${PARAM_SPARSE_CHECKOUT_DIRECTORIES}"
cd "${CHECKOUT_DIR}"
RESULT_SHA="$(git rev-parse HEAD)"
EXIT_CODE="$?"
if [ "${EXIT_CODE}" != 0 ] ; then
exit "${EXIT_CODE}"
fi
printf "%s" "${RESULT_SHA}" > "$(results.commit.path)"
printf "%s" "${PARAM_URL}" > "$(results.url.path)"

View File

@ -0,0 +1,60 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: helm-upgrade-from-source
labels:
app.kubernetes.io/version: "0.3"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/categories: Deployment
tekton.dev/tags: helm
tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64"
spec:
description: >-
These tasks will install / upgrade a helm chart into your Kubernetes /
OpenShift Cluster using Helm
params:
- name: charts_dir
description: The directory in source that contains the helm chart
- name: release_version
description: The helm release version in semantic versioning format
default: "v1.0.0"
- name: release_name
description: The helm release name
default: "helm-release"
- name: release_namespace
description: The helm release namespace
default: ""
- name: overwrite_values
description: "Specify the values you want to overwrite, comma separated: autoscaling.enabled=true,replicas=1"
default: ""
- name: values_file
description: "The values file to be used"
default: "values.yaml"
- name: helm_image
description: "helm image to be used"
default: "docker.io/lachlanevenson/k8s-helm:v3.10.2" #tag: v3.6.0
- name: upgrade_extra_params
description: "Extra parameters passed for the helm upgrade command"
default: ""
workspaces:
- name: source
- name: kubeconfig-dir
optional: true
steps:
- name: upgrade
image: $(params.helm_image)
workingDir: /workspace/source
script: |
echo "Setting up kubeconfig..."
[[ "$(workspaces.kubeconfig-dir.bound)" == "true" ]] && \
[[ -f $(workspaces.kubeconfig-dir.path)/kubeconfig ]] && \
export KUBECONFIG=$(workspaces.kubeconfig-dir.path)/kubeconfig
echo "Setting up variables..."
release_name="$(echo '$(params.release_name)' | tr '[:upper:]' '[:lower:]')"
echo "Release name: $release_name"
echo "Getting helm dependencies..."
helm dependency build "$(params.charts_dir)"
echo "installing helm chart..."
helm upgrade --install --wait --values "$(params.charts_dir)/$(params.values_file)" --namespace "$(params.release_namespace)" --version "$(params.release_version)" "$release_name" "$(params.charts_dir)" --debug --set "$(params.overwrite_values)" $(params.upgrade_extra_params)

View File

@ -0,0 +1,54 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: kubernetes-actions
labels:
app.kubernetes.io/version: "0.2"
annotations:
tekton.dev/pipelines.minVersion: "0.17.0"
tekton.dev/categories: Kubernetes
tekton.dev/tags: CLI, kubectl
tekton.dev/displayName: "kubernetes actions"
tekton.dev/platforms: "linux/amd64"
spec:
description: >-
This task is the generic kubectl CLI task which can be used
to run all kinds of k8s commands
workspaces:
- name: manifest-dir
optional: true
- name: kubeconfig-dir
optional: true
results:
- name: output-result
description: some result can be emitted if someone wants to.
params:
- name: script
description: The Kubernetes CLI script to run
type: string
default: "kubectl $@"
- name: args
description: The Kubernetes CLI arguments to run
type: array
default:
- "help"
- name: image
default: gcr.io/cloud-builders/kubectl@sha256:8ab94be8b2b4f3d117f02d868b39540fddd225447abf4014f7ba4765cb39f753 #image is huge
description: Kubectl wrapper image
steps:
- name: kubectl
image: $(params.image)
script: |
#!/usr/bin/env bash
[[ "$(workspaces.manifest-dir.bound)" == "true" ]] && \
cd $(workspaces.manifest-dir.path)
[[ "$(workspaces.kubeconfig-dir.bound)" == "true" ]] && \
[[ -f $(workspaces.kubeconfig-dir.path)/kubeconfig ]] && \
export KUBECONFIG=$(workspaces.kubeconfig-dir.path)/kubeconfig
$(params.script)
args:
- "$(params.args)"

View File

@ -0,0 +1,179 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: sonarqube-scanner
labels:
app.kubernetes.io/version: "0.5"
annotations:
tekton.dev/pipelines.minVersion: "0.17.0"
tekton.dev/categories: Security
tekton.dev/tags: security
tekton.dev/displayName: "sonarqube scanner"
tekton.dev/platforms: "linux/amd64"
spec:
description: >-
The following task can be used to perform static analysis on the source code
provided the SonarQube server is hosted
SonarQube is the leading tool for continuously inspecting the Code Quality and Security
of your codebases, all while empowering development teams. Analyze over 25 popular
programming languages including C#, VB.Net, JavaScript, TypeScript and C++. It detects
bugs, vulnerabilities and code smells across project branches and pull requests.
This version has been tweeked in order to handle the token authentication method.
workspaces:
- name: source
description: "Workspace containing the code which needs to be scanned by SonarQube"
- name: sonar-settings
description: "Optional workspace where SonarQube properties can be mounted"
optional: true
- name: sonar-credentials
description: |
A workspace containing a login or password for use within sonarqube.
optional: true
params:
- name: SONAR_HOST_URL
description: SonarQube server URL
default: ""
- name: SONAR_PROJECT_KEY
description: Project's unique key
default: ""
- name: PROJECT_VERSION
description: "Version of the project. Default: 1.0"
default: "1.0"
- name: SOURCE_TO_SCAN
description: "Comma-separated paths to directories containing main source files"
default: "."
- name: SONAR_ORGANIZATION
description: "The organization in sonarqube where the project exists"
default: ""
- name: SONAR_SCANNER_IMAGE
description: "The sonarqube scanner CLI image which will run the scan"
default: "docker.io/sonarsource/sonar-scanner-cli:4.6@sha256:7a976330a8bad1beca6584c1c118e946e7a25fdc5b664d5c0a869a6577d81b4f"
- name: SONAR_LOGIN_KEY
description: Name of the file of the login within the sonarqube credentials workspace
default: "login"
- name: SONAR_PASSWORD_KEY
description: Name of the file of the password within the sonarqube credentials workspace
default: "password"
- name: SONAR_TOKEN_KEY
description: Name of the file of the token within the sonarqube credentials workspace
default: "token"
steps:
- name: sonar-properties-create
image: registry.access.redhat.com/ubi8/ubi-minimal:8.2
workingDir: $(workspaces.source.path)
env:
- name: SONAR_HOST_URL
value: $(params.SONAR_HOST_URL)
- name: SONAR_PROJECT_KEY
value: $(params.SONAR_PROJECT_KEY)
- name: PROJECT_VERSION
value: $(params.PROJECT_VERSION)
- name: SOURCE_TO_SCAN
value: $(params.SOURCE_TO_SCAN)
- name: SONAR_ORGANIZATION
value: $(params.SONAR_ORGANIZATION)
script: |
#!/usr/bin/env bash
replaceValues() {
filename=$1
thekey=$2
newvalue=$3
if ! grep -R "^[#]*\s*${thekey}=.*" $filename >/dev/null; then
echo "APPENDING because '${thekey}' not found"
echo "" >>$filename
echo "$thekey=$newvalue" >>$filename
else
echo "SETTING because '${thekey}' found already"
sed -ir "s|^[#]*\s*${thekey}=.*|$thekey=$newvalue|" $filename
fi
}
if [[ "$(workspaces.sonar-settings.bound)" == "true" ]]; then
if [[ -f $(workspaces.sonar-settings.path)/sonar-project.properties ]]; then
echo "using user provided sonar-project.properties file"
cp -RL $(workspaces.sonar-settings.path)/sonar-project.properties $(workspaces.source.path)/sonar-project.properties
fi
fi
if [[ -f $(workspaces.source.path)/sonar-project.properties ]]; then
if [[ -n "${SONAR_HOST_URL}" ]]; then
echo "replacing sonar host URL"
replaceValues $(workspaces.source.path)/sonar-project.properties sonar.host.url "${SONAR_HOST_URL}"
fi
if [[ -n "${SONAR_PROJECT_KEY}" ]]; then
echo "replacing sonar project key"
replaceValues $(workspaces.source.path)/sonar-project.properties sonar.projectKey "${SONAR_PROJECT_KEY}"
fi
echo "Values in sonar-project.properties file replaced successfully..."
else
echo "Creating sonar-project.properties file..."
touch sonar-project.properties
[[ -n "${SONAR_PROJECT_KEY}" ]] && {
echo "sonar.projectKey=${SONAR_PROJECT_KEY}" >> sonar-project.properties
} || {
echo "missing property SONAR_PROJECT_KEY"
exit 1
}
[[ -n "${SONAR_HOST_URL}" ]] && {
echo "sonar.host.url=${SONAR_HOST_URL}" >> sonar-project.properties
} || {
echo "missing property SONAR_HOST_URL"
exit 1
}
[[ -n "${PROJECT_VERSION}" ]] && {
echo "sonar.projectVersion=${PROJECT_VERSION}" >> sonar-project.properties
} || {
echo "missing property PROJECT_VERSION"
exit 1
}
[[ -n "${SONAR_ORGANIZATION}" ]] && {
echo "sonar.organization=${SONAR_ORGANIZATION}" >> sonar-project.properties
} || {
echo "missing property SONAR_ORGANIZATION"
exit 1
}
echo "sonar.sources=${SOURCE_TO_SCAN}" >> sonar-project.properties
echo "---------------------------"
cat $(workspaces.source.path)/sonar-project.properties
fi
if [[ "$(workspaces.sonar-credentials.bound)" == "true" ]]; then
if [[ -f $(workspaces.sonar-credentials.path)/$(params.SONAR_PASSWORD_KEY) ]]; then
SONAR_PASSWORD=`cat $(workspaces.sonar-credentials.path)/$(params.SONAR_PASSWORD_KEY)`
replaceValues $(workspaces.source.path)/sonar-project.properties sonar.password "${SONAR_PASSWORD}"
fi
if [[ -f $(workspaces.sonar-credentials.path)/$(params.SONAR_LOGIN_KEY) ]]; then
SONAR_LOGIN=`cat $(workspaces.sonar-credentials.path)/$(params.SONAR_LOGIN_KEY)`
replaceValues $(workspaces.source.path)/sonar-project.properties sonar.login "${SONAR_LOGIN}"
fi
if [[ -f $(workspaces.sonar-credentials.path)/$(params.SONAR_TOKEN_KEY) ]]; then
SONAR_TOKEN=`cat $(workspaces.sonar-credentials.path)/$(params.SONAR_TOKEN_KEY)`
replaceValues $(workspaces.source.path)/sonar-project.properties sonar.token "${SONAR_TOKEN}"
replaceValues $(workspaces.source.path)/sonar-project.properties sonar.login "${SONAR_TOKEN}"
fi
fi
{{- if .Values.config.sonarqube.additionalScript.enabled}}
- name: prepare-cli
image: {{ .Values.config.sonarqube.additionalScript.image}}
workingDir: $(workspaces.source.path)
command:
- /bin/sh
args:
- -c
- |
{{- .Values.config.sonarqube.additionalScript.script | nindent 10}}
{{- end}}
- name: sonar-scan
image: $(params.SONAR_SCANNER_IMAGE)
workingDir: $(workspaces.source.path)
command:
- sonar-scanner
# TODO: mise en place result https://tekton.dev/docs/pipelines/tasks/#emitting-results https://tekton.dev/docs/pipelines/pipelines/#adding-finally-to-the-pipeline

View File

@ -0,0 +1,56 @@
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: build
spec:
description: |
This task builds all dockerfile in a repo based on a yaml file.
workspaces:
- name: shared-data
description: |
This workspace contains the cloned repo files, so they can be read by the
next task.
- name: dockerconfig
description: |
This workspace contains the docker config.json file, so it can be used by
the next task.
params:
- name: registrydns
type: string
description: The registry dns name.
default: harbor.weebo.fr
- name: buildctl_tcp
type: string
description: The buildctl tcp address.
default: tcp://buildkitd.buildkit.svc.cluster.local:1234
- name: repo-branch
type: string
description: The git repo branch to clone from.
default: main
- name: path-dockerfile
type: string
description: The folder where the dockerfile are.
default: .
- name: context-dockerfile
type: string
description: The context where the dockerfile are.
default: .
- name: DOCKERFILE
type: string
description: The dockerfile to build.
default: Dockerfile
- name: IMAGE
type: string
description: The image name to build (repo/imagename).
steps:
- image: harbor.weebo.fr/cache/moby/buildkit:v0.11.4
name: build-all
env:
- name: DOCKER_CONFIG
value: $(workspaces.dockerconfig.path)
workingDir: $(workspaces.shared-data.path)
script: |
#!/usr/bin/env ash
buildctl --addr $(params.buildctl_tcp) build --progress=plain --frontend dockerfile.v0 --local context=$(params.context-dockerfile) --local dockerfile=$(params.path-dockerfile) --opt filename=$(params.DOCKERFILE) --output type=image,name=$(params.registrydns)/$(params.IMAGE):$(params.repo-branch),push=true
# https://tekton.dev/docs/pipelines/tasks/#specifying-workspaces

View File

@ -0,0 +1,34 @@
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: {{.Values.config.prefix}}-event-listener
spec:
serviceAccountName: {{.Values.config.prefix}}-sa
triggers:
- name: {{.Values.config.prefix}}-trigger
interceptors:
- ref:
name: "gitea"
kind: ClusterInterceptor
apiVersion: triggers.tekton.dev
params:
- name: secretRef
value:
secretName: {{.Values.config.prefix}}-gitea-secret
secretKey: secretToken
- name: eventTypes
value:
- push
- ref:
name: "cel"
params:
- name: filter
value: "body.ref.startsWith('refs/heads/')"
- name: overlays
value:
- key: branch_name
expression: "body.ref.split('/')[2]"
bindings:
- ref: {{.Values.config.prefix}}-trigger-binding
template:
ref: {{.Values.config.prefix}}-pipeline-template

View File

@ -0,0 +1,20 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: "{{.Values.config.prefix}}-webhook"
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
haproxy-ingress.github.io/ssl-redirect: "false"
kubernetes.io/ingress.class: "{{.Values.config.ingress.class}}"
spec:
rules:
- host: "{{.Values.config.ingress.domain}}"
http:
paths:
- path: "/{{.Values.config.name}}/{{.Values.config.prefix}}"
pathType: Exact
backend:
service:
name: "el-{{.Values.config.prefix}}-event-listener"
port:
number: 8080

View File

@ -0,0 +1,43 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: "terra-job"
labels:
app.kubernetes.io/managed-by: "{{ .Release.Service }}"
app.kubernetes.io/instance: "{{ .Release.Name }}"
app.kubernetes.io/version: "{{ .Chart.AppVersion }}"
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
schedule: "0 0 1 * *"
jobTemplate:
spec:
template:
metadata:
name: "{{ .Release.Name }}"
labels:
app.kubernetes.io/managed-by: "{{ .Release.Service }}"
app.kubernetes.io/instance: "{{ .Release.Name }}"
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
restartPolicy: Never
serviceAccountName: "{{.Values.config.prefix}}-sa"
containers:
- name: apply-terraform
image: hashicorp/terraform:latest
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- cd /terraform && touch anotherNAmeThatsoudnothing.tf && rm *.tf && cp /app/*.tf . && terraform init && terraform apply -auto-approve
volumeMounts:
- name: terra-job
mountPath: /terraform
- name: terraform-sa
mountPath: /app/
volumes:
- name: terra-job
persistentVolumeClaim:
claimName: terra-job
- name: terraform-sa
configMap:
name: terraform-sa

View File

@ -0,0 +1,11 @@
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: terra-job
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: local-path

View File

@ -0,0 +1,111 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: {{.Values.config.prefix}}-pipeline
spec:
## TODO https://tekton.dev/docs/pipelines/pipelines/#using-execution-status-of-pipelinetask
description: |
This pipeline builds batleforc template-rust.
params:
- name: repo-url
type: string
description: The git repo URL to clone from.
- name: repo-branch
type: string
default: main
description: The git repo branch to clone from.
- name: repo-revision
type: string
default: main
description: The git repo revision to clone from.
workspaces:
- name: shared-data
description: |
This workspace contains the cloned repo files, so they can be read by the
next task.
- name: dockerconfig
description: |
This workspace contains the docker config.json file, so it can be used by
the next task.
- name: kubeconfig
description: |
This workspace contains the kubeconfig file, it define the namespace to rollout.
{{- if .Values.config.sonarqube.useToken }}
- name: sonarqube
description: |
This workspace contains the sonarqube credentials.
{{- end }}
tasks:
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-data
params:
- name: url
value: $(params.repo-url)
- name: revision
value: $(params.repo-revision)
- name: build-docker
runAfter: ["fetch-source"]
taskRef:
name: build
workspaces:
- name: shared-data
workspace: shared-data
- name: dockerconfig
workspace: dockerconfig
params:
- name: path-dockerfile
value: .
- name: context-dockerfile
value: .
- name: IMAGE
value: {{.Values.config.registry.imageName}}
- name: repo-branch
value: $(params.repo-branch)
{{ if .Values.config.sonarqube.enabled }}
- name: sonarqube-scan
runAfter: ["build-docker"]
taskRef:
name: sonarqube-scanner
workspaces:
- name: source
workspace: shared-data
{{ if .Values.config.sonarqube.useToken }}
- name: sonar-credentials
workspace: sonarqube
{{ end }}
params:
- name: SONAR_HOST_URL
value: {{.Values.config.sonarqube.host}}
- name: SONAR_SCANNER_IMAGE
value: {{.Values.config.sonarqube.image}}
{{ if .Values.config.sonarqube.useToken }}
- name: SONAR_TOKEN_KEY
value: token
{{ end }}
{{ end }}
- name: helm-upgrade
{{ if .Values.config.sonarqube.enabled }}
runAfter: ["sonarqube-scan"]
{{ else }}
runAfter: ["build-docker"]
{{ end }}
taskRef:
name: helm-upgrade-from-source
workspaces:
- name: source
workspace: shared-data
- name: kubeconfig-dir
workspace: kubeconfig
params:
- name: charts_dir
value: ./chart
- name: release_name
value: $(params.repo-branch)
- name: release_namespace
value: {{.Release.Namespace}}
- name: overwrite_values
value: "image.tag=$(params.repo-branch)"

74
cicd/templates/rbac.yaml Normal file
View File

@ -0,0 +1,74 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{.Values.config.prefix}}-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{.Values.config.prefix}}-sa
rules:
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{.Values.config.prefix}}-sa
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{.Values.config.prefix}}-sa
subjects:
- kind: ServiceAccount
name: {{.Values.config.prefix}}-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{.Values.config.prefix}}-sa-binding-2
subjects:
- kind: ServiceAccount
name: {{.Values.config.prefix}}-sa
namespace: {{.Release.Namespace}}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: tekton-triggers-eventlistener-roles
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{.Values.config.prefix}}-sa-clusterbinding
subjects:
- kind: ServiceAccount
name: {{.Values.config.prefix}}-sa
namespace: {{.Release.Namespace}}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: tekton-triggers-eventlistener-clusterroles
---
apiVersion: v1
kind: Secret
metadata:
name: {{.Values.config.prefix}}-sa
annotations:
kubernetes.io/service-account.name: {{.Values.config.prefix}}-sa
type: kubernetes.io/service-account-token

View File

@ -0,0 +1,61 @@
# Configmap containing Terraform file
apiVersion: v1
kind: ConfigMap
metadata:
name: terraform-sa
data:
main.tf: |
terraform {
required_providers {
harbor = {
source = "goharbor/harbor"
version = "3.9.4"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "2.22.0"
}
}
}
variable "kubepath" {
type = string
default = "/var/run/secrets/kubernetes.io/serviceaccount"
}
provider "kubernetes" {
host = "https://kubernetes.default.svc"
token = file("${var.kubepath}/token")
cluster_ca_certificate = file("${var.kubepath}/ca.crt")
}
resource "kubernetes_secret_v1" "kubeconfig" {
metadata {
name = "kubeconfig"
namespace = "{{.Release.Namespace}}"
}
data = {
"kubeconfig" = <<EOF
apiVersion: v1
kind: Config
clusters:
- name: tpl
cluster:
server: https://kubernetes.default.svc
certificate-authority-data: >-
${base64encode(file("${var.kubepath}/ca.crt"))}
users:
- name: tpl
user:
token: >-
${file("${var.kubepath}/token")}
contexts:
- name: tpl
context:
user: tpl
cluster: tpl
namespace: {{.Release.Namespace}}
current-context: tpl
EOF
}
}

View File

@ -0,0 +1,12 @@
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: {{.Values.config.prefix}}-trigger-binding
spec:
params:
- name: gitrepositoryurl
value: $(body.repository.clone_url)
- name: gitrevision
value: $(body.head_commit.id)
- name: gitbranch
value: $(extensions.branch_name)

View File

@ -0,0 +1,50 @@
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: {{.Values.config.prefix}}-pipeline-template
spec:
params:
- name: gitrevision
description: The git revision (SHA)
default: master
- name: gitbranch
description: The git branch
default: master
- name: gitrepositoryurl
description: The git repository url ("https://github.com/batleforc/rust-template")
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: {{.Values.config.prefix}}-pipeline-run-
spec:
pipelineRef:
name: {{.Values.config.prefix}}-pipeline
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: local-path
- name: dockerconfig
secret:
secretName: harbor-auth
- name: kubeconfig
secret:
secretName: kubeconfig
{{- if .Values.config.sonarqube.useToken }}
- name: sonarqube
secret:
secretName: tpl-bu-sonarqube
{{ end }}
params:
- name: repo-revision
value: $(tt.params.gitrevision)
- name: repo-branch
value: $(tt.params.gitbranch)
- name: repo-url
value: $(tt.params.gitrepositoryurl)

24
cicd/values.yaml Normal file
View File

@ -0,0 +1,24 @@
config:
prefix: botdiscord
name: batleforc
ingress:
class: haproxy
domain: webhook.weebo.fr
registry:
imageName: batleforc/botdiscord
sonarqube:
enabled: false
host: https://qube.weebo.fr
image: harbor.weebo.fr/sonar/rust:v1.17.12
useToken: false
additionalScript:
enabled: false
image: harbor.weebo.fr/sonar/rust:v1.17.12-prepare
script: |
set -x
git config --global --add safe.directory /workspace/source
git fetch --unshallow
cargo clippy --message-format=json > clippy-report.json
cargo audit --json > audit-report.json
cargo outdated --depth 1 --format json > outdated-report.json
cargo sonar --clippy --clippy-path clippy-report.json --audit --audit-path audit-report.json --outdated --outdated-path outdated-report.json

10
sonar-project.properties Normal file
View File

@ -0,0 +1,10 @@
sonar.projectKey=BotDiscord
sonar.projectname=botdiscord
sonar.projectversion=1.0
sonar.sources=.
sonar.projectDescription=Bot Discord
sonar.links.homepage=https://git.weebo.fr/sandbox/BotDiscord
sonar.links.ci=https://cicd.weebo.fr/#/namespaces/bot-discord/pipelineruns
sonar.externalIssuesReportPaths=sonar-issues.json
#community.rust.clippy.reportPaths=clippy-report.json
sonar.exclusions=deploy/**,compose.yaml,devfile.yaml,cog.toml