CloudFormation Init in AWS CDK EC2 provides advanced instance initialization capabilities using AWS CloudFormation helper scripts for complex configuration management.
The main class for creating CloudFormation Init configurations:
class CloudFormationInit {
static fromElements(...elements: InitElement[]): CloudFormationInit;
static fromConfig(config: InitConfig): CloudFormationInit;
static fromConfigSets(props: ConfigSetProps): CloudFormationInit;
addConfig(configName: string, config: InitConfig): void;
addConfigSet(configSetName: string, configNames: string[]): void;
attach(attachedResource: CfnResource, options: AttachInitOptions): void;
}
class InitConfig {
constructor(elements: InitElement[]);
add(...elements: InitElement[]): void;
}
interface ConfigSetProps {
readonly configSets: Record<string, string[]>;
readonly configs: Record<string, InitConfig>;
}Base classes and implementations for different initialization elements:
abstract class InitElement {
// Factory methods for creating different types of elements
}
class InitPackage extends InitElement {
static yum(packageName: string): InitPackage;
static rpm(packageName: string, options?: InitPackageOptions): InitPackage;
static msi(packageName: string, options?: InitPackageOptions): InitPackage;
static python(packageName: string, version?: string): InitPackage;
static rubyGem(packageName: string, version?: string): InitPackage;
}
class InitFile extends InitElement {
static fromString(fileName: string, content: string, options?: InitFileOptions): InitFile;
static fromFileInline(fileName: string, sourceFileName: string, options?: InitFileOptions): InitFile;
static fromAsset(fileName: string, asset: Asset, options?: InitFileOptions): InitFile;
static fromExistingAsset(fileName: string, asset: Asset, options?: InitFileOptions): InitFile;
static fromS3Object(fileName: string, bucket: s3.IBucket, key: string, options?: InitFileOptions): InitFile;
static fromUrl(fileName: string, url: string, options?: InitFileOptions): InitFile;
}
class InitService extends InitElement {
static enable(serviceName: string, options?: InitServiceOptions): InitService;
static disable(serviceName: string, options?: InitServiceOptions): InitService;
static systemdConfigFile(serviceName: string, options: InitServiceOptions): InitService;
}
class InitCommand extends InitElement {
static shellCommand(command: string, options?: InitCommandOptions): InitCommand;
static argvCommand(argv: string[], options?: InitCommandOptions): InitCommand;
}
class InitUser extends InitElement {
constructor(userName: string, options?: InitUserOptions);
}
class InitGroup extends InitElement {
constructor(groupName: string, options?: InitGroupOptions);
}
class InitSource extends InitElement {
static fromS3(targetDirectory: string, bucket: s3.IBucket, key: string): InitSource;
static fromUrl(targetDirectory: string, url: string): InitSource;
static fromAsset(targetDirectory: string, asset: Asset): InitSource;
static fromExistingAsset(targetDirectory: string, asset: Asset): InitSource;
static fromGitHub(targetDirectory: string, owner: string, repo: string, options?: InitSourceOptions): InitSource;
}Interfaces for configuring different init elements:
interface InitFileOptions {
readonly mode?: string;
readonly owner?: string;
readonly group?: string;
readonly base64Encoded?: boolean;
readonly serviceRestartHandles?: InitServiceRestartHandle[];
}
interface InitServiceOptions {
readonly enabled?: boolean;
readonly ensureRunning?: boolean;
readonly files?: string[];
readonly packages?: InitPackage[];
readonly sources?: InitSource[];
readonly commands?: InitCommand[];
readonly serviceRestartHandle?: InitServiceRestartHandle;
}
interface InitCommandOptions {
readonly key?: string;
readonly cwd?: string;
readonly env?: Record<string, string>;
readonly ignoreErrors?: boolean;
readonly testCmd?: string;
readonly waitAfterCompletion?: InitCommandWaitDuration;
readonly serviceRestartHandles?: InitServiceRestartHandle[];
}
interface InitPackageOptions {
readonly version?: string[];
readonly serviceRestartHandles?: InitServiceRestartHandle[];
}
interface InitUserOptions {
readonly userId?: number;
readonly groups?: string[];
readonly homeDir?: string;
}
interface InitGroupOptions {
readonly groupId?: number;
}
interface InitSourceOptions {
readonly serviceRestartHandles?: InitServiceRestartHandle[];
}Classes for managing service restarts and dependencies:
class InitServiceRestartHandle {
constructor();
}
enum InitCommandWaitDuration {
NONE = 'none',
FOREVER = 'forever'
}
interface AttachInitOptions {
readonly platform?: InitPlatform;
readonly userData?: UserData;
readonly ignoreFailures?: boolean;
readonly includeUrl?: boolean;
readonly includeRole?: boolean;
readonly printLog?: boolean;
readonly configSets?: string[];
}
interface ApplyCloudFormationInitOptions {
readonly timeout?: Duration;
readonly includeUrl?: boolean;
readonly includeRole?: boolean;
readonly printLog?: boolean;
readonly ignoreFailures?: boolean;
readonly configSets?: string[];
}
enum InitPlatform {
LINUX = 'linux',
WINDOWS = 'windows'
}import * as ec2 from "@aws-cdk/aws-ec2";
import * as cdk from "@aws-cdk/core";
const vpc = new ec2.Vpc(this, "MyVpc");
// Create basic init configuration
const init = ec2.CloudFormationInit.fromElements(
ec2.InitPackage.yum("httpd"),
ec2.InitFile.fromString("/var/www/html/index.html", "<h1>Hello World</h1>"),
ec2.InitService.enable("httpd", {
enabled: true,
ensureRunning: true
})
);
const instance = new ec2.Instance(this, "WebServer", {
vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
machineImage: ec2.MachineImage.latestAmazonLinux(),
init,
initOptions: {
timeout: cdk.Duration.minutes(10),
includeUrl: true,
includeRole: true,
printLog: true
}
});const webConfig = new ec2.InitConfig([
ec2.InitPackage.yum("httpd"),
ec2.InitPackage.yum("php"),
ec2.InitService.enable("httpd")
]);
const appConfig = new ec2.InitConfig([
ec2.InitFile.fromString("/var/www/html/app.php", "<?php phpinfo(); ?>"),
ec2.InitCommand.shellCommand("chown -R apache:apache /var/www/html")
]);
const init = ec2.CloudFormationInit.fromConfigSets({
configSets: {
"install": ["web", "app"],
"update": ["app"]
},
configs: {
"web": webConfig,
"app": appConfig
}
});
const instance = new ec2.Instance(this, "ConfiguredInstance", {
vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.SMALL),
machineImage: ec2.MachineImage.latestAmazonLinux(),
init,
initOptions: {
configSets: ["install"],
timeout: cdk.Duration.minutes(15)
}
});import * as s3 from "@aws-cdk/aws-s3";
import * as s3deploy from "@aws-cdk/aws-s3-deployment";
const appBucket = new s3.Bucket(this, "AppBucket");
// Deploy application code to S3
new s3deploy.BucketDeployment(this, "DeployApp", {
sources: [s3deploy.Source.asset("./app")],
destinationBucket: appBucket
});
const serviceRestartHandle = new ec2.InitServiceRestartHandle();
const init = ec2.CloudFormationInit.fromElements(
// Install packages
ec2.InitPackage.yum("httpd"),
ec2.InitPackage.yum("php"),
ec2.InitPackage.yum("mysql"),
// Create users and groups
ec2.InitUser.new("appuser", {
homeDir: "/home/appuser",
groups: ["apache"]
}),
// Download application from S3
ec2.InitSource.fromS3("/var/www/html", appBucket, "app.zip"),
// Create configuration files
ec2.InitFile.fromString(
"/etc/httpd/conf.d/app.conf",
`<VirtualHost *:80>
DocumentRoot /var/www/html
ServerName myapp.com
</VirtualHost>`,
{
mode: "000644",
owner: "root",
group: "root",
serviceRestartHandles: [serviceRestartHandle]
}
),
ec2.InitFile.fromString(
"/var/www/html/config.php",
`<?php
define('DB_HOST', 'localhost');
define('DB_USER', 'appuser');
define('DB_PASS', 'password');
?>`,
{
mode: "000600",
owner: "apache",
group: "apache"
}
),
// Run setup commands
ec2.InitCommand.shellCommand("chown -R apache:apache /var/www/html", {
cwd: "/var/www"
}),
ec2.InitCommand.shellCommand("chmod +x /var/www/html/setup.sh"),
ec2.InitCommand.shellCommand("/var/www/html/setup.sh", {
env: {
"APP_ENV": "production"
},
testCmd: "test -f /var/www/html/setup.complete"
}),
// Configure services
ec2.InitService.enable("httpd", {
enabled: true,
ensureRunning: true,
serviceRestartHandle: serviceRestartHandle
}),
ec2.InitService.enable("mysqld", {
enabled: true,
ensureRunning: true
})
);const windowsInit = ec2.CloudFormationInit.fromElements(
// Install IIS
ec2.InitCommand.shellCommand("powershell.exe -Command Install-WindowsFeature -name Web-Server -IncludeManagementTools"),
// Create application directory
ec2.InitCommand.shellCommand("mkdir C:\\MyApp"),
// Download application
ec2.InitSource.fromS3("C:\\MyApp", appBucket, "windows-app.zip"),
// Create website configuration
ec2.InitFile.fromString(
"C:\\inetpub\\wwwroot\\web.config",
`<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appSettings>
<add key="Environment" value="Production" />
</appSettings>
</configuration>`
),
// Configure IIS site
ec2.InitCommand.shellCommand("powershell.exe -Command New-Website -Name MyApp -Port 80 -PhysicalPath C:\\MyApp")
);
const windowsInstance = new ec2.Instance(this, "WindowsInstance", {
vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE),
machineImage: ec2.MachineImage.latestWindows(
ec2.WindowsVersion.WINDOWS_SERVER_2022_ENGLISH_FULL_BASE
),
init: windowsInit,
initOptions: {
platform: ec2.InitPlatform.WINDOWS,
timeout: cdk.Duration.minutes(20)
}
});const dbInit = ec2.CloudFormationInit.fromElements(
// Install MySQL
ec2.InitPackage.yum("mysql-server"),
// Create database directories
ec2.InitCommand.shellCommand("mkdir -p /var/lib/mysql/data"),
ec2.InitCommand.shellCommand("chown -R mysql:mysql /var/lib/mysql"),
// Create MySQL configuration
ec2.InitFile.fromString(
"/etc/my.cnf",
`[mysqld]
datadir=/var/lib/mysql/data
socket=/var/lib/mysql/mysql.sock
user=mysql
server-id=1
log-bin=mysql-bin
bind-address=0.0.0.0
[mysql_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid`,
{
mode: "000644",
owner: "root",
group: "root"
}
),
// Initialize database
ec2.InitCommand.shellCommand("mysql_install_db --user=mysql --datadir=/var/lib/mysql/data"),
// Start MySQL service
ec2.InitService.enable("mysqld", {
enabled: true,
ensureRunning: true
}),
// Set up database and users
ec2.InitCommand.shellCommand(`mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'MySecurePassword123!';"`, {
ignoreErrors: true
}),
ec2.InitCommand.shellCommand(`mysql -u root -pMySecurePassword123! -e "CREATE DATABASE myapp;"`)
);const webServiceHandle = new ec2.InitServiceRestartHandle();
const dbServiceHandle = new ec2.InitServiceRestartHandle();
const dependentInit = ec2.CloudFormationInit.fromElements(
// Install packages
ec2.InitPackage.yum("httpd"),
ec2.InitPackage.yum("mysql-server"),
// Configuration that requires web service restart
ec2.InitFile.fromString(
"/etc/httpd/conf.d/custom.conf",
"ServerTokens Prod\nServerSignature Off",
{
serviceRestartHandles: [webServiceHandle]
}
),
// Configuration that requires database restart
ec2.InitFile.fromString(
"/etc/my.cnf",
"[mysqld]\nmax_connections=200\ninnodb_buffer_pool_size=512M",
{
serviceRestartHandles: [dbServiceHandle]
}
),
// Services that will be restarted when their config changes
ec2.InitService.enable("httpd", {
enabled: true,
ensureRunning: true,
serviceRestartHandle: webServiceHandle
}),
ec2.InitService.enable("mysqld", {
enabled: true,
ensureRunning: true,
serviceRestartHandle: dbServiceHandle
})
);ignoreFailures: false in production to catch initialization errors