Stacktape

Sign up for freeSign up



Web Services

Overview

  • Web service is a computing resource - it runs your code. Web service runs continuously and scales based on the CPU and RAM usage.

  • Web service has a publicly accessible HTTPS URL endpoint for routing traffic to the service container (Only HTTPS requests (port 443) are accepted).

  • Similarly to functions and batch jobs, web services are serverless and fully managed. This means you don't have to worry about administration tasks such as provisioning and managing servers, scaling, VM security, OS security & much more.

  • The container image can be supplied in 3 different ways:

    • built automatically from your source code by Stacktape
    • built using a supplied Dockerfile by Stacktape
    • pre-built images
  • Web services run securely within a Virtual Private Cloud (VPC).

When to use

Advantages

  • Control over underlying environment - Web service can run any Docker image or image built using your own Dockerfile.
  • Price for workloads with predictable load - Compared to functions, web services are cheaper if your workload has a predictable load.
  • Load-balanced and auto-scalable - Web services can automatically horizontally scale based on the CPU and Memory utilization.
  • High availability - Web services run in multiple Availability Zones.
  • Secure by default - Underlying environment is securely managed by AWS.

Disadvantages

  • Scaling speed - Unlike lambda functions that scale almost instantly, web service requires more time - from several seconds to few minutes to add another container.

  • Not fully serverless - While web services can automatically scale up and down, they can't scale to 0. This means, if your workload is unused, you are still paying for at least one instance (minimum ~$8/month)

Basic usage

Copy

import express from 'express';
const app = express();
app.get('/', async (req, res) => {
res.send({ message: 'Hello' });
});
// for your use port number stored in PORT environment variable for your application
// this environment variable is automatically injected by Stacktape
app.listen(process.env.PORT, () => {
console.info(`Server running on port ${process.env.PORT}`);
});

Example server container written in Typescript

Copy

resources:
webService:
type: web-service
properties:
packaging:
type: stacktape-image-buildpack
properties:
entryfilePath: src/main.ts
resources:
cpu: 2
memory: 2048

Example web service config

WebService  API reference
type
Required
properties.packaging
Required
properties.resources
Required
properties.cors
properties.customDomains
properties.cdn
properties.alarms
properties.disabledGlobalAlarms
properties.environment
properties.logging
properties.scaling
properties.internalHealthCheck
properties.accessControl
overrides

Image

Environment variables

Most commonly used types of environment variables:

Copy

resources:
webService:
type: web-service
properties:
packaging:
type: stacktape-image-buildpack
properties:
entryfilePath: src/main.ts
environment:
- name: STATIC_ENV_VAR
value: my-env-var
- name: DYNAMICALLY_SET_ENV_VAR
value: $MyCustomDirective('input-for-my-directive')
- name: DB_HOST
value: $ResourceParam('myDatabase', 'host')
- name: DB_PASSWORD
value: $Secret('dbSecret.password')
resources:
cpu: 2
memory: 2048

Healthcheck

The purpose of the container health check is to monitor the health of the container from the inside.

Once an essential container of an instance is determined UNHEALTHY, the instance is automatically replaced with a new one.

