diff --git a/.env.template b/.env.template index 1aa2db5..9503012 100644 --- a/.env.template +++ b/.env.template @@ -1 +1,2 @@ -NAMESPACE=ecosystem \ No newline at end of file +NAMESPACE=ecosystem +STAGE=development \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bfa5a8..f0df24a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [v2.9.1-3] - 2023-12-06 +### Added +- [#2] Add patch templates for using the chart in airgapped environments. +- [#4] Add default configuration for using k8s-minio and add shared secrets k8s-promtail to send data to k8s-loki + ## [v2.9.1-2] - 2023-09-27 ### Fixed - Fix release to helm-registry diff --git a/Jenkinsfile b/Jenkinsfile index 9d3fdcf..de7c0e8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,5 @@ #!groovy -@Library('github.com/cloudogu/ces-build-lib@1.67.0') +@Library('github.com/cloudogu/ces-build-lib@1.68.0') import com.cloudogu.ces.cesbuildlib.* git = new Git(this, "cesmarvin") @@ -12,9 +12,14 @@ changelog = new Changelog(this) repositoryName = "k8s-loki" productionReleaseBranch = "main" -node('docker') { - K3d k3d = new K3d(this, "${WORKSPACE}", "${WORKSPACE}/k3d", env.PATH) +registryNamespace = "k8s" +registryUrl = "registry.cloudogu.com" + +goVersion = "1.21" +helmTargetDir = "target/k8s" +helmChartDir = "${helmTargetDir}/helm" +node('docker') { timestamps { catchError { timeout(activity: false, time: 60, unit: 'MINUTES') { @@ -23,33 +28,57 @@ node('docker') { make 'clean' } - kubevalImage = "cytopia/kubeval:0.15" - stage("Lint k8s Resources") { - new Docker(this) - .image(kubevalImage) - .inside("-v ${WORKSPACE}/loki/manifests/:/data -t --entrypoint=") - { - sh "kubeval manifests/loki.yaml --ignore-missing-schemas" + new Docker(this) + .image("golang:${goVersion}") + .mountJenkinsUser() + .inside("--volume ${WORKSPACE}:/${repositoryName} -w /${repositoryName}") + { + stage('Generate k8s Resources') { + make 'helm-update-dependencies' + make 'helm-generate' + archiveArtifacts "${helmTargetDir}/**/*" } - } - stage('Set up k3d cluster') { - k3d.startK3d() - } - stage('Install kubectl') { - k3d.installKubectl() - } + stage("Lint helm") { + make 'helm-lint' + } + } - stage('Test loki') { - echo "Loki testing stage not implemented yet" + K3d k3d = new K3d(this, "${WORKSPACE}", "${WORKSPACE}/k3d", env.PATH) + + try { + stage('Set up k3d cluster') { + k3d.startK3d() + } + + stage('Deploy minio') { + withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'harborhelmchartpush', usernameVariable: 'HARBOR_USERNAME', passwordVariable: 'HARBOR_PASSWORD']]) { + k3d.helm("registry login ${registryUrl} --username '${HARBOR_USERNAME}' --password '${HARBOR_PASSWORD}'") + k3d.helm("install k8s-minio oci://${registryUrl}/${registryNamespace}/k8s-minio --version 2023.9.23-3") + } + } + + stage('Deploy k8s-loki') { + k3d.helm("install ${repositoryName} ${helmChartDir}") + } + + stage('Test k8s-loki') { + // Sleep because it takes time for the controller to create the resource. Without it would end up + // in error "no matching resource found when run the wait command" + sleep(20) + k3d.kubectl("wait --for=condition=ready pod -l app.kubernetes.io/instance=k8s-loki --timeout=300s") + } + } catch(Exception e) { + k3d.collectAndArchiveLogs() + throw e as java.lang.Throwable + } finally { + stage('Remove k3d cluster') { + k3d.deleteK3d() + } } } } - stage('Remove k3d cluster') { - k3d.deleteK3d() - } - stageAutomaticRelease() } } @@ -59,40 +88,27 @@ void stageAutomaticRelease() { Makefile makefile = new Makefile(this) String releaseVersion = makefile.getVersion() String changelogVersion = git.getSimpleBranchName() - String registryNamespace = "k8s" - String registryUrl = "registry.cloudogu.com" - - stage('Finish Release') { - gitflow.finishRelease(changelogVersion, productionReleaseBranch) - } - - stage('Generate release resource') { - make 'generate-release-resource' - } - - stage('Push to Registry') { - GString targetResourceYaml = "target/make/${registryNamespace}/${repositoryName}_${releaseVersion}.yaml" - - DoguRegistry registry = new DoguRegistry(this) - registry.pushK8sYaml(targetResourceYaml, repositoryName, registryNamespace, "${releaseVersion}") - } stage('Push Helm chart to Harbor') { new Docker(this) - .image("golang:1.20") + .image("golang:${goVersion}") .mountJenkinsUser() .inside("--volume ${WORKSPACE}:/${repositoryName} -w /${repositoryName}") { - make "k8s/helm/charts" - make 'helm-package-release' + make 'helm-package' + archiveArtifacts "${helmTargetDir}/**/*" withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'harborhelmchartpush', usernameVariable: 'HARBOR_USERNAME', passwordVariable: 'HARBOR_PASSWORD']]) { sh ".bin/helm registry login ${registryUrl} --username '${HARBOR_USERNAME}' --password '${HARBOR_PASSWORD}'" - sh ".bin/helm push target/make/k8s/helm/${repositoryName}-${releaseVersion}.tgz oci://${registryUrl}/${registryNamespace}" + sh ".bin/helm push ${helmChartDir}/${repositoryName}-${releaseVersion}.tgz oci://${registryUrl}/${registryNamespace}" } } } + stage('Finish Release') { + gitflow.finishRelease(changelogVersion, productionReleaseBranch) + } + stage('Add Github-Release') { releaseId = github.createReleaseWithChangelog(changelogVersion, changelog, productionReleaseBranch) } diff --git a/Makefile b/Makefile index b5a0311..5d41a07 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ ARTIFACT_ID=k8s-loki -MAKEFILES_VERSION=8.4.0 -VERSION=2.9.1-2 +MAKEFILES_VERSION=9.0.1 +VERSION=2.9.1-3 .DEFAULT_GOAL:=help @@ -15,35 +15,9 @@ include build/make/self-update.mk ##@ Release -K8S_PRE_GENERATE_TARGETS=generate-release-resource include build/make/k8s-component.mk -.PHONY: generate-release-resource -generate-release-resource: $(K8S_RESOURCE_TEMP_FOLDER) - @cp manifests/loki.yaml ${K8S_RESOURCE_TEMP_YAML} - .PHONY: loki-release loki-release: ## Interactively starts the release workflow for loki @echo "Starting git flow release..." @build/make/release.sh loki - -##@ Helm dev targets -# Loki needs a copy of the targets from k8s.mk without image-import because we use an external image here. - -.PHONY: ${K8S_HELM_RESSOURCES}/charts -${K8S_HELM_RESSOURCES}/charts: ${BINARY_HELM} - @cd ${K8S_HELM_RESSOURCES} && ${BINARY_HELM} repo add grafana https://grafana.github.io/helm-charts && ${BINARY_HELM} dependency build - -.PHONY: helm-loki-apply -helm-loki-apply: ${BINARY_HELM} ${K8S_HELM_RESSOURCES}/charts helm-generate $(K8S_POST_GENERATE_TARGETS) ## Generates and installs the helm chart. - @echo "Apply generated helm chart" - @${BINARY_HELM} upgrade -i ${ARTIFACT_ID} ${K8S_HELM_TARGET} --namespace ${NAMESPACE} - -.PHONY: helm-loki-reinstall -helm-loki-reinstall: helm-delete helm-loki-apply ## Uninstalls the current helm chart and reinstalls it. - -.PHONY: helm-loki-chart-import -helm-loki-chart-import: ${BINARY_HELM} ${K8S_HELM_RESSOURCES}/charts k8s-generate helm-generate-chart helm-package-release ## Pushes the helm chart to the k3ces registry. - @echo "Import ${K8S_HELM_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..." - @${BINARY_HELM} push ${K8S_HELM_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/k8s ${BINARY_HELM_ADDITIONAL_PUSH_ARGS} - @echo "Done." diff --git a/build/make/coder-lib.sh b/build/make/coder-lib.sh index 5be68fc..2b5d198 100755 --- a/build/make/coder-lib.sh +++ b/build/make/coder-lib.sh @@ -2,8 +2,19 @@ # a collection of helpful functions to update coder workspaces for rapid development set -e -u -x -o pipefail +function getContainerBin() { + if [ -x "$(command -v podman)" ]; then + echo "podman"; + else + echo "docker"; + fi +} + function getCoderUser() { - coder users show me -o json | jq -r '.username' + # check if coder is installed, so that there is no problem with build and release targets if this is called before + if [ -x "$(command -v coder)" ]; then + coder users show me -o json | jq -r '.username'; + fi } function getAllWorkspaces() { @@ -40,23 +51,27 @@ function generateUniqueWorkspaceName() { function buildImage() { local tag="$1" - local buildDir="${2:-./build}" - local secretDir="${3:-./secretArgs}" + local containerBuildDir="${2:-./container}" + local secretDir="${3:-./secrets}" local containerExec="${4:-podman}" - local secretArgs=() + # include build-secrets if there are any - # shellcheck disable=SC2231 - for secretPath in $secretDir/*; do - # do not match .sh scripts - [[ $secretPath == *.sh ]] && continue - local secretName - secretName=$(basename "$secretPath") - secretArgs+=("--secret=id=$secretName,src=$secretDir/$secretName") - done + local secretArgs=() + if [ -d "$secretDir" ]; then + # shellcheck disable=SC2231 + for secretPath in $secretDir/*; do + # do not match .sh scripts + [[ $secretPath == *.sh ]] && continue + local secretName + secretName=$(basename "$secretPath") + secretArgs+=("--secret=id=$secretName,src=$secretDir/$secretName") + done + fi + if [ "$containerExec" = "podman" ]; then - $containerExec build -t "$tag" --pull=newer "$buildDir" "${secretArgs[@]}" + $containerExec build -t "$tag" --pull=newer "$containerBuildDir" "${secretArgs[@]}" else - $containerExec build -t "$tag" --pull "$buildDir" "${secretArgs[@]}" + $containerExec build -t "$tag" --pull "$containerBuildDir" "${secretArgs[@]}" fi } diff --git a/build/make/coder.mk b/build/make/coder.mk index f80d991..07f4d43 100644 --- a/build/make/coder.mk +++ b/build/make/coder.mk @@ -28,10 +28,9 @@ CHANGELOG_FILE=${WORKDIR}/CHANGELOG.md TEMPLATE_RELEASE_TAR_GZ=${RELEASE_DIR}/${TEMPLATE_NAME}-template.tar.gz TEST_WORKSPACE_PREFIX?=test-${TEMPLATE_NAME} -# only set if coder is installed, so that there is no problem with build and release targets -CODER_USER?=$(shell if [ -x "$(command -v coder)" ]; then coder users show me -o json | jq -r '.username'; else echo ""; fi ) +CODER_USER?=$(shell . ${CODER_LIB_PATH} && getCoderUser) -CONTAINER_BIN?=$(shell if [ -x "$(command -v podman)" ]; then echo "podman"; else echo "docker"; fi) +CONTAINER_BIN?=$(shell . ${CODER_LIB_PATH} && getContainerBin) GOPASS_BIN?=$(shell command -v gopass 2> /dev/null) EXCLUDED_TEMPLATE_FILES?=rich-parameters.yaml variables.yaml diff --git a/build/make/k8s-component.mk b/build/make/k8s-component.mk index a8b733d..9d29183 100644 --- a/build/make/k8s-component.mk +++ b/build/make/k8s-component.mk @@ -1,67 +1,84 @@ -DEV_VERSION?=${VERSION}-dev -## Image URL to use all building/pushing image targets -IMAGE_DEV?=${K3CES_REGISTRY_URL_PREFIX}/${ARTIFACT_ID}:${DEV_VERSION} +COMPONENT_DEV_VERSION?=${VERSION}-dev -include $(WORKDIR)/build/make/k8s.mk +include ${BUILD_DIR}/make/k8s.mk -BINARY_HELM = $(UTILITY_BIN_PATH)/helm -BINARY_HELM_VERSION?=v3.12.0-dev.1.0.20230817154107-a749b663101d BINARY_HELM_ADDITIONAL_PUSH_ARGS?=--plain-http BINARY_HELM_ADDITIONAL_PACK_ARGS?= BINARY_HELM_ADDITIONAL_UNINST_ARGS?= BINARY_HELM_ADDITIONAL_UPGR_ARGS?= -K8S_HELM_TARGET ?= $(K8S_RESOURCE_TEMP_FOLDER)/helm -K8S_HELM_RESSOURCES ?= k8s/helm -K8S_HELM_RELEASE_TGZ=${K8S_HELM_TARGET}/${ARTIFACT_ID}-${VERSION}.tgz -K8S_HELM_DEV_RELEASE_TGZ=${K8S_HELM_TARGET}/${ARTIFACT_ID}-${DEV_VERSION}.tgz -K8S_HELM_ARTIFACT_NAMESPACE?=k8s +HELM_TARGET_DIR ?= $(K8S_RESOURCE_TEMP_FOLDER)/helm +HELM_SOURCE_DIR ?= k8s/helm +HELM_RELEASE_TGZ=${HELM_TARGET_DIR}/${ARTIFACT_ID}-${VERSION}.tgz +HELM_DEV_RELEASE_TGZ=${HELM_TARGET_DIR}/${ARTIFACT_ID}-${COMPONENT_DEV_VERSION}.tgz +HELM_ARTIFACT_NAMESPACE?=k8s K8S_RESOURCE_COMPONENT ?= "${K8S_RESOURCE_TEMP_FOLDER}/component-${ARTIFACT_ID}-${VERSION}.yaml" -K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML ?= $(WORKDIR)/build/make/k8s-component.tpl +K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML ?= $(BUILD_DIR)/make/k8s-component.tpl +# HELM_PRE_GENERATE_TARGETS allows to execute targets that affect Helm source files AND Helm target files. +HELM_PRE_GENERATE_TARGETS ?= +# HELM_POST_GENERATE_TARGETS allows to execute targets that only affect Helm target files. +HELM_POST_GENERATE_TARGETS ?= +HELM_PRE_APPLY_TARGETS ?= +COMPONENT_PRE_APPLY_TARGETS ?= + +# This can be used by components with own images to build and push to the dev registry. +# These components should override this variable with `image-import`. +IMAGE_IMPORT_TARGET?= ##@ K8s - Helm general .PHONY: helm-init-chart helm-init-chart: ${BINARY_HELM} ## Creates a Chart.yaml-template with zero values - @echo "Initialize ${K8S_HELM_RESSOURCES}/Chart.yaml..." - @mkdir -p ${K8S_HELM_RESSOURCES}/tmp/ - @${BINARY_HELM} create ${K8S_HELM_RESSOURCES}/tmp/${ARTIFACT_ID} - @cp ${K8S_HELM_RESSOURCES}/tmp/${ARTIFACT_ID}/Chart.yaml ${K8S_HELM_RESSOURCES}/ - @rm -dr ${K8S_HELM_RESSOURCES}/tmp - @sed -i 's/appVersion: ".*"/appVersion: "0.0.0-replaceme"/' ${K8S_HELM_RESSOURCES}/Chart.yaml - @sed -i 's/version: .*/version: 0.0.0-replaceme/' ${K8S_HELM_RESSOURCES}/Chart.yaml - -.PHONY: helm-generate-chart -helm-generate-chart: k8s-generate ${K8S_HELM_TARGET}/Chart.yaml ## Generates the final helm chart. - -.PHONY: ${K8S_HELM_TARGET}/Chart.yaml -${K8S_HELM_TARGET}/Chart.yaml: $(K8S_RESOURCE_TEMP_FOLDER) k8s-generate - @echo "Generate helm chart..." - @rm -drf ${K8S_HELM_TARGET} # delete folder, so the chart is newly created. - @mkdir -p ${K8S_HELM_TARGET}/templates - @cp $(K8S_RESOURCE_TEMP_YAML) ${K8S_HELM_TARGET}/templates - @sed -i "s/'{{ .Namespace }}'/'{{ .Release.Namespace }}'/" ${K8S_HELM_TARGET}/templates/$(ARTIFACT_ID)_$(VERSION).yaml - @cp -r ${K8S_HELM_RESSOURCES}/** ${K8S_HELM_TARGET} + @echo "Initialize ${HELM_SOURCE_DIR}/Chart.yaml..." + @mkdir -p ${HELM_SOURCE_DIR}/tmp/ + @${BINARY_HELM} create ${HELM_SOURCE_DIR}/tmp/${ARTIFACT_ID} + @cp ${HELM_SOURCE_DIR}/tmp/${ARTIFACT_ID}/Chart.yaml ${HELM_SOURCE_DIR}/ + @rm -dr ${HELM_SOURCE_DIR}/tmp + @sed -i 's/appVersion: ".*"/appVersion: "0.0.0-replaceme"/' ${HELM_SOURCE_DIR}/Chart.yaml + @sed -i 's/version: .*/version: 0.0.0-replaceme/' ${HELM_SOURCE_DIR}/Chart.yaml + +.PHONY: helm-generate +helm-generate: ${HELM_TARGET_DIR}/Chart.yaml ${HELM_POST_GENERATE_TARGETS} ## Generates the final helm chart. + +# this is phony because of it is easier this way than the makefile-single-run way +.PHONY: ${HELM_TARGET_DIR}/Chart.yaml +${HELM_TARGET_DIR}/Chart.yaml: $(K8S_RESOURCE_TEMP_FOLDER) validate-chart ${HELM_PRE_GENERATE_TARGETS} copy-helm-files + @echo "Generate Helm chart..." @if [[ ${STAGE} == "development" ]]; then \ - sed -i 's/appVersion: "0.0.0-replaceme"/appVersion: '$(DEV_VERSION)'/' ${K8S_HELM_TARGET}/Chart.yaml; \ - sed -i 's/version: 0.0.0-replaceme/version: '$(DEV_VERSION)'/' ${K8S_HELM_TARGET}/Chart.yaml; \ + sed -i 's/appVersion: "0.0.0-replaceme"/appVersion: '$(COMPONENT_DEV_VERSION)'/' ${HELM_TARGET_DIR}/Chart.yaml; \ + sed -i 's/version: 0.0.0-replaceme/version: '$(COMPONENT_DEV_VERSION)'/' ${HELM_TARGET_DIR}/Chart.yaml; \ else \ - sed -i 's/appVersion: "0.0.0-replaceme"/appVersion: "${VERSION}"/' ${K8S_HELM_TARGET}/Chart.yaml; \ - sed -i 's/version: 0.0.0-replaceme/version: ${VERSION}/' ${K8S_HELM_TARGET}/Chart.yaml; \ + sed -i 's/appVersion: "0.0.0-replaceme"/appVersion: "${VERSION}"/' ${HELM_TARGET_DIR}/Chart.yaml; \ + sed -i 's/version: 0.0.0-replaceme/version: ${VERSION}/' ${HELM_TARGET_DIR}/Chart.yaml; \ fi -##@ K8s - Helm dev targets +.PHONY: copy-helm-files +copy-helm-files: + @echo "Copying Helm files..." + @rm -drf ${HELM_TARGET_DIR} # delete folder, so the chart is newly created. + @mkdir -p ${HELM_TARGET_DIR}/templates + @cp -r ${HELM_SOURCE_DIR}/** ${HELM_TARGET_DIR} + +.PHONY: validate-chart +validate-chart: + @if [ ! -f ${HELM_SOURCE_DIR}/Chart.yaml ] ; then \ + echo "Could not find source Helm chart under \$${HELM_SOURCE_DIR}/Chart.yaml" ; \ + exit 22 ; \ + fi -.PHONY: helm-generate -helm-generate: helm-generate-chart ## Generates the final helm chart with dev-urls. +.PHONY: helm-update-dependencies +helm-update-dependencies: ${BINARY_HELM} ## Update Helm chart dependencies + @$(BINARY_HELM) dependency update "${HELM_SOURCE_DIR}" + +##@ K8s - Helm dev targets .PHONY: helm-apply -helm-apply: ${BINARY_HELM} check-k8s-namespace-env-var image-import helm-generate $(K8S_POST_GENERATE_TARGETS) ## Generates and installs the helm chart. +helm-apply: ${BINARY_HELM} check-k8s-namespace-env-var ${IMAGE_IMPORT_TARGET} helm-generate ${HELM_PRE_APPLY_TARGETS} ## Generates and installs the Helm chart. @echo "Apply generated helm chart" - @${BINARY_HELM} upgrade -i ${ARTIFACT_ID} ${K8S_HELM_TARGET} ${BINARY_HELM_ADDITIONAL_UPGR_ARGS} --namespace ${NAMESPACE} + @${BINARY_HELM} upgrade -i ${ARTIFACT_ID} ${HELM_TARGET_DIR} ${BINARY_HELM_ADDITIONAL_UPGR_ARGS} --namespace ${NAMESPACE} .PHONY: helm-delete -helm-delete: ${BINARY_HELM} check-k8s-namespace-env-var ## Uninstalls the current helm chart. +helm-delete: ${BINARY_HELM} check-k8s-namespace-env-var ## Uninstalls the current Helm chart. @echo "Uninstall helm chart" @${BINARY_HELM} uninstall ${ARTIFACT_ID} --namespace=${NAMESPACE} ${BINARY_HELM_ADDITIONAL_UNINST_ARGS} || true @@ -69,52 +86,58 @@ helm-delete: ${BINARY_HELM} check-k8s-namespace-env-var ## Uninstalls the curren helm-reinstall: helm-delete helm-apply ## Uninstalls the current helm chart and reinstalls it. .PHONY: helm-chart-import -helm-chart-import: check-all-vars check-k8s-artifact-id helm-generate-chart helm-package-release image-import ## Imports the currently available chart into the cluster-local registry. +helm-chart-import: ${CHECK_VAR_TARGETS} helm-generate helm-package ${IMAGE_IMPORT_TARGET} ## Imports the currently available chart into the cluster-local registry. @if [[ ${STAGE} == "development" ]]; then \ - echo "Import ${K8S_HELM_DEV_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ - ${BINARY_HELM} push ${K8S_HELM_DEV_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${K8S_HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ + echo "Import ${HELM_DEV_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ + ${BINARY_HELM} push ${HELM_DEV_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ else \ - echo "Import ${K8S_HELM_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ - ${BINARY_HELM} push ${K8S_HELM_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${K8S_HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ + echo "Import ${HELM_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ + ${BINARY_HELM} push ${HELM_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ fi @echo "Done." ##@ K8s - Helm release targets .PHONY: helm-generate-release -helm-generate-release: ${K8S_HELM_TARGET}/templates/$(ARTIFACT_ID)_$(VERSION).yaml ## Generates the final helm chart with release urls. +helm-generate-release: update-urls ## Generates the final helm chart with release URLs. + -${K8S_HELM_TARGET}/templates/$(ARTIFACT_ID)_$(VERSION).yaml: $(K8S_PRE_GENERATE_TARGETS) ${K8S_HELM_TARGET}/Chart.yaml - @sed -i "s/'{{ .Namespace }}'/'{{ .Release.Namespace }}'/" ${K8S_HELM_TARGET}/templates/$(ARTIFACT_ID)_$(VERSION).yaml +.PHONY: helm-package +helm-package: helm-delete-existing-tgz ${HELM_RELEASE_TGZ} ## Generates and packages the helm chart with release URLs. -.PHONY: helm-package-release -helm-package-release: ${BINARY_HELM} helm-delete-existing-tgz ${K8S_HELM_RELEASE_TGZ} ## Generates and packages the helm chart with release urls. +${HELM_RELEASE_TGZ}: ${BINARY_HELM} ${HELM_TARGET_DIR}/Chart.yaml ${HELM_POST_GENERATE_TARGETS} ## Generates and packages the helm chart with release URLs. + @echo "Package generated helm chart" + @if [[ ${STAGE} == "development" ]]; then \ + echo "WARNING: You are using a development environment" ; \ + fi + @${BINARY_HELM} package ${HELM_TARGET_DIR} -d ${HELM_TARGET_DIR} ${BINARY_HELM_ADDITIONAL_PACK_ARGS} .PHONY: helm-delete-existing-tgz -helm-delete-existing-tgz: ## Remove an existing Helm package. -# remove - @rm -f ${K8S_HELM_RELEASE_TGZ}* +helm-delete-existing-tgz: ## Remove an existing Helm package from the target directory. + @echo "Delete ${HELM_RELEASE_TGZ}*" + @rm -f ${HELM_RELEASE_TGZ}* -${K8S_HELM_RELEASE_TGZ}: ${BINARY_HELM} ${K8S_HELM_TARGET}/templates/$(ARTIFACT_ID)_$(VERSION).yaml helm-generate-chart $(K8S_POST_GENERATE_TARGETS) ## Generates and packages the helm chart with release urls. - @echo "Package generated helm chart" - @${BINARY_HELM} package ${K8S_HELM_TARGET} -d ${K8S_HELM_TARGET} ${BINARY_HELM_ADDITIONAL_PACK_ARGS} +##@ K8s - Helm lint targets -${BINARY_HELM}: $(UTILITY_BIN_PATH) ## Download helm locally if necessary. - $(call go-get-tool,$(BINARY_HELM),helm.sh/helm/v3/cmd/helm@${BINARY_HELM_VERSION}) +.PHONY: helm-lint +helm-lint: $(BINARY_HELM) helm-generate + @$(BINARY_HELM) lint "${HELM_TARGET_DIR}" ##@ K8s - Component dev targets .PHONY: component-generate -component-generate: ${K8S_RESOURCE_TEMP_FOLDER} ## Generate the component yaml resource. +component-generate: ${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML} ${COMPONENT_POST_GENERATE_TARGETS} ## Generate the component yaml resource. + +${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML}: ${K8S_RESOURCE_TEMP_FOLDER} @echo "Generating temporary K8s component resource: ${K8S_RESOURCE_COMPONENT}" @if [[ ${STAGE} == "development" ]]; then \ - sed "s|NAMESPACE|$(K8S_HELM_ARTIFACT_NAMESPACE)|g" "${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML}" | sed "s|NAME|$(ARTIFACT_ID)|g" | sed "s|VERSION|$(DEV_VERSION)|g" > "${K8S_RESOURCE_COMPONENT}"; \ + sed "s|NAMESPACE|$(HELM_ARTIFACT_NAMESPACE)|g" "${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML}" | sed "s|NAME|$(ARTIFACT_ID)|g" | sed "s|VERSION|$(COMPONENT_DEV_VERSION)|g" > "${K8S_RESOURCE_COMPONENT}"; \ else \ - sed "s|NAMESPACE|$(K8S_HELM_ARTIFACT_NAMESPACE)|g" "${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML}" | sed "s|NAME|$(ARTIFACT_ID)|g" | sed "s|VERSION|$(VERSION)|g" > "${K8S_RESOURCE_COMPONENT}"; \ + sed "s|NAMESPACE|$(HELM_ARTIFACT_NAMESPACE)|g" "${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML}" | sed "s|NAME|$(ARTIFACT_ID)|g" | sed "s|VERSION|$(VERSION)|g" > "${K8S_RESOURCE_COMPONENT}"; \ fi .PHONY: component-apply -component-apply: check-k8s-namespace-env-var image-import helm-generate helm-chart-import component-generate $(K8S_POST_GENERATE_TARGETS) ## Applies the component yaml resource to the actual defined context. +component-apply: check-k8s-namespace-env-var ${COMPONENT_PRE_APPLY_TARGETS} ${IMAGE_IMPORT_TARGET} helm-generate helm-chart-import component-generate ## Applies the component yaml resource to the actual defined context. @kubectl apply -f "${K8S_RESOURCE_COMPONENT}" --namespace="${NAMESPACE}" @echo "Done." @@ -124,4 +147,4 @@ component-delete: check-k8s-namespace-env-var component-generate $(K8S_POST_GENE @echo "Done." .PHONY: component-reinstall -component-reinstall: component-delete component-apply ## Reinstalls the component yaml resource from the actual defined context. \ No newline at end of file +component-reinstall: component-delete component-apply ## Reinstalls the component yaml resource from the actual defined context. diff --git a/build/make/k8s-component.tpl b/build/make/k8s-component.tpl index 0192eec..fa0eaa6 100644 --- a/build/make/k8s-component.tpl +++ b/build/make/k8s-component.tpl @@ -1,3 +1,6 @@ +# Use the property .spec.deployNamespace to define the namespace the component should be deployed to. +# Make environment variable 'COMPONENT_DEPLOY_NAMESPACE' is responsible for that. +# If 'COMPONENT_DEPLOY_NAMESPACE' is empty the property 'deployNamespace' will be deleted. apiVersion: k8s.cloudogu.com/v1 kind: Component metadata: diff --git a/build/make/k8s-controller.mk b/build/make/k8s-controller.mk index b1ffb76..ea3d457 100644 --- a/build/make/k8s-controller.mk +++ b/build/make/k8s-controller.mk @@ -1,20 +1,6 @@ -# This script can be used to build and deploy kubernetes controllers. It is required to implement the controller -# specific targets `manifests` and `generate`: -# -# Examples: -# -#.PHONY: manifests -#manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. -# @echo "Generate manifests..." -# @$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases -# -#.PHONY: generate -#generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. -# @echo "Auto-generate deepcopy functions..." -# @$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." - # This script requires the k8s.mk script -include $(WORKDIR)/build/make/k8s-component.mk +include ${BUILD_DIR}/make/k8s-component.mk +include ${BUILD_DIR}/make/k8s-crd.mk ## Variables @@ -49,7 +35,7 @@ build-controller: ${SRC} compile ## Builds the controller Go binary. # Allows to perform tasks before locally running the controller K8S_RUN_PRE_TARGETS ?= .PHONY: run -run: manifests generate $(K8S_RUN_PRE_TARGETS) ## Run a controller from your host. +run: generate-deepcopy $(K8S_RUN_PRE_TARGETS) ## Run a controller from your host. go run -ldflags "-X main.Version=$(VERSION)" ./main.go ##@ K8s - Integration test with envtest @@ -58,33 +44,13 @@ $(K8S_INTEGRATION_TEST_DIR): @mkdir -p $@ .PHONY: k8s-integration-test -k8s-integration-test: $(K8S_INTEGRATION_TEST_DIR) manifests generate envtest ## Run k8s integration tests. +k8s-integration-test: $(K8S_INTEGRATION_TEST_DIR) ${ENVTEST} ## Run k8s integration tests. @echo "Running K8s integration tests..." @KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -tags=k8s_integration ./... -coverprofile ${K8S_INTEGRATION_TEST_DIR}/report-k8s-integration.out -##@ K8s - Controller Resource - -# The pre generation script creates a K8s resource yaml containing generated manager yaml. -.PHONY: k8s-create-temporary-resource - k8s-create-temporary-resource: $(K8S_RESOURCE_TEMP_FOLDER) manifests kustomize - @echo "Generating temporary k8s resources $(K8S_RESOURCE_TEMP_YAML)..." - cd $(WORKDIR)/config/manager && $(KUSTOMIZE) edit set image controller=$(IMAGE) - $(KUSTOMIZE) build config/default > $(K8S_RESOURCE_TEMP_YAML) - @echo "Done." - -##@ K8s - Download Kubernetes Utility Tools - -CONTROLLER_GEN = $(UTILITY_BIN_PATH)/controller-gen -.PHONY: controller-gen -controller-gen: ## Download controller-gen locally if necessary. - $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.13.0) - -KUSTOMIZE = $(UTILITY_BIN_PATH)/kustomize -.PHONY: kustomize -kustomize: ## Download kustomize locally if necessary. - $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v4@v4.5.7) +##@ Controller specific targets -ENVTEST = $(UTILITY_BIN_PATH)/setup-envtest -.PHONY: envtest -envtest: ## Download envtest-setup locally if necessary. - $(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest) \ No newline at end of file +.PHONY: generate-deepcopy +generate-deepcopy: ${CONTROLLER_GEN} ## Generate code containing DeepCopy* method implementations. + @echo "Auto-generate deepcopy functions..." + @$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." diff --git a/build/make/k8s-crd.mk b/build/make/k8s-crd.mk new file mode 100644 index 0000000..4cbcd88 --- /dev/null +++ b/build/make/k8s-crd.mk @@ -0,0 +1,115 @@ +ARTIFACT_CRD_ID = $(ARTIFACT_ID)-crd +DEV_CRD_VERSION ?= ${VERSION}-dev +HELM_CRD_SOURCE_DIR ?= ${WORKDIR}/k8s/helm-crd +HELM_CRD_TARGET_DIR ?= $(K8S_RESOURCE_TEMP_FOLDER)/helm-crd +HELM_CRD_RELEASE_TGZ = ${HELM_CRD_TARGET_DIR}/${ARTIFACT_CRD_ID}-${VERSION}.tgz +HELM_CRD_DEV_RELEASE_TGZ = ${HELM_CRD_TARGET_DIR}/${ARTIFACT_CRD_ID}-${DEV_CRD_VERSION}.tgz + +K8S_RESOURCE_CRD_COMPONENT ?= "${K8S_RESOURCE_TEMP_FOLDER}/component-${ARTIFACT_CRD_ID}-${VERSION}.yaml" +K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML ?= $(BUILD_DIR)/make/k8s-component.tpl +# CRD_POST_MANIFEST_TARGETS can be used to post-process CRD YAMLs after their creation. +CRD_POST_MANIFEST_TARGETS ?= crd-add-labels + +# This can be used by external components to prevent generate and copy controller manifests by overriding with an empty value. +CRD_HELM_MANIFEST_TARGET?=manifests + +##@ K8s - CRD targets + +.PHONY: manifests +manifests: ${CONTROLLER_GEN} manifests-run ${CRD_POST_MANIFEST_TARGETS} ## Generate CustomResourceDefinition YAMLs. + +.PHONY: manifests-run +manifests-run: + @echo "Generate manifests..." + @$(CONTROLLER_GEN) crd paths="./..." output:crd:artifacts:config=${HELM_CRD_SOURCE_DIR}/templates + +.PHONY: crd-add-labels +crd-add-labels: $(BINARY_YQ) + @echo "Adding labels to CRD..." + @for file in ${HELM_CRD_SOURCE_DIR}/templates/*.yaml ; do \ + $(BINARY_YQ) -i e ".metadata.labels.app = \"ces\"" $${file} ;\ + $(BINARY_YQ) -i e ".metadata.labels.\"app.kubernetes.io/name\" = \"${ARTIFACT_ID}\"" $${file} ;\ + done + +.PHONY: crd-helm-generate ## Generates the Helm CRD chart +crd-helm-generate: ${CRD_HELM_MANIFEST_TARGET} validate-crd-chart ${HELM_CRD_TARGET_DIR}/Chart.yaml ${K8S_POST_CRD_HELM_GENERATE_TARGETS} + +# this is phony because of it is easier this way than the makefile-single-run way +.PHONY: ${HELM_CRD_TARGET_DIR}/Chart.yaml +${HELM_CRD_TARGET_DIR}/Chart.yaml: ${K8S_RESOURCE_TEMP_FOLDER} + @echo "Copying Helm CRD files..." + @rm -drf ${HELM_CRD_TARGET_DIR}/templates + @mkdir -p ${HELM_CRD_TARGET_DIR}/templates + @cp -r ${HELM_CRD_SOURCE_DIR}/** ${HELM_CRD_TARGET_DIR} + + @echo "Generate Helm CRD chart..." + @sed -i 's/name: artifact-crd-replaceme/name: ${ARTIFACT_CRD_ID}/' ${HELM_CRD_TARGET_DIR}/Chart.yaml + @if [[ ${STAGE} == "development" ]]; then \ + sed -i 's/appVersion: "0.0.0-replaceme"/appVersion: "${DEV_CRD_VERSION}"/' ${HELM_CRD_TARGET_DIR}/Chart.yaml; \ + sed -i 's/version: 0.0.0-replaceme/version: ${DEV_CRD_VERSION}/' ${HELM_CRD_TARGET_DIR}/Chart.yaml; \ + else \ + sed -i 's/appVersion: "0.0.0-replaceme"/appVersion: "${VERSION}"/' ${HELM_CRD_TARGET_DIR}/Chart.yaml; \ + sed -i 's/version: 0.0.0-replaceme/version: ${VERSION}/' ${HELM_CRD_TARGET_DIR}/Chart.yaml; \ + fi + +.PHONY: validate-crd-chart +validate-crd-chart: + @if [ ! -f ${HELM_CRD_SOURCE_DIR}/Chart.yaml ] ; then \ + echo "Could not find CRD source Helm chart under \$${HELM_CRD_SOURCE_DIR}/Chart.yaml" ; \ + exit 23 ; \ + fi + +.PHONY: crd-helm-apply +crd-helm-apply: ${BINARY_HELM} check-k8s-namespace-env-var crd-helm-generate ## Generates and installs the Helm CRD chart. + @echo "Apply generated Helm CRD chart" + @${BINARY_HELM} upgrade -i ${ARTIFACT_CRD_ID} ${HELM_CRD_TARGET_DIR} ${BINARY_HELM_ADDITIONAL_UPGR_ARGS} --namespace ${NAMESPACE} + +.PHONY: crd-helm-delete +crd-helm-delete: ${BINARY_HELM} check-k8s-namespace-env-var ## Uninstalls the current Helm CRD chart. + @echo "Uninstall Helm CRD chart" + @${BINARY_HELM} uninstall ${ARTIFACT_CRD_ID} --namespace=${NAMESPACE} ${BINARY_HELM_ADDITIONAL_UNINST_ARGS} || true + +.PHONY: crd-helm-package +crd-helm-package: crd-helm-delete-existing-tgz ${HELM_CRD_RELEASE_TGZ} ## Generates and packages the Helm CRD chart. + +.PHONY: crd-helm-delete-existing-tgz +crd-helm-delete-existing-tgz: ## Remove an existing Helm CRD package. + @rm -f ${HELM_CRD_RELEASE_TGZ}* + +${HELM_CRD_RELEASE_TGZ}: ${BINARY_HELM} crd-helm-generate ## Generates and packages the Helm CRD chart. + @echo "Package generated helm crd-chart" + @${BINARY_HELM} package ${HELM_CRD_TARGET_DIR} -d ${HELM_CRD_TARGET_DIR} ${BINARY_HELM_ADDITIONAL_PACK_ARGS} + +.PHONY: crd-helm-chart-import +crd-helm-chart-import: ${CHECK_VAR_TARGETS} check-k8s-artifact-id crd-helm-generate crd-helm-package ## Imports the currently available Helm CRD chart into the cluster-local registry. + @if [[ ${STAGE} == "development" ]]; then \ + echo "Import ${HELM_CRD_DEV_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ + ${BINARY_HELM} push ${HELM_CRD_DEV_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ + else \ + echo "Import ${HELM_CRD_RELEASE_TGZ} into K8s cluster ${K3CES_REGISTRY_URL_PREFIX}..."; \ + ${BINARY_HELM} push ${HELM_CRD_RELEASE_TGZ} oci://${K3CES_REGISTRY_URL_PREFIX}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ + fi + @echo "Done." + +.PHONY: crd-helm-lint +crd-helm-lint: $(BINARY_HELM) crd-helm-generate + @$(BINARY_HELM) lint "${HELM_CRD_TARGET_DIR}" + +.PHONY: crd-component-generate +crd-component-generate: ${K8S_RESOURCE_TEMP_FOLDER} ## Generate the CRD component YAML resource. + @echo "Generating temporary K8s crd-component resource: ${K8S_RESOURCE_CRD_COMPONENT}" + @if [[ ${STAGE} == "development" ]]; then \ + sed "s|NAMESPACE|$(HELM_ARTIFACT_NAMESPACE)|g" "${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML}" | sed "s|NAME|$(ARTIFACT_CRD_ID)|g" | sed "s|VERSION|$(DEV_CRD_VERSION)|g" > "${K8S_RESOURCE_CRD_COMPONENT}"; \ + else \ + sed "s|NAMESPACE|$(HELM_ARTIFACT_NAMESPACE)|g" "${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML}" | sed "s|NAME|$(ARTIFACT_CRD_ID)|g" | sed "s|VERSION|$(VERSION)|g" > "${K8S_RESOURCE_CRD_COMPONENT}"; \ + fi + +.PHONY: crd-component-apply +crd-component-apply: check-k8s-namespace-env-var crd-helm-chart-import crd-component-generate ## Applies the CRD component YAML resource to the actual defined context. + @kubectl apply -f "${K8S_RESOURCE_CRD_COMPONENT}" --namespace="${NAMESPACE}" + @echo "Done." + +.PHONY: crd-component-delete +crd-component-delete: check-k8s-namespace-env-var crd-component-generate ## Deletes the CRD component YAML resource from the actual defined context. + @kubectl delete -f "${K8S_RESOURCE_CRD_COMPONENT}" --namespace="${NAMESPACE}" || true + @echo "Done." diff --git a/build/make/k8s-dogu.mk b/build/make/k8s-dogu.mk index c498dcd..9c244a3 100644 --- a/build/make/k8s-dogu.mk +++ b/build/make/k8s-dogu.mk @@ -1,7 +1,7 @@ # Variables # Path to the dogu json of the dogu -DOGU_JSON_FILE=$(WORKDIR)/dogu.json -DOGU_JSON_DEV_FILE=${TARGET_DIR}/dogu.json +DOGU_JSON_FILE=${WORKDIR}/dogu.json +DOGU_JSON_DEV_FILE=${WORKDIR}/${TARGET_DIR}/dogu.json # Name of the dogu is extracted from the dogu.json ARTIFACT_ID=$(shell $(BINARY_YQ) -e ".Name" $(DOGU_JSON_FILE) | sed "s|.*/||g") # Namespace of the dogu is extracted from the dogu.json @@ -13,27 +13,32 @@ IMAGE=$(shell $(BINARY_YQ) -e ".Image" $(DOGU_JSON_FILE)):$(VERSION) IMAGE_DEV_WITHOUT_TAG=$(shell $(BINARY_YQ) -e ".Image" $(DOGU_JSON_FILE) | sed "s|registry\.cloudogu\.com\(.\+\)|${K3CES_REGISTRY_URL_PREFIX}\1|g") IMAGE_DEV=${IMAGE_DEV_WITHOUT_TAG}:${VERSION} -include $(WORKDIR)/build/make/k8s.mk +include $(BUILD_DIR)/make/k8s.mk ##@ K8s - EcoSystem .PHONY: build -build: image-import install-dogu-descriptor k8s-apply ## Builds a new version of the dogu and deploys it into the K8s-EcoSystem. +build: image-import install-dogu-descriptor create-dogu-resource apply-dogu-resource ## Builds a new version of the dogu and deploys it into the K8s-EcoSystem. ##@ K8s - Dogu - Resource # The additional k8s yaml files K8S_RESOURCE_PRODUCTIVE_FOLDER ?= $(WORKDIR)/k8s K8S_RESOURCE_PRODUCTIVE_YAML ?= $(K8S_RESOURCE_PRODUCTIVE_FOLDER)/$(ARTIFACT_ID).yaml -K8S_RESOURCE_DOGU_CR_TEMPLATE_YAML ?= $(WORKDIR)/build/make/k8s-dogu.tpl +K8S_RESOURCE_DOGU_CR_TEMPLATE_YAML ?= $(BUILD_DIR)/make/k8s-dogu.tpl +K8S_RESOURCE_DOGU ?= $(K8S_RESOURCE_TEMP_FOLDER)/$(ARTIFACT_ID).yaml # The pre generation script creates a k8s resource yaml containing the dogu crd and the content from the k8s folder. -.PHONY: k8s-create-temporary-resource - k8s-create-temporary-resource: ${BINARY_YQ} $(K8S_RESOURCE_TEMP_FOLDER) - @echo "Generating temporary K8s resources $(K8S_RESOURCE_TEMP_YAML)..." - @rm -f $(K8S_RESOURCE_TEMP_YAML) - @sed "s|NAMESPACE|$(ARTIFACT_NAMESPACE)|g" $(K8S_RESOURCE_DOGU_CR_TEMPLATE_YAML) | sed "s|NAME|$(ARTIFACT_ID)|g" | sed "s|VERSION|$(VERSION)|g" >> $(K8S_RESOURCE_TEMP_YAML) +.PHONY: create-dogu-resource +create-dogu-resource: ${BINARY_YQ} $(K8S_RESOURCE_TEMP_FOLDER) + @echo "Generating temporary K8s resources $(K8S_RESOURCE_DOGU)..." + @rm -f $(K8S_RESOURCE_DOGU) + @sed "s|NAMESPACE|$(ARTIFACT_NAMESPACE)|g" $(K8S_RESOURCE_DOGU_CR_TEMPLATE_YAML) | sed "s|NAME|$(ARTIFACT_ID)|g" | sed "s|VERSION|$(VERSION)|g" >> $(K8S_RESOURCE_DOGU) @echo "Done." +.PHONY: apply-dogu-resource +apply-dogu-resource: + @kubectl apply -f "$(K8S_RESOURCE_DOGU)" + ##@ K8s - Dogu .PHONY: install-dogu-descriptor diff --git a/build/make/k8s.mk b/build/make/k8s.mk index 63ba3c5..0f9fe02 100644 --- a/build/make/k8s.mk +++ b/build/make/k8s.mk @@ -6,13 +6,18 @@ endif ## Variables +BINARY_YQ = $(UTILITY_BIN_PATH)/yq +BINARY_YQ_4_VERSION?=v4.40.3 +BINARY_HELM = $(UTILITY_BIN_PATH)/helm +BINARY_HELM_VERSION?=v3.13.0 +CONTROLLER_GEN = $(UTILITY_BIN_PATH)/controller-gen +CONTROLLER_GEN_VERSION?=v0.13.0 + # Setting SHELL to bash allows bash commands to be executed by recipes. # Options are set to exit when a recipe line exits non-zero or a piped command fails. SHELL = /usr/bin/env bash -o pipefail .SHELLFLAGS = -ec -BINARY_YQ = $(UTILITY_BIN_PATH)/yq - # The productive tag of the image IMAGE ?= @@ -22,16 +27,28 @@ STAGE?=production K3S_CLUSTER_FQDN?=k3ces.local K3S_LOCAL_REGISTRY_PORT?=30099 K3CES_REGISTRY_URL_PREFIX="${K3S_CLUSTER_FQDN}:${K3S_LOCAL_REGISTRY_PORT}" +## Image URL to use all building/pushing image targets +IMAGE_DEV?=${K3CES_REGISTRY_URL_PREFIX}/${ARTIFACT_ID} +IMAGE_DEV_VERSION=${IMAGE_DEV}:${VERSION} # Variables for the temporary yaml files. These are used as template to generate a development resource containing # the current namespace and the dev image. -K8S_RESOURCE_TEMP_FOLDER ?= $(TARGET_DIR)/make/k8s -K8S_RESOURCE_TEMP_YAML ?= $(K8S_RESOURCE_TEMP_FOLDER)/$(ARTIFACT_ID)_$(VERSION).yaml +K8S_RESOURCE_TEMP_FOLDER ?= $(TARGET_DIR)/k8s + +# This can be used by components with own images to check if all image env var are set. +# These components should override this variable with `check-all-vars`. +CHECK_VAR_TARGETS?=check-all-vars-without-image ##@ K8s - Variables .PHONY: check-all-vars -check-all-vars: check-k8s-image-env-var check-k8s-artifact-id check-etc-hosts check-insecure-cluster-registry check-k8s-namespace-env-var ## Conduct a sanity check against selected build artefacts or local environment +check-all-vars: check-all-vars-without-image check-all-image-vars ## Conduct a sanity check against selected build artefacts or local environment + +.PHONY: check-all-image-vars +check-all-image-vars: check-k8s-image-env-var check-k8s-image-dev-var check-etc-hosts check-insecure-cluster-registry + +.PHONY: check-all-vars-without-image +check-all-vars-without-image: check-k8s-artifact-id check-k8s-namespace-env-var .PHONY: check-k8s-namespace-env-var check-k8s-namespace-env-var: @@ -60,32 +77,6 @@ check-insecure-cluster-registry: ${K8S_RESOURCE_TEMP_FOLDER}: @mkdir -p $@ -.PHONY: k8s-delete -k8s-delete: k8s-generate $(K8S_POST_GENERATE_TARGETS) ## Deletes all dogu related resources from the K8s cluster. - @echo "Delete old dogu resources..." - @kubectl delete -f $(K8S_RESOURCE_TEMP_YAML) --wait=false --ignore-not-found=true --namespace=${NAMESPACE} - -# The additional targets executed after the generate target, executed before each apply and delete. The generate target -# produces a temporary yaml. This yaml is accessible via K8S_RESOURCE_TEMP_YAML an can be changed before the apply/delete. -K8S_POST_GENERATE_TARGETS ?= -# The additional targets executed before the generate target, executed before each apply and delete. -K8S_PRE_GENERATE_TARGETS ?= k8s-create-temporary-resource - -.PHONY: k8s-generate -k8s-generate: ${BINARY_YQ} $(K8S_RESOURCE_TEMP_FOLDER) $(K8S_PRE_GENERATE_TARGETS) ## Generates the final resource yaml. - @echo "Applying general transformations..." - @if [[ ${STAGE} == "development" ]]; then \ - $(BINARY_YQ) -i e "(select(.kind == \"Deployment\").spec.template.spec.containers[]|select(.image == \"*$(ARTIFACT_ID)*\").image)=\"$(IMAGE_DEV)\"" $(K8S_RESOURCE_TEMP_YAML); \ - else \ - $(BINARY_YQ) -i e "(select(.kind == \"Deployment\").spec.template.spec.containers[]|select(.image == \"*$(ARTIFACT_ID)*\").image)=\"$(IMAGE)\"" $(K8S_RESOURCE_TEMP_YAML); \ - fi - @echo "Done." - -.PHONY: k8s-apply -k8s-apply: k8s-generate image-import $(K8S_POST_GENERATE_TARGETS) ## Applies all generated K8s resources to the current cluster and namespace. - @echo "Apply generated K8s resources..." - @sed -i "s/'{{ .Namespace }}'/$(NAMESPACE)/" $(K8S_RESOURCE_TEMP_YAML) - @kubectl apply -f $(K8S_RESOURCE_TEMP_YAML) --namespace=${NAMESPACE} ##@ K8s - Docker @@ -96,8 +87,8 @@ docker-build: check-k8s-image-env-var ## Builds the docker image of the K8s app. .PHONY: docker-dev-tag docker-dev-tag: check-k8s-image-dev-var docker-build ## Tags a Docker image for local K3ces deployment. - @echo "Tagging image with dev tag $(IMAGE_DEV)..." - @DOCKER_BUILDKIT=1 docker tag ${IMAGE} $(IMAGE_DEV) + @echo "Tagging image with dev tag $(IMAGE_DEV_VERSION)..." + @DOCKER_BUILDKIT=1 docker tag ${IMAGE} $(IMAGE_DEV_VERSION) .PHONY: check-k8s-image-dev-var check-k8s-image-dev-var: @@ -108,8 +99,8 @@ endif .PHONY: image-import image-import: check-all-vars check-k8s-artifact-id docker-dev-tag ## Imports the currently available image into the cluster-local registry. - @echo "Import $(IMAGE_DEV) into K8s cluster ${K3S_CLUSTER_FQDN}..." - @docker push $(IMAGE_DEV) + @echo "Import $(IMAGE_DEV_VERSION) into K8s cluster ${K3S_CLUSTER_FQDN}..." + @docker push $(IMAGE_DEV_VERSION) @echo "Done." ## Functions @@ -127,8 +118,31 @@ __check_defined = \ $(if $(value $1),, \ $(error Undefined $1$(if $2, ($2)))) +##@ K8s - Download Utilities + .PHONY: install-yq ## Installs the yq YAML editor. install-yq: ${BINARY_YQ} -${BINARY_YQ}: $(UTILITY_BIN_PATH) ## Download yq locally if necessary. - $(call go-get-tool,$(BINARY_YQ),github.com/mikefarah/yq/v4@v4.25.1) +${BINARY_YQ}: $(UTILITY_BIN_PATH) + $(call go-get-tool,$(BINARY_YQ),github.com/mikefarah/yq/v4@${BINARY_YQ_4_VERSION}) + +##@ K8s - Download Kubernetes Utilities + +.PHONY: install-helm ## Download helm locally if necessary. +install-helm: ${BINARY_HELM} + +${BINARY_HELM}: $(UTILITY_BIN_PATH) + $(call go-get-tool,$(BINARY_HELM),helm.sh/helm/v3/cmd/helm@${BINARY_HELM_VERSION}) + +.PHONY: controller-gen +controller-gen: ${CONTROLLER_GEN} ## Download controller-gen locally if necessary. + +${CONTROLLER_GEN}: + $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@${CONTROLLER_GEN_VERSION}) + +ENVTEST = $(UTILITY_BIN_PATH)/setup-envtest +.PHONY: envtest +envtest: ${ENVTEST} ## Download envtest-setup locally if necessary. + +${ENVTEST}: + $(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest) \ No newline at end of file diff --git a/build/make/mocks.mk b/build/make/mocks.mk index 9e61b46..e313369 100644 --- a/build/make/mocks.mk +++ b/build/make/mocks.mk @@ -8,7 +8,7 @@ ${MOCKERY_BIN}: ${UTILITY_BIN_PATH} $(call go-get-tool,$(MOCKERY_BIN),github.com/vektra/mockery/v2@$(MOCKERY_VERSION)) ${MOCKERY_YAML}: - @cp ${WORKDIR}/build/make/mockery.yaml ${WORKDIR}/.mockery.yaml + @cp ${BUILD_DIR}/make/mockery.yaml ${WORKDIR}/.mockery.yaml .PHONY: mocks mocks: ${MOCKERY_BIN} ${MOCKERY_YAML} ## This target is used to generate mocks for all interfaces in a project. diff --git a/build/make/release.mk b/build/make/release.mk index 82ba1ba..328f7ba 100644 --- a/build/make/release.mk +++ b/build/make/release.mk @@ -6,10 +6,14 @@ dogu-release: ## Start a dogu release build/make/release.sh dogu +.PHONY: node-release +node-release: ## Start a node package release + build/make/release.sh node-pkg + .PHONY: go-release go-release: ## Start a go tool release build/make/release.sh go-tool .PHONY: dogu-cve-release dogu-cve-release: ## Start a dogu release of a new build if the local build fixes critical CVEs - @bash -c "build/make/release_cve.sh \"${REGISTRY_USERNAME}\" \"${REGISTRY_PASSWORD}\" \"${TRIVY_IMAGE_SCAN_FLAGS}\" \"${DRY_RUN}\"" + @bash -c "build/make/release_cve.sh \"${REGISTRY_USERNAME}\" \"${REGISTRY_PASSWORD}\" \"${TRIVY_IMAGE_SCAN_FLAGS}\" \"${DRY_RUN}\" \"${CVE_SEVERITY}\"" diff --git a/build/make/release_cve.sh b/build/make/release_cve.sh index 21738cb..6c5fc6d 100755 --- a/build/make/release_cve.sh +++ b/build/make/release_cve.sh @@ -3,6 +3,15 @@ set -o errexit set -o pipefail set -o nounset +function readCveSeverityIfUnset() { + if [ -z "${CVE_SEVERITY}" ]; then + echo "CVE_SEVERITY is unset" + while [[ -z ${CVE_SEVERITY} ]]; do + read -r -p "select the desired cve severity (CRITICAL, HIGH, MEDIUM, ...): " CVE_SEVERITY + done + fi +} + function readCredentialsIfUnset() { if [ -z "${USERNAME}" ]; then echo "username is unset" @@ -72,7 +81,7 @@ function pullRemoteImage() { } function buildLocalImage() { - docker build . -t "$(imageFromDogu):$(versionFromDogu)" + docker build --no-cache . -t "$(imageFromDogu):$(versionFromDogu)" } function scanImage() { @@ -85,7 +94,7 @@ function parseTrivyJsonResult() { # First select results which have the property "Vulnerabilities". Filter the vulnerability ids with the given severity and afterward put the values in an array. # This array is used to format the values with join(" ") in a whitespace delimited string list. - jq -rc "[.Results[] | select(.Vulnerabilities) | .Vulnerabilities | .[] | select(.Severity == \"${severity}\") | .VulnerabilityID] | join(\" \")" "${trivy_result_file}" + jq -rc "[.Results[] | select(.Vulnerabilities) | .Vulnerabilities | .[] | select(.Severity == \"${severity}\") | .VulnerabilityID] | unique | join(\" \")" "${trivy_result_file}" } RELEASE_SH="build/make/release.sh" @@ -93,7 +102,7 @@ RELEASE_SH="build/make/release.sh" REGISTRY_URL="registry.cloudogu.com" DOGU_JSON_FILE="dogu.json" -CVE_SEVERITY="CRITICAL" +CVE_SEVERITY= TRIVY_PATH= TRIVY_RESULT_FILE= @@ -106,6 +115,7 @@ PASSWORD="" DRY_RUN= function runMain() { + readCveSeverityIfUnset readCredentialsIfUnset dockerLogin @@ -137,6 +147,7 @@ function runMain() { exit 3 fi + echo "Fixed ${CVE_SEVERITY} CVEs: ${cve_in_remote_but_not_in_local}" "${RELEASE_SH}" "dogu-cve-release" "${cve_in_remote_but_not_in_local}" "${DRY_RUN}" } @@ -146,6 +157,7 @@ if [[ -n "${BASH_VERSION}" && "${BASH_SOURCE[0]}" == "${0}" ]]; then PASSWORD="${2:-""}" TRIVY_IMAGE_SCAN_FLAGS="${3:-""}" DRY_RUN="${4:-""}" + CVE_SEVERITY="${5:-""}" TRIVY_PATH="/tmp/trivy-dogu-cve-release-$(nameFromDogu)" TRIVY_RESULT_FILE="${TRIVY_PATH}/results.json" diff --git a/build/make/yarn.mk b/build/make/yarn.mk index 12792b4..6ff7de9 100644 --- a/build/make/yarn.mk +++ b/build/make/yarn.mk @@ -5,14 +5,6 @@ YARN_LOCK=$(WORKDIR)/yarn.lock .PHONY: yarn-install yarn-install: $(YARN_TARGET) ## Execute yarn install -ifeq ($(ENVIRONMENT), ci) - -$(YARN_TARGET): $(YARN_LOCK) - @echo "Yarn install on CI server" - @yarn install - -else - $(YARN_TARGET): $(YARN_LOCK) $(PASSWD) @echo "Executing yarn..." @docker run --rm \ @@ -24,4 +16,24 @@ $(YARN_TARGET): $(YARN_LOCK) $(PASSWD) yarn install @touch $@ -endif +.PHONY yarn-publish-ci: +yarn-publish-ci: ## Execute yarn publish with '--non-interactive' flag to suppress the version prompt + @echo "Executing yarn publish..." + @docker run --rm \ + -u "$(UID_NR):$(GID_NR)" \ + -v $(PASSWD):/etc/passwd:ro \ + -v $(WORKDIR):$(WORKDIR) \ + -w $(WORKDIR) \ + node:$(NODE_VERSION) \ + yarn publish --non-interactive + +.PHONY yarn-publish: ## Execute yarn publish +yarn-publish: $(YARN_BUILD_TARGET) + @echo "Executing yarn publish..." + @docker run --rm \ + -u "$(UID_NR):$(GID_NR)" \ + -v $(PASSWD):/etc/passwd:ro \ + -v $(WORKDIR):$(WORKDIR) \ + -w $(WORKDIR) \ + node:$(NODE_VERSION) \ + yarn publish diff --git a/docs/operations/operations_de.md b/docs/operations/operations_de.md new file mode 100644 index 0000000..b6fb5a0 --- /dev/null +++ b/docs/operations/operations_de.md @@ -0,0 +1,75 @@ +# k8s-loki betreiben + +## Installation + +`k8s-loki` kann als Komponente über den Komponenten-Operator des CES installiert werden. +Dazu muss eine entsprechende Custom-Resource (CR) für die Komponente erstellt werden. + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-loki + labels: + app: ces +spec: + name: k8s-loki + namespace: k8s + version: 2.9.1-2 +``` + +Die neue yaml-Datei kann anschließend im Kubernetes-Cluster erstellt werden: + +```shell +kubectl apply -f k8s-loki.yaml --namespace ecosystem +``` + +Der Komponenten-Operator erstellt nun die `k8s-loki`-Komponente im `ecosystem`-Namespace. + +## Upgrade + +Zum Upgrade muss die gewünschte Version in der Custom-Resource angegeben werden. +Dazu wird die erstellte CR yaml-Datei editiert und die gewünschte Version eingetragen. +Anschließend die editierte yaml Datei erneut auf den Cluster anwenden: + +```shell +kubectl apply -f k8s-loki.yaml --namespace ecosystem +``` + +## Konfiguration + +Die Komponente kann über das Feld `spec.valuesYamlOverwrite`. Die Konfigurationsmöglichkeiten entsprechen denen von +[Grafana Loki](https://grafana.com/docs/loki/latest/setup/install/helm/reference/). +Die Konfiguration für das "Grafana Loki" Helm-Chart muss in der `values.yaml` unter dem Key `loki` abgelegt werden. + +**Beispiel:** +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-loki + labels: + app: ces +spec: + name: k8s-loki + namespace: k8s + version: 2.9.1-2 + valuesYamlOverwrite: | + loki: + write: + replicas: 3 + read: + replicas: 3 + backend: + replicas: 3 +``` + +### Zusätzliche Konfiguration + +Neben der oben beschriebenen Standard-Konfiguration von Loki, verfügt die `k8s-loki`-Komponente über zusätzliche +Konfiguration: + +| Parameter | Beschreibung | Default-Wert | +|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------| +| lokiGatewaySecretName | Der Name des K8S-Secrets, das erzeugt wird um Username und Passwort für den Loki-Gateway für z.B. `k8s-promtail` und `k8s-ces-control` bereitzustellen | `k8s-loki-gateway-secret` | + diff --git a/docs/operations/operations_en.md b/docs/operations/operations_en.md new file mode 100644 index 0000000..9bf3d35 --- /dev/null +++ b/docs/operations/operations_en.md @@ -0,0 +1,76 @@ +# operate k8s-loki + +## Installation + +`k8s-loki` can be installed as a component via the CES component operator. +To do this, a corresponding custom resource (CR) must be created for the component. + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-loki + labels: + app: ces +spec: + name: k8s-loki + namespace: k8s + version: 2.9.1-2 +``` + +The new yaml file can then be created in the Kubernetes cluster: + +```shell +kubectl apply -f k8s-loki.yaml --namespace ecosystem +``` + +The component operator now creates the `k8s-loki` component in the `ecosystem` namespace. + +## Upgrade + +To upgrade, the desired version must be specified in the custom resource. +To do this, the CR yaml file created is edited and the desired version is entered. +Then apply the edited yaml file to the cluster again: + +```shell +kubectl apply -f k8s-loki.yaml --namespace ecosystem +``` + +## Configuration + +The component can be overwritten via the `spec.valuesYamlOverwrite` field. The configuration options correspond to those +of +[Grafana Loki](https://grafana.com/docs/loki/latest/setup/install/helm/reference/). +The configuration for the "Grafana Loki" helm chart must be stored in `values.yaml` under the key `loki`. + +**Beispiel:** + +```yaml +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-loki + labels: + app: ces +spec: + name: k8s-loki + namespace: k8s + version: 2.9.1-2 + valuesYamlOverwrite: | + loki: + write: + replicas: 3 + read: + replicas: 3 + backend: + replicas: 3 +``` + +### Additional configuration + +In addition to the standard Loki configuration described above, the `k8s-loki` component has additional configuration: + +| Parameters | Description | Default-Value | +|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------| +| lokiGatewaySecretName | The name of the K8S secret that is generated to provide username and password for the Loki gateway for e.g. `k8s-promtail` and `k8s-ces-control`. | `k8s-loki-gateway-secret` | + diff --git a/k8s/helm/Chart.yaml b/k8s/helm/Chart.yaml index b8bbb73..85516a9 100644 --- a/k8s/helm/Chart.yaml +++ b/k8s/helm/Chart.yaml @@ -8,3 +8,8 @@ dependencies: - name: loki version: 5.23.0 repository: https://grafana.github.io/helm-charts + +annotations: + # For k8s-minio it is important to include "prerelease"-versions like "2023.9.23-2", so there must be a "-0" after the patch-version. + # see https://helm.sh/docs/chart_best_practices/dependencies/#prerelease-versions for more information + "k8s.cloudogu.com/ces-dependency/k8s-minio": "^2023.9.23-0" \ No newline at end of file diff --git a/k8s/helm/component-patch-tpl.yaml b/k8s/helm/component-patch-tpl.yaml new file mode 100644 index 0000000..4f4fb1a --- /dev/null +++ b/k8s/helm/component-patch-tpl.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +values: + images: + kubectl: docker.io/bitnami/kubectl:1.28.4 + loki: docker.io/grafana/loki:2.9.1 + monitoring: docker.io/grafana/loki:2.9.1 + gateway: docker.io/nginxinc/nginx-unprivileged:1.23-alpine + sidecar: kiwigrid/k8s-sidecar:1.24.3 +patches: + values.yaml: + loki: + kubectlImage: + registry: "{{ registryFrom .images.kubectl }}" + repository: "{{ repositoryFrom .images.kubectl }}" + tag: "{{ tagFrom .images.kubectl }}" + image: + registry: "{{ registryFrom .images.loki }}" + repository: "{{ repositoryFrom .images.loki }}" + tag: "{{ tagFrom .images.loki }}" + monitoring: + lokiCanary: + registry: "{{ registryFrom .images.monitoring }}" + repository: "{{ repositoryFrom .images.monitoring }}" + tag: "{{ tagFrom .images.monitoring }}" + gateway: + image: + registry: "{{ registryFrom .images.gateway }}" + repository: "{{ repositoryFrom .images.gateway }}" + tag: "{{ tagFrom .images.gateway }}" + sidecar: + image: + repository: "{{ registryFrom .images.sidecar }}/{{ repositoryFrom .images.sidecar }}" + tag: "{{ tagFrom .images.sidecar }}" diff --git a/k8s/helm/templates/loki-gateway-secret.yaml b/k8s/helm/templates/loki-gateway-secret.yaml new file mode 100644 index 0000000..7af7cfe --- /dev/null +++ b/k8s/helm/templates/loki-gateway-secret.yaml @@ -0,0 +1,14 @@ +{{ $username := "loki-gateway-user" }} +{{ $password := randAlphaNum 24 }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.lokiGatewaySecretName }} + labels: + app: ces + app.kubernetes.io/name: k8s-loki +type: kubernetes.io/basic-auth +data: + .htpasswd: {{ htpasswd $username $password | b64enc }} + username: {{ $username | b64enc }} + password: {{ $password | b64enc }} \ No newline at end of file diff --git a/k8s/helm/values.yaml b/k8s/helm/values.yaml new file mode 100644 index 0000000..7b19768 --- /dev/null +++ b/k8s/helm/values.yaml @@ -0,0 +1,129 @@ +lokiGatewaySecretName: "k8s-loki-gateway-secret" + +loki: + nameOverride: "k8s-loki" + kubectlImage: + registry: docker.io + repository: bitnami/kubectl + tag: 1.28.4 + # Loki Write, Read and Backend are setting environment variables to for the minio access keys. + write: + replicas: 1 + extraArgs: + - '-config.expand-env=true' + extraEnv: + - name: MINIO_LOKI_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: k8s-minio-service-account-loki + key: accessKeyId + - name: MINIO_LOKI_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: k8s-minio-service-account-loki + key: accessKeySecret + persistence: + size: 1Gi + read: + replicas: 1 + extraArgs: + - '-config.expand-env=true' + extraEnv: + - name: MINIO_LOKI_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: k8s-minio-service-account-loki + key: accessKeyId + - name: MINIO_LOKI_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: k8s-minio-service-account-loki + key: accessKeySecret + backend: + replicas: 1 + extraArgs: + - '-config.expand-env=true' + extraEnv: + - name: MINIO_LOKI_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: k8s-minio-service-account-loki + key: accessKeyId + - name: MINIO_LOKI_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: k8s-minio-service-account-loki + key: accessKeySecret + persistence: + size: 1Gi + + # Loki configuration. + loki: + podLabels: + app: ces + storage: + # chunks seems to be the important one, but it is good practice to set all three. + bucketNames: + chunks: loki-log-bucket + admin: loki-log-bucket + ruler: loki-log-bucket + # configure storage option (minio in this case). + type: s3 + s3: + s3: null + endpoint: http://k8s-minio.ecosystem.svc:9000 + region: null + s3ForcePathStyle: true + insecure: true + accessKeyId: ${MINIO_LOKI_ACCESS_KEY_ID} + secretAccessKey: ${MINIO_LOKI_SECRET_ACCESS_KEY} + # Relevant for multi-tenant mode + auth_enabled: false + # Enable basic authentication in the Gateway and get the credentials from the provided secret. The credentials must + # be encrypted with htpasswd and base64-encoded as follows: + # echo "" | htpasswd -n -i | base64 ; echo + # Fill the "data -> .htpasswd" field in the secret with the corresponding value. + gateway: + basicAuth: + enabled: true + existingSecret: k8s-loki-gateway-secret + monitoring: + # Activates the Grafana agent to enable self-monitoring. However, it does not currently work with authentication + # (see: https://github.com/grafana/loki/issues/10873 ). With the configuration below, a working client is created, but + # another client without authentication information continues to be created automatically, filling the logs with 401 + # errors. + selfMonitoring: + enabled: false + # logsInstance: + # clients: + # - url: http://k8s-loki-gateway.ecosystem.svc.cluster.local/loki/api/v1/push + # basicAuth: + # username: + # name: k8s-loki-gateway-secret + # key: username + # password: + # name: k8s-loki-gateway-secret + # key: password + + # Loki Canary is a standalone app that audits the log-capturing performance of a Grafana Loki cluster. + # Loki Canary generates artificial log lines. These log lines are sent to the Loki cluster. + lokiCanary: + podLabels: + app: ces + extraEnv: + - name: USER + valueFrom: + secretKeyRef: + name: k8s-loki-gateway-secret + key: username + - name: PASS + valueFrom: + secretKeyRef: + name: k8s-loki-gateway-secret + key: password + extraArgs: + - "-user=$(USER)" + - "-pass=$(PASS)" + # A test to check the Loki-Logging-Stack functionality. Only works with self monitoring enabled. + test: + enabled: false \ No newline at end of file diff --git a/manifests/loki.yaml b/manifests/loki.yaml deleted file mode 100644 index d1f5fab..0000000 --- a/manifests/loki.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# This is a dummy file, required for the makefile's yaml file generation process for the dogu-controller. -apiVersion: v1 -kind: ConfigMap -metadata: - name: loki-dummy -data: {} \ No newline at end of file diff --git a/release_args.sh b/release_args.sh new file mode 100755 index 0000000..7a93b98 --- /dev/null +++ b/release_args.sh @@ -0,0 +1,77 @@ +#!/bin/bash +set -o errexit +set -o nounset +set -o pipefail + +componentTemplateFile=k8s/helm/component-patch-tpl.yaml +lokiTempChart="/tmp/loki" +lokiTempValues="${lokiTempChart}/values.yaml" +lokiTempChartYaml="${lokiTempChart}/Chart.yaml" +lokiValues="k8s/helm/values.yaml" + +# this function will be sourced from release.sh and be called from release_functions.sh +update_versions_modify_files() { + echo "Update helm dependencies" + make helm-update-dependencies > /dev/null + + # Extract loki chart + local lokiVersion + lokiVersion=$(yq '.dependencies[] | select(.name=="loki").version' < "k8s/helm/Chart.yaml") + local lokiPackage + lokiPackage="k8s/helm/charts/loki-${lokiVersion}.tgz" + + echo "Extract loki helm chart" + tar -zxvf "${lokiPackage}" -C "/tmp" > /dev/null + + local lokiAppVersion + lokiAppVersion=$(yq '.appVersion' < "${lokiTempChartYaml}") + + echo "Set images in component patch template" + + local lokiKubectlRegistry + local lokiKubectlRepo + local lokiKubectlTag + lokiKubectlRegistry=$(yq '.loki.kubectlImage.registry' < "${lokiValues}") + lokiKubectlRepo=$(yq '.loki.kubectlImage.repository' < "${lokiValues}") + lokiKubectlTag=$(yq '.loki.kubectlImage.tag' < "${lokiValues}") + setAttributeInComponentPatchTemplate ".values.images.kubectl" "${lokiKubectlRegistry}/${lokiKubectlRepo}:${lokiKubectlTag}" + + local lokiImageRegistry + local lokiImageRepo + lokiImageRegistry=$(yq '.loki.image.registry' < "${lokiTempValues}") + lokiImageRepo=$(yq '.loki.image.repository' < "${lokiTempValues}") + setAttributeInComponentPatchTemplate ".values.images.loki" "${lokiImageRegistry}/${lokiImageRepo}:${lokiAppVersion}" + + local lokiCanaryRegistry + local lokiCanaryRepo + lokiCanaryRegistry=$(yq '.loki.monitoring.lokiCanary.image.registry' < "${lokiTempValues}") + lokiCanaryRepo=$(yq '.loki.monitoring.lokiCanary.image.repository' < "${lokiTempValues}") + setAttributeInComponentPatchTemplate ".values.images.monitoring" "${lokiImageRegistry}/${lokiImageRepo}:${lokiAppVersion}" + + local lokiGatewayRegistry + local lokiGatewayRepo + local lokiGatewayTag + lokiGatewayRegistry=$(yq '.gateway.image.registry' < "${lokiTempValues}") + lokiGatewayRepo=$(yq '.gateway.image.repository' < "${lokiTempValues}") + lokiGatewayTag=$(yq '.gateway.image.tag' < "${lokiTempValues}") + setAttributeInComponentPatchTemplate ".values.images.gateway" "${lokiGatewayRegistry}/${lokiGatewayRepo}:${lokiGatewayTag}" + + local lokiSidecarRegistryRepo + local lokiSidecarTag + lokiSidecarRegistryRepo=$(yq '.sidecar.image.repository' < "${lokiTempValues}") + lokiSidecarTag=$(yq '.sidecar.image.tag' < "${lokiTempValues}") + setAttributeInComponentPatchTemplate ".values.images.sidecar" "${lokiSidecarRegistryRepo}:${lokiSidecarTag}" + + rm -rf ${lokiTempChart} +} + +setAttributeInComponentPatchTemplate() { + local key="${1}" + local value="${2}" + + yq -i "${key} = \"${value}\"" "${componentTemplateFile}" +} + +update_versions_stage_modified_files() { + git add "${componentTemplateFile}" +}