Python和Docker实现AWS ECR/ECS上全自动容器化部署网站前端

发布于:2025-03-13 ⋅ 阅读:(13) ⋅ 点赞:(0)

以类似ChatGPT的网站前端界面的HTML页面、CSS样式表和JavaScript脚本为例,用Python代码将整个前端代码文件的目录,其中包括所有创建的前端代码文件用Docker打包成镜像文件,提前检查Docker软件是否已经安装,并如果容器服务不存在,则在Amazon ECR中注册容器服务,在Amazon ECS中上传对应的镜像文件并启动运行和返回运行状态,程序需要异常处理和日志文件记录每一次运行的参数和结果,所有运行所需的参数都存储在ini配置文件中。

这个解决方案提供了完整的CI/CD流水线基础框架,可以根据实际需求扩展自动化测试、蓝绿部署等高级功能。分步解决方案包含前端代码和部署脚本。以下是完整的实现:

  1. 前端代码文件结构:
chatgpt-frontend/
├── static/
│   ├── css/
│   │   └── style.css
│   └── js/
│       └── script.js
├── templates/
│   └── index.html
├── Dockerfile
├── requirements.txt
├── deploy.py
└── config.ini
  1. 前端代码文件内容:

static/css/style.css:

.chat-container {
    max-width: 800px;
    margin: 0 auto;
    padding: 20px;
    background-color: #f5f5f5;
    border-radius: 10px;
    height: 80vh;
    display: flex;
    flex-direction: column;
}

.chat-messages {
    flex: 1;
    overflow-y: auto;
    padding: 10px;
    background-color: white;
    border-radius: 5px;
    margin-bottom: 10px;
}

.message {
    margin: 10px 0;
    padding: 10px;
    border-radius: 5px;
    max-width: 70%;
}

.user-message {
    background-color: #e3f2fd;
    margin-left: auto;
}

.bot-message {
    background-color: #f5f5f5;
}

.input-container {
    display: flex;
    gap: 10px;
}

input[type="text"] {
    flex: 1;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
}

button {
    padding: 10px 20px;
    background-color: #007bff;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

button:hover {
    background-color: #0056b3;
}

templates/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ChatGPT Clone</title>
    <link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
    <div class="chat-container">
        <div class="chat-messages" id="chat-messages">
            <div class="message bot-message">Hello! How can I help you today?</div>
        </div>
        <div class="input-container">
            <input type="text" id="user-input" placeholder="Type your message...">
            <button onclick="sendMessage()">Send</button>
        </div>
    </div>
    <script src="/static/js/script.js"></script>
</body>
</html>

static/js/script.js:

function appendMessage(message, isUser) {
    const chatMessages = document.getElementById('chat-messages');
    const messageDiv = document.createElement('div');
    messageDiv.className = `message ${isUser ? 'user-message' : 'bot-message'}`;
    messageDiv.textContent = message;
    chatMessages.appendChild(messageDiv);
    chatMessages.scrollTop = chatMessages.scrollHeight;
}

async function sendMessage() {
    const userInput = document.getElementById('user-input');
    const message = userInput.value.trim();
    
    if (message) {
        appendMessage(message, true);
        userInput.value = '';
        
        try {
            const response = await fetch('/api/chat', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ message })
            });
            
            const data = await response.json();
            appendMessage(data.reply, false);
        } catch (error) {
            appendMessage('Error connecting to the server', false);
        }
    }
}

Dockerfile:

FROM nginx:alpine
COPY ./static /usr/share/nginx/html/static
COPY ./templates /usr/share/nginx/html/templates
COPY ./templates/index.html /usr/share/nginx/html/index.html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

requirements.txt:

boto3==1.34.28
configparser==5.3.0
docker==6.1.3

config.ini:

[aws]
region = us-west-2
ecr_repository = chatgpt-frontend
ecs_cluster = ecs-cluster
ecs_service = chatgpt-frontend-service
task_definition = chatgpt-frontend-task

[deployment]
image_name = chatgpt-frontend
image_tag = latest
port = 80

deploy.py:

import os
import subprocess
import configparser
import logging
import boto3
from docker import from_env
from docker.errors import DockerException
from botocore.exceptions import ClientError, NoCredentialsError

