Skip to content
IRC-CodingIRC-Coding
Fundamentos Cloud ComputingIaaS PaaS SaaSAWS Azure GCPFunciones ServerlessLambda FunctionsCloud

Fundamentos Cloud Computing: IaaS, PaaS, SaaS

Aprende Cloud Computing con IaaS, PaaS, SaaS. Comparativa AWS, Azure, GCP y funciones Serverless con Lambda y ejemplos prácticos.

S

schutzgeist

27 min read
Fundamentos Cloud Computing: IaaS, PaaS, SaaS

Fundamentos de Cloud Computing: IaaS, PaaS, SaaS, AWS, Azure, GCP y Funciones Serverless

Este artículo es una introducción exhaustiva a los fundamentos de Cloud Computing, incluyendo modelos IaaS, PaaS y SaaS, comparativas de AWS, Azure y GCP, así como funciones Serverless con ejemplos prácticos.

En Resumen

Cloud Computing ofrece recursos de TI bajo demanda a través de Internet. IaaS proporciona control de infraestructura, PaaS simplifica el desarrollo, SaaS entrega aplicaciones listas para usar. Serverless elimina la gestión de servidores.

Descripción Técnica Concisa

Cloud Computing es la provisión de recursos de TI (capacidad de cómputo, almacenamiento, bases de datos) a través de Internet con un modelo de precios de pago por uso.

Modelos de servicios:

IaaS (Infrastructure as a Service)

  • Concepto: Recursos de infraestructura virtualizados
  • Recursos: VMs, almacenamiento, redes
  • Responsabilidad: Sistemas operativos, middleware, aplicaciones
  • Ejemplos: AWS EC2, Azure VMs, Google Compute Engine
  • Ventajas: Flexibilidad máxima, control total

PaaS (Platform as a Service)

  • Concepto: Plataforma de desarrollo e implementación
  • Recursos: Runtime, bases de datos, herramientas de desarrollo
  • Responsabilidad: Aplicaciones, datos
  • Ejemplos: AWS Elastic Beanstalk, Azure App Service, Google App Engine
  • Ventajas: Desarrollo simplificado, escalado automático

SaaS (Software as a Service)

  • Concepto: Aplicaciones de software listas para usar
  • Recursos: Aplicación completa
  • Responsabilidad: Solo uso y configuración
  • Ejemplos: Office 365, Salesforce, Gmail
  • Ventajas: Sin instalación, disponible inmediatamente

Cloud Computing Serverless

  • Concepto: Ejecución de código basada en eventos
  • Recursos: Funciones, disparadores, APIs
  • Responsabilidad: Solo código y configuración
  • Ejemplos: AWS Lambda, Azure Functions, Google Cloud Functions
  • Ventajas: Sin gestión de servidores, pago por uso

Puntos Clave Para Evaluación

  • Cloud Computing: Recursos de TI bajo demanda a través de Internet
  • IaaS: Infrastructure as Service, infraestructura virtualizada
  • PaaS: Platform as Service, plataforma de desarrollo
  • SaaS: Software as Service, aplicaciones listas para usar
  • Serverless: Ejecución de código basada en eventos sin gestión de servidores
  • AWS: Amazon Web Services, plataforma cloud líder
  • Azure: Cloud de Microsoft, enfocada en empresas
  • GCP: Google Cloud Platform, especializada en datos e IA
  • Relevancia IHK: Infraestructura TI moderna y estrategias de implementación

Componentes Principales

  1. Modelos de servicios: IaaS, PaaS, SaaS, Serverless
  2. Proveedores cloud: AWS, Azure, GCP
  3. Servicios de cómputo: VMs, contenedores, funciones
  4. Servicios de almacenamiento: Object, bloque, almacenamiento de archivos
  5. Servicios de red: VPC, balanceador de carga, CDN
  6. Servicios de bases de datos: SQL, NoSQL, caché
  7. Seguridad: IAM, encriptación, cumplimiento normativo
  8. Monitoreo: Logging, métricas, alertas

Ejemplos Prácticos

1. Función AWS Lambda Serverless con Python

import json
import boto3
import os
import logging
from datetime import datetime

# Logger konfigurieren
logger = logging.getLogger()
logger.setLevel(logging.INFO)

# AWS Clients
dynamodb = boto3.resource('dynamodb')
s3_client = boto3.client('s3')
sns_client = boto3.client('sns')

# Environment Variables
TABLE_NAME = os.environ.get('TABLE_NAME', 'users')
BUCKET_NAME = os.environ.get('BUCKET_NAME', 'user-uploads')
SNS_TOPIC_ARN = os.environ.get('SNS_TOPIC_ARN')

# DynamoDB Table
table = dynamodb.Table(TABLE_NAME)

def lambda_handler(event, context):
    """
    Lambda Handler für User-Management
    Unterstützt verschiedene Event-Typen:
    - API Gateway: User CRUD Operationen
    - S3: File Upload Verarbeitung
    - DynamoDB Streams: Daten-Änderungen
    """
    
    try:
        # Event-Typ bestimmen
        event_source = event.get('Records', [{}])[0].get('eventSource', '')
        
        if 'aws:apigateway' in event_source or 'httpMethod' in event:
            return handle_api_gateway_event(event)
        elif 'aws:s3' in event_source:
            return handle_s3_event(event)
        elif 'aws:dynamodb' in event_source:
            return handle_dynamodb_event(event)
        else:
            return handle_direct_event(event)
            
    except Exception as e:
        logger.error(f"Error processing event: {str(e)}")
        return create_response(500, {'error': str(e)})

def handle_api_gateway_event(event):
    """API Gateway Events verarbeiten"""
    http_method = event.get('httpMethod', '')
    path = event.get('path', '')
    
    logger.info(f"API Gateway Event: {http_method} {path}")
    
    if http_method == 'GET' and path == '/users':
        return get_all_users()
    elif http_method == 'GET' and path.startswith('/users/'):
        user_id = path.split('/')[-1]
        return get_user(user_id)
    elif http_method == 'POST' and path == '/users':
        return create_user(json.loads(event.get('body', '{}')))
    elif http_method == 'PUT' and path.startswith('/users/'):
        user_id = path.split('/')[-1]
        return update_user(user_id, json.loads(event.get('body', '{}')))
    elif http_method == 'DELETE' and path.startswith('/users/'):
        user_id = path.split('/')[-1]
        return delete_user(user_id)
    else:
        return create_response(404, {'error': 'Endpoint not found'})

def handle_s3_event(event):
    """S3 Events verarbeiten (File Upload)"""
    for record in event.get('Records', []):
        bucket = record['s3']['bucket']['name']
        key = record['s3']['object']['key']
        size = record['s3']['object']['size']
        
        logger.info(f"S3 Event: {bucket}/{key} ({size} bytes)")
        
        try:
            # File-Informationen speichern
            file_info = {
                'bucket': bucket,
                'key': key,
                'size': size,
                'upload_time': datetime.utcnow().isoformat(),
                'processed': False
            }
            
            # Metadaten aus S3 holen
            response = s3_client.head_object(Bucket=bucket, Key=key)
            file_info.update({
                'content_type': response.get('ContentType', ''),
                'metadata': response.get('Metadata', {})
            })
            
            # File-Informationen in DynamoDB speichern
            table.put_item(
                Item={
                    'PK': f'FILE#{key}',
                    'SK': 'METADATA',
                    **file_info
                }
            )
            
            # Benachrichtigung senden
            if SNS_TOPIC_ARN:
                send_notification(f"New file uploaded: {key}", file_info)
            
            logger.info(f"Successfully processed S3 event for {key}")
            
        except Exception as e:
            logger.error(f"Error processing S3 event for {key}: {str(e)}")
    
    return create_response(200, {'message': 'S3 event processed'})

