Add: Multiple auto-deploy solutions for OpenShift after GitHub Actions

This commit is contained in:
2025-09-25 18:40:31 -03:00
parent 6f6e4ed19d
commit e95f3e3f7c
4 changed files with 662 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
name: Deploy to OpenShift (Manual Trigger)
on:
workflow_dispatch:
inputs:
openshift_server:
description: 'OpenShift Server URL'
required: true
default: 'https://api.your-cluster.com'
openshift_token:
description: 'OpenShift Token'
required: true
type: string
namespace:
description: 'Target Namespace'
required: true
default: 'resource-governance'
image_tag:
description: 'Image Tag to Deploy'
required: false
default: 'latest'
env:
IMAGE_NAME: resource-governance
REGISTRY: andersonid
jobs:
deploy-to-openshift:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install OpenShift CLI
run: |
curl -L https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/linux/oc.tar.gz | tar -xz -C /usr/local/bin/
chmod +x /usr/local/bin/oc
- name: Login to OpenShift
run: |
oc login ${{ inputs.openshift_server }} --token="${{ inputs.openshift_token }}" --insecure-skip-tls-verify=true
- name: Deploy to OpenShift
run: |
# Usar tag fornecida ou latest
IMAGE_TAG="${{ inputs.image_tag }}"
if [ "$IMAGE_TAG" = "latest" ]; then
# Para latest, usar o commit SHA atual
IMAGE_TAG="${{ github.sha }}"
fi
echo "🚀 Deploying image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$IMAGE_TAG"
echo "📦 Target namespace: ${{ inputs.namespace }}"
# Verificar se o namespace existe
if ! oc get namespace ${{ inputs.namespace }} > /dev/null 2>&1; then
echo "📋 Creating namespace ${{ inputs.namespace }}..."
oc create namespace ${{ inputs.namespace }}
fi
# Aplicar manifests básicos
oc apply -f k8s/rbac.yaml -n ${{ inputs.namespace }}
oc apply -f k8s/configmap.yaml -n ${{ inputs.namespace }}
# Atualizar deployment com nova imagem
oc set image deployment/${{ env.IMAGE_NAME }} ${{ env.IMAGE_NAME }}=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$IMAGE_TAG -n ${{ inputs.namespace }} || true
# Aplicar deployment, service e route
oc apply -f k8s/deployment.yaml -n ${{ inputs.namespace }}
oc apply -f k8s/service.yaml -n ${{ inputs.namespace }}
oc apply -f k8s/route.yaml -n ${{ inputs.namespace }}
# Aguardar rollout
echo "⏳ Waiting for rollout..."
oc rollout status deployment/${{ env.IMAGE_NAME }} -n ${{ inputs.namespace }} --timeout=300s
# Verificar status
echo "✅ Deployment completed!"
oc get deployment ${{ env.IMAGE_NAME }} -n ${{ inputs.namespace }}
oc get pods -n ${{ inputs.namespace }} -l app.kubernetes.io/name=${{ env.IMAGE_NAME }}
# Obter URL da rota
ROUTE_URL=$(oc get route ${{ env.IMAGE_NAME }}-route -n ${{ inputs.namespace }} -o jsonpath='{.spec.host}' 2>/dev/null || echo "")
if [ -n "$ROUTE_URL" ]; then
echo "🌐 Application URL: https://$ROUTE_URL"
fi

277
AUTO-DEPLOY-GUIDE.md Normal file
View File

