Skip to content

Commit

Permalink
feat(apprunner): add HealthCheckConfiguration property in Service (#2…
Browse files Browse the repository at this point in the history
…7029)

This PR adds HealthCheckConfiguration property in Service construct.

Closes #26972.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
go-to-k authored Sep 27, 2023
1 parent f47d09c commit 4e8c9c4
Show file tree
Hide file tree
Showing 13 changed files with 923 additions and 1 deletion.
22 changes: 22 additions & 0 deletions packages/@aws-cdk/aws-apprunner-alpha/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,25 @@ const service = new apprunner.Service(stack, 'Service', {

service.addSecret('LATER_SECRET', apprunner.Secret.fromSecretsManager(secret, 'field'));
```

## HealthCheck

To configure the health check for the service, use the `healthCheck` attribute.

You can specify it by static methods `HealthCheck.http` or `HealthCheck.tcp`.

```ts
new apprunner.Service(this, 'Service', {
source: apprunner.Source.fromEcrPublic({
imageConfiguration: { port: 8000 },
imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest',
}),
healthCheck: apprunner.HealthCheck.http({
healthyThreshold: 5,
interval: Duration.seconds(10),
path: '/',
timeout: Duration.seconds(10),
unhealthyThreshold: 10,
}),
});
```
151 changes: 151 additions & 0 deletions packages/@aws-cdk/aws-apprunner-alpha/lib/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,15 @@ export interface ServiceProps {
* @default - no VPC connector, uses the DEFAULT egress type instead
*/
readonly vpcConnector?: IVpcConnector;

/**
* Settings for the health check that AWS App Runner performs to monitor the health of a service.
*
* You can specify it by static methods `HealthCheck.http` or `HealthCheck.tcp`.
*
* @default - no health check configuration
*/
readonly healthCheck?: HealthCheck;
}

/**
Expand Down Expand Up @@ -848,6 +857,145 @@ export class GitHubConnection {
}
}

/**
* The health check protocol type
*/
export enum HealthCheckProtocolType {
/**
* HTTP protocol
*/
HTTP = 'HTTP',

/**
* TCP protocol
*/
TCP = 'TCP',
}

/**
* Describes the settings for the health check that AWS App Runner performs to monitor the health of a service.
*/
interface HealthCheckCommonOptions {
/**
* The number of consecutive checks that must succeed before App Runner decides that the service is healthy.
*
* @default 1
*/
readonly healthyThreshold?: number;

/**
* The time interval, in seconds, between health checks.
*
* @default Duration.seconds(5)
*/
readonly interval?: cdk.Duration;

/**
* The time, in seconds, to wait for a health check response before deciding it failed.
*
* @default Duration.seconds(2)
*/
readonly timeout?: cdk.Duration;

/**
* The number of consecutive checks that must fail before App Runner decides that the service is unhealthy.
*
* @default 5
*/
readonly unhealthyThreshold?: number;
}

/**
* Properties used to define HTTP Based healthchecks.
*/
export interface HttpHealthCheckOptions extends HealthCheckCommonOptions {
/**
* The URL that health check requests are sent to.
*
* @default /
*/
readonly path?: string;
}

/**
* Properties used to define TCP Based healthchecks.
*/
export interface TcpHealthCheckOptions extends HealthCheckCommonOptions { }

/**
* Contains static factory methods for creating health checks for different protocols
*/
export class HealthCheck {
/**
* Construct a HTTP health check
*/
public static http(options: HttpHealthCheckOptions = {}): HealthCheck {
return new HealthCheck(
HealthCheckProtocolType.HTTP,
options.healthyThreshold,
options.interval,
options.timeout,
options.unhealthyThreshold,
options.path,
);
}

/**
* Construct a TCP health check
*/
public static tcp(options: TcpHealthCheckOptions = {}): HealthCheck {
return new HealthCheck(
HealthCheckProtocolType.TCP,
options.healthyThreshold,
options.interval,
options.timeout,
options.unhealthyThreshold,
);
}

private constructor(
public readonly healthCheckProtocolType: HealthCheckProtocolType,
public readonly healthyThreshold: number = 1,
public readonly interval: cdk.Duration = cdk.Duration.seconds(5),
public readonly timeout: cdk.Duration = cdk.Duration.seconds(2),
public readonly unhealthyThreshold: number = 5,
public readonly path?: string,
) {
if (this.healthCheckProtocolType === HealthCheckProtocolType.HTTP) {
if (this.path !== undefined && this.path.length === 0) {
throw new Error('path length must be greater than 0');
}
if (this.path === undefined) {
this.path = '/';
}
}

if (this.healthyThreshold < 1 || this.healthyThreshold > 20) {
throw new Error(`healthyThreshold must be between 1 and 20, got ${this.healthyThreshold}`);
}
if (this.unhealthyThreshold < 1 || this.unhealthyThreshold > 20) {
throw new Error(`unhealthyThreshold must be between 1 and 20, got ${this.unhealthyThreshold}`);
}
if (this.interval.toSeconds() < 1 || this.interval.toSeconds() > 20) {
throw new Error(`interval must be between 1 and 20 seconds, got ${this.interval.toSeconds()}`);
}
if (this.timeout.toSeconds() < 1 || this.timeout.toSeconds() > 20) {
throw new Error(`timeout must be between 1 and 20 seconds, got ${this.timeout.toSeconds()}`);
}
}

public bind(): CfnService.HealthCheckConfigurationProperty {
return {
healthyThreshold: this.healthyThreshold,
interval: this.interval?.toSeconds(),
path: this.path,
protocol: this.healthCheckProtocolType,
timeout: this.timeout?.toSeconds(),
unhealthyThreshold: this.unhealthyThreshold,
};
}
}

/**
* Attributes for the App Runner Service
*/
Expand Down Expand Up @@ -1097,6 +1245,9 @@ export class Service extends cdk.Resource implements iam.IGrantable {
vpcConnectorArn: this.props.vpcConnector?.vpcConnectorArn,
},
},
healthCheckConfiguration: this.props.healthCheck ?
this.props.healthCheck.bind() :
undefined,
});

// grant required privileges for the role
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Fixture with packages imported, but nothing else
import { Stack, SecretValue } from 'aws-cdk-lib';
import { Duration, Stack, SecretValue } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as apprunner from '@aws-cdk/aws-apprunner-alpha';
import * as path from 'path';
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"Resources": {
"ServiceInstanceRoleDFA90CEC": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "tasks.apprunner.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
}
},
"ServiceDBC79909": {
"Type": "AWS::AppRunner::Service",
"Properties": {
"HealthCheckConfiguration": {
"HealthyThreshold": 5,
"Interval": 10,
"Path": "/",
"Protocol": "HTTP",
"Timeout": 10,
"UnhealthyThreshold": 10
},
"InstanceConfiguration": {
"InstanceRoleArn": {
"Fn::GetAtt": [
"ServiceInstanceRoleDFA90CEC",
"Arn"
]
}
},
"NetworkConfiguration": {
"EgressConfiguration": {
"EgressType": "DEFAULT"
}
},
"SourceConfiguration": {
"AuthenticationConfiguration": {},
"ImageRepository": {
"ImageConfiguration": {
"Port": "8000"
},
"ImageIdentifier": "public.ecr.aws/aws-containers/hello-app-runner:latest",
"ImageRepositoryType": "ECR_PUBLIC"
}
}
}
}
},
"Parameters": {
"BootstrapVersion": {
"Type": "AWS::SSM::Parameter::Value<String>",
"Default": "/cdk-bootstrap/hnb659fds/version",
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
}
},
"Rules": {
"CheckBootstrapVersion": {
"Assertions": [
{
"Assert": {
"Fn::Not": [
{
"Fn::Contains": [
[
"1",
"2",
"3",
"4",
"5"
],
{
"Ref": "BootstrapVersion"
}
]
}
]
},
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
}
]
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 4e8c9c4

Please sign in to comment.