def handle_dynamodb_event(event):
    """DynamoDB Streams verarbeiten"""
    for record in event.get('Records', []):
        event_name = record['eventName']
        
        if event_name == 'INSERT':
            new_image = record['dynamodb']['NewImage']
            handle_user_insert(new_image)
        elif event_name == 'MODIFY':
            old_image = record['dynamodb']['OldImage']
            new_image = record['dynamodb']['NewImage']
            handle_user_update(old_image, new_image)
        elif event_name == 'REMOVE':
            old_image = record['dynamodb']['OldImage']
            handle_user_delete(old_image)
    
    return create_response(200, {'message': 'DynamoDB event processed'})

def get_all_users():
    """Alle Benutzer abrufen"""
    try:
        response = table.scan(
            FilterExpression="begins_with(PK, :pk)",
            ExpressionAttributeValues={':pk': 'USER#'}
        )
        
        users = []
        for item in response.get('Items', []):
            users.append({
                'id': item.get('SK'),
                'username': item.get('username'),
                'email': item.get('email'),
                'created_at': item.get('created_at')
            })
        
        return create_response(200, {'users': users})
        
    except Exception as e:
        logger.error(f"Error getting users: {str(e)}")
        return create_response(500, {'error': str(e)})

def get_user(user_id):
    """Einen Benutzer abrufen"""
    try:
        response = table.get_item(
            Key={
                'PK': f'USER#{user_id}',
                'SK': 'PROFILE'
            }
        )
        
        if 'Item' in response:
            user = response['Item']
            return create_response(200, {'user': user})
        else:
            return create_response(404, {'error': 'User not found'})
            
    except Exception as e:
        logger.error(f"Error getting user {user_id}: {str(e)}")
        return create_response(500, {'error': str(e)})

def create_user(user_data):
    """Neuen Benutzer erstellen"""
    try:
        user_id = str(int(datetime.utcnow().timestamp() * 1000))
        
        user_item = {
            'PK': f'USER#{user_id}',
            'SK': 'PROFILE',
            'user_id': user_id,
            'username': user_data.get('username'),
            'email': user_data.get('email'),
            'created_at': datetime.utcnow().isoformat(),
            'status': 'active'
        }
        
        # Validierung
        if not user_data.get('username') or not user_data.get('email'):
            return create_response(400, {'error': 'Username and email are required'})
        
        # Benutzer speichern
        table.put_item(Item=user_item)
        
        # Benachrichtigung senden
        if SNS_TOPIC_ARN:
            send_notification(f"New user created: {user_data.get('username')}", user_item)
        
        logger.info(f"Created user: {user_id}")
        
        return create_response(201, {'user': user_item})
        
    except Exception as e:
        logger.error(f"Error creating user: {str(e)}")
        return create_response(500, {'error': str(e)})

def update_user(user_id, user_data):
    """Benutzer aktualisieren"""
    try:
        # Prüfen ob Benutzer existiert
        response = table.get_item(
            Key={
                'PK': f'USER#{user_id}',
                'SK': 'PROFILE'
            }
        )
        
        if 'Item' not in response:
            return create_response(404, {'error': 'User not found'})
        
        # Update-Expression erstellen
        update_expression = "SET "
        expression_values = {}
        expression_names = {}
        
        if 'username' in user_data:
            update_expression += "#username = :username, "
            expression_values[':username'] = user_data['username']
            expression_names['#username'] = 'username'
        
        if 'email' in user_data:
            update_expression += "email = :email, "
            expression_values[':email'] = user_data['email']
        
        if 'status' in user_data:
            update_expression += "status = :status, "
            expression_values[':status'] = user_data['status']
        
        update_expression += "updated_at = :updated_at"
        expression_values[':updated_at'] = datetime.utcnow().isoformat()
        
        # Update ausführen
        table.update_item(
            Key={
                'PK': f'USER#{user_id}',
                'SK': 'PROFILE'
            },
            UpdateExpression=update_expression,
            ExpressionAttributeValues=expression_values,
            ExpressionAttributeNames=expression_names if expression_names else None
        )
        
        logger.info(f"Updated user: {user_id}")
        
        return create_response(200, {'message': 'User updated successfully'})
        
    except Exception as e:
        logger.error(f"Error updating user {user_id}: {str(e)}")
        return create_response(500, {'error': str(e)})

def delete_user(user_id):
    """Benutzer löschen"""
    try:
        # Prüfen ob Benutzer existiert
        response = table.get_item(
            Key={
                'PK': f'USER#{user_id}',
                'SK': 'PROFILE'
            }
        )
        
        if 'Item' not in response:
            return create_response(404, {'error': 'User not found'})
        
        # Benutzer löschen
        table.delete_item(
            Key={
                'PK': f'USER#{user_id}',
                'SK': 'PROFILE'
            }
        )
        
        logger.info(f"Deleted user: {user_id}")
        
        return create_response(200, {'message': 'User deleted successfully'})
        
    except Exception as e:
        logger.error(f"Error deleting user {user_id}: {str(e)}")
        return create_response(500, {'error': str(e)})

def handle_user_insert(new_image):
    """User Insert Event verarbeiten"""
    user_id = new_image.get('user_id', {}).get('S')
    username = new_image.get('username', {}).get('S')
    
    logger.info(f"User inserted: {user_id} ({username})")
    
    # Zusätzliche Logik für neue Benutzer
    # z.B. Willkommens-E-Mail senden, Default-Einstellungen erstellen

def handle_user_update(old_image, new_image):
    """User Update Event verarbeiten"""
    user_id = new_image.get('user_id', {}).get('S')
    
    logger.info(f"User updated: {user_id}")
    
    # Änderungen protokollieren
    changes = {}
    for key in new_image:
        if key in old_image and new_image[key] != old_image[key]:
            changes[key] = {
                'old': old_image[key],
                'new': new_image[key]
            }
    
    if changes:
        logger.info(f"User {user_id} changes: {changes}")

def handle_user_delete(old_image):
    """User Delete Event verarbeiten"""
    user_id = old_image.get('user_id', {}).get('S')
    username = old_image.get('username', {}).get('S')
    
    logger.info(f"User deleted: {user_id} ({username})")
    
    # Aufräumarbeiten durchführen
    # z.B. zugehörige Daten löschen

def send_notification(message, data):
    """SNS Benachrichtigung senden"""
    try:
        sns_client.publish(
            TopicArn=SNS_TOPIC_ARN,
            Subject=message,
            Message=json.dumps(data, default=str)
        )
        logger.info(f"Notification sent: {message}")
    except Exception as e:
        logger.error(f"Error sending notification: {str(e)}")

def create_response(status_code, body):
    """HTTP Response erstellen"""
    return {
        'statusCode': status_code,
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Headers': 'Content-Type',
            'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS'
        },
        'body': json.dumps(body, default=str)
    }

