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:28] 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. | ||