Atualmente temos três processos de integração/entrega que são gerenciados pelo time de SRE da Engenharia Protheus.

Temos os clientes de Produção do SmartERP, os clientes de Produção do Smart eSocial e os ambientes do Sistêmico.

O processo de geração dos artefatos é automatizado,  Tudo ocorre devido a jobs autônomos disparados em cada processo do sistema. Como utilizamos JOBs para atualização, disparamos vários processos ao mesmo tempo, a fim de ganharmos tempo com a atualização do ambiente.

Dentre este jobs, temos:

  • Montagem do RPO
  • Montagem dos artefatos de implantação/atualização
  • Compilação/montagem das imagens e charts.

As Tarefas de montagem do RPO (Repositório de fontes Protheus) para utilização das soluções smart (backoffice, sistemico/release, taf e etc.). Está salvo no repositório: https://code.engpro.totvs.com.br/smarterp/pipeline-rpo

Parâmetros

Os parâmetros de execução, ficam salvos no arquivo .config na raiz deste repositório. Nele é possível configurar os parâmetros de execução e montagem do RPO de acordo com cada necessidade.

Release de geração: $RELEASE
Origem do RPO: $RPOSOURCE
Aplica expedição continua: $EXPCONT
Aplica expediçoes da next: $EXPCONTNEXT
Expedições ignoradas do published: $MODULE_PUBLISH_BLACKLIST
Expedições aceitas do latest: $MODULE_LATEST_ALLOW
Aplica pacote pontuais: $PATCHPONTUAL
Gera RPO para Mercado Internacional: $GERAMI
Aplica fontes antigos no RPO: $APPLYOLD
Realiza a geração do JITT: $JITT
Versão do APPSERVER do JITT: $APPVERSION
Versão do SO do JITT: $SOVERSION
Chama a geração das imagens ao termino do processo: $BUILDIMAGE

Gravação.

Após a geração do RPO, o mesmo fica salvo dentro do bucket do smartsre que fica atualmente dentro do arte/engenharia/bundle/apo.

Cron

O repositório esta configurado para ser executado automaticamente as quintas (backoffice) e sabados (taf e sistemico/release). Para configurar o cron, basta chamar via api:


curl --request POST \
--url https://drone.engpro.totvs.com.br/api/repos/smarterp/pipeline-rpo/cron \
--header 'Authorization: Bearer xxxxxxxxxxxx' \
--header 'Content-Type: application/json' \
--data '{
"name": "master-cron",
"expr": "* 0 10 * * 4",
"branch": "master"
}'

Execução via API.

A execução via API, por enquanto está restrita somente aos parâmetros configurados no .config, sendo que somente é possível passar a versão a ser gerada.


Tarefa utilizada para empacotar os artefatos utilizados nas imagens utilizadas pelas soluções SmartSRE. Está salvo no repositório: https://code.engpro.totvs.com.br/smarterp/pipeline-imagem

Parâmetros

Os parâmetros de execução, ficam salvos no arquivo .config na raiz deste repositório. Nele é possível configurar os parâmetros de execução e montagem dos artefatos de acordo com cada necessidade.

Release de geração: $RELEASE
Gera com UPDDISTR: $UPDDISTR
Gera com UPDDISTR com condicional?: $UPDDISTRCOND || Informar uma expressao logica para execução do flag de upddistr (Usado na automação do sistemico)
Local do dicionario padrão: ${DICIONARIO_PADRAO_PATH}
Local do dicionario Mercado Internacional: ${DICIONARIO_MI_PATH}
Gera dados do mercado internacional?: ${GERAMI}
Atualiza Web-Files (Published)?: ${UPDATE_WEBFILES}
Atualiza MeuRH (Published)?: ${UPDATE_MEURH}
Atualiza versão do SmartReports?: ${UPDATE_TREPORTS}
Executa o CI das Imagens (codeengpro)?: ${GERA_IMAGEM}
Repo (codeengpro) da Imagem a ser gerada: ${IMAGEM_REPO}
Branch (codeengpro) da Imagem a ser gerada: ${IMAGEM_BRANCH}
Executa o CI do Chart (cloud104)?: ${GERA_CHART}
Repo (cloud104) da Imagem a ser gerada: ${CHART_REPO}
Branch (cloud104) da Imagem a ser gerada: ${CHART_BRANCH}
Local do Arquivo de Values do chart: ${CHART_VALUES}

