← Назад к вопросам

Приведи пример настройки сервиса с нуля

1.7 Middle🔥 232 комментариев
#Linux и администрирование

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пример настройки веб-сервиса с нуля на AWS

Представлю пошаговый пример разворачивания веб-приложения с бэкендом на Node.js, фронтендом на React и базой данных PostgreSQL в облаке AWS. Использую инфраструктуру как код (IaC) через Terraform, контейнеризацию с Docker и оркестрацию через AWS ECS.

1. Архитектурный план

Создам отказоустойчивую среду с:

  • VPC с публичными и приватными подсетями в 2 AZ
  • Application Load Balancer (ALB) для входящего трафика
  • ECS Fargate для контейнеров без управления серверами
  • RDS PostgreSQL в приватной подсети
  • S3 для статики фронтенда
  • CloudWatch для логирования и мониторинга

2. Инфраструктура как код (Terraform)

# main.tf - основная конфигурация
terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "eu-west-1"
}

# Создание VPC
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"
  
  name = "app-vpc"
  cidr = "10.0.0.0/16"
  
  azs             = ["eu-west-1a", "eu-west-1b"]
  public_subnets  = ["10.0.1.0/24", "10.0.2.0/24"]
  private_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
  
  enable_nat_gateway = true
  single_nat_gateway = true
  
  tags = {
    Environment = "production"
  }
}

# Security Group для ALB
resource "aws_security_group" "alb_sg" {
  name_prefix = "alb-sg-"
  vpc_id      = module.vpc.vpc_id
  
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# RDS PostgreSQL
module "db" {
  source  = "terraform-aws-modules/rds/aws"
  version = "6.0.0"
  
  identifier = "appdb"
  
  engine               = "postgres"
  engine_version       = "15"
  family               = "postgres15"
  instance_class       = "db.t3.micro"
  
  allocated_storage     = 20
  storage_encrypted    = true
  
  db_name  = "app_production"
  username = var.db_username
  password = var.db_password
  
  vpc_security_group_ids = [aws_security_group.db_sg.id]
  
  maintenance_window = "Mon:00:00-Mon:03:00"
  backup_window      = "03:00-06:00"
  
  tags = {
    Environment = "production"
  }
}

3. Docker-образы

# backend/Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# frontend/Dockerfile
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

4. Конфигурация ECS Task Definition

{
  "family": "app-task",
  "networkMode": "awsvpc",
  "executionRoleArn": "arn:aws:iam::account-id:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::account-id:role/ecsTaskRole",
  "cpu": "1024",
  "memory": "2048",
  "requiresCompatibilities": ["FARGATE"],
  "containerDefinitions": [
    {
      "name": "backend",
      "image": "account-id.dkr.ecr.eu-west-1.amazonaws.com/backend:latest",
      "portMappings": [
        {
          "containerPort": 3000,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "DATABASE_URL",
          "value": "postgresql://user:pass@db-host:5432/appdb"
        },
        {
          "name": "NODE_ENV",
          "value": "production"
        }
      ],
      "secrets": [
        {
          "name": "API_KEY",
          "valueFrom": "arn:aws:secretsmanager:region:account-id:secret:api-key"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/app",
          "awslogs-region": "eu-west-1",
          "awslogs-stream-prefix": "backend"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3
      }
    }
  ]
}

5. CI/CD Pipeline (GitHub Actions)

# .github/workflows/deploy.yml
name: Deploy to ECS

on:
  push:
    branches: [ main ]

env:
  AWS_REGION: eu-west-1
  ECR_REPOSITORY: backend
  ECS_SERVICE: app-service
  ECS_CLUSTER: app-cluster
  ECS_TASK_DEFINITION: task-definition.json

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v2
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ env.AWS_REGION }}
    
    - name: Login to Amazon ECR
      id: login-ecr
      run: |
        aws ecr get-login-password --region $AWS_REGION | \
        docker login --username AWS --password-stdin ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.$AWS_REGION.amazonaws.com
    
    - name: Build, tag, and push image
      run: |
        docker build -t ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPOSITORY:latest .
        docker push ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPOSITORY:latest
    
    - name: Download task definition
      run: |
        aws ecs describe-task-definition --task-definition $ECS_TASK_DEFINITION \
          --query taskDefinition > task-definition.json
    
    - name: Register new task definition
      run: |
        aws ecs register-task-definition --cli-input-json file://task-definition.json
    
    - name: Update ECS service
      run: |
        aws ecs update-service \
          --cluster $ECS_CLUSTER \
          --service $ECS_SERVICE \
          --task-definition $ECS_TASK_DEFINITION \
          --force-new-deployment

6. Мониторинг и логирование

# cloudwatch-alarms.yml
Resources:
  HighCPUAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: "High-CPU-Utilization"
      AlarmDescription: "CPU utilization > 70% for 5 minutes"
      MetricName: "CPUUtilization"
      Namespace: "AWS/ECS"
      Statistic: "Average"
      Period: 300
      EvaluationPeriods: 1
      Threshold: 70
      ComparisonOperator: "GreaterThanThreshold"
      Dimensions:
        - Name: "ClusterName"
          Value: "app-cluster"
        - Name: "ServiceName"
          Value: "app-service"
      AlarmActions:
        - !Ref CPUAutoScalingPolicy

7. Скрипт инициализации

#!/bin/bash
# deploy.sh - скрипт автоматического развертывания

set -e  # Прерывать при ошибках

echo "=== Начало развертывания ==="

# Инициализация Terraform
echo "1. Инициализация Terraform..."
terraform init -backend-config="bucket=my-tfstate-bucket" \
               -backend-config="key=app/terraform.tfstate"

# Проверка конфигурации
echo "2. Проверка конфигурации..."
terraform validate

# Планирование изменений
echo "3. План развертывания..."
terraform plan -out=tfplan -var-file="production.tfvars"

# Применение изменений
read -p "Применить изменения? (yes/no): " -r
if [[ $REPLY =~ ^[Yy]es$ ]]
then
    echo "4. Применение конфигурации..."
    terraform apply tfplan
fi

# Сборка и деплой приложения
echo "5. Сборка Docker образов..."
docker-compose -f docker-compose.prod.yml build

echo "6. Загрузка образов в ECR..."
aws ecr get-login-password --region eu-west-1 | docker login \
    --username AWS \
    --password-stdin $ACCOUNT_ID.dkr.ecr.eu-west-1.amazonaws.com

docker-compose -f docker-compose.prod.yml push

echo "7. Обновление сервиса ECS..."
aws ecs update-service \
    --cluster app-cluster \
    --service app-service \
    --force-new-deployment

echo "8. Проверка деплоя..."
aws ecs wait services-stable \
    --cluster app-cluster \
    --services app-service

echo "=== Развертывание завершено ==="
echo "ALB DNS: $(terraform output -raw alb_dns_name)"

Ключевые принципы настройки:

  1. Идемпотентность - многократное выполнение дает одинаковый результат
  2. Неизменяемая инфраструктура - вместо изменения, создаем новые ресурсы
  3. Безопасность по умолчанию - минимальные необходимые права, секреты в менеджерах
  4. Наблюдаемость - логи, метрики и трейсинг из коробки
  5. Отказоустойчивость - распределение по AZ, health checks, автоматическое восстановление

Этот пример показывает полный цикл от инфраструктуры до деплоя приложения с учетом лучших практик DevOps: автоматизация, мониторинг, безопасность и масштабируемость.

Приведи пример настройки сервиса с нуля | PrepBro