def handle_direct_event(event):
    """Direkte Events (z.B. Scheduled Events)"""
    event_source = event.get('source', '')
    
    if event_source == 'aws.events':
        # Scheduled Event (z.B. tägliche Bereinigung)
        return handle_scheduled_event(event)
    else:
        return create_response(400, {'error': 'Unknown event type'})

def handle_scheduled_event(event):
    """Scheduled Events verarbeiten"""
    logger.info("Processing scheduled event")
    
    # Tägliche Bereinigungsaufgaben
    # z.B. inaktive Benutzer deaktivieren, alte Logs löschen
    
    return create_response(200, {'message': 'Scheduled event processed'})

2. Azure Functions con C#

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Azure.Data.Tables;
using Azure.Storage.Blobs;
using Azure.Storage.Queues;
using Azure.Communication.Email;

public class CloudFunctions
{
    private readonly string _connectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
    private readonly string _tableName = Environment.GetEnvironmentVariable("TableName") ?? "users";
    private readonly string _containerName = Environment.GetEnvironmentVariable("ContainerName") ?? "uploads";

    // HTTP Trigger Function
    [FunctionName("ProcessUser")]
    public async Task<IActionResult> ProcessUser(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = "users")] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a user request.");

        try
        {
            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);

            // Validación
            if (data?.name == null || data?.email == null)
            {
                return new BadRequestObjectResult(new { error = "Name and email are required" });
            }

            // Table Storage Client
            var tableClient = new TableClient(_connectionString, _tableName);
            await tableClient.CreateIfNotExistsAsync();

            // Crear entidad de usuario
            var user = new TableEntity("User", Guid.NewGuid().ToString())
            {
                { "Name", data.name },
                { "Email", data.email },
                { "CreatedAt", DateTime.UtcNow },
                { "Status", "Active" }
            };

            // Guardar en Table Storage
            await tableClient.UpsertEntityAsync(user);

            // Enviar mensaje a la cola para procesamiento adicional
            var queueClient = new QueueClient(_connectionString, "user-processing");
            await queueClient.CreateIfNotExistsAsync();
            await queueClient.SendMessageAsync(JsonConvert.SerializeObject(new { 
                Action = "UserCreated", 
                UserId = user.RowKey,
                Email = data.email 
            }));

            log.LogInformation($"User {user.RowKey} created successfully");

            return new OkObjectResult(new { 
                message = "User created successfully",
                userId = user.RowKey
            });
        }
        catch (Exception ex)
        {
            log.LogError($"Error processing user: {ex.Message}");
            return new StatusCodeResult(500);
        }
    }

    // Blob Trigger Function
    [FunctionName("ProcessImageUpload")]
    public async Task ProcessImageUpload(
        [BlobTrigger("uploads/{name}", Connection = "AzureWebJobsStorage")] Stream myBlob,
        string name,
        ILogger log)
    {
        log.LogInformation($"C# Blob trigger function ProcessImageUpload processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");

        try
        {
            // Procesar imagen (por ejemplo, crear miniatura)
            if (name.ToLower().EndsWith(".jpg") || name.ToLower().EndsWith(".png"))
            {
                var blobServiceClient = new BlobServiceClient(_connectionString);
                var containerClient = blobServiceClient.GetBlobContainerClient(_containerName);
                
                // Crear miniatura (versión simplificada)
                var thumbnailBlobClient = containerClient.GetBlobClient($"thumbnails/{name}");
                await thumbnailBlobClient.UploadAsync(myBlob, overwrite: true);

                // Guardar metadatos en Table Storage
                var tableClient = new TableClient(_connectionString, "imageMetadata");
                await tableClient.CreateIfNotExistsAsync();

                var metadata = new TableEntity("Image", name)
                {
                    { "OriginalSize", myBlob.Length },
                    { "ProcessedAt", DateTime.UtcNow },
                    { "ThumbnailPath", $"thumbnails/{name}" },
                    { "Status", "Processed" }
                };

                await tableClient.UpsertEntityAsync(metadata);

                log.LogInformation($"Image {name} processed successfully");
            }
        }
        catch (Exception ex)
        {
            log.LogError($"Error processing image {name}: {ex.Message}");
            throw;
        }
    }

    // Queue Trigger Function
    [FunctionName("ProcessUserQueue")]
    public async Task ProcessUserQueue(
        [QueueTrigger("user-processing", Connection = "AzureWebJobsStorage")] string queueMessage,
        ILogger log)
    {
        log.LogInformation($"C# Queue trigger function processed: {queueMessage}");

        try
        {
            dynamic message = JsonConvert.DeserializeObject(queueMessage);
            string action = message.Action;
            string userId = message.UserId;
            string email = message.Email;

            if (action == "UserCreated")
            {
                // Enviar correo de bienvenida
                await SendWelcomeEmail(email, log);
                
                // Registrar usuario en sistemas externos
                await RegisterUserInExternalSystems(userId, email, log);
            }

            log.LogInformation($"Queue message processed for user {userId}");
        }
        catch (Exception ex)
        {
            log.LogError($"Error processing queue message: {ex.Message}");
            throw;
        }
    }

    // Timer Trigger Function
    [FunctionName("CleanupTask")]
    public async Task CleanupTask(
        [TimerTrigger("0 0 2 * * *")] TimerInfo myTimer,  // Diariamente a las 2 de la madrugada
        ILogger log)
    {
        log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

        try
        {
            // Limpiar archivos temporales antiguos
            await CleanupTempFiles(log);
            
            // Desactivar usuarios inactivos
            await DeactivateInactiveUsers(log);
            
            // Actualizar estadísticas
            await UpdateStatistics(log);

            log.LogInformation("Cleanup task completed successfully");
        }
        catch (Exception ex)
        {
            log.LogError($"Error in cleanup task: {ex.Message}");
        }
    }

    // Event Grid Trigger Function
    [FunctionName("HandleResourceEvent")]
    public async Task HandleResourceEvent(
        [EventGridTrigger] EventGridEvent eventGridEvent,
        ILogger log)
    {
        log.LogInformation($"C# Event Grid trigger function processed event: {eventGridEvent.EventType}");

        try
        {
            dynamic data = eventGridEvent.Data;
            string resourceType = data.resourceType;
            string resourceName = data.resourceName;

            if (resourceType == "Microsoft.Storage/storageAccounts/blobServices")
            {
                // Procesar evento de blob
                log.LogInformation($"Blob event: {resourceName}");
            }
            else if (resourceType == "Microsoft.Sql/servers/databases")
            {
                // Procesar evento de SQL
                log.LogInformation($"SQL event: {resourceName}");
            }

            log.LogInformation($"Event processed: {eventGridEvent.EventType}");
        }
        catch (Exception ex)
        {
            log.LogError($"Error processing event: {ex.Message}");
        }
    }

    // Service Bus Trigger Function
    [FunctionName("ProcessOrder")]
    public async Task ProcessOrder(
        [ServiceBusTrigger("orders", Connection = "ServiceBusConnection")] string orderMessage,
        ILogger log)
    {
        log.LogInformation($"C# Service Bus trigger function processed message: {orderMessage}");

        try
        {
            dynamic order = JsonConvert.DeserializeObject(orderMessage);
            string orderId = order.OrderId;
            string customerId = order.CustomerId;
            decimal amount = order.Amount;

            // Procesar pedido
            await ProcessOrderInDatabase(orderId, customerId, amount, log);
            
            // Enviar confirmación
            await SendOrderConfirmation(customerId, orderId, amount, log);
            
            // Actualizar inventario
            await UpdateInventory(order, log);

            log.LogInformation($"Order {orderId} processed successfully");
        }
        catch (Exception ex)
        {
            log.LogError($"Error processing order: {ex.Message}");
            throw;
        }
    }

    // Métodos auxiliares
    private async Task SendWelcomeEmail(string email, ILogger log)
    {
        try
        {
            // Azure Communication Services para correo electrónico
            var connectionString = Environment.GetEnvironmentVariable("CommunicationServicesConnectionString");
            var emailClient = new EmailClient(connectionString);

            var emailMessage = new EmailMessage(
                "DoNotReply@yourdomain.com",
                email,
                "Welcome to our service!",
                "Thank you for registering. We're excited to have you on board!"
            );

            await emailClient.SendAsync(emailMessage);
            log.LogInformation($"Welcome email sent to {email}");
        }
        catch (Exception ex)
        {
            log.LogError($"Error sending welcome email: {ex.Message}");
        }
    }

    private async Task RegisterUserInExternalSystems(string userId, string email, ILogger log)
    {
        // Registrar en sistema CRM
        log.LogInformation($"Registering user {userId} in CRM system");
        
        // Añadir a sistema de boletín
        log.LogInformation($"Adding user {userId} to newsletter system");
        
        // Inicializar seguimiento de análisis
        log.LogInformation($"Initializing analytics for user {userId}");
    }

    private async Task CleanupTempFiles(ILogger log)
    {
        var blobServiceClient = new BlobServiceClient(_connectionString);
        var containerClient = blobServiceClient.GetBlobContainerClient("temp");
        
        await foreach (var blobItem in containerClient.GetBlobsAsync())
        {
            if (blobItem.Properties.LastModified < DateTime.UtcNow.AddDays(-1))
            {
                await containerClient.DeleteBlobAsync(blobItem.Name);
                log.LogInformation($"Deleted temp file: {blobItem.Name}");
            }
        }
    }

    private async Task DeactivateInactiveUsers(ILogger log)
    {
        var tableClient = new TableClient(_connectionString, _tableName);
        
        await foreach (var user in tableClient.QueryAsync<TableEntity>(filter: $"Status eq 'Active'"))
        {
            var lastLogin = user.GetDateTime("LastLogin") ?? user.GetDateTime("CreatedAt");
            
            if (lastLogin < DateTime.UtcNow.AddDays(-90))
            {
                user["Status"] = "Inactive";
                await tableClient.UpdateEntityAsync(user);
                log.LogInformation($"Deactivated inactive user: {user.RowKey}");
            }
        }
    }

    private async Task UpdateStatistics(ILogger log)
    {
        // Actualizar estadísticas en tabla separada
        var statsTable = new TableClient(_connectionString, "statistics");
        await statsTable.CreateIfNotExistsAsync();
        
        var stats = new TableEntity("Daily", DateTime.UtcNow.ToString("yyyy-MM-dd"))
        {
            { "ActiveUsers", await GetActiveUserCount() },
            { "TotalUsers", await GetTotalUserCount() },
            { "ProcessedImages", await GetProcessedImageCount() },
            { "UpdatedAt", DateTime.UtcNow }
        };
        
        await statsTable.UpsertEntityAsync(stats);
        log.LogInformation("Daily statistics updated");
    }

    private async Task<int> GetActiveUserCount()
    {
        // Implementación del conteo de usuarios activos
        return 0;
    }

    private async Task<int> GetTotalUserCount()
    {
        // Implementación del conteo total de usuarios
        return 0;
    }

    private async Task<int> GetProcessedImageCount()
    {
        // Implementación del conteo de imágenes procesadas
        return 0;
    }

    private async Task ProcessOrderInDatabase(string orderId, string customerId, decimal amount, ILogger log)
    {
        // Guardar pedido en base de datos
        log.LogInformation($"Processing order {orderId} for customer {customerId}");
    }

    private async Task SendOrderConfirmation(string customerId, string orderId, decimal amount, ILogger log)
    {
        // Enviar confirmación de pedido
        log.LogInformation($"Sending order confirmation for {orderId}");
    }

    private async Task UpdateInventory(dynamic order, ILogger log)
    {
        // Actualizar existencias
        log.LogInformation($"Updating inventory for order {order.OrderId}");
    }
}