Gravação.

Após a geração dos artefatos, os mesmos são salvos dentro do bucket do smartsre que fica atualmente dentro do arte/engenharia/bundle/smartsre/espelho.

Cron

O repositorio esta configurado para ser executado automaticamente as quintas (backoffice). Para configurar o cron, basta chamar via api: 

curl --request POST \
  --url https://drone.engpro.totvs.com.br/api/repos/smarterp/pipeline-imagem/cron \
  --header 'Authorization: Bearer xxxxxxxxxxxx' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "backoffice-cron",
  "expr": "* 0 11 * * 4",
  "branch": "backoffice"
  }'

Integração

Origem

Este repositório está integrado com o pipeline-rpo, sendo que algumas branchs são disparadas diretamente pelo pipeline-rpo. Devido a isto, não possuímos cron para todas as branchs

Imagens e charts

Após a conclusão do processo de empacotamento dos artefatos, este repositório pode ser configurado para disparar o CI/CD de outros repositórios, como das IMAGENS e CHARTS.

Execução via API.

A execução via API, por enquanto está restrita somente aos parâmetros configurados no .config, sendo que somente é possível passar a versão a ser gerada.

Uma vez montado os artefatos, realizamos a atualização do repositório de imagem e do repositório de charts. Ambos repositórios irão variar em decorrência ao tipo do recurso que iremos atualizar. Atualmente controlamos:

ProdutoImagemChart
SmartERP - BackofficeGitea: SmartERP/Protheus (Develop/Master)GitHub: Cloud104/SmartERP (Develop/Master)
SmartERP - SistêmicoGitea: SmartERP/SmartERP (Develop/Master)GitHub: Cloud104/SmartERP (release/smarterp-sistemico)
SmartERP - ReleaseGitea: SmartERP/SmartERP (Develop/Master)GitHub: Cloud104/SmartERP (release/12.1.2x10)
SmarteSocial - Produção (TAF)Gitea: SmartERP/smartesocial (Develop/Master)GitHub: Cloud104/smartesocial (Develop/Master)
SmartTSS - ProduçãoGitea: SmartERP/tss (Develop/Master)Não tem REPO
SmartTransmiteGitea: SmartERP/tss (Develop/Master)GitHub: Cloud104/smarttransmite (Develop/Master)


Para todos os repositórios listados, seguimos o seguinte fluxo de trabalho:

A atualização das topologias variam em de acordo com a cada cluster. Dentro os modelos de atualização temos:

Ocorre após a homologação do SmartERP Backoffice de forma manual através do script:

#!/bin/bash
set -f

desiredVersion=$1
needbackup=$2
environments=$3

function LauncherExternalId() {
	kubectl get namespace $i -o json | jq -r .metadata.labels.External_id
}

if [ "$desiredVersion" == " " ]; then
	echo Informe a versao desejada para atualização
	exit 1
fi

if [ "$needbackup" == " " ]; then
	needbackup="false"
fi

if [ "$environments" == " " ]; then
	environments='cfields\|ctecnologia\|cbul2o\|cj0u6a\|ckwcoi\|ctvey3'
fi

hlmbkp="/totvs/ambientes/helm/$(date '+%Y%m%d')"
mkdir -p $hlmbkp

function backupIsRunning() {
	kubectl -n $i get pods | grep protheus-backup-update | grep -iv 'completed\|failed\|error\|evicted' | wc -l
}