# Configure logging
logging.basicConfig(
    filename='deployment.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

class DeploymentError(Exception):
    pass

class AWSClients:
    def __init__(self, region):
        self.ecr = boto3.client('ecr', region_name=region)
        self.ecs = boto3.client('ecs', region_name=region)

def load_config():
    config = configparser.ConfigParser()
    if not config.read('config.ini'):
        raise DeploymentError("Configuration file config.ini not found")
    return config

def check_docker():
    try:
        docker_client = from_env()
        docker_client.ping()
        logging.info("Docker is running")
    except DockerException:
        logging.error("Docker not installed or not running")
        raise DeploymentError("Docker not available")

def build_docker_image(image_name, image_tag):
    try:
        client = from_env()
        image, build_logs = client.images.build(
            path='.',
            tag=f"{image_name}:{image_tag}",
            rm=True
        )
        logging.info(f"Successfully built image {image.tags}")
        return image
    except DockerException as e:
        logging.error(f"Docker build error: {str(e)}")
        raise DeploymentError("Docker build failed")

def push_to_ecr(aws_clients, image_name, image_tag):
    try:
        auth = aws_clients.ecr.get_authorization_token()
        username, password = auth['authorizationData'][0]['authorizationToken'].decode('utf-8').split(':')
        registry = auth['authorizationData'][0]['proxyEndpoint']
        
        client = from_env()
        client.login(username=username, password=password, registry=registry)
        
        ecr_image = f"{registry.replace('https://', '')}/{image_name}:{image_tag}"
        image = client.images.get(f"{image_name}:{image_tag}")
        image.tag(ecr_image)
        
        push_log = client.images.push(ecr_image)
        logging.info(f"Image pushed to ECR: {ecr_image}")
        return ecr_image
    except ClientError as e:
        logging.error(f"AWS API error: {str(e)}")
        raise DeploymentError("ECR operation failed")

def deploy_to_ecs(aws_clients, ecr_image, config):
    try:
        # Update task definition
        task_definition = {
            'family': config['deployment']['image_name'],
            'executionRoleArn': 'ecsTaskExecutionRole',
            'containerDefinitions': [{
                'name': 'web',
                'image': ecr_image,
                'portMappings': [{
                    'containerPort': int(config['deployment']['port']),
                    'hostPort': int(config['deployment']['port'])
                }],
                'essential': True
            }],
            'requiresCompatibilities': ['FARGATE'],
            'networkMode': 'awsvpc',
            'cpu': '256',
            'memory': '512'
        }
        
        response = aws_clients.ecs.register_task_definition(**task_definition)
        task_arn = response['taskDefinition']['taskDefinitionArn']
        logging.info(f"Registered task definition: {task_arn}")
        
        # Update service
        aws_clients.ecs.update_service(
            cluster=config['aws']['ecs_cluster'],
            service=config['aws']['ecs_service'],
            taskDefinition=task_arn,
            forceNewDeployment=True
        )
        logging.info("Service updated successfully")
        
    except ClientError as e:
        logging.error(f"ECS deployment error: {str(e)}")
        raise DeploymentError("ECS deployment failed")

def main():
    try:
        config = load_config()
        aws_clients = AWSClients(config['aws']['region'])
        
        logging.info("Starting deployment process")
        
        # Docker operations
        check_docker()
        build_docker_image(
            config['deployment']['image_name'],
            config['deployment']['image_tag']
        )
        ecr_image = push_to_ecr(
            aws_clients,
            config['deployment']['image_name'],
            config['deployment']['image_tag']
        )
        
        # ECS deployment
        deploy_to_ecs(aws_clients, ecr_image, config)
        
        logging.info("Deployment completed successfully")
        print("Deployment successful! Service is updating...")
        
    except DeploymentError as e:
        logging.error(f"Deployment failed: {str(e)}")
        print(f"Error: {str(e)}")
    except Exception as e:
        logging.error(f"Unexpected error: {str(e)}")
        print(f"Unexpected error: {str(e)}")

if __name__ == "__main__":
    main()

使用说明:

  1. 确保已安装以下依赖:
  • Docker
  • Python 3.8+
  • AWS CLI 配置好凭证
  1. 部署步骤:
# 安装Python依赖
pip install -r requirements.txt

# 配置AWS凭证(如果尚未配置)
aws configure

# 运行部署脚本
python deploy.py

这个实现包含以下功能:

  1. 前端界面:
  • 响应式聊天界面
  • 消息气泡显示
  • 用户输入和发送功能
  • 模拟API调用(需后端实现)
  1. 部署功能:
  • Docker镜像构建和推送
  • ECS服务更新
  • 完整的错误处理
  • 日志记录
  • 配置管理
  1. 安全特性:
  • AWS凭证安全管理
  • Docker安全构建
  • 安全组配置(需在AWS控制台预先配置)

注意:实际部署前需要完成以下准备工作:

  1. 在AWS创建ECR仓库
  2. 创建ECS集群和任务执行角色
  3. 配置VPC和安全组
  4. 在config.ini中填写正确的AWS资源配置