// Entidad de tabla para usuarios
public class UserEntity : ITableEntity
{
    public string PartitionKey { get; set; }
    public string RowKey { get; set; }
    public DateTimeOffset? Timestamp { get; set; }
    public ETag ETag { get; set; }

    public string Name { get; set; }
    public string Email { get; set; }
    public DateTime CreatedAt { get; set; }
    public string Status { get; set; }
    public DateTime? LastLogin { get; set; }
}

3. Google Cloud Functions con JavaScript

const { Storage } = require('@google-cloud/storage');
const { PubSub } = require('@google-cloud/pubsub');
const { Datastore } = require('@google-cloud/datastore');
const { Firestore } = require('@google-cloud/firestore');
const { Logging } = require('@google-cloud/logging');

// Cloud Clients initialisieren
const storage = new Storage();
const pubsub = new PubSub();
const datastore = new Datastore();
const firestore = new Firestore();
const logging = new Logging();

// Logger
const logger = logging.log('cloud-functions');

/**
 * HTTP Trigger Function - User Management
 * @param {Object} req Express request object.
 * @param {Object} res Express response object.
 */
exports.userManagement = async (req, res) => {
    const method = req.method;
    const path = req.path;
    
    logger.info(`HTTP Request: ${method} ${path}`);
    
    try {
        if (method === 'GET' && path === '/users') {
            return await getAllUsers(req, res);
        } else if (method === 'GET' && path.startsWith('/users/')) {
            const userId = path.split('/')[2];
            return await getUser(userId, req, res);
        } else if (method === 'POST' && path === '/users') {
            return await createUser(req, res);
        } else if (method === 'PUT' && path.startsWith('/users/')) {
            const userId = path.split('/')[2];
            return await updateUser(userId, req, res);
        } else if (method === 'DELETE' && path.startsWith('/users/')) {
            const userId = path.split('/')[2];
            return await deleteUser(userId, req, res);
        } else {
            return res.status(404).json({ error: 'Endpoint not found' });
        }
    } catch (error) {
        logger.error(`Error in userManagement: ${error.message}`);
        return res.status(500).json({ error: error.message });
    }
};

/**
 * Cloud Storage Trigger - File Upload Processing
 * @param {Object} file The storage object.
 * @param {Object} context The event metadata.
 */