echo "iniciando atualização dos ambientes"

if [ ! -f "/totvs/ambientes/helm/smarterp-$desiredVersion.tgz" ]; then
	wget -O /totvs/ambientes/helm/smarterp-$desiredVersion.tgz http://smarterp-charts.storage.googleapis.com/smarterp-$desiredVersion.tgz
fi

for i in $(envs | grep -v $desiredVersion | grep -i $environments | grep -iv 'migratio\|canceled\|inactive' | cut -f1 -d ' '); do

	if [ ! -f "$hlmbkp/$i.yaml" ]; then
		echo backup to helm values
		helm get values $i >$hlmbkp/$i.yaml
	fi

	echo $i

	cStatus=$(kubectl -n $i get configmap protheus-updater-config -o json | jq -r '.data.UPDATER_STATUS')

	if [ "$cStatus" == "" ]; then
		cStatus="FAILED"
	fi

	# Possibilidade de executar varias vezes em paralelo
	baseVersion=$(kubectl get namespace $i -o json | jq -r .metadata.labels.BaseVersion)
	UpdateVersion=$(kubectl get namespace $i -o json | jq -r .metadata.labels.UpdaterDesiredVersion)

	if [ "$cStatus" == "OK" ] || [ "$cStatus" == "FAILED" ]; then

		if [ "$baseVersion" != "$desiredVersion" ] && [ "$baseVersion" == "$UpdateVersion" ]; then

			qtpod=$(kubectl -n $i get deploy -l base=false -o jsonpath='{range .items[?(@.status.availableReplicas>=1)]}{@.metadata.name}{"\n"}{end}' | wc -l)
			echo "$i | pods actives -> $qtpod"

			if [ "$qtpod" == "0" ]; then
				monitorId=$(curl --request POST 'https://api.uptimerobot.com/v2/getMonitors' --form 'api_key=u752568-980824d9145b401cc6b723da' --form 'search='$i' - Protheus' | jq '.monitors[].id')

				# STOP
				curl --request POST 'https://api.uptimerobot.com/v2/editMonitor' --form 'api_key=u752568-980824d9145b401cc6b723da' --form 'id='$monitorId --form 'status=0'

				kubectl label ns $i --overwrite UpdaterDesiredVersion=$desiredVersion
				kubectl -n $i patch configmap protheus-updater-config -p '{"data":{ "UPDATER_STATUS":"UPDATING" }}'

				echo $i | grep -i development
				if [ "$?" == 1 ]; then
					echo updating global values
					env="producao"
				else
					#	echo updating global values
					env="homologacao"
				fi

				if [ "$needbackup" == "true" ]; then
					kubectl -n $i create job --from=cronjob/protheus-daily-backup protheus-backup-update-$(date '+%Y%m%d')
					sleep 5s

					while [[ "$(backupIsRunning)" != "0" ]]; do
						echo "$i Waiting backup file..."
						sleep 10
					done
				fi

				chartfile="/totvs/ambientes/helm/smarterp-$desiredVersion.tgz"

				for pod in $(kubectl -n $i get deploy --no-headers -l base=false | awk '$3 != '0' {print $1}'); do
					kubectl -n $i scale deploy $pod --replicas=0
				done

				kubectl -n $i scale deploy protheus-sleeper --replicas=0
				kubectl -n $i scale deploy -l base=true --replicas=1
				kubectl -n $i delete pods --all --force --grace-period=0

				echo "$i | clean components topology"
				kubectl -n $i delete deploy --all
				# Descomentar os serviços que foram alterados no ultimo chart (HELM 2 somente)
				# kubectl -n $i delete configmap $(kubectl -n $i get configmap --no-headers | grep -i 'appserver\|config' | cut -f1 -d ' ')
				# kubectl -n $i delete configmap --all

				# excluido serviços criados recentemente para atualização.
				# kubectl -n $i delete ingress $(kubectl -n $i get ingress --no-headers | grep -i 'report\|pgadmin\|logserver' | cut -f1 -d ' ')
				# kubectl -n $i delete service $(kubectl -n $i get service --no-headers | grep -i 'report\|pgadmin\|logserver' | cut -f1 -d ' ')
				# exclui todos os services, tirando o nodeport
				# kubectl -n $i delete service $(kubectl -n $i get service --no-headers | grep -v $i | grep -iv 'np' | cut -f1 -d ' ')

				# kubectl -n $i delete cronjob --all
				# kubectl -n $i delete job --all

				# kubectl -n $i delete pvc pgsql-disk
				# kubectl -n $i delete PodDisruptionBudget --all
				# kubectl -n $i patch pvc protheus-data-claim -p '{"metadata":{"finalizers": null}}' &
				# kubectl -n $i delete PersistentVolume protheus-volume-$i &
				# kubectl patch pv protheus-volume-$i -p '{"metadata":{"finalizers": null}}'
				# kubectl -n $i delete uptimerobot --all

				setvalues=""
				# Informar os novos values aqui
				# exemplo:
				# setvalues=$setvalues' --set global.logserver.enabled=true --set global.logserver.secretAccessKey="'$secretLogServer'"'

				echo "$i | executing helm upgrade to $desiredVersion"
				eval helm upgrade $i $chartfile --namespace=$i --install --timeout 1800000 --debug --recreate-pods -f $hlmbkp/$i.yaml $setvalues
				# --no-hooks

				if [ "$?" == "0" ]; then
					echo "$i | updating kubectl values to $desiredVersion"

					kubectl label ns $i --overwrite BaseVersion="$desiredVersion"
					kubectl -n $i patch configmap protheus-updater-config -p '{"data":{ "UPDATER_STATUS":"OK" }}'
					kubectl -n $i patch configmap protheus-updater-config -p '{"data":{"HOOK_ENVIRONMENT_'$env'":""}}'
					kubectl -n $i patch configmap protheus-updater-config -p '{"data":{"HOOK_UPDATEDATA_'$env'":""}}'
					kubectl -n $i patch configmap protheus-updater-config -p '{"data":{"HOOK_UPDATEDATADICTONARY_'$env'":"" }}'

					# echo "$i | shutdown services"
					for pod in $(kubectl -n $i get deploy --no-headers | awk '$3 != '0' {print $1}'); do
						kubectl -n $i scale deploy $pod --replicas=0
					done

					for pod in $(kubectl -n $i get deploy --no-headers | grep -i "appserver\|config\|rest" | awk '$3 == '0' {print $1}'); do
						kubectl -n $i patch service ${pod}-svc -p '{"metadata":{"annotations":{"tks.sh/sleeper.user":""}}}'
					done

					for j in $(kubectl -n $i get deploy -l base=false --no-headers | grep -i 'config\|rest' | cut -d ' ' -f 1); do
						kubectl -n $i patch deploy $j -p '{"metadata":{"labels":{"base":"true" }}}'
						kubectl -n $i patch deploy $j -p '{"spec":{"template":{"metadata":{"labels":{"base":"true" }}}}}'
						kubectl -n $i patch deploy $j -p '{"metadata":{"annotations":{"tks.sh/sleeper.depends":"" }}}'
					done

					for j in $(kubectl -n $i get deploy -l base=false --no-headers | grep -iv 'config\|rest\|carol' | cut -d ' ' -f 1); do  
						depends=$(kubectl -n $i get deploy $j -o yaml | yq -r '.metadata.annotations."tks.sh/sleeper.depends"')",protheus-config-$env-all,protheus-rest-$env-all" 
						kubectl -n $i patch deploy $j -p '{"metadata":{"annotations":{"tks.sh/sleeper.depends":"'$depends'" }}}'
					done

					kubectl -n $i delete pods --all --force --grace-period=0

					# echo "$i | Start hypnus and license"
					# kubectl -n $i scale deploy protheus-license --replicas=1
					kubectl -n $i scale deploy protheus-sleeper --replicas=1

					topology=$(echo $i | cut -f1 -d '-')

					# START
					curl --request POST 'https://api.uptimerobot.com/v2/editMonitor' --form 'api_key=u752568-980824d9145b401cc6b723da' --form 'id='$monitorId --form 'status=1'

				else
					echo "$i HELM" >>/totvs/ambientes/erro.txt
					kubectl -n $i patch configmap protheus-updater-config -p '{"data":{ "UPDATER_STATUS":"FAILED" }}'
					exit 1
				fi

				#exit 0
			fi
			# sleep 5s
		fi
	else
		echo "$i status" >>/totvs/ambientes/erro.txt
	fi