ContainerHealthCheck  API reference
Parent:WebService
healthCheckCommand
Required
intervalSeconds
Default: 30
timeoutSeconds
Default: 5
retries
Default: 3
startPeriodSeconds

  • Example: A shell command sends a curl request every 20 seconds to determine if the service is available. If the request fails (or doesn't return in 5 seconds), the command returns with non-zero exit code, and the healtcheck is considered failed.

Copy

resources:
myWebService:
type: web-service
properties:
packaging:
type: stacktape-image-buildpack
properties:
entryfilePath: src/index.ts
internalHealthCheck:
healthCheckCommand: ['CMD-SHELL', 'curl -f http://localhost/ || exit 1']
intervalSeconds: 20
timeoutSeconds: 5
startPeriodSeconds: 150
retries: 2
resources:
cpu: 2
memory: 2048

Shutdown

  • When a running web service instance is deregistered (removed), all running containers receive a SIGTERM signal.
  • You then have 30 seconds to clean up. After 30 seconds, your process recives a SIGKILL signal.

Copy

process.on('SIGTERM', () => {
console.info('Received SIGTERM signal. Cleaning up and exiting process...');
// Finish any outstanding requests, or close a database connection...
process.exit(0);
});

Cleaning up before container shutdown.

Logging

  • Every time your code outputs (prints) something to the stdout or stderr, your log will be captured and stored in a AWS CloudWatch log group.
  • You can browse your logs in 2 ways:
    • go to your web service's log-group in the AWS CloudWatch console. You can use stacktape stack-info command to get a direct link.
    • use stacktape logs command that will print logs to the console
ContainerWorkloadContainerLogging  API reference
Parent:WebService
disabled
retentionDays
Default: 90

Resources

  • You must configure computing resources (CPU and RAM) for your web service.
  • Configured resources are valid for every container instance in the web service (if there are more than 1 instance running).
ContainerWorkloadResourcesConfig  API reference
Parent:WebService
cpu
memory

Copy

resources:
myWebService:
type: web-service
properties:
packaging:
type: stacktape-image-buildpack
properties:
entryfilePath: src/index.ts
resources:
cpu: 0.25
memory: 512

Scaling

  • Configures scaling behavior of your web service. You can configure:
    • Initial, minimum and maximum amount of concurrently running instances in your workload.
    • Conditions which trigger the scaling (up or down) using a scaling policy.
ContainerWorkloadScaling  API reference
Parent:WebService
minInstances
Default: 1
maxInstances
Default: 1
scalingPolicy

Scaling policy

  • A scaling policy specifies CPU and memory metric thresholds which trigger the scaling process.

  • Depending on the thresholds, the workload can either scale out (add instances) or scale in (remove instances).

  • If both keepAvgCpuUtilizationUnder and keepAvgMemoryUtilizationUnder are used, the workload will scale-out if one of the metrics is above the target value. However, to scale in, both of these metrics need to be below their respective target values.

  • Scaling policy is more aggressive in adding capacity then removing capacity. For example, if the policy's specified metric reaches its target value, the policy assumes that your application is already heavily loaded. So it responds by adding capacity proportional to the metric value as fast as it can. The higher the metric, the more capacity is added.

  • When the metric falls below the target value, the policy expects that utilization will eventually increase again. Therefore it slows down the scale-in process by removing capacity only when utilization passes a threshold that is far enough below the target value (usually 20% lower).

ContainerWorkloadScalingPolicy  API reference
keepAvgCpuUtilizationUnder
Default: 80
keepAvgMemoryUtilizationUnder
Default: 80

Copy

resources:
myWebService:
type: web-service
properties:
packaging:
type: stacktape-image-buildpack
properties:
entryfilePath: src/index.ts
resources:
cpu: 0.5
memory: 1024
scaling:
minInstances: 1
maxInstances: 5
scalingPolicy:
keepAvgMemoryUtilizationUnder: 80
keepAvgCpuUtilizationUnder: 80

Example usage of scaling configuration

Storage

  • Each web service instance has access to its own ephemeral storage. It's removed after the web service instances is removed.
  • It has a fixed size of 20GB.
  • If you have 2 concurrently running web service intances, they do not share this storage.
  • To store data persistently, consider using Buckets.

Accessing other resources

  • For most of the AWS resources, resource-to-resource communication is not allowed by default. This helps to enforce security and resource isolation. Access must be explicitly granted using IAM (Identity and Access Management) permissions.

  • Access control of Relational Databases is not managed by IAM. These resources are not "cloud-native" by design and have their own access control mechanism (connection string with username and password). They are accessible by default, and you don't need to grant any extra IAM permissions. You can further restrict the access to your relational databases by configuring their access control mode.

  • Stacktape automatically handles IAM permissions for the underlying AWS services that it creates (i.e. granting web services permission to write logs to Cloudwatch, allowing web services to communicate with their event source and many others).


If your workload needs to communicate with other infrastructure components, you need to add permissions manually. You can do this in 2 ways:

Using allowAccessTo

  • List of resource names or AWS services that this web service will be able to access (basic IAM permissions will be granted automatically). Granted permissions differ based on the resource.
  • Works only for resources managed by Stacktape (not arbitrary Cloudformation resources)
  • This is useful if you don't want to deal with IAM permissions yourself. Handling permissions using raw IAM role statements can be cumbersome, time-consuming and error-prone.

Copy

resources:
photosBucket:
type: bucket
myWebService:
type: web-service
properties:
packaging:
type: stacktape-image-buildpack
properties:
entryfilePath: src/index.ts
accessControl:
allowAccessTo:
# access to the bucket
- photosBucket
# access to AWS SES
- aws:ses
resources:
cpu: 0.25
memory: 512

AccessControl  API reference
Parent:WebService
iamRoleStatements
allowAccessTo

Granted permissions when using with specific resource:

  • Bucket
    • list objects in a bucket
    • create / get / delete / tag object in a bucket
  • DynamoDb Table
    • get / put / update / delete item in a table
    • scan / query a table
    • describe table stream
  • MongoDB Atlas Cluster
    • Allows connection to a cluster with accessibilityMode set to scoping-workloads-in-vpc. To learn more about MongoDB Atlas clusters accessibility modes, refer to MongoDB Atlas cluster docs.
  • Relational database
    • Allows connection to a relational database with accessibilityMode set to scoping-workloads-in-vpc. To learn more about relational database accessibility modes, refer to Relational databases docs.
  • Redis cluster
    • Allows connection to a redis cluster with accessibilityMode set to scoping-workloads-in-vpc. To learn more about redis cluster accessibility modes, refer to Redis clusters docs.
  • Event bus
    • publish events to the specified Event bus
  • Function
    • invoke the specified function
  • Batch job
    • submit batch-job instance into batch-job queue
    • list submitted job instances in a batch-job queue
    • describe / terminate a batch-job instance
    • list executions of state machine which executes the batch-job according to its strategy
    • start / terminate execution of a state machine which executes the batch-job according to its strategy
  • User auth pool
    • full control over the user pool (cognito-idp:*)
    • for more information about allowed methods refer to AWS docs



Granted permissions when using with AWS service:

  • aws:ses (Simple Email Service)
    • gives full permissions to aws ses (ses:*).
    • for more information about allowed methods refer to AWS docs

Using iamRoleStatements

  • List of raw IAM role statement objects. These will be appended to the web service's role.
  • Allow you to set granular control over your web service's permissions.
  • Can be used to give access to any Cloudformation resource

Copy

resources:
myWebService:
type: web-service
properties:
packaging:
type: stacktape-image-buildpack
properties:
entryfilePath: server/index.ts
accessControl:
iamRoleStatements:
- Resource:
- $CfResourceParam('NotificationTopic', 'Arn')
Effect: 'Allow'
Action:
- 'sns:Publish'
resources:
cpu: 2
memory: 2048
cloudformationResources:
NotificationTopic:
Type: 'AWS::SNS::Topic'

StpIamRoleStatement  API reference
Resource
Required
Sid
Effect
Action
Condition

Default VPC connection

CORS

Cross-origin resource sharing (CORS) is a browser security feature that restricts cross-origin HTTP requests that are initiated from scripts running in the browser.

A cross-origin HTTP request is a request that is made to a different domain or a different subdomain than the one browser is currently on.


Example: If your website has domain mydomain.com and it communicates with your web-service which has domain api.mydomain.com then the browser must perform cross origin request when communcating with this web-service.


There are two types of cross-origin requests:

  1. Simple requests

    • requests that do not require CORS preflight.
    • To understand what is considered a simple request refer to Mozilla docs.
    • You do not need to configure CORS on your gateway for these types of requests. However, responses from your application should still include Access-Control-Allow-Origin header where the value of the header key is set to *(any origin) or is set to the origins allowed to access that resource. Refer to Mozilla docs for more information.
  2. NON-simple (preflighted) requests

    • all cross origin requests that are not considered simple are NON-simple and require preflight requests.
    • If you send NON-simple CORS requests from browser to your API, you can enable CORS which takes care of preflight requests, and sets the neccessary response headers.

If you need to use NON-simple cross origin requests you need to enable CORS. CORS can be enabled with a signle line.

If you are handling CORS within your application, it is unnecessary to enable it within configuration.

Copy

resources:
myWebService:
type: 'web-service'
properties:
resources:
cpu: 2
memory: 2048
packaging:
type: stacktape-image-buildpack
properties:
entryfilePath: src/main.ts
cors:
enabled: true

web-service with CORS enabled

You can additionally configure CORS headers by setting properties in cors configuration.

If you do not specify any additional properties, default CORS configuration is used:

  • AllowedMethods: Inferred from methods used by integrations associated with the api gateway
  • AllowedOrigins: *
  • AllowedHeaders: Content-Type, X-Amz-Date, Authorization, X-Api-Key, X-Amz-Security-Token, X-Amz-User-Agent
HttpApiCorsConfig  API reference
Parent:WebService
enabled
Required
allowedOrigins
allowedHeaders
allowedMethods
allowCredentials
exposedResponseHeaders
maxAge

Custom domain names

Stacktape allows you to connect your custom domain names to some of your resources (Web Service, HTTP API Gateways, Application Load Balancers and Buckets with CDNs).

Connecting a custom domain to the resource does 2 things:

  • Creates DNS records:
    • If you use your custom domain with a resource, Stacktape automatically creates a DNS record (during deploy) pointing the specified domain name to the resource.
  • Adds TLS certificates
    • If the origin resource (HTTP API Gateway, Application Load Balancer or CDN) uses HTTPS protocol, Stacktape takes care of issuing and attaching correct (free, AWS-managed) certificate to the resource. This means, you do not have to deal with TLS termination as it is handled by the connected resource.
    • If you want to use your own certificates, you can configure customCertificateArns.

To manage a custom domain, it first needs to be added to your AWS account. This means that a hosted zone (collection of records managed together for a given domain) for your domain exists in your AWS account and your domain registrar's name servers are pointing to it. To learn more, refer to Adding a domain guide.

DomainConfiguration  API reference
Parent:(WebService  or CdnConfiguration)
domainName
Required
customCertificateArn
disableDnsRecordCreation

Copy

resources:
myWebService:
type: web-service
properties:
resources:
cpu: 2
memory: 2048
packaging:
type: stacktape-image-buildpack
properties:
entryfilePath: src/main.ts
customDomains:
- domainName: whatever.mydomain.com

CDN

You can configure AWS Cloudfront CDN (Content Delivery Network) to be in front of your web-service.

  • CDN is a globally distributed network that can cache responses from your Web Service at the edge - close to your users.
  • AWS Cloudfront has 205 edge locations on 6 continents.
  • The CDN is used to:
    • reduce latency & improve load times
    • reduce bandwidth costs
    • reduce the amount of traffic coming to the origin (Web Service container)
    • improve security
  • CDN caches responses from the origin at the edge for specified amount of time.
  • If the content requested by the client is in the CDN cache, the CDN immediately returns it to the client without making a request to the origin.
  • If the content is NOT in the cache, the CDN makes a request to the Origin. The response from the origin is then forwarded to the client, and cached at the edge.

For information about using CDN refer to our CDN docs.

Referenceable parameters

The following parameters can be easily referenced using $ResourceParam directive directive.

To learn more about referencing parameters, refer to referencing parameters.

domain
  • Web service default domain name

  • Usage: $ResourceParam('<<resource-name>>', 'domain')
url
  • Web service default URL

  • Usage: $ResourceParam('<<resource-name>>', 'url')
customDomains
  • Comma-separated list of custom domain names assigned to the Web Service (only available if you use custom domain names)

  • Usage: $ResourceParam('<<resource-name>>', 'customDomains')
customDomainUrls
  • Comma-separated list of custom domain name URLs (only available if you use custom domain names)

  • Usage: $ResourceParam('<<resource-name>>', 'customDomainUrls')
cdnDomain
  • Default domain of the CDN distribution (only available if you DO NOT configure custom domain names for the CDN).

  • Usage: $ResourceParam('<<resource-name>>', 'cdnDomain')
cdnUrl
  • Default url of the CDN distribution (only available if you DO NOT configure custom domain names for the CDN).

  • Usage: $ResourceParam('<<resource-name>>', 'cdnUrl')
cdnCustomDomains
  • Comma-separated list of custom domain names assigned to the CDN (only available if you configure custom domain names for the CDN).

  • Usage: $ResourceParam('<<resource-name>>', 'cdnCustomDomains')
cdnCustomDomainUrls
  • Comma-separated list of custom domain name URLs of the CDN (only available if you configure custom domain names for the CDN).

  • Usage: $ResourceParam('<<resource-name>>', 'cdnCustomDomainUrls')

Pricing

You are charged for:

  • Virtual CPU / hour:

    • depending on the region $0.04048 - $0.0696
  • Memory GB / hour:

    • depending on the region $0.004445 - $0.0076

The duration is rounded to 1 second with a 1 minute minimum. To learn more, refer to AWS Fargate pricing.

API reference

StpIamRoleStatement  API reference
Resource
Required
Sid
Effect
Action
Condition

Need help? Ask a question on SlackDiscord or info@stacktape.com.