exports.processFileUpload = async (file, context) => {
    const bucketName = file.bucket;
    const fileName = file.name;
    const fileSize = file.size;
    const contentType = file.contentType;
    
    logger.info(`Processing file upload: ${bucketName}/${fileName} (${fileSize} bytes)`);
    
    try {
        // Metadaten extrahieren
        const [metadata] = await storage.bucket(bucketName).file(fileName).getMetadata();
        
        // File-Informationen in Firestore speichern
        const fileDoc = {
            bucketName,
            fileName,
            fileSize,
            contentType,
            uploadedAt: new Date(),
            metadata: metadata.metadata || {},
            processed: false
        };
        
        await firestore.collection('files').doc(fileName).set(fileDoc);
        
        // Bildverarbeitung bei Bildern
        if (contentType && contentType.startsWith('image/')) {
            await processImage(bucketName, fileName);
        }
        
        // Pub/Sub Nachricht für weitere Verarbeitung
        const dataBuffer = Buffer.from(JSON.stringify({
            action: 'file_uploaded',
            fileName,
            bucketName,
            fileSize
        }));
        
        await pubsub.topic('file-processing').publish(dataBuffer);
        
        logger.info(`File ${fileName} processed successfully`);
        
    } catch (error) {
        logger.error(`Error processing file ${fileName}: ${error.message}`);
        throw error;
    }
};

/**
 * Pub/Sub Trigger - Asynchronous Processing
 * @param {Object} message The Pub/Sub message object.
 * @param {Object} context The event metadata.
 */
exports.processAsyncTask = async (message, context) => {
    const data = JSON.parse(Buffer.from(message.data, 'base64').toString());
    const action = data.action;
    
    logger.info(`Processing async task: ${action}`);
    
    try {
        switch (action) {
            case 'file_uploaded':
                await handleFileUploaded(data);
                break;
            case 'user_created':
                await handleUserCreated(data);
                break;
            case 'order_placed':
                await handleOrderPlaced(data);
                break;
            default:
                logger.warn(`Unknown action: ${action}`);
        }
        
        logger.info(`Async task ${action} completed successfully`);
        
    } catch (error) {
        logger.error(`Error processing async task ${action}: ${error.message}`);
        throw error;
    }
};

/**
 * Firestore Trigger - Database Changes
 * @param {Object} change The Firestore change object.
 * @param {Object} context The event metadata.
 */
exports.handleUserChange = async (change, context) => {
    const userId = context.params.userId;
    const beforeData = change.before.data();
    const afterData = change.after.data();
    
    logger.info(`User change detected: ${userId}`);
    
    try {
        if (!beforeData && afterData) {
            // User created
            logger.info(`User created: ${userId}`);
            await onUserCreated(userId, afterData);
        } else if (beforeData && afterData) {
            // User updated
            logger.info(`User updated: ${userId}`);
            await onUserUpdated(userId, beforeData, afterData);
        } else if (beforeData && !afterData) {
            // User deleted
            logger.info(`User deleted: ${userId}`);
            await onUserDeleted(userId, beforeData);
        }
        
    } catch (error) {
        logger.error(`Error handling user change for ${userId}: ${error.message}`);
        throw error;
    }
};

/**
 * Scheduled Function - Daily Tasks
 * @param {Object} event The Cloud Scheduler event.
 * @param {Object} context The event metadata.
 */
exports.dailyMaintenance = async (event, context) => {
    logger.info('Running daily maintenance tasks');
    
    try {
        // Inaktive Benutzer deaktivieren
        await deactivateInactiveUsers();
        
        // Alte Dateien aufräumen
        await cleanupOldFiles();
        
        // Statistiken aktualisieren
        await updateDailyStatistics();
        
        // Backups verifizieren
        await verifyBackups();
        
        logger.info('Daily maintenance completed successfully');
        
    } catch (error) {
        logger.error(`Error in daily maintenance: ${error.message}`);
        throw error;
    }
};

// Helper Functions

async function getAllUsers(req, res) {
    try {
        const usersSnapshot = await firestore.collection('users').get();
        const users = [];
        
        usersSnapshot.forEach(doc => {
            users.push({
                id: doc.id,
                ...doc.data()
            });
        });
        
        return res.status(200).json({ users });
    } catch (error) {
        logger.error(`Error getting all users: ${error.message}`);
        return res.status(500).json({ error: error.message });
    }
}

async function getUser(userId, req, res) {
    try {
        const userDoc = await firestore.collection('users').doc(userId).get();
        
        if (!userDoc.exists) {
            return res.status(404).json({ error: 'User not found' });
        }
        
        return res.status(200).json({ 
            user: {
                id: userDoc.id,
                ...userDoc.data()
            }
        });
    } catch (error) {
        logger.error(`Error getting user ${userId}: ${error.message}`);
        return res.status(500).json({ error: error.message });
    }
}

async function createUser(req, res) {
    try {
        const { name, email, username } = req.body;
        
        // Validierung
        if (!name || !email || !username) {
            return res.status(400).json({ 
                error: 'Name, email, and username are required' 
            });
        }
        
        // Prüfen ob Benutzer bereits existiert
        const existingUser = await firestore.collection('users')
            .where('email', '==', email)
            .get();
        
        if (!existingUser.empty) {
            return res.status(409).json({ error: 'User with this email already exists' });
        }
        
        // Neuen Benutzer erstellen
        const userDoc = {
            name,
            email,
            username,
            createdAt: new Date(),
            status: 'active',
            lastLogin: null
        };
        
        const userRef = await firestore.collection('users').add(userDoc);
        
        // Pub/Sub Nachricht senden
        const dataBuffer = Buffer.from(JSON.stringify({
            action: 'user_created',
            userId: userRef.id,
            email,
            name
        }));
        
        await pubsub.topic('user-events').publish(dataBuffer);
        
        logger.info(`User created: ${userRef.id}`);
        
        return res.status(201).json({ 
            message: 'User created successfully',
            userId: userRef.id
        });
    } catch (error) {
        logger.error(`Error creating user: ${error.message}`);
        return res.status(500).json({ error: error.message });
    }
}

async function updateUser(userId, req, res) {
    try {
        const userDoc = await firestore.collection('users').doc(userId).get();
        
        if (!userDoc.exists) {
            return res.status(404).json({ error: 'User not found' });
        }
        
        const updates = req.body;
        updates.updatedAt = new Date();
        
        await firestore.collection('users').doc(userId).update(updates);
        
        logger.info(`User updated: ${userId}`);
        
        return res.status(200).json({ 
            message: 'User updated successfully' 
        });
    } catch (error) {
        logger.error(`Error updating user ${userId}: ${error.message}`);
        return res.status(500).json({ error: error.message });
    }
}

async function deleteUser(userId, req, res) {
    try {
        const userDoc = await firestore.collection('users').doc(userId).get();
        
        if (!userDoc.exists) {
            return res.status(404).json({ error: 'User not found' });
        }
        
        await firestore.collection('users').doc(userId).delete();
        
        logger.info(`User deleted: ${userId}`);
        
        return res.status(200).json({ 
            message: 'User deleted successfully' 
        });
    } catch (error) {
        logger.error(`Error deleting user ${userId}: ${error.message}`);
        return res.status(500).json({ error: error.message });
    }
}

async function processImage(bucketName, fileName) {
    try {
        // Thumbnail erstellen (vereinfacht)
        const thumbnailName = `thumbnails/${fileName}`;
        
        // In der Praxis würden Sie hier Bildverarbeitungsbibliotheken verwenden
        // z.B. sharp für Bildverarbeitung
        
        await storage.bucket(bucketName).file(fileName).copy(
            storage.bucket(bucketName).file(thumbnailName)
        );
        
        // Metadaten aktualisieren
        await firestore.collection('files').doc(fileName).update({
            thumbnailPath: thumbnailName,
            processed: true,
            processedAt: new Date()
        });
        
        logger.info(`Image processed: ${fileName}`);
        
    } catch (error) {
        logger.error(`Error processing image ${fileName}: ${error.message}`);
        throw error;
    }
}