@@ -0,0 +1,277 @@
# 🚀 Deploy Automático - Guia Completo
## 📋 Visão Geral
Este guia explica como configurar deploy automático após o GitHub Actions criar a imagem no Docker Hub.
## 🔍 **SITUAÇÃO ATUAL:**
### ✅ **GitHub Actions (Funcionando):**
- Builda a imagem automaticamente
- Faz push para Docker Hub
- **NÃO faz deploy no OpenShift**
### ❌ **OpenShift (Manual):**
- **NÃO detecta** mudanças na imagem automaticamente
- Precisa de **rollout manual**
- Blue-Green só funciona se configurado
## 🚀 **SOLUÇÕES PARA DEPLOY AUTOMÁTICO:**
### **Opção 1: Deploy Manual via GitHub Actions** ⭐ (Recomendado)
#### **Como usar:**
1. Vá para: `Actions``Deploy to OpenShift (Manual Trigger)`
2. Clique em `Run workflow`
3. Preencha os campos:
- **OpenShift Server URL**: `https://api.your-cluster.com`
- **OpenShift Token**: Seu token do OpenShift
- **Target Namespace**: `resource-governance`
- **Image Tag**: `latest` ou tag específica
4. Clique em `Run workflow`
#### **Vantagens:**
- ✅ Seguro (requer confirmação manual)
- ✅ Funciona com qualquer cluster OpenShift
- ✅ Controle total sobre quando fazer deploy
- ✅ Logs detalhados no GitHub Actions
---
### **Opção 2: Deploy Automático Local** 🔄
#### **Como usar:**
```bash
# Deploy automático com latest
./scripts/auto-deploy.sh
# Deploy automático com tag específica
./scripts/auto-deploy.sh v1.0.0
# Deploy automático com commit SHA
./scripts/auto-deploy.sh 6f6e4ed19d2fbcccba548eeaf0d9e2624f41afba
```
#### **Vantagens:**
- ✅ Deploy automático
- ✅ Verifica se a imagem existe no Docker Hub
- ✅ Blue-Green deployment (zero downtime)
- ✅ Logs detalhados
#### **Configuração:**
```bash
# 1. Fazer login no OpenShift
oc login https://api.your-cluster.com
# 2. Executar deploy automático
./scripts/auto-deploy.sh latest
```
---
### **Opção 3: Webhook para Deploy Automático** 🌐
#### **Como configurar:**
1. **Instalar dependências:**
```bash
pip install flask
```
2. **Configurar variáveis de ambiente:**
```bash
export IMAGE_NAME="resource-governance"
export REGISTRY="andersonid"
export NAMESPACE="resource-governance"
export AUTO_DEPLOY_SCRIPT="./scripts/auto-deploy.sh"
```
3. **Executar webhook server:**
```bash
python3 scripts/webhook-deploy.py
```
4. **Configurar webhook no Docker Hub:**
- Acesse: https://hub.docker.com/r/andersonid/resource-governance/webhooks
- Clique em `Create Webhook`
- **Webhook URL**: `http://your-server:8080/webhook/dockerhub`
- **Trigger**: `Push to repository`
- **Tag**: `latest`
#### **Endpoints disponíveis:**
- `POST /webhook/dockerhub` - Webhook do Docker Hub
- `POST /webhook/github` - Webhook do GitHub
- `POST /deploy/<tag>` - Deploy manual
- `GET /health` - Health check
- `GET /status` - Status do serviço
#### **Vantagens:**
- ✅ Deploy completamente automático
- ✅ Funciona com Docker Hub e GitHub
- ✅ API REST para controle
- ✅ Logs detalhados
---
### **Opção 4: Cron Job para Deploy Automático** ⏰
#### **Como configurar:**
1. **Criar script de verificação:**
```bash
#!/bin/bash
# scripts/check-and-deploy.sh
# Verificar se há nova imagem
LATEST_SHA=$(curl -s "https://api.github.com/repos/andersonid/openshift-resource-governance/commits/main" | jq -r '.sha')
CURRENT_SHA=$(oc get deployment resource-governance -n resource-governance -o jsonpath='{.spec.template.spec.containers[0].image}' | cut -d: -f2)
if [ "$LATEST_SHA" != "$CURRENT_SHA" ]; then
echo "Nova versão detectada: $LATEST_SHA"
./scripts/auto-deploy.sh $LATEST_SHA
else
echo "Versão já está atualizada: $CURRENT_SHA"
fi
```
2. **Configurar cron job:**
```bash
# Executar a cada 5 minutos
*/5 * * * * /path/to/scripts/check-and-deploy.sh >> /var/log/auto-deploy.log 2>&1
```
#### **Vantagens:**
- ✅ Deploy automático baseado em tempo
- ✅ Verifica mudanças automaticamente
- ✅ Simples de configurar
---
## 🔧 **CONFIGURAÇÃO DO BLUE-GREEN DEPLOYMENT:**
### **Estratégia Rolling Update (Zero Downtime):**
```yaml
# k8s/deployment.yaml
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0 # Nunca derruba pods até o novo estar pronto
maxSurge: 1 # Permite 1 pod extra durante o rollout
```
### **Health Checks:**
```yaml
# k8s/deployment.yaml
livenessProbe:
httpGet:
path: /api/v1/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /api/v1/health
port: 8080
initialDelaySeconds: 15
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 5
successThreshold: 2
```
---
## 📊 **MONITORAMENTO DO DEPLOY:**
### **Verificar Status:**
```bash
# Status do deployment
oc get deployment resource-governance -n resource-governance
# Status dos pods
oc get pods -n resource-governance -l app.kubernetes.io/name=resource-governance
# Logs do deployment
oc logs -f deployment/resource-governance -n resource-governance
# Histórico de rollouts
oc rollout history deployment/resource-governance -n resource-governance
```
### **Verificar Imagem Atual:**
```bash
# Imagem atual do deployment
oc get deployment resource-governance -n resource-governance -o jsonpath='{.spec.template.spec.containers[0].image}'
# Verificar se a imagem existe no Docker Hub
skopeo inspect docker://andersonid/resource-governance:latest
```
---
## 🚨 **TROUBLESHOOTING:**
### **Problemas Comuns:**
#### 1. **Deploy falha com "ImagePullBackOff"**
```bash
# Verificar se a imagem existe
skopeo inspect docker://andersonid/resource-governance:latest
# Verificar logs do pod
oc describe pod -l app.kubernetes.io/name=resource-governance -n resource-governance
```
#### 2. **Rollout fica travado**
```bash
# Verificar status do rollout
oc rollout status deployment/resource-governance -n resource-governance
# Forçar restart se necessário
oc rollout restart deployment/resource-governance -n resource-governance
```
#### 3. **Webhook não funciona**
```bash
# Verificar logs do webhook
python3 scripts/webhook-deploy.py
# Testar webhook manualmente
curl -X POST http://localhost:8080/deploy/latest
```
---
## 🎯 **RECOMENDAÇÕES:**
### **Para Desenvolvimento:**
- Use **Opção 1** (Deploy Manual via GitHub Actions)
- Controle total sobre quando fazer deploy
- Logs detalhados no GitHub
### **Para Produção:**
- Use **Opção 2** (Deploy Automático Local) com cron job
- Configure webhook para deploy automático
- Monitore logs e status
### **Para Equipes:**
- Use **Opção 3** (Webhook) com API REST
- Configure notificações
- Implemente rollback automático
---
## 🔗 **LINKS ÚTEIS:**
- **GitHub Actions**: https://github.com/andersonid/openshift-resource-governance/actions
- **Docker Hub**: https://hub.docker.com/r/andersonid/resource-governance
- **OpenShift CLI**: https://docs.openshift.com/container-platform/latest/cli_reference/openshift_cli/
---
**Desenvolvido por:** Anderson Nobre
**Suporte:** Abra uma issue no GitHub se tiver problemas

