Переделка CI/CD
This commit is contained in:
Vendored
+270
-72
@@ -1,88 +1,286 @@
|
|||||||
@Library(['jlib']) _
|
/*
|
||||||
|
! Jenkins Watchdog Pipeline
|
||||||
|
|
||||||
node("docker") {
|
Этот Pipeline реализует сборку на Kubernetes worker-ноде с контролем и завершением со стороны Jenkins master-ноды.
|
||||||
// Временная метка в логе Jenkins
|
Master отслеживает статус worker'а в реальном времени и завершает процесс в случае ошибки, таймаута или успешного завершения.
|
||||||
timestamps() {
|
|
||||||
// Цветные букавы в логе Jenkins
|
|
||||||
ansiColor("xterm"){
|
|
||||||
// Получаем актуальную версию репы, где лежит пайп
|
|
||||||
checkout scm
|
|
||||||
|
|
||||||
env.stand = env.BRANCH_NAME
|
|
||||||
|
|
||||||
if (!(stand in ["prod", "test", "dev"])) {
|
|
||||||
error("stand не соответствует 'prod', 'test' или 'dev'")
|
|
||||||
}
|
|
||||||
|
|
||||||
stage("Prepare environments") {
|
|
||||||
envConfig = "build/vars/build.yaml"
|
|
||||||
support.getVarsV2(envConfig)
|
|
||||||
|
|
||||||
// пока не будет готов отдельный dev стенд
|
|
||||||
env.namespace = "${env.namespace}-${stand}"
|
|
||||||
env.registryContainerName = "${env.registryContainerName}-${stand}"
|
|
||||||
env.version = sh(script: "git rev-parse HEAD", returnStdout: true).trim()
|
|
||||||
println "Success prepare"
|
|
||||||
}
|
|
||||||
|
|
||||||
stage("Scan Image") {
|
|
||||||
/* Убрал на время для перехода на Helm всех микросервисов
|
|
||||||
def scannerHome = tool 'SonarScanner';
|
|
||||||
// Волшебный ключ -Dsonar.qualitygate.wait=true
|
|
||||||
withCredentials([string(credentialsId: 'sonarqube-access-personal-account-backend', variable: 'tokenAccess')]) {
|
|
||||||
sh "${scannerHome}/bin/sonar-scanner -Dsonar.sources=. -Dsonar.projectKey=personal-account-backend -Dsonar.host.url=https://sq.adl.nubes.ru -Dsonar.login=${tokenAccess}"
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
stage("Build image") {
|
// Статусы воркера. Необходимо мастеру для определения состояния джоба
|
||||||
println "Start building image ${env.registryContainerName}:${env.version}"
|
def workerFailed = false
|
||||||
if (registryRepoPath)
|
def workerSuccess = false
|
||||||
env.imageName = "${registryRepoPath}/${env.registryContainerName}"
|
def DEBUGGING_MODE = false
|
||||||
else
|
// Мапа для запуска мастера и воркера параллельно
|
||||||
env.imageName = "${env.registryContainerName}"
|
def parallelSteps = [:]
|
||||||
|
|
||||||
app = docker.build("${env.imageName}:${env.version}", "--no-cache -f ./build/Dockerfile .")
|
// Блок констант
|
||||||
|
// Мапа, в которой будут переменные из vars/build.yaml
|
||||||
|
buildVars = [:]
|
||||||
|
buildVars.system = [:]
|
||||||
|
buildVars.kubeconfig = "config.kube"
|
||||||
|
|
||||||
println "Start uploading image ${env.registryContainerName}:${env.version} to Nexus"
|
// Подгрузка либы. Версия в свойствах папки Jenkins
|
||||||
|
library "jlib"
|
||||||
|
cmdbVars = constants.cmdbVars
|
||||||
|
|
||||||
docker.withRegistry("https://${registryUrl}/${registryRepoPath}", "registry-jenkins-cred") {
|
TimeoutTime = [
|
||||||
app.push("${env.version}")
|
time: binding.hasVariable('timeoutTime') ? timeoutTime : (cmdbVars?.system?.timeoutTime ?: 20),
|
||||||
app.push("latest")
|
unit: binding.hasVariable('timeoutUnit') ? timeoutUnit : (cmdbVars?.system?.timeoutUnit ?: "MINUTES")
|
||||||
}
|
]
|
||||||
}
|
|
||||||
|
|
||||||
stage("Update version in Kubernetes") {
|
parallelSteps["worker"] = {
|
||||||
dir ("build") {
|
node("docker") {
|
||||||
withCredentials([vaultString(credentialsId: "${env.vaultPath}", variable: "pem")]) {
|
timestamps() {
|
||||||
sh """
|
ansiColor("xterm"){
|
||||||
set +x
|
dir (env.BUILD_NUMBER) {
|
||||||
echo "${pem}" | base64 -d > auth.config
|
try {
|
||||||
set -x
|
stage ("Prepare environments") {
|
||||||
"""
|
// Выкачивание проекта из Git
|
||||||
|
checkout scm
|
||||||
|
// Определение типа джобы:
|
||||||
|
// - сборка и пуш в кубер: DEV / PR
|
||||||
|
// - проверка образа (из DEV) и пуш в кубер: TEST / PROD
|
||||||
|
logger.info("Targeting stand for deploy")
|
||||||
|
// Если PR - в DEV
|
||||||
|
if (env.CHANGE_ID)
|
||||||
|
buildVars.gitBranch = "dev"
|
||||||
|
else
|
||||||
|
buildVars.gitBranch = env.BRANCH_NAME
|
||||||
|
|
||||||
|
// Проверка на нужные бренчи
|
||||||
|
if (!(buildVars.gitBranch in ["prod", "test", "dev"])) {
|
||||||
|
logger.err("Ветка в Git не соответствует 'prod', 'test' или 'dev'", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
convertJinjaV2("./helm/values.yaml", debug=true)
|
envConfig = "build/vars/build.yaml"
|
||||||
|
support.getVarsAll(envConfig, buildVars)
|
||||||
|
|
||||||
sh """
|
logger.info("Get kubeconfig")
|
||||||
helm upgrade --wait \
|
try {
|
||||||
--kubeconfig auth.config \
|
withCredentials([vaultString(credentialsId: "${buildVars.vaultPath}", variable: "pem")]) {
|
||||||
--install \
|
runsh """
|
||||||
--namespace ${env.namespace} \
|
set +x
|
||||||
-f ./helm/values.yaml \
|
echo "${pem}" | base64 -d > ${ buildVars.kubeconfig }
|
||||||
${env.appName} ./helm/
|
set -x
|
||||||
"""
|
""", true
|
||||||
|
}
|
||||||
|
logger.info("kubeconfig getting successfully")
|
||||||
|
} catch (Exception kubeconfigGetError) {
|
||||||
|
logger.err("Не удалось получить кубконфиг для подключению к Kubernetes-кластеру. Ошибка: ${kubeconfigGetError.message}", true)
|
||||||
|
}
|
||||||
|
|
||||||
sh "kubectl --kubeconfig=auth.config get pods --namespace ${env.namespace}"
|
logger.info("Getting version...")
|
||||||
|
try {
|
||||||
|
version = runsh buildVars.getCommandVersion
|
||||||
|
logger.info("Version app: ${ version }")
|
||||||
|
} catch (Exception versionGetError) {
|
||||||
|
logger.err("Не удалось получить версию приложения. Ошибка: ${versionGetError.message}", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение токена для авторизации в GITEA
|
||||||
|
withCredentials([vaultString(credentialsId: "gitea.services.ngcloud.ru-deck-token", variable: "token")]) { GITEA_AUTH_TOKEN = token }
|
||||||
|
|
||||||
|
// Сборка Image (Только DEV)
|
||||||
|
if (buildVars.gitBranch == "dev") {
|
||||||
|
if (buildVars.needBuildLib.toBoolean()) {
|
||||||
|
stage ("Check library") {
|
||||||
|
headers = [ [ name: "Authorization", value: "Bearer ${ GITEA_AUTH_TOKEN }" ] ]
|
||||||
|
// Проверка что либа существует
|
||||||
|
try {
|
||||||
|
retry(3) {
|
||||||
|
httpcall.get( url="https://gitea.services.ngcloud.ru/api/v1/packages/deck/npm/%40nubes%2F${ buildVars.app.name }/${ version }", headerList=headers)
|
||||||
|
}
|
||||||
|
needToBuildLib = false
|
||||||
|
} catch (Exception errGetPackage) {
|
||||||
|
logger.info("Package does not exist. It's OK")
|
||||||
|
needToBuildLib = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage ("Build library") {
|
||||||
|
if (needToBuildLib.toBoolean()) {
|
||||||
|
retry(3) {
|
||||||
|
try {
|
||||||
|
docker.build("${ buildVars.registryImageName }:${ version }", "--no-cache --build-arg GITEA_AUTH_TOKEN=${ GITEA_AUTH_TOKEN } -f ./build/Dockerfile_build_lib .")
|
||||||
|
} catch (Exception errorDocker) {
|
||||||
|
logger.err("Не удалось собрать библиотеку. Ошибка: ${ errorDocker.message }", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage ("Build image") {
|
||||||
|
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
|
||||||
|
logger.info("Start building image ${ buildVars.registryContainerName }:${ version }")
|
||||||
|
retry(3) {
|
||||||
|
try {
|
||||||
|
app = docker.build("${ buildVars.registryImageName }:${ version }", "--no-cache --build-arg GITEA_AUTH_TOKEN=${ GITEA_AUTH_TOKEN } -f ./build/Dockerfile .")
|
||||||
|
} catch (Exception errorDocker) {
|
||||||
|
logger.err("Не удалось собрать основной образ. Ошибка: ${ errorDocker.message }", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Start uploading image ${ buildVars.registryImageName }:${ version }")
|
||||||
|
docker.withRegistry("https://${ buildVars.registryUrl }/${ buildVars.repoPath }", "registry-jenkins-cred") {
|
||||||
|
// retry на случай если 500 случайно отдаст registry
|
||||||
|
retry(3) {
|
||||||
|
try {
|
||||||
|
app.push("${ version }")
|
||||||
|
} catch (Exception errorDocker) {
|
||||||
|
logger.err("Не удалось запушить образ в Registry. Ошибка: ${ errorDocker.message }", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Проверка Image в Registry (Всё кроме DEV)
|
||||||
|
if (buildVars.gitBranch != "dev") {
|
||||||
|
stage("Check if image exist") {
|
||||||
|
docker.withRegistry("https://${ buildVars.registryUrl }/${ buildVars.repoPath }", "registry-jenkins-cred") {
|
||||||
|
def img = docker.image("${ buildVars.registryImageName }:${ version }")
|
||||||
|
// TODO переписать либу docker под себя
|
||||||
|
// try/catch не поможет, ошибка выведет всегда 'script returned exit code 1'
|
||||||
|
// retry на случай если 500 случайно отдаст registry
|
||||||
|
retry(3) {
|
||||||
|
try {
|
||||||
|
img.pull()
|
||||||
|
} catch (Exception errorDocker) {
|
||||||
|
logger.err("Не удалось получить образ из Registry. Ошибка: ${ errorDocker.message }", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Деплой в Kubernetes (все стенды)
|
||||||
|
stage("Deploy to K8s test") {
|
||||||
|
logger.info("Check exist pods in k8s...")
|
||||||
|
retry(3) {
|
||||||
|
runsh "kubectl --kubeconfig=${ buildVars.kubeconfig } --namespace ${ buildVars.namespace } get po"
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Prepare list of args on helm...")
|
||||||
|
commandArgs = [
|
||||||
|
"--set deployment.image.repository=${ buildVars.registryUrl }/${ buildVars.registryImageName }",
|
||||||
|
"--set deployment.readinessProbe.httpGet.path=${ buildVars.app.health }",
|
||||||
|
"--set deployment.containerPort=${ buildVars.app.port }",
|
||||||
|
"--set deployment.resources.requests.cpu=${ buildVars.app.cpu }m",
|
||||||
|
"--set deployment.resources.requests.memory=${ buildVars.app.mem }Mi",
|
||||||
|
"--set deployment.resources.limits.cpu=${ buildVars.app.cpu }m",
|
||||||
|
"--set deployment.resources.limits.memory=${ buildVars.app.mem }Mi",
|
||||||
|
|
||||||
|
"--set deployment.image.tag=${ version }",
|
||||||
|
"--set stand=${ buildVars.gitBranch }"
|
||||||
|
]
|
||||||
|
// Если включен Vault
|
||||||
|
if (buildVars.needStoreVaultSecret.toBoolean()) {
|
||||||
|
commandArgs.add("--set vault.secretStore=${ buildVars.namespace }")
|
||||||
|
commandArgs.add("--set serviceAccountRole=${ buildVars.namespace }-sa")
|
||||||
|
commandArgs.add("--set vault.secrets=\"{${ buildVars.storedSecretsList.join(',') }}\"")
|
||||||
|
commandArgs.add("--set vault.enable=true")
|
||||||
|
} else {
|
||||||
|
commandArgs.add("--set vault.enable=false")
|
||||||
|
}
|
||||||
|
|
||||||
|
installArgs = [
|
||||||
|
"--kubeconfig ${ buildVars.kubeconfig }",
|
||||||
|
"--install",
|
||||||
|
"--namespace ${ buildVars.namespace }",
|
||||||
|
]
|
||||||
|
|
||||||
|
cmdTemplate = "helm template ${commandArgs.join(' ')} ./build/helm/"
|
||||||
|
cmd = "helm upgrade ${ buildVars.app.name } ${installArgs.join(' ')} ${commandArgs.join(' ')} ./build/helm/"
|
||||||
|
logger.info("""Command for push...
|
||||||
|
${cmd}
|
||||||
|
""")
|
||||||
|
|
||||||
|
logger.info("Template helm-release...")
|
||||||
|
runsh cmdTemplate
|
||||||
|
|
||||||
|
logger.info("Push helm-release...")
|
||||||
|
retry(3) {
|
||||||
|
// От того, что Helm-чарт будет ждать, мало что изменится
|
||||||
|
runsh cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Check exist pods in k8s...")
|
||||||
|
retry(3) {
|
||||||
|
runsh "kubectl --kubeconfig=${ buildVars.kubeconfig } --namespace ${ buildVars.namespace } get po"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Нужны проверки после установки
|
||||||
|
buildVars.application = [:]
|
||||||
|
buildVars.application.typeOfProject = "deployments.apps"
|
||||||
|
buildVars.application.namespace = buildVars.namespace
|
||||||
|
|
||||||
|
// sleep ибо загрузка манифестов в K8S занимает какое-то время
|
||||||
|
sleep(5)
|
||||||
|
try {
|
||||||
|
k8sStagesV2.correctReplicaActive(cmdbVars=buildVars, applicationName=buildVars.app.name)
|
||||||
|
// Чтобы не оставлять мусора за собой в эвентах
|
||||||
|
sh "kubectl --kubeconfig=${ buildVars.kubeconfig } --namespace ${ buildVars.namespace } delete events --all"
|
||||||
|
} catch (Exception errorRun) {
|
||||||
|
logger.info("Не удалось произвести проверку работы микросервиса. Дебаг:")
|
||||||
|
runsh "kubectl --kubeconfig=${ buildVars.kubeconfig } --namespace ${ buildVars.namespace } events | grep ${ buildVars.app.name }"
|
||||||
|
runsh "kubectl --kubeconfig=${ buildVars.kubeconfig } --namespace ${ buildVars.namespace } logs -l 'app=${ buildVars.app.name }'"
|
||||||
|
error("Не удалось произвести проверку работы микросервиса. Детали в логах pipeline")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBuild.result = 'SUCCESS'
|
||||||
|
}
|
||||||
|
catch (Exception err) {
|
||||||
|
logger.err("Произошла ошибка")
|
||||||
|
logger.err(err.message, true)
|
||||||
|
currentBuild.description = err.message
|
||||||
|
currentBuild.result = "FAILURE"
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (currentBuild.result == 'FAILURE') {
|
||||||
|
echo "Worker stage действительно упал — ставим флаг workerFailed"
|
||||||
|
workerFailed = true
|
||||||
|
} else if (currentBuild.result == 'SUCCESS') {
|
||||||
|
echo "Worker stage завершился успешно - ставим флаг workerSuccess"
|
||||||
|
workerSuccess = true
|
||||||
|
} else {
|
||||||
|
echo "Неопознаный currentBuild.result: ${currentBuild.result} — ставим флаг workerFailed"
|
||||||
|
workerFailed = true
|
||||||
|
}
|
||||||
|
runsh "rm -rf ${env.BUILD_NUMBER}"
|
||||||
|
}
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parallelSteps["master"] = {
|
||||||
|
node("master") {
|
||||||
|
try {
|
||||||
|
stage ("Master: start watchdog") {
|
||||||
|
timeout(time: TimeoutTime.time, unit: TimeoutTime.unit) {
|
||||||
|
while (true) {
|
||||||
|
// Следим за окончанием сборки
|
||||||
|
if (DEBUGGING_MODE) {
|
||||||
|
sleep 1
|
||||||
|
// Только в режиме отладки используем echo
|
||||||
|
echo "DEBUG: workerFailed = ${workerFailed}"
|
||||||
|
echo "DEBUG: workerSuccess = ${workerSuccess}"
|
||||||
|
}
|
||||||
|
// Проверка флагов без использования шагов Jenkins
|
||||||
|
if (workerFailed) {
|
||||||
|
echo "Watchdog: обнаружен сбой в воркере"
|
||||||
|
break
|
||||||
|
} else if (workerSuccess) {
|
||||||
|
echo "Watchdog: воркер завершил работу в Jenkins"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
runsh "rm -rf ${env.BUILD_NUMBER}"
|
||||||
println "Success build job. Now start cleanup"
|
}
|
||||||
|
catch (Exception masterErrorTimeout) {
|
||||||
cleanWs(
|
logger.err("Ошибка по таймауту")
|
||||||
deleteDirs: true,
|
|
||||||
disableDeferredWipeout: true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parallel parallelSteps
|
||||||
@@ -1,53 +1,49 @@
|
|||||||
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: "{{ .Chart.Name }}"
|
app: '{{ .Chart.Name }}'
|
||||||
stand: "{{ .Values.stand }}"
|
stand: '{{ .Values.stand }}'
|
||||||
name: "{{ .Chart.Name }}"
|
name: '{{ .Chart.Name }}'
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: "{{ .Chart.Name }}"
|
app: '{{ .Chart.Name }}'
|
||||||
stand: "{{ .Values.stand }}"
|
stand: '{{ .Values.stand }}'
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: "{{ .Chart.Name }}"
|
app: '{{ .Chart.Name }}'
|
||||||
stand: "{{ .Values.stand }}"
|
stand: '{{ .Values.stand }}'
|
||||||
contragentCode: 'WZ01112'
|
contragentCode: 'WZ01112'
|
||||||
billingObject: 'None'
|
billingObject: 'None'
|
||||||
spec:
|
spec:
|
||||||
{{- if .Values.vault.enabled }}
|
{{- if .Values.vault.enable }}
|
||||||
serviceAccountName: "{{ .Values.vault.serviceAccountName }}"
|
serviceAccountName: '{{ .Values.serviceAccountRole }}'
|
||||||
{{- end }}
|
{{- end }}
|
||||||
containers:
|
containers:
|
||||||
# Основное приложение
|
- image: '{{ .Values.deployment.image.repository }}:{{.Values.deployment.image.tag }}'
|
||||||
- name: app
|
|
||||||
image: "{{ .Values.mainContainer.image.repository }}:{{ .Values.mainContainer.image.tag }}"
|
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
|
name: app
|
||||||
ports:
|
ports:
|
||||||
- containerPort: {{ .Values.mainContainer.containerPort }}
|
- containerPort: {{ .Values.deployment.containerPort }}
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
resources:
|
|
||||||
{{- toYaml .Values.mainContainer.resources | nindent 12 }}
|
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
failureThreshold: 3
|
{{- toYaml (omit .Values.deployment.readinessProbe "httpGet") | nindent 12 }}
|
||||||
initialDelaySeconds: 10
|
httpGet:
|
||||||
periodSeconds: 30
|
{{- toYaml .Values.deployment.readinessProbe.httpGet | nindent 14 }}
|
||||||
successThreshold: 1
|
port: {{ .Values.deployment.containerPort }}
|
||||||
timeoutSeconds: 2
|
|
||||||
{{- toYaml .Values.mainContainer.readinessProbe | nindent 12 }}
|
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
failureThreshold: 3
|
{{- toYaml (omit .Values.deployment.livenessProbe "tcpSocket") | nindent 12 }}
|
||||||
initialDelaySeconds: 30
|
tcpSocket:
|
||||||
periodSeconds: 10
|
port: {{ .Values.deployment.containerPort }}
|
||||||
successThreshold: 1
|
|
||||||
timeoutSeconds: 1
|
resources:
|
||||||
{{- toYaml .Values.mainContainer.livenessProbe | nindent 12 }}
|
{{- toYaml .Values.deployment.resources | nindent 12 }}
|
||||||
{{- if .Values.vault.enabled }}
|
{{- if .Values.vault.enable }}
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: "{{ .Values.vault.target.name }}"
|
name: '{{ .Chart.Name }}-secrets'
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: "{{ .Chart.Name }}"
|
name: '{{ .Chart.Name }}'
|
||||||
labels:
|
labels:
|
||||||
app: "{{ .Chart.Name }}"
|
app: '{{ .Chart.Name }}'
|
||||||
stand: "{{ .Values.stand }}"
|
stand: '{{ .Values.stand }}'
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- port: {{ .Values.mainContainer.containerPort }}
|
- port: {{ .Values.deployment.containerPort }}
|
||||||
targetPort: {{ .Values.mainContainer.containerPort }}
|
targetPort: {{ .Values.deployment.containerPort }}
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
selector:
|
selector:
|
||||||
app: "{{ .Chart.Name }}"
|
app: '{{ .Chart.Name }}'
|
||||||
stand: "{{ .Values.stand }}"
|
stand: '{{ .Values.stand }}'
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
{{- if .Values.vault.enabled }}
|
{{- if .Values.vault.enable }}
|
||||||
|
---
|
||||||
apiVersion: external-secrets.io/v1beta1
|
apiVersion: external-secrets.io/v1beta1
|
||||||
kind: ExternalSecret
|
kind: ExternalSecret
|
||||||
metadata:
|
metadata:
|
||||||
name: "{{ .Chart.Name }}"
|
name: '{{ .Chart.Name }}'
|
||||||
|
labels:
|
||||||
|
app: '{{ .Chart.Name }}'
|
||||||
spec:
|
spec:
|
||||||
refreshInterval: "60s"
|
refreshInterval: '60s'
|
||||||
secretStoreRef:
|
secretStoreRef:
|
||||||
name: "{{ .Values.vault.secretStore }}"
|
name: '{{ .Values.vault.secretStore }}' # имя SecretStore
|
||||||
kind: SecretStore
|
kind: SecretStore
|
||||||
target:
|
target:
|
||||||
name: "{{ .Values.vault.target.name }}"
|
name: '{{ .Chart.Name }}-secrets' # имя будущего секрета kubernetes
|
||||||
data:
|
data:
|
||||||
{{- range .Values.vault.data }}
|
{{- range .Values.vault.secrets }}
|
||||||
- secretKey: {{ .secretKey }}
|
- secretKey: {{ . }}
|
||||||
remoteRef:
|
remoteRef:
|
||||||
key: "{{ .remoteRef.key }}"
|
key: "deck/kubernetes/{{ $.Values.stand }}/{{ $.Chart.Name }}"
|
||||||
property: "{{ .remoteRef.property }}"
|
property: {{ . }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
+31
-77
@@ -1,88 +1,42 @@
|
|||||||
#
|
# Пример для DEV сборки
|
||||||
# Данный конфигурационный файл не является конечным исполнением
|
stand: dev
|
||||||
# Параметры подставлены исключительно для тестов и могут быть измененены в соответствии с Pipeline
|
|
||||||
#
|
|
||||||
|
|
||||||
stand: {{ stand }}
|
deployment:
|
||||||
|
|
||||||
mainContainer:
|
|
||||||
###### Репозиторий
|
|
||||||
image:
|
image:
|
||||||
repository: "{{ registryUrl }}/{{ imageName }}"
|
repository: drn.tst.nubes.ru/deck-auth-api-test
|
||||||
tag: {{ version }}
|
tag: $VERSION
|
||||||
containerPort: {{ appPort }}
|
containerPort: 8080
|
||||||
###### Ресурсы
|
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests: # Начальные запросы
|
||||||
cpu: "500m"
|
cpu: "500m"
|
||||||
memory: "1024Mi"
|
memory: "256Mi"
|
||||||
limits:
|
limits:
|
||||||
cpu: "1000m"
|
cpu: "2" # Максимальные лимиты
|
||||||
memory: "1024Mi"
|
memory: "1024Mi"
|
||||||
###### Пробы контейнера
|
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
tcpSocket:
|
failureThreshold: 5
|
||||||
port: {{ appPort }}
|
initialDelaySeconds: 10
|
||||||
livenessProbe:
|
periodSeconds: 30
|
||||||
|
successThreshold: 1
|
||||||
|
timeoutSeconds: 5
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /api/v1
|
path: /api/v1/health
|
||||||
port: {{ appPort }}
|
|
||||||
scheme: HTTP
|
scheme: HTTP
|
||||||
|
livenessProbe:
|
||||||
# Для Vault есть условие
|
failureThreshold: 5
|
||||||
# Предварительно в Namespace должен быть создан SecretStore
|
initialDelaySeconds: 30
|
||||||
#
|
periodSeconds: 15
|
||||||
# Читать: https://confluence.ad.nubes.ru/pages/viewpage.action?pageId=58626585
|
successThreshold: 1
|
||||||
# (Вариант 2. Используя external-operator)
|
timeoutSeconds: 1
|
||||||
|
|
||||||
vault:
|
vault:
|
||||||
secretStore: "{{ namespace }}"
|
enable: true
|
||||||
enabled: true
|
secretStore: deck-test
|
||||||
serviceAccountName: "{{ namespace }}-sa"
|
secrets:
|
||||||
target:
|
- VITE_BACKEND_HOST
|
||||||
name: "{{ appName }}-envs"
|
- VITE_AUTH_HOST
|
||||||
data:
|
- VITE_KEYCLOAK_CLIENT_ID
|
||||||
- secretKey: LUCEE_EXTENSIONS
|
- VITE_KEYCLOAK_REALM
|
||||||
remoteRef:
|
- VITE_KEYCLOAK_REDIRECT_URI
|
||||||
key: "deck/kubernetes/{{ stand}}/{{ appName }}"
|
- VITE_KEYCLOAK_URL
|
||||||
property: LUCEE_EXTENSIONS
|
- VITE_KEYCLOAK_CLIENT_SECRET
|
||||||
|
|
||||||
- secretKey: ORCHESTRATOR_AUTH
|
|
||||||
remoteRef:
|
|
||||||
key: "deck/kubernetes/{{ stand}}/{{ appName }}"
|
|
||||||
property: ORCHESTRATOR_AUTH
|
|
||||||
|
|
||||||
- secretKey: cfconfig_datasources_cmdb_database
|
|
||||||
remoteRef:
|
|
||||||
key: "deck/kubernetes/{{ stand}}/{{ appName }}"
|
|
||||||
property: cfconfig_datasources_cmdb_database
|
|
||||||
|
|
||||||
- secretKey: cfconfig_datasources_cmdb_dbdriver
|
|
||||||
remoteRef:
|
|
||||||
key: "deck/kubernetes/{{ stand}}/{{ appName }}"
|
|
||||||
property: cfconfig_datasources_cmdb_dbdriver
|
|
||||||
|
|
||||||
- secretKey: cfconfig_datasources_cmdb_host
|
|
||||||
remoteRef:
|
|
||||||
key: "deck/kubernetes/{{ stand}}/{{ appName }}"
|
|
||||||
property: cfconfig_datasources_cmdb_host
|
|
||||||
|
|
||||||
- secretKey: cfconfig_datasources_cmdb_name
|
|
||||||
remoteRef:
|
|
||||||
key: "deck/kubernetes/{{ stand}}/{{ appName }}"
|
|
||||||
property: cfconfig_datasources_cmdb_name
|
|
||||||
|
|
||||||
- secretKey: cfconfig_datasources_cmdb_password
|
|
||||||
remoteRef:
|
|
||||||
key: "deck/kubernetes/{{ stand}}/{{ appName }}"
|
|
||||||
property: cfconfig_datasources_cmdb_password
|
|
||||||
|
|
||||||
- secretKey: cfconfig_datasources_cmdb_port
|
|
||||||
remoteRef:
|
|
||||||
key: "deck/kubernetes/{{ stand}}/{{ appName }}"
|
|
||||||
property: cfconfig_datasources_cmdb_port
|
|
||||||
|
|
||||||
- secretKey: cfconfig_datasources_cmdb_username
|
|
||||||
remoteRef:
|
|
||||||
key: "deck/kubernetes/{{ stand}}/{{ appName }}"
|
|
||||||
property: cfconfig_datasources_cmdb_username
|
|
||||||
|
|||||||
+47
-13
@@ -1,14 +1,48 @@
|
|||||||
main:
|
##### Переменные #####
|
||||||
registryUrl: 'registry.ngcloud.ru' # Где хранится приложение
|
######################
|
||||||
registryRepoPath: 'deck' # Где хранится приложение (registry.ngcloud.ru/deck)
|
app:
|
||||||
appName: "svc-api" # наименование контейнера в K8S
|
# Имя приложения / Имя микросервиса
|
||||||
registryContainerName: "deck-{{ appName }}" # Наименование приложения в Nexus
|
name: "svc-api"
|
||||||
vaultPath: "config.deck-{{ appName }}-{{ stand }}" # Путь где лежит инфраструктурный kubeconfig для установки Helm-чарта
|
# Порт на котором приложение будет работать
|
||||||
namespace: "deck" # Namespace приложения, где он будет развёрнут
|
port: 8080
|
||||||
appPort: 8080 # Порт, на котором работает приложение
|
# Health-Check приложения
|
||||||
|
health: "/api/v1"
|
||||||
|
# CPU пода (milicores)
|
||||||
|
cpu: 1000
|
||||||
|
# Mem пода (megabytes)
|
||||||
|
mem: 1024
|
||||||
|
|
||||||
version:
|
# Получение версии приложения
|
||||||
release: 0
|
# Используется для построения дашбордов / публикации в Registry
|
||||||
major: 0
|
getCommandVersion: "awk -F'\"' '/APIVersion/ {print \\$2; exit}' v1/Application.cfc"
|
||||||
minor: "{{ BUILD_NUMBER }}"
|
|
||||||
version: "{{ release }}.{{ major }}.{{ minor }}"
|
# Если включено, то необходимо сделать файл Dockerfile_build_lib
|
||||||
|
# Либа будет загружена в deck/npm/nubes/{appName}/{version}
|
||||||
|
needBuildLib: false
|
||||||
|
# Нужно ли хранить секреты в Vault
|
||||||
|
needStoreVaultSecret: true
|
||||||
|
# Наименование key, которые нужно забрать из Vault
|
||||||
|
storedSecretsList:
|
||||||
|
- "LUCEE_EXTENSIONS"
|
||||||
|
- "ORCHESTRATOR_AUTH"
|
||||||
|
- "cfconfig_datasources_cmdb_database"
|
||||||
|
- "cfconfig_datasources_cmdb_dbdriver"
|
||||||
|
- "cfconfig_datasources_cmdb_host"
|
||||||
|
- "cfconfig_datasources_cmdb_name"
|
||||||
|
- "cfconfig_datasources_cmdb_port"
|
||||||
|
- "cfconfig_datasources_cmdb_username"
|
||||||
|
- "cfconfig_datasources_cmdb_password"
|
||||||
|
|
||||||
|
##### Константы #####
|
||||||
|
#####################
|
||||||
|
# Путь до секрета в Vault
|
||||||
|
vaultPath: "config.deck-${ app.name }-${ gitBranch }"
|
||||||
|
# Где хранится образ (Registry.app)
|
||||||
|
registryUrl: "registry.ngcloud.ru"
|
||||||
|
registryRepoPath: "deck"
|
||||||
|
registryContainerName: "deck-${ app.name }"
|
||||||
|
registryImageName: "${ registryRepoPath ? registryRepoPath + '/' + registryContainerName : registryContainerName }"
|
||||||
|
|
||||||
|
# В какой namespace попадает проект в Kubernetes (по хорошему нужно изменить)
|
||||||
|
# Ибо счас всё хранится в одном кубере. Кубер умрёт - 3 сренда в OUT
|
||||||
|
namespace: "deck-${ gitBranch }"
|
||||||
Reference in New Issue
Block a user