async function handleFileUploaded(data) {
    const { fileName, bucketName } = data;
    
    // Zusätzliche Verarbeitung
    logger.info(`Handling file uploaded event for: ${fileName}`);
    
    // Analytics-Tracking
    await firestore.collection('analytics').add({
        event: 'file_uploaded',
        fileName,
        bucketName,
        timestamp: new Date()
    });
}

async function handleUserCreated(data) {
    const { userId, email, name } = data;
    
    // Willkommens-E-Mail senden
    logger.info(`Sending welcome email to ${email}`);
    
    // Benutzer in weiteren Systemen registrieren
    logger.info(`Registering user ${userId} in external systems`);
    
    // Analytics-Event
    await firestore.collection('analytics').add({
        event: 'user_created',
        userId,
        email,
        name,
        timestamp: new Date()
    });
}

async function handleOrderPlaced(data) {
    const { orderId, customerId, amount } = data;
    
    logger.info(`Processing order ${orderId} for customer ${customerId}`);
    
    // Bestellverarbeitung
    await firestore.collection('orders').doc(orderId).set({
        orderId,
        customerId,
        amount,
        status: 'processing',
        createdAt: new Date()
    });
}

async function onUserCreated(userId, userData) {
    logger.info(`User created event: ${userId}`);
    
    // Zusätzliche Logik für neue Benutzer
    await firestore.collection('user_activity').add({
        userId,
        action: 'created',
        timestamp: new Date()
    });
}

async function onUserUpdated(userId, beforeData, afterData) {
    logger.info(`User updated event: ${userId}`);
    
    // Änderungen protokollieren
    const changes = {};
    
    Object.keys(afterData).forEach(key => {
        if (beforeData[key] !== afterData[key]) {
            changes[key] = {
                before: beforeData[key],
                after: afterData[key]
            };
        }
    });
    
    if (Object.keys(changes).length > 0) {
        await firestore.collection('user_activity').add({
            userId,
            action: 'updated',
            changes,
            timestamp: new Date()
        });
    }
}

async function onUserDeleted(userId, userData) {
    logger.info(`User deleted event: ${userId}`);
    
    // Aufräumarbeiten
    await firestore.collection('user_activity').add({
        userId,
        action: 'deleted',
        timestamp: new Date()
    });
}

async function deactivateInactiveUsers() {
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - 90);
    
    const inactiveUsers = await firestore.collection('users')
        .where('lastLogin', '<', cutoffDate)
        .where('status', '==', 'active')
        .get();
    
    const batch = firestore.batch();
    
    inactiveUsers.forEach(doc => {
        const userRef = firestore.collection('users').doc(doc.id);
        batch.update(userRef, { status: 'inactive', deactivatedAt: new Date() });
    });
    
    await batch.commit();
    
    logger.info(`Deactivated ${inactiveUsers.size} inactive users`);
}

async function cleanupOldFiles() {
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - 30);
    
    const oldFiles = await firestore.collection('files')
        .where('uploadedAt', '<', cutoffDate)
        .where('processed', '==', true)
        .get();
    
    for (const doc of oldFiles) {
        const { bucketName, fileName } = doc.data();
        
        try {
            await storage.bucket(bucketName).file(fileName).delete();
            await firestore.collection('files').doc(doc.id).delete();
        } catch (error) {
            logger.error(`Error deleting old file ${fileName}: ${error.message}`);
        }
    }
    
    logger.info(`Cleaned up ${oldFiles.size} old files`);
}

async function updateDailyStatistics() {
    const today = new Date().toISOString().split('T')[0];
    
    const activeUsers = await firestore.collection('users')
        .where('status', '==', 'active')
        .get();
    
    const totalUsers = await firestore.collection('users').get();
    
    const processedFiles = await firestore.collection('files')
        .where('processed', '==', true)
        .get();
    
    const stats = {
        date: today,
        activeUsers: activeUsers.size,
        totalUsers: totalUsers.size,
        processedFiles: processedFiles.size,
        updatedAt: new Date()
    };
    
    await firestore.collection('daily_stats').doc(today).set(stats);
    
    logger.info(`Daily statistics updated for ${today}`);
}

async function verifyBackups() {
    // Backup-Verifikation implementieren
    logger.info('Verifying backups');
    
    // Prüfen ob tägliche Backups vorhanden sind
    // Backup-Integrität überprüfen
    // Benachrichtigung bei Problemen
}

4. Infraestructura como Código con Terraform

# Provider Konfiguration
terraform {
  required_version = ">= 1.0"
  
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
    
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
    
    google = {
      source  = "hashicorp/google"
      version = "~> 4.0"
    }
  }
  
  backend "s3" {
    bucket = "terraform-state-bucket"
    key    = "cloud-infrastructure/terraform.tfstate"
    region = "eu-west-1"
  }
}

# AWS Provider
provider "aws" {
  region = var.aws_region
  
  default_tags {
    tags = {
      Environment = var.environment
      Project     = var.project_name
      ManagedBy   = "Terraform"
    }
  }
}

# Azure Provider
provider "azurerm" {
  features {}
  
  subscription_id = var.azure_subscription_id
  tenant_id       = var.azure_tenant_id
}

# Google Provider
provider "google" {
  project = var.gcp_project_id
  region  = var.gcp_region
}

# Variablen
variable "project_name" {
  description = "Name of the project"
  type        = string
  default     = "cloud-app"
}

variable "environment" {
  description = "Environment (dev, staging, prod)"
  type        = string
  default     = "dev"
}

variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "eu-west-1"
}

variable "azure_subscription_id" {
  description = "Azure subscription ID"
  type        = string
  sensitive   = true
}

variable "azure_tenant_id" {
  description = "Azure tenant ID"
  type        = string
  sensitive   = true
}

variable "gcp_project_id" {
  description = "Google Cloud project ID"
  type        = string
  sensitive   = true
}

variable "gcp_region" {
  description = "Google Cloud region"
  type        = string
  default     = "europe-west1"
}

# AWS Resources

# S3 Bucket für statische Inhalte
resource "aws_s3_bucket" "static_content" {
  bucket = "${var.project_name}-${var.environment}-static-content"
  
  tags = {
    Purpose = "Static Content Storage"
  }
}

resource "aws_s3_bucket_versioning" "static_content" {
  bucket = aws_s3_bucket.static_content.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_public_access_block" "static_content" {
  bucket = aws_s3_bucket.static_content.id
  
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

# Lambda Function
resource "aws_iam_role" "lambda_role" {
  name = "${var.project_name}-${var.environment}-lambda-role"
  
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_basic" {
  role       = aws_iam_role.lambda_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_iam_role_policy" "lambda_dynamodb" {
  name = "${var.project_name}-${var.environment}-lambda-dynamodb"
  role = aws_iam_role.lambda_role.id
  
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "dynamodb:GetItem",
          "dynamodb:PutItem",
          "dynamodb:UpdateItem",
          "dynamodb:DeleteItem",
          "dynamodb:Query",
          "dynamodb:Scan"
        ]
        Resource = "arn:aws:dynamodb:${var.aws_region}:*:table/${var.project_name}-${var.environment}-*"
      }
    ]
  })
}