done

echo "=) update finish!....."

spd-say -l "en-us" "     pay attention, it's done"

exit 0

Atualização ocorre de forma automática ao termino da publicação do chart no GCP para a branch develop

#!/bin/bash

if [ "$1" == "" ]; then
   echo need to provide new version
   exit
fi

for i in $(kubectl get ns --no-headers --sort-by=.metadata.creationTimestamp | grep -i 'cbul2o' | cut -d ' ' -f 1); do
   echo $i

   kubectl patch ns $i -p '{"metadata":{"labels":{"UpdaterDesiredVersion":"'$1'", "UpdaterIgnoreUsing": "true"}}}'

   kubectl -n $i patch configmap protheus-updater-config -p '{"data":{ "UPDATER_STATUS":"OK" }}'
   kubectl -n $i patch configmap protheus-updater-config -p '{"data":{"HOOK_ENVIRONMENT_producao":""}}'
   kubectl -n $i patch configmap protheus-updater-config -p '{"data":{"HOOK_UPDATEDATA_producao":""}}'
   kubectl -n $i patch configmap protheus-updater-config -p '{"data":{"HOOK_UPDATEDATADICTONARY_producao":"" }}'

   kubectl -n $i scale deploy -l base=false --replicas=0
   kubectl -n $i scale deploy -l base=true --replicas=1

   kubectl -n $i delete pods --all --force --grace-period=0

   kubectl -n $i delete job force-update
   kubectl -n $i create job --from=cronjob/protheus-updater force-update
