Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
|
ada:howto:sicoferp:factory:new-migracion-sicoferp:front:iac [2024/06/24 12:24] 192.168.177.98 |
ada:howto:sicoferp:factory:new-migracion-sicoferp:front:iac [2024/08/13 14:26] (actual) 192.168.177.33 |
||
|---|---|---|---|
| Línea 28: | Línea 28: | ||
| **Al hacer Docker Build se ejecuta la siguiente receta: | **Al hacer Docker Build se ejecuta la siguiente receta: | ||
| ** | ** | ||
| + | |||
| + | <code> | ||
| # Usa una imagen base de Node.js | # Usa una imagen base de Node.js | ||
| - | |||
| FROM node:20-alpine AS build-step | FROM node:20-alpine AS build-step | ||
| # Establecer el límite de memoria para Node.js | # Establecer el límite de memoria para Node.js | ||
| + | ENV NODE_OPTIONS=--max_old_space_size=4096 | ||
| - | ENV NODE_OPTIONS=–max_old_space_size=4096 | + | # Variable de entorno que define el ambiente |
| ARG TYPE | ARG TYPE | ||
| # Crea un directorio /app en la imagen | # Crea un directorio /app en la imagen | ||
| - | |||
| RUN mkdir -p /app | RUN mkdir -p /app | ||
| # Establece el directorio de trabajo | # Establece el directorio de trabajo | ||
| - | |||
| WORKDIR /app | WORKDIR /app | ||
| # Copia los archivos de tu proyecto al directorio de trabajo | # Copia los archivos de tu proyecto al directorio de trabajo | ||
| - | |||
| COPY package.json /app | COPY package.json /app | ||
| # Instala las dependencias del proyecto | # Instala las dependencias del proyecto | ||
| - | |||
| RUN npm install | RUN npm install | ||
| # Copia el resto de los archivos de tu proyecto al directorio de trabajo | # Copia el resto de los archivos de tu proyecto al directorio de trabajo | ||
| - | |||
| COPY . /app | COPY . /app | ||
| # Construye la aplicación Angular | # Construye la aplicación Angular | ||
| - | |||
| RUN npm run build:${TYPE} | RUN npm run build:${TYPE} | ||
| # Configura la imagen de producción de Nginx | # Configura la imagen de producción de Nginx | ||
| - | |||
| FROM nginx:alpine | FROM nginx:alpine | ||
| # Copia los archivos generados de la compilación de Angular a la carpeta de Nginx | # Copia los archivos generados de la compilación de Angular a la carpeta de Nginx | ||
| - | + | COPY --from=build-step /app/dist/mfsicof /usr/share/nginx/html | |
| - | COPY –from=build-step /app/dist/mfsicof /usr/share/nginx/html | + | |
| # Expone el puerto 80 para que se pueda acceder a la aplicación desde el navegador | # Expone el puerto 80 para que se pueda acceder a la aplicación desde el navegador | ||
| - | |||
| EXPOSE 80 | EXPOSE 80 | ||
| # Comando para iniciar Nginx cuando se ejecute el contenedor | # Comando para iniciar Nginx cuando se ejecute el contenedor | ||
| + | CMD ["nginx", "-g", "daemon off;"] | ||
| - | CMD [“nginx”, “-g”, “daemon off;”] | + | </code> |
| Línea 116: | Línea 109: | ||
| ** | ** | ||
| Ve a "New Item". | Ve a "New Item". | ||
| - | Selecciona "Freestyle project" y da un nombre a tu proyecto. | + | Selecciona "Pipeline" y da un nombre a tu proyecto. |
| Haz clic en "OK". | Haz clic en "OK". | ||
| Línea 128: | Línea 121: | ||
| * En GitLab, ve a tu proyecto. | * En GitLab, ve a tu proyecto. | ||
| * Navega a "Settings" > "Webhooks". | * Navega a "Settings" > "Webhooks". | ||
| - | * Añade una nueva URL de webhook apuntando a tu Jenkins (e.g., //http://your-jenkins-url/gitlab-webhook//). | + | * Añade una nueva URL de webhook apuntando a tu Jenkins. |
| * Selecciona los eventos que deseas que disparen el webhook, como "Push events". | * Selecciona los eventos que deseas que disparen el webhook, como "Push events". | ||
| - | **5.5 Añadir un paso de ejecución de shell:** | + | **5.5 Añadir pasos de ejecución shell del pipeline** |
| - | + | ||
| - | ====== * En la sección "Build", haz clic en "Add build step" y selecciona "Execute shell". Copia y pega el siguiente script: | + | |
| - | ====== | + | |
| - | # Definir la URI del host Docker | ||
| - | DOCKER_HOST_URI="tcp://172.17.0.1:2375" | + | <code> |
| - | # Exportar la variable DOCKER_HOST | + | pipeline { |
| + | agent any | ||
| - | export DOCKER_HOST=$DOCKER_HOST_URI | + | environment { |
| + | DOCKER_HOST_URI = 'tcp://172.17.0.1:2375' | ||
| + | GIT_REPO = 'http://10.1.140.120/ada-microservices-ecosystem/frontends/mfsicof.git' | ||
| + | GIT_BRANCH = 'master' | ||
| + | CREDENTIALS_ID = 'f0a2166c-1e70-47b4-9205-5284d47227f1' | ||
| + | SLACK_CREDENTIALS = 'slack_secret_2' | ||
| + | SLACK_CHANNEL = 'ada-ecosystem-deploy' | ||
| + | SLACK_BASE_URL = 'https://slack.com/api' | ||
| + | SLACK_USERNAME = 'jenkins' | ||
| + | } | ||
| - | # Extraer la versión y el nombre del archivo package.json | + | stages { |
| - | TAG_NAME=$(jq -r '.version' package.json) | + | stage('Send Initial Notification') { |
| - | NAME=$(jq -r '.name' package.json) | + | steps { |
| + | script { | ||
| + | def fullJobName = env.JOB_NAME.replaceAll('/', ' » ') | ||
| + | def buildCauseDescription = currentBuild.getBuildCauses().first().shortDescription | ||
| + | def initialMessage = "${fullJobName} - #${env.BUILD_NUMBER} Started by ${buildCauseDescription} (${env.BUILD_URL})" | ||
| + | slackSend(channel: env.SLACK_CHANNEL, message: initialMessage, color: 'good', tokenCredentialId: env.SLACK_CREDENTIALS) | ||
| + | } | ||
| + | } | ||
| + | } | ||
| - | # Modificar el nombre para insertar un guion después de 'mf' | + | stage('Checkout') { |
| + | steps { | ||
| + | script { | ||
| + | checkout([ | ||
| + | $class: 'GitSCM', | ||
| + | branches: [[name: GIT_BRANCH]], | ||
| + | doGenerateSubmoduleConfigurations: false, | ||
| + | extensions: [], | ||
| + | submoduleCfg: [], | ||
| + | userRemoteConfigs: [[ | ||
| + | url: GIT_REPO, | ||
| + | credentialsId: CREDENTIALS_ID | ||
| + | ]] | ||
| + | ]) | ||
| + | } | ||
| + | } | ||
| + | } | ||
| - | CONTAINER_NAME=$(echo $NAME | sed 's/^mf/mf-/') | + | stage('Clean Workspace') { |
| + | steps { | ||
| + | script { | ||
| + | echo "*********************************SE LIMPIA EL ESPACIO DE TRABAJO**********************" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| - | # Quitar el guion del nombre del repositorio | + | stage('Set Environment Variables') { |
| + | steps { | ||
| + | script { | ||
| + | echo "*********************************VARIABLES DE ENTORNO*********************************" | ||
| + | def tagName = sh(script: "jq -r '.version' package.json", returnStdout: true).trim() | ||
| + | def name = sh(script: "jq -r '.name' package.json", returnStdout: true).trim() | ||
| - | REPOSITORY_NAME="ecosystemuser/${NAME}" | + | def containerName = name.replaceFirst(/^mf/, 'mf-') |
| + | def repositoryName = "ecosystemuser/${name}" | ||
| - | # Imprimir los nombres para visualización | + | env.TAG_NAME = tagName |
| + | env.NAME = name | ||
| + | env.CONTAINER_NAME = containerName | ||
| + | env.REPOSITORY_NAME = repositoryName | ||
| - | echo "REPOSITORY_NAME: $REPOSITORY_NAME" | + | echo " TAG_NAME=${env.TAG_NAME}" |
| - | echo "CONTAINER_NAME: $CONTAINER_NAME" | + | echo " NAME=${env.NAME}" |
| + | echo " CONTAINER_NAME=${env.CONTAINER_NAME}" | ||
| + | echo " REPOSITORY_NAME=${env.REPOSITORY_NAME}" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | stage('Docker Build & Push') { | ||
| + | steps { | ||
| + | script { | ||
| + | echo "************************EJECUCION DE COMANDOS DOCKER***************************" | ||
| + | sh """ | ||
| + | export DOCKER_HOST=${env.DOCKER_HOST_URI} | ||
| + | docker build --no-cache --build-arg TYPE=prod -t ${env.REPOSITORY_NAME}:${env.TAG_NAME} . | ||
| + | docker tag ${env.REPOSITORY_NAME}:${env.TAG_NAME} ${env.REPOSITORY_NAME}:latest | ||
| + | docker push ${env.REPOSITORY_NAME}:${env.TAG_NAME} | ||
| + | docker push ${env.REPOSITORY_NAME}:latest | ||
| + | """ | ||
| + | echo "*******************TERMINA EJECUCION DE COMANDOS DOCKER***********************" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| - | # Construir la imagen Docker con el argumento de construcción | + | stage('Deploy Docker Container') { |
| + | steps { | ||
| + | script { | ||
| + | echo "*******************INICIA EJECUCION Deploy Docker Container***********************" | ||
| + | sh """ | ||
| + | export DOCKER_HOST=${env.DOCKER_HOST_URI} | ||
| + | if [ \$(docker ps -aq -f name=${env.CONTAINER_NAME}) ]; then | ||
| + | docker stop ${env.CONTAINER_NAME} || true | ||
| + | docker rm -fv ${env.CONTAINER_NAME} || true | ||
| + | fi | ||
| + | docker run -d -p 8095:80 --name ${env.CONTAINER_NAME} ${env.REPOSITORY_NAME}:latest | ||
| + | """ | ||
| + | echo "*******************TERMINA EJECUCION Deploy Docker Container***********************" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| - | docker build --no-cache --build-arg TYPE=prod -t $REPOSITORY_NAME:$TAG_NAME . | + | |
| + | stage('Merge Branches') { | ||
| + | steps { | ||
| + | script { | ||
| + | def warningMessage = '' | ||
| + | sh ''' | ||
| + | # Configuración de usuario git | ||
| + | git config --global user.email "simon.gil@ada.co" | ||
| + | git config --global user.name "simon.gil" | ||
| + | GIT_USER='simon.gil' | ||
| + | GIT_TOKEN='jwPyfnRVxbD2ihgVPByN' | ||
| + | git config credential.helper "store --file=.git-credentials" | ||
| + | echo "http://${GIT_USER}:${GIT_TOKEN}@10.1.140.120" > .git-credentials | ||
| + | |||
| + | # Borrar las ramas locales develop, qa y pre-production si existen | ||
| + | delete_local_branches() { | ||
| + | for BRANCH in "$@"; do | ||
| + | if git show-ref --quiet refs/heads/\$BRANCH; then | ||
| + | echo "Borrando la rama local \$BRANCH..." | ||
| + | git branch -D \$BRANCH | ||
| + | fi | ||
| + | done | ||
| + | } | ||
| + | delete_local_branches develop qa pre-production | ||
| + | |||
| + | # Re-crear la rama master desde el remoto | ||
| + | git fetch origin master:master | ||
| + | git checkout master | ||
| + | ''' | ||
| + | |||
| + | def branches = ['develop', 'qa', 'pre-production'] | ||
| + | branches.each { branch -> | ||
| + | def branchWarningMessage = sh(script: """ | ||
| + | # Función para fusionar ramas | ||
| + | merge_branch() { | ||
| + | BRANCH=\$1 | ||
| + | |||
| + | if git ls-remote --exit-code --heads origin \$BRANCH >/dev/null 2>&1; then | ||
| + | echo "La rama \$BRANCH existe en el remoto. Haciendo pull y checkout..." | ||
| + | git fetch origin \$BRANCH:\$BRANCH | ||
| + | git checkout \$BRANCH | ||
| + | else | ||
| + | echo "La rama \$BRANCH no existe en el remoto. Creando una nueva rama basada en master..." | ||
| + | git checkout origin/master -b \$BRANCH | ||
| + | git push origin \$BRANCH | ||
| + | fi | ||
| + | |||
| + | CURRENT_VERSION=\$(jq -r '.version' package.json) | ||
| + | echo "La versión de \$BRANCH : \$CURRENT_VERSION" | ||
| + | |||
| + | git checkout master | ||
| + | MASTER_VERSION=\$(jq -r '.version' package.json) | ||
| + | echo "La versión de Master : \$MASTER_VERSION" | ||
| + | |||
| + | if dpkg --compare-versions "\$CURRENT_VERSION" "le" "\$MASTER_VERSION"; then | ||
| + | echo "La versión en la rama \$BRANCH es igual o menor que la versión en master. Realizando merge..." | ||
| + | git checkout \$BRANCH | ||
| + | git merge origin/master | ||
| + | git push origin \$BRANCH | ||
| + | else | ||
| + | echo "Advertencia: La versión en la rama \$BRANCH es superior a la versión en master. No se realizará el merge." | ||
| + | return 1 | ||
| + | fi | ||
| + | |||
| + | git checkout \$BRANCH | ||
| + | } | ||
| + | |||
| + | merge_branch ${branch} | ||
| + | """, returnStatus: true) | ||
| - | # Etiquetar la imagen con latest | + | if (branchWarningMessage != 0) { |
| + | echo "Agrego mensaje advertencia." | ||
| + | warningMessage += "Advertencia: La versión de la rama ${branch} es superior a la versión de master. No se realizará el merge en dicha rama.\n" | ||
| + | echo "Mostrar mensaje : (${warningMessage})" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | sh ''' | ||
| + | # Limpiar credenciales | ||
| + | rm .git-credentials | ||
| + | git config --unset credential.helper | ||
| + | ''' | ||
| + | |||
| + | if (warningMessage) { | ||
| + | echo "Warning : (${warningMessage})" | ||
| + | echo "Agrego mensaje advertencia 2." | ||
| + | def WAR_NAME = warningMessage | ||
| + | env.WARNING_MESSAGE = WAR_NAME | ||
| + | echo "Mostrar mensaje : ${env.WARNING_MESSAGE}" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| - | docker tag $REPOSITORY_NAME:$TAG_NAME $REPOSITORY_NAME:latest | + | } |
| + | |||
| + | post { | ||
| + | success { | ||
| + | script { | ||
| + | echo "Sending Slack notification for SUCCESS..." | ||
| + | def fullJobName = env.JOB_NAME.replaceAll('/', ' » ') | ||
| + | def buildStatus = currentBuild.result ?: 'UNKNOWN' | ||
| + | def buildDuration = currentBuild.durationString | ||
| + | def customMessage = "${fullJobName} - #${env.BUILD_NUMBER} ${buildStatus} after ${buildDuration} (${env.BUILD_URL})" | ||
| + | slackSend(channel: env.SLACK_CHANNEL, message: customMessage, color: 'good', tokenCredentialId: env.SLACK_CREDENTIALS) | ||
| + | if (env.WARNING_MESSAGE) { | ||
| + | slackSend(channel: env.SLACK_CHANNEL, message: env.WARNING_MESSAGE, color: 'warning', tokenCredentialId: env.SLACK_CREDENTIALS) | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | failure { | ||
| + | script { | ||
| + | echo "Sending Slack notification for FAILURE..." | ||
| + | def fullJobName = env.JOB_NAME.replaceAll('/', ' » ') | ||
| + | def buildStatus = currentBuild.result ?: 'UNKNOWN' | ||
| + | def buildDuration = currentBuild.durationString | ||
| + | def customMessage = "${fullJobName} - #${env.BUILD_NUMBER} ${buildStatus} after ${buildDuration} (${env.BUILD_URL})" | ||
| + | slackSend(channel: env.SLACK_CHANNEL, message: customMessage, color: 'danger', tokenCredentialId: env.SLACK_CREDENTIALS) | ||
| + | if (env.WARNING_MESSAGE) { | ||
| + | slackSend(channel: env.SLACK_CHANNEL, message: env.WARNING_MESSAGE, color: 'warning', tokenCredentialId: env.SLACK_CREDENTIALS) | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | unstable { | ||
| + | script { | ||
| + | echo "Sending Slack notification for UNSTABLE..." | ||
| + | def fullJobName = env.JOB_NAME.replaceAll('/', ' » ') | ||
| + | def buildStatus = currentBuild.result ?: 'UNKNOWN' | ||
| + | def buildDuration = currentBuild.durationString | ||
| + | def customMessage = "${fullJobName} - #${env.BUILD_NUMBER} ${buildStatus} after ${buildDuration} (${env.BUILD_URL})" | ||
| + | slackSend(channel: env.SLACK_CHANNEL, message: customMessage, color: 'warning', tokenCredentialId: env.SLACK_CREDENTIALS) | ||
| + | if (env.WARNING_MESSAGE) { | ||
| + | slackSend(channel: env.SLACK_CHANNEL, message: env.WARNING_MESSAGE, color: 'warning', tokenCredentialId: env.SLACK_CREDENTIALS) | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | aborted { | ||
| + | script { | ||
| + | echo "Sending Slack notification for ABORTED..." | ||
| + | def fullJobName = env.JOB_NAME.replaceAll('/', ' » ') | ||
| + | def buildStatus = currentBuild.result ?: 'UNKNOWN' | ||
| + | def buildDuration = currentBuild.durationString | ||
| + | def customMessage = "${fullJobName} - #${env.BUILD_NUMBER} ${buildStatus} after ${buildDuration} (${env.BUILD_URL})" | ||
| + | slackSend(channel: env.SLACK_CHANNEL, message: customMessage, color: '#439FE0', tokenCredentialId: env.SLACK_CREDENTIALS) | ||
| + | if (env.WARNING_MESSAGE) { | ||
| + | slackSend(channel: env.SLACK_CHANNEL, message: env.WARNING_MESSAGE, color: 'warning', tokenCredentialId: env.SLACK_CREDENTIALS) | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| - | # Empujar la imagen con la etiqueta latest a Docker Hub | ||
| - | docker push $REPOSITORY_NAME:$TAG_NAME | + | </code> |
| - | docker push $REPOSITORY_NAME:latest | + | |
| - | if [ "$(docker ps -aq -f name=$CONTAINER_NAME)" ]; then | + | Activar esta configuración en el pipeline |
| - | docker stop $CONTAINER_NAME | + | {{:ada:howto:sicoferp:factory:new-migracion-sicoferp:front:opcion.png?800|}} |
| - | docker rm -fv $CONTAINER_NAME | + | |
| - | fi | + | |
| - | # Ejecutar el nuevo contenedor con la imagen "latest" | ||
| - | docker run -d -p 8095:80 --name $CONTAINER_NAME $REPOSITORY_NAME:latest | + | **5.6 Una vez configurado** |
| + | Probar el pipeline si funciona correctamente, replicar los webhook para cada ambiente. | ||