resource "aws_lambda_function" "api_handler" {
  filename         = "lambda.zip"
  function_name    = "${var.project_name}-${var.environment}-api-handler"
  role            = aws_iam_role.lambda_role.arn
  handler         = "index.handler"
  runtime         = "python3.9"
  timeout         = 30
  
  source_code_hash = filebase64sha256("lambda.zip")
  
  environment {
    variables = {
      ENVIRONMENT = var.environment
      PROJECT    = var.project_name
    }
  }
  
  tags = {
    Purpose = "API Handler"
  }
}

# API Gateway
resource "aws_api_gateway_rest_api" "api" {
  name        = "${var.project_name}-${var.environment}-api"
  description = "API Gateway for ${var.project_name}"
}

resource "aws_api_gateway_resource" "users" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  parent_id   = aws_api_gateway_rest_api.api.root_resource_id
  path_part   = "users"
}

resource "aws_api_gateway_method" "users_get" {
  rest_api_id   = aws_api_gateway_rest_api.api.id
  resource_id   = aws_api_gateway_resource.users.id
  http_method   = "GET"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "users_get" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  resource_id = aws_api_gateway_resource.users.id
  http_method = aws_api_gateway_method.users_get.http_method
  
  integration_http_method = "POST"
  type                    = "AWS_PROXY"
  uri                     = aws_lambda_function.api_handler.invoke_arn
}

resource "aws_api_gateway_method" "users_post" {
  rest_api_id   = aws_api_gateway_rest_api.api.id
  resource_id   = aws_api_gateway_resource.users.id
  http_method   = "POST"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "users_post" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  resource_id = aws_api_gateway_resource.users.id
  http_method = aws_api_gateway_method.users_post.http_method
  
  integration_http_method = "POST"
  type                    = "AWS_PROXY"
  uri                     = aws_lambda_function.api_handler.invoke_arn
}

resource "aws_api_gateway_deployment" "api" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  
  triggers = {
    redeployment = sha1(jsonencode([
      aws_api_gateway_resource.users.id,
      aws_api_gateway_method.users_get.id,
      aws_api_gateway_method.users_post.id,
      aws_api_gateway_integration.users_get.id,
      aws_api_gateway_integration.users_post.id
    ]))
  }
  
  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_api_gateway_stage" "api" {
  deployment_id = aws_api_gateway_deployment.api.id
  rest_api_id   = aws_api_gateway_rest_api.api.id
  stage_name    = var.environment
  
  tags = {
    Environment = var.environment
  }
}

# Lambda Permission für API Gateway
resource "aws_lambda_permission" "api_gateway" {
  statement_id  = "AllowExecutionFromAPIGateway"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.api_handler.function_name
  principal     = "apigateway.amazonaws.com"
  
  source_arn = "${aws_api_gateway_rest_api.api.execution_arn}/*/${aws_api_gateway_method.users_get.http_method}${aws_api_gateway_resource.users.path}"
}

# DynamoDB Table
resource "aws_dynamodb_table" "users" {
  name           = "${var.project_name}-${var.environment}-users"
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "PK"
  range_key      = "SK"
  
  attribute {
    name = "PK"
    type = "S"
  }
  
  attribute {
    name = "SK"
    type = "S"
  }
  
  point_in_time_recovery {
    enabled = true
  }
  
  tags = {
    Purpose = "User Data"
  }
}

# Azure Resources

# Resource Group
resource "azurerm_resource_group" "main" {
  name     = "${var.project_name}-${var.environment}-rg"
  location = var.azure_location
  
  tags = {
    Environment = var.environment
    Project     = var.project_name
  }
}

# Storage Account
resource "azurerm_storage_account" "main" {
  name                     = "${var.project_name}${var.environment}storage"
  resource_group_name      = azurerm_resource_group.main.name
  location                 = azurerm_resource_group.main.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
  
  tags = {
    Environment = var.environment
    Project     = var.project_name
  }
}

# Function App
resource "azurerm_function_app" "main" {
  name                       = "${var.project_name}-${var.environment}-functions"
  location                   = azurerm_resource_group.main.location
  resource_group_name        = azurerm_resource_group.main.name
  app_service_plan_id        = azurerm_service_plan.main.id
  storage_account_name       = azurerm_storage_account.main.name
  storage_account_access_key = azurerm_storage_account.main.primary_access_key
  os_type                    = "linux"
  version                    = "~4"
  
  app_settings = {
    "FUNCTIONS_WORKER_RUNTIME" = "node"
    "WEBSITE_NODE_DEFAULT_VERSION" = "14"
    "Environment" = var.environment
    "Project" = var.project_name
  }
  
  tags = {
    Environment = var.environment
    Project     = var.project_name
  }
}

# App Service Plan
resource "azurerm_service_plan" "main" {
  name                = "${var.project_name}-${var.environment}-asp"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  os_type             = "Linux"
  sku_name            = "B1"
  
  tags = {
    Environment = var.environment
    Project     = var.project_name
  }
}

# Google Cloud Resources

# Cloud Storage Bucket
resource "google_storage_bucket" "static_content" {
  name          = "${var.project_name}-${var.environment}-static"
  project       = var.gcp_project_id
  location      = var.gcp_region
  storage_class = "STANDARD"
  
  uniform_bucket_level_access = true
  
  labels = {
    environment = var.environment
    project     = var.project_name
  }
}

# Cloud Function
resource "google_cloudfunctions_function" "api_handler" {
  name        = "${var.project_name}-${var.environment}-api-handler"
  description = "API Handler Function"
  runtime     = "python39"
  
  available_memory_mb = 256
  timeout           = 60
  
  source_archive_bucket = google_storage_bucket.function_code.name
  source_archive_object = google_storage_bucket_object.function_code.name
  
  trigger_http = true
  
  entry_point = "handler"
  
  environment_variables = {
    ENVIRONMENT = var.environment
    PROJECT    = var.project_name
  }
  
  labels = {
    environment = var.environment
    project     = var.project_name
  }
}

# Bucket für Function Code
resource "google_storage_bucket" "function_code" {
  name          = "${var.project_name}-${var.environment}-functions"
  project       = var.gcp_project_id
  location      = var.gcp_region
  storage_class = "STANDARD"
  
  uniform_bucket_level_access = true
}

# Function Code Upload
resource "google_storage_bucket_object" "function_code" {
  name   = "function-code.zip"
  bucket = google_storage_bucket.function_code.name
  source = "function-code.zip"
}

# Firestore Database
resource "google_firestore_database" "main" {
  name     = "${var.project_name}-${var.environment}"
  location = var.gcp_region
  type     = "FIRESTORE_NATIVE"
  
  labels = {
    environment = var.environment
    project     = var.project_name
  }
}

# Outputs
output "aws_api_url" {
  description = "AWS API Gateway URL"
  value       = "${aws_api_gateway_deployment.api.invoke_url}/${var.environment}"
}

output "azure_function_url" {
  description = "Azure Function App URL"
  value       = "https://${azurerm_function_app.main.default_hostname}/api"
}

output "gcp_function_url" {
  description = "Google Cloud Function URL"
  value       = google_cloudfunctions_function.api_handler.https_trigger_url
}

output "aws_s3_bucket" {
  description = "AWS S3 Bucket name"
  value       = aws_s3_bucket.static_content.id
}