done

Atualização ocorre de forma automática ao termino da publicação do chart no GCP para a branch release ou sistêmico

#!/bin/bash

if [ "$1" == "" ]; then
   echo need to provide new version
   exit
fi

for i in $(kubectl get ns --no-headers --sort-by=.metadata.creationTimestamp | grep -i 'cbul2o' | cut -d ' ' -f 1); do
   echo $i

   kubectl patch ns $i -p '{"metadata":{"labels":{"UpdaterDesiredVersion":"'$1'", "UpdaterIgnoreUsing": "true"}}}'

   kubectl -n $i patch configmap protheus-updater-config -p '{"data":{ "UPDATER_STATUS":"OK" }}'
   kubectl -n $i patch configmap protheus-updater-config -p '{"data":{"HOOK_ENVIRONMENT_producao":""}}'
   kubectl -n $i patch configmap protheus-updater-config -p '{"data":{"HOOK_UPDATEDATA_producao":""}}'
   kubectl -n $i patch configmap protheus-updater-config -p '{"data":{"HOOK_UPDATEDATADICTONARY_producao":"" }}'

   kubectl -n $i scale deploy -l base=false --replicas=0
   kubectl -n $i scale deploy -l base=true --replicas=1

   kubectl -n $i delete pods --all --force --grace-period=0

   kubectl -n $i delete job force-update
   kubectl -n $i create job --from=cronjob/protheus-updater force-update
done

Atualização ocorre de forma automática ao término da publicação do chart no GCP para a branch develop.

Atualização utiliza o SmartUpdater do cluster e não do NS