117
scripts/auto-deploy.sh Executable file
View File

@@ -0,0 +1,117 @@
#!/bin/bash
# Script para deploy automático após GitHub Actions
# Este script pode ser executado localmente ou via webhook
set -e
# Cores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configurações
IMAGE_NAME="resource-governance"
REGISTRY="andersonid"
NAMESPACE="resource-governance"
IMAGE_TAG=${1:-latest}
echo -e "${BLUE}🚀 Auto-Deploy para OpenShift${NC}"
echo "================================"
echo "Imagem: ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"
echo "Namespace: ${NAMESPACE}"
echo ""
# 1. Verificar login no OpenShift
if ! oc whoami > /dev/null 2>&1; then
echo -e "${RED}❌ Não logado no OpenShift. Por favor, faça login com 'oc login'.${NC}"
exit 1
fi
echo -e "${GREEN}✅ Logado no OpenShift como: $(oc whoami)${NC}"
echo ""
# 2. Verificar se a imagem existe no Docker Hub
echo -e "${BLUE}🔍 Verificando imagem no Docker Hub...${NC}"
if ! skopeo inspect docker://${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} > /dev/null 2>&1; then
echo -e "${RED}❌ Imagem ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} não encontrada no Docker Hub!${NC}"
exit 1
fi
echo -e "${GREEN}✅ Imagem encontrada no Docker Hub${NC}"
echo ""
# 3. Verificar se o namespace existe
if ! oc get namespace ${NAMESPACE} > /dev/null 2>&1; then
echo -e "${BLUE}📋 Criando namespace ${NAMESPACE}...${NC}"
oc create namespace ${NAMESPACE}
else
echo -e "${GREEN}✅ Namespace ${NAMESPACE} já existe${NC}"
fi
echo ""
# 4. Aplicar manifests básicos
echo -e "${BLUE}📋 Aplicando manifests básicos...${NC}"
oc apply -f k8s/rbac.yaml -n ${NAMESPACE}
oc apply -f k8s/configmap.yaml -n ${NAMESPACE}
echo ""
# 5. Verificar se o deployment existe
if oc get deployment ${IMAGE_NAME} -n ${NAMESPACE} > /dev/null 2>&1; then
echo -e "${BLUE}🔄 Deployment existente encontrado. Iniciando atualização...${NC}"
# Obter imagem atual
CURRENT_IMAGE=$(oc get deployment ${IMAGE_NAME} -n ${NAMESPACE} -o jsonpath='{.spec.template.spec.containers[0].image}')
echo "Imagem atual: ${CURRENT_IMAGE}"
echo "Nova imagem: ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"
# Verificar se a imagem mudou
if [ "${CURRENT_IMAGE}" = "${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}" ]; then
echo -e "${YELLOW}⚠️ Imagem já está atualizada. Nenhuma ação necessária.${NC}"
exit 0
fi
# Atualizar deployment com nova imagem
echo -e "${BLUE}🔄 Atualizando imagem do deployment...${NC}"
oc set image deployment/${IMAGE_NAME} ${IMAGE_NAME}=${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} -n ${NAMESPACE}
# Aguardar rollout
echo -e "${BLUE}⏳ Aguardando rollout (pode levar alguns minutos)...${NC}"
oc rollout status deployment/${IMAGE_NAME} -n ${NAMESPACE} --timeout=300s
echo -e "${GREEN}✅ Rollout concluído com sucesso!${NC}"
else
echo -e "${BLUE}📦 Deployment não encontrado. Criando novo deployment...${NC}"
# Aplicar deployment, service e route
oc apply -f k8s/deployment.yaml -n ${NAMESPACE}
oc apply -f k8s/service.yaml -n ${NAMESPACE}
oc apply -f k8s/route.yaml -n ${NAMESPACE}
# Aguardar rollout inicial
echo -e "${BLUE}⏳ Aguardando rollout inicial...${NC}"
oc rollout status deployment/${IMAGE_NAME} -n ${NAMESPACE} --timeout=300s
echo -e "${GREEN}✅ Rollout inicial concluído com sucesso!${NC}"
fi
echo ""
# 6. Verificar status final
echo -e "${BLUE}📊 STATUS FINAL:${NC}"
echo "================"
oc get deployment ${IMAGE_NAME} -n ${NAMESPACE}
echo ""
oc get pods -n ${NAMESPACE} -l app.kubernetes.io/name=${IMAGE_NAME}
echo ""
# 7. Obter URLs de acesso
ROUTE_URL=$(oc get route ${IMAGE_NAME}-route -n ${NAMESPACE} -o jsonpath='{.spec.host}' 2>/dev/null || echo "")
echo -e "${BLUE}🌐 URLs de acesso:${NC}"
if [ -n "$ROUTE_URL" ]; then
echo " OpenShift: https://$ROUTE_URL"
else
echo " OpenShift: Rota não encontrada ou não disponível."
fi
echo " Port-forward: http://localhost:8080 (se ativo)"
echo ""
echo -e "${GREEN}✅ Auto-deploy concluído com sucesso!${NC}"
echo -e "${BLUE}🔄 Estratégia: Rolling Update com maxUnavailable=0 (zero downtime)${NC}"

