Настройка Serverless Framework для веб-приложения

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Настройка Serverless Framework для веб-приложения
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Настройка Serverless Framework для веб-приложения

Serverless Framework — это инструмент развёртывания и управления serverless-функциями поверх провайдеров (AWS, GCP, Azure, Cloudflare). Он не абстрагирует облако полностью — вы всё ещё работаете с провайдер-специфичными ресурсами, но конфигурация, деплой и управление окружениями объединены в один serverless.yml.

Установка и базовая структура

npm install -g serverless
serverless --version  # 3.x или 4.x

# Новый проект
serverless create --template aws-nodejs-typescript --path my-service
cd my-service
npm install

Структура проекта:

my-service/
├── serverless.yml          # основная конфигурация
├── serverless.env.yml      # переменные окружения (не в git)
├── src/
│   ├── functions/
│   │   ├── api/
│   │   │   ├── handler.ts
│   │   │   └── index.ts    # конфиг функции
│   │   └── worker/
│   │       ├── handler.ts
│   │       └── index.ts
│   └── libs/
│       ├── api-gateway.ts  # хелперы для ответов
│       └── lambda.ts       # middleware-обёртка
├── tsconfig.json
└── package.json

serverless.yml — правильная конфигурация

service: my-web-service
frameworkVersion: '3'

plugins:
  - serverless-esbuild          # быстрая сборка TypeScript
  - serverless-offline          # локальная разработка
  - serverless-dotenv-plugin    # .env файлы

provider:
  name: aws
  runtime: nodejs20.x
  region: eu-west-1
  stage: ${opt:stage, 'dev'}
  memorySize: 512
  timeout: 10
  logRetentionInDays: 14

  environment:
    NODE_ENV: ${self:provider.stage}
    DATABASE_URL: ${env:DATABASE_URL}
    JWT_SECRET: ${env:JWT_SECRET}

  # IAM-права — минимально необходимые
  iam:
    role:
      statements:
        - Effect: Allow
          Action:
            - s3:GetObject
            - s3:PutObject
          Resource: 'arn:aws:s3:::${self:custom.bucketName}/*'
        - Effect: Allow
          Action:
            - dynamodb:Query
            - dynamodb:PutItem
            - dynamodb:UpdateItem
          Resource: !GetAtt UsersTable.Arn

  # API Gateway v2 (HTTP API) — дешевле и быстрее REST API
  httpApi:
    cors:
      allowedOrigins:
        - https://my-site.com
        - http://localhost:3000
      allowedHeaders:
        - Content-Type
        - Authorization
      allowedMethods:
        - GET
        - POST
        - PUT
        - DELETE

custom:
  bucketName: my-service-${self:provider.stage}-assets
  esbuild:
    bundle: true
    minify: ${strToBool(${ssm:/my-service/minify, 'false'})}
    sourcemap: true
    target: node20
    platform: node
    concurrency: 10
  serverless-offline:
    httpPort: 3001
    lambdaPort: 3002

functions:
  - ${file(src/functions/api/index.ts)}
  - ${file(src/functions/worker/index.ts)}

resources:
  Resources:
    UsersTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:service}-${self:provider.stage}-users
        BillingMode: PAY_PER_REQUEST
        AttributeDefinitions:
          - AttributeName: pk
            AttributeType: S
          - AttributeName: sk
            AttributeType: S
        KeySchema:
          - AttributeName: pk
            KeyType: HASH
          - AttributeName: sk
            KeyType: RANGE
        TimeToLiveSpecification:
          AttributeName: ttl
          Enabled: true

Конфигурация функции

// src/functions/api/index.ts
import type { AWS } from '@serverless/typescript';

const apiFunction: AWS['functions'] = {
  api: {
    handler: 'src/functions/api/handler.main',
    events: [
      {
        httpApi: {
          method: 'ANY',
          path: '/api/{proxy+}',
          authorizer: {
            name: 'jwtAuthorizer',
            type: 'jwt',
            identitySource: '$request.header.Authorization',
            issuerUrl: 'https://cognito-idp.eu-west-1.amazonaws.com/${env:COGNITO_POOL_ID}',
            audience: ['${env:COGNITO_CLIENT_ID}'],
          },
        },
      },
    ],
    environment: {
      // Переопределяем provider-уровень если нужно
    },
  },
};

export default apiFunction;

Handler с middleware

// src/libs/lambda.ts
import middy from '@middy/core';
import middyJsonBodyParser from '@middy/http-json-body-parser';
import httpErrorHandler from '@middy/http-error-handler';
import cors from '@middy/http-cors';
import type { APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2 } from 'aws-lambda';

type Handler = (event: APIGatewayProxyEventV2) => Promise<APIGatewayProxyStructuredResultV2>;

export const middyfy = (handler: Handler) =>
  middy(handler)
    .use(middyJsonBodyParser())
    .use(httpErrorHandler())
    .use(cors({ origin: process.env.ALLOWED_ORIGIN ?? '*' }));

// src/libs/api-gateway.ts
export const formatJSONResponse = (response: Record<string, unknown>, statusCode = 200) => ({
  statusCode,
  body: JSON.stringify(response),
  headers: { 'Content-Type': 'application/json' },
});

// src/functions/api/handler.ts
import { middyfy } from '@libs/lambda';
import { formatJSONResponse } from '@libs/api-gateway';

const handler = async (event) => {
  const { body, pathParameters, queryStringParameters } = event;

  return formatJSONResponse({ message: 'ok', data: body });
};

export const main = middyfy(handler);

Управление окружениями

# Разные стейджи
serverless deploy --stage dev
serverless deploy --stage staging
serverless deploy --stage prod

# Параметры через SSM Parameter Store (безопаснее env vars)
serverless deploy --stage prod --param="dbPassword=$(aws ssm get-parameter --name /prod/db-password --with-decryption --query Parameter.Value --output text)"

SSM в serverless.yml:

provider:
  environment:
    DB_PASSWORD: ${ssm:/my-service/${self:provider.stage}/db-password}
    API_KEY: ${ssm:/my-service/api-key~true}  # ~true = decrypt SecureString

Локальная разработка

npm run dev  # serverless offline start

# Вызов функции локально
serverless invoke local --function api --data '{"pathParameters": {"proxy": "users"}}'

# Логи в реальном времени (prod)
serverless logs --function api --tail --stage prod

Оптимизация размера бандла

esbuild + tree shaking значительно уменьшают cold start. Но не все зависимости bundleable:

custom:
  esbuild:
    bundle: true
    exclude:
      - '@aws-sdk/*'  # уже есть в Lambda runtime для Node 18+
      - 'pg-native'   # native addon — исключаем, используем чистый pg
    external:
      - 'sharp'       # native binary — отдельный слой Lambda

Для sharp (обработка изображений) создаём Lambda Layer:

mkdir -p layer/nodejs
cd layer/nodejs
npm install sharp
cd ../..
# В serverless.yml:
# layers:
#   sharp:
#     path: layer
#     compatibleRuntimes: [nodejs20.x]

CI/CD интеграция

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm ci
      - name: Deploy to prod
        run: npx serverless deploy --stage prod
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          DATABASE_URL: ${{ secrets.DATABASE_URL }}

Сроки

Базовая настройка Serverless Framework с одной функцией и деплоем в dev/prod — 1 день. Полноценная структура с несколькими функциями, DynamoDB, SSM-секретами и CI/CD — 3–4 дня. Миграция существующего Express-приложения на serverless-архитектуру — 1–2 недели в зависимости от количества зависимостей.