#!/bin/bash

if [ "$1" == "" ]; then
   echo need to provide new version
   exit
fi

for i in $(kubectl get ns --no-headers --sort-by=.metadata.creationTimestamp | grep -i 'c0fbc5' | cut -d ' ' -f 1); do
   kubectl patch ns $i -p '{"metadata":{"labels":{"UpdaterDesiredVersion":"'$1'", "UpdaterIgnoreUsing": "true"}}}'
done

Atualização ocorre de forma manual, através de script de atualização.

#!/bin/bash
set -f

function updateIsRunning() {
  kubectl -n $i get pods | grep -i "protheus-appserver-" | grep -i 'Running' | grep -iv 'completed\|failed\|Init' | wc -l
}

function stopMonitor() {
  monitorId=$(curl --request POST 'https://api.uptimerobot.com/v2/getMonitors' --form 'api_key=u592805-9185b8fb1fd629c4b289786e' --form 'search='$i' Homolog Rest' | jq '.monitors[].id')
  postMonitor $monitorId '0'

  monitorId=$(curl --request POST 'https://api.uptimerobot.com/v2/getMonitors' --form 'api_key=u592805-9185b8fb1fd629c4b289786e' --form 'search='$i' Homolog Webapp' | jq '.monitors[].id')
  postMonitor $monitorId '0'

  monitorId=$(curl --request POST 'https://api.uptimerobot.com/v2/getMonitors' --form 'api_key=u592805-9185b8fb1fd629c4b289786e' --form 'search='$i' Prod Rest' | jq '.monitors[].id')
  postMonitor $monitorId '0'

  monitorId=$(curl --request POST 'https://api.uptimerobot.com/v2/getMonitors' --form 'api_key=u592805-9185b8fb1fd629c4b289786e' --form 'search='$i' Prod Webapp' | jq '.monitors[].id')
  postMonitor $monitorId '0'

}

function startMonitor() {
  monitorId=$(curl --request POST 'https://api.uptimerobot.com/v2/getMonitors' --form 'api_key=u592805-9185b8fb1fd629c4b289786e' --form 'search='$i' Homolog Rest' | jq '.monitors[].id')
  postMonitor $monitorId '1'

  monitorId=$(curl --request POST 'https://api.uptimerobot.com/v2/getMonitors' --form 'api_key=u592805-9185b8fb1fd629c4b289786e' --form 'search='$i' Homolog Webapp' | jq '.monitors[].id')
  postMonitor $monitorId '1'

  monitorId=$(curl --request POST 'https://api.uptimerobot.com/v2/getMonitors' --form 'api_key=u592805-9185b8fb1fd629c4b289786e' --form 'search='$i' Prod Rest' | jq '.monitors[].id')
  postMonitor $monitorId '1'

  monitorId=$(curl --request POST 'https://api.uptimerobot.com/v2/getMonitors' --form 'api_key=u592805-9185b8fb1fd629c4b289786e' --form 'search='$i' Prod Webapp' | jq '.monitors[].id')
  postMonitor $monitorId '1'
}

function postMonitor() {
  curl --request POST 'https://api.uptimerobot.com/v2/editMonitor' --form 'api_key=u592805-9185b8fb1fd629c4b289786e' --form 'id='$1 --form 'status='$2
}

desiredVersion=$1
environments=$2

if [ "$desiredVersion" == " " ]; then
  echo Informe a versao desejada para atualização
  exit 1
fi

if [ "$environments" == " " ]; then
  environments=$(kubectl get ns --no-headers --sort-by=.metadata.creationTimestamp | cut -d' ' -f1)
fi

hlmbkp="/totvs/ambientes/helm-taf/$(date '+%Y%m%d')"
mkdir -p $hlmbkp

cd $hlmbkp

echo "iniciando atualização dos ambientes"