180
scripts/webhook-deploy.py Executable file
View File

@@ -0,0 +1,180 @@
#!/usr/bin/env python3
"""
Webhook para deploy automático após GitHub Actions
Este script pode ser executado como um serviço para detectar mudanças no Docker Hub
"""
import os
import json
import subprocess
import logging
from flask import Flask, request, jsonify
from datetime import datetime
# Configuração do logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = Flask(__name__)
# Configurações
IMAGE_NAME = os.getenv('IMAGE_NAME', 'resource-governance')
REGISTRY = os.getenv('REGISTRY', 'andersonid')
NAMESPACE = os.getenv('NAMESPACE', 'resource-governance')
SCRIPT_PATH = os.getenv('AUTO_DEPLOY_SCRIPT', './scripts/auto-deploy.sh')
@app.route('/webhook/dockerhub', methods=['POST'])
def dockerhub_webhook():
"""Webhook para receber notificações do Docker Hub"""
try:
data = request.get_json()
# Verificar se é uma notificação de push
if data.get('push_data', {}).get('tag') == 'latest':
logger.info(f"Recebida notificação de push para {REGISTRY}/{IMAGE_NAME}:latest")
# Executar deploy automático
result = run_auto_deploy('latest')
return jsonify({
'status': 'success',
'message': 'Deploy automático iniciado',
'result': result
}), 200
else:
logger.info(f"Push ignorado - tag: {data.get('push_data', {}).get('tag')}")
return jsonify({'status': 'ignored', 'message': 'Tag não é latest'}), 200
except Exception as e:
logger.error(f"Erro no webhook: {e}")
return jsonify({'status': 'error', 'message': str(e)}), 500
@app.route('/webhook/github', methods=['POST'])
def github_webhook():
"""Webhook para receber notificações do GitHub"""
try:
# Verificar se é um push para main
if request.headers.get('X-GitHub-Event') == 'push':
data = request.get_json()
if data.get('ref') == 'refs/heads/main':
logger.info("Recebida notificação de push para main branch")
# Executar deploy automático
result = run_auto_deploy('latest')
return jsonify({
'status': 'success',
'message': 'Deploy automático iniciado',
'result': result
}), 200
else:
logger.info(f"Push ignorado - branch: {data.get('ref')}")
return jsonify({'status': 'ignored', 'message': 'Branch não é main'}), 200
else:
logger.info(f"Evento ignorado: {request.headers.get('X-GitHub-Event')}")
return jsonify({'status': 'ignored', 'message': 'Evento não é push'}), 200
except Exception as e:
logger.error(f"Erro no webhook: {e}")
return jsonify({'status': 'error', 'message': str(e)}), 500
@app.route('/deploy/<tag>', methods=['POST'])
def manual_deploy(tag):
"""Deploy manual com tag específica"""
try:
logger.info(f"Deploy manual solicitado para tag: {tag}")
result = run_auto_deploy(tag)
return jsonify({
'status': 'success',
'message': f'Deploy manual iniciado para tag: {tag}',
'result': result
}), 200
except Exception as e:
logger.error(f"Erro no deploy manual: {e}")
return jsonify({'status': 'error', 'message': str(e)}), 500
def run_auto_deploy(tag):
"""Executar script de deploy automático"""
try:
logger.info(f"Executando deploy automático para tag: {tag}")
# Executar script de deploy
result = subprocess.run(
[SCRIPT_PATH, tag],
capture_output=True,
text=True,
timeout=600 # 10 minutos timeout
)
if result.returncode == 0:
logger.info("Deploy automático concluído com sucesso")
return {
'success': True,
'stdout': result.stdout,
'stderr': result.stderr
}
else:
logger.error(f"Deploy automático falhou: {result.stderr}")
return {
'success': False,
'stdout': result.stdout,
'stderr': result.stderr
}
except subprocess.TimeoutExpired:
logger.error("Deploy automático timeout")
return {
'success': False,
'error': 'Timeout'
}
except Exception as e:
logger.error(f"Erro ao executar deploy automático: {e}")
return {
'success': False,
'error': str(e)
}
@app.route('/health', methods=['GET'])
def health():
"""Health check"""
return jsonify({
'status': 'healthy',
'timestamp': datetime.now().isoformat(),
'image': f'{REGISTRY}/{IMAGE_NAME}',
'namespace': NAMESPACE
}), 200
@app.route('/status', methods=['GET'])
def status():
"""Status do serviço"""
try:
# Verificar se está logado no OpenShift
result = subprocess.run(['oc', 'whoami'], capture_output=True, text=True)
return jsonify({
'status': 'running',
'timestamp': datetime.now().isoformat(),
'openshift_user': result.stdout.strip() if result.returncode == 0 else 'Not logged in',
'image': f'{REGISTRY}/{IMAGE_NAME}',
'namespace': NAMESPACE,
'script_path': SCRIPT_PATH
}), 200
except Exception as e:
return jsonify({
'status': 'error',
'message': str(e)
}), 500
if __name__ == '__main__':
port = int(os.getenv('PORT', 8080))
debug = os.getenv('DEBUG', 'false').lower() == 'true'
logger.info(f"Iniciando webhook server na porta {port}")
logger.info(f"Configurações: IMAGE_NAME={IMAGE_NAME}, REGISTRY={REGISTRY}, NAMESPACE={NAMESPACE}")
app.run(host='0.0.0.0', port=port, debug=debug)