output "azure_storage_account" {
  description = "Azure Storage Account name"
  value       = azurerm_storage_account.main.name
}

output "gcp_storage_bucket" {
  description = "Google Cloud Storage Bucket name"
  value       = google_storage_bucket.static_content.name
}

Comparación de modelos de servicio en la nube

CaracterísticaIaaSPaaSSaaSServerless
ControlMáximoMedioMínimoMínimo
FlexibilidadAltaMediaBajaAlta
GestiónCompletaParcialNingunaMínima
EscaladoManualAutomáticoAutomáticoAutomático
CostosPago por usoPago por usoSuscripciónPago por uso
ComplejidadAltaMediaBajaMedia

Comparación de proveedores cloud

AWS vs Azure vs GCP

CriterioAWSAzureGCP
Cuota de mercado~32%~23%~11%
Servicios200+100+90+
PreciosComplejoTransparenteEconómico
DocumentaciónCompletaBuenaBuena
ComunidadLa más grandeEnterpriseEn crecimiento
IA/MLSageMakerAzure MLVertex AI

Comparación de servicios de compute

ServicioAWSAzureGCP
VMsEC2Virtual MachinesCompute Engine
ContenedoresECS/EKSAKSGKE
ServerlessLambdaFunctionsCloud Functions
BatchBatchBatchCloud Batch

Patrones de arquitectura serverless

Arquitectura dirigida por eventos

graph TD
    A[Client] --> B[API Gateway]
    B --> C[Lambda Function]
    C --> D[Database]
    C --> E[Queue]
    E --> F[Processor Function]
    F --> G[Storage]
    F --> H[Notification]

Microservicios con serverless

graph LR
    A[User Service] --> B[API Gateway]
    C[Order Service] --> B
    D[Product Service] --> B
    B --> E[Frontend]
    
    A --> F[Event Bus]
    C --> F
    D --> F
    
    F --> G[Analytics]
    F --> H[Notifications]

Modelos de precios

Componentes de pago por uso

  • Compute: Uso de CPU por segundo/milisegundo
  • Memory: Uso de memoria por GB-segundo
  • Storage: GB por mes
  • Network: Transferencia de datos por GB
  • Requests: Número de invocaciones
  • Duration: Tiempo de ejecución

Estrategias de optimización de costos

# Cost Monitoring Example
def monitor_costs():
    # AWS Cost Explorer
    # Azure Cost Management
    # Google Cloud Cost Management
    
    # Optimización:
    # 1. Rightsizing de recursos
    # 2. Scheduled Scaling
    # 3. Reserved Instances
    # 4. Spot Instances
    # 5. Auto-Scaling

Mejores prácticas de seguridad

Capas de seguridad en la nube

  1. Identity & Access Management (IAM)
  2. Seguridad de red (VPC, Firewalls)
  3. Encriptación de datos (En reposo, En tránsito)
  4. Cumplimiento (GDPR, HIPAA, SOC2)
  5. Monitoreo (CloudTrail, Audit Logs)

Configuración de seguridad

# Example Security Policies
security_policies:
  iam:
    - principle_of_least_privilege
    - mfa_required
    - regular_access_review
  
  network:
    - private_subnets
    - security_groups
    - ddos_protection
  
  data:
    - encryption_at_rest
    - encryption_in_transit
    - key_rotation

Estrategias multi-cloud

Arquitectura de nube híbrida

graph TB
    subgraph "On-Premise"
        A[Legacy Systems]
        B[Database]
    end
    
    subgraph "Private Cloud"
        C[VMs]
        D[Storage]
    end
    
    subgraph "Public Cloud"
        E[Serverless]
        F[Containers]
        G[AI/ML]
    end
    
    A --> E
    B --> F
    C --> G
    D --> E

Beneficios del multi-cloud

  • Evitar dependencia de un proveedor
  • Usar los mejores servicios disponibles
  • Optimizar costos
  • Distribución geográfica
  • Recuperación ante desastres

Estrategias de migración

Enfoques de migración a la nube

  1. Rehost (Lift and Shift)
  2. Replatform (Lift and Reshape)
  3. Repurchase (Drop and Shop)
  4. Refactor (Re-architect)
  5. Retire (Decommission)
  6. Retain (Keep On-Premise)

Planificación de la migración

# Migration Assessment Tool
def assess_migration_readiness():
    factors = {
        'application_complexity': 'high',
        'data_sensitivity': 'medium',
        'compliance_requirements': 'high',
        'team_skills': 'medium',
        'budget_constraints': 'medium'
    }
    
    # Recommendation Engine
    if factors['application_complexity'] == 'low':
        return 'rehost'
    elif factors['team_skills'] == 'high':
        return 'refactor'
    else:
        return 'replatform'

Monitoreo y observabilidad

Stack de monitoreo en la nube

graph LR
    A[Applications] --> B[Logs]
    A --> C[Metrics]
    A --> D[Traces]
    
    B --> E[Log Analytics]
    C --> F[Metrics Dashboard]
    D --> G[APM Tools]
    
    E --> H[Alerting]
    F --> H
    G --> H

Métricas clave

  • Rendimiento: Tiempo de respuesta, Throughput
  • Disponibilidad: Uptime, Tasa de errores
  • Costo: Utilización de recursos, Gasto
  • Seguridad: Intentos de acceso fallidos, Amenazas
  • Negocio: Engagement de usuarios, Ingresos

Ventajas y desventajas

Ventajas de Cloud Computing

  • Escalabilidad: Recursos bajo demanda
  • Flexibilidad: Modelo de pago por uso
  • Alcance global: Disponibilidad mundial
  • Innovación: Acceso rápido a nuevas tecnologías
  • Eficiencia de costos: Sin inversiones iniciales

Desventajas

  • Dependencia del proveedor: Riesgo de lock-in
  • Preocupaciones de seguridad: Datos en la nube
  • Cumplimiento: Requisitos regulatorios
  • Complejidad: Gestión multi-cloud
  • Exceso de costos: Gastos no controlados

Preguntas frecuentes en exámenes

  1. ¿Cuál es la diferencia entre IaaS, PaaS y SaaS? IaaS proporciona infraestructura, PaaS proporciona plataforma y SaaS proporciona software listo para usar, con control y esfuerzo de gestión decrecientes.

  2. Explica qué es serverless computing. Serverless significa ejecutar código sin gestionar servidores, con modelo de pago por uso, escalado automático y activación basada en eventos.

  3. ¿Cuándo se utilizan estrategias multi-cloud? Para evitar dependencia de un proveedor, aprovechar los mejores servicios disponibles, optimizar costos y lograr distribución geográfica.

  4. ¿Cuáles son los aspectos de seguridad más importantes en la nube? IAM, seguridad de red, encriptación de datos, cumplimiento normativo y monitoreo son los aspectos de seguridad más críticos.

Fuentes principales

  1. https://aws.amazon.com/
  2. https://azure.microsoft.com/
  3. https://cloud.google.com/
  4. https://www.terraform.io/

Más artículos sobre cloud

Cloud Computing es fundamental para el desarrollo moderno de software. Los siguientes artículos te ayudarán a comprender todos los aspectos de las arquitecturas cloud.

Cloud Native y arquitectura

Volver al blog
Share:

Entradas relacionadas