for i in $(kubectl get ns --no-headers --sort-by=.metadata.creationTimestamp | grep -iv $desiredVersion | grep -i $environments | cut -f1 -d ' '); do

  qtpod=$(kubectl -n $i get deploy -o jsonpath='{range .items[?(@.status.availableReplicas>=1)]}{@.metadata.name}{"\n"}{end}' | grep 'appserver\|rest' | wc -l)
  echo "$i | pods actives -> $qtpod"

  if [ "$qtpod" == "0" ] || [ "$qtpod" == "4" ]; then

    sleep 3s
    # Possibilidade de executar varias vezes em paralelo
    baseVersion=$(kubectl get namespace $i -o json | jq -r .metadata.labels.BaseVersion)
    UpdateVersion=$(kubectl get namespace $i -o json | jq -r .metadata.labels.UpdaterDesiredVersion)

    if [ "$baseVersion" != "$desiredVersion" ] && [ "$baseVersion" == "$UpdateVersion" ]; then
      kubectl label ns $i --overwrite UpdaterDesiredVersion=$desiredVersion
      kubectl -n $i scale deploy protheus-sleeper --replicas=0

      stopMonitor $i >>/dev/null 2>&1

      if [ ! -f "$hlmbkp/$i.yaml" ]; then
        echo backup to helm values
        helm get values $i >$hlmbkp/$i.yaml
      fi

      if [ ! -f "/totvs/ambientes/helm/taf-standard-$desiredVersion.tgz" ]; then
        wget -O /totvs/ambientes/helm/taf-standard-$desiredVersion.tgz http://smartesocial-charts.storage.googleapis.com/taf-standard-$desiredVersion.tgz
      fi

      chartfile="/totvs/ambientes/helm/taf-standard-$desiredVersion.tgz"

      echo "$i | clean components topologie"
      kubectl -n $i delete pods --all --force --grace-period=0

      newHelmValues=""
	  # informar somente se tiver novos values
      # exemplo: newHelmValues=$newHelmValues' --set protheus-base.cloudProvider=aws'

      kubectl -n $i delete cronjob --all
      kubectl -n $i delete job --all
      kubectl -n $i delete configmap --all
      kubectl -n $i delete deploy --all
      kubectl -n $i delete ingress --all

      # exclui todos os services, tirando o nodeport
      # kubectl -n $i delete service $(kubectl -n $i get service --no-headers | grep -v $i | grep -iv 'np' | cut -f1 -d ' ')
      # helm delete $i --no-hooks --purge

      echo "$i | executing helm upgrade to $desiredVersion"
      helm upgrade $i $chartfile --namespace=$i --debug --install --recreate-pods --timeout 180000 -f $hlmbkp/$i.yaml $newHelmValues

      if [ "$?" == "0" ]; then
        echo "$i | updating kubectl values to $desiredVersion"
        kubectl label ns $i --overwrite BaseVersion="$desiredVersion"
      else
        echo "$i | error helm updating to $desiredVersion"
        exit 1
      fi

      echo "$i | Updating environment"
      kubectl -n $i scale deploy --all --replicas=0
      kubectl -n $i scale deploy -l base=true --replicas=1
      kubectl -n $i scale deploy protheus-appserver-producao-all --replicas=1
      kubectl -n $i scale deploy protheus-appserver-homologacao-all --replicas=1
      kubectl -n $i scale deploy protheus-sleeper --replicas=0

      sleep 10
      while [[ "$(updateIsRunning)" != "2" ]]; do
        echo "$i Waiting update... "
        sleep 10
      done

      startMonitor $i >>/dev/null 2>&1

      kubectl -n $i scale deploy --all --replicas=0
      kubectl -n $i scale deploy protheus-sleeper --replicas=1
    fi
  fi

done

spd-say -l "en-us" "     pay attention, it's done"

exit 0

Após a conclusão dos jobs supracitados, realizamos a atualização das topologias via Helm. Este processo para o cluster de produção é manual e controlado pelo SRE.