diff --git a/README.md b/README.md index 044b2c8..21e7c8a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,10 @@ Move your [Docker Compose](https://docs.docker.com/compose/) application stack f ## Install -`npm i kiss-docker-compose` +``` +npm i kiss-docker-compose +npm i aws-cdk-lib +``` ## Inline Docker Compose File @@ -180,5 +183,5 @@ export AWS_REGION=us-east-2 Deploy: ``` -cdk deploy --app='./lib/integ.default.js' +npx cdk deploy --app='./lib/integ.default.js' ``` diff --git a/src/index.ts b/src/index.ts index 7e85e1c..8b78a72 100644 --- a/src/index.ts +++ b/src/index.ts @@ -133,6 +133,7 @@ export class KissDockerCompose extends Construct { this.regionOfEC2Instances, this.regionOfECR, props.dockerComposeFileAsString, + undefined, props.machineImage, ); } @@ -319,6 +320,10 @@ export function Ec2InstanceRole(scope: Construct, id: string): cdk.aws_iam.Role * @param regionOfEC2Instances EC2 instance region. Usually cdk.Stack.of(this).region * @param regionOfECR ECR region. Usually cdk.Stack.of(this).region * @param dockerComposeFileAsString always the same as props.dockerComposeFileAsString + * @param swapCountIn128MBChunks Default 0. If set to null or 0 or less, does not set swap. + * Sets up a swap file with size = Math.Round(swapCountIn128MBChunks) * 128M. + * For example, if swapCountIn128MBChunks == 1 then there will be 128MB of swap. There is NOT a check to verify there is enough + * storage on the instance to support the swap file size. * @param machineImage Used to initialize the EC2 Instance. * @returns A NEW EC2 instance which will run Docker Compose when launched and when restarted. */ @@ -333,6 +338,7 @@ export function EC2Instance( regionOfEC2Instances: string, regionOfECR: string, dockerComposeFileAsString: string, + swapCountIn128MBChunks?: number, machineImage?: cdk.aws_ec2.IMachineImage, ): cdk.aws_ec2.Instance { if ( @@ -427,9 +433,12 @@ export function EC2Instance( ec2.InitFile.fromString('/home/ec2-user/docker-compose.yml', dockerComposeFileAsString), ec2.InitFile.fromString('/etc/install.sh', installAndStartupScript()), ec2.InitFile.fromString('/etc/systemd/system/docker-compose-app.service', dockerComposeAppService()), + ec2.InitFile.fromString('/etc/set-up-swap.sh', setUpSwap(swapCountIn128MBChunks)), ec2.InitFile.fromString('/home/ec2-user/docker-compose-setup.sh', dockerComposeSetup(cdk.Stack.of(scope).account, regionOfECR, repoURIs)), ec2.InitCommand.shellCommand('chmod +x /etc/install.sh'), ec2.InitCommand.shellCommand('/etc/install.sh'), + ec2.InitCommand.shellCommand('chmod +x /etc/set-up-swap.sh'), + ec2.InitCommand.shellCommand('sudo /etc/set-up-swap.sh'), ec2.InitFile.fromString('/home/ec2-user/on-stop.sh', onStopScript()), ec2.InitCommand.shellCommand('chmod +x /home/ec2-user/on-stop.sh'), @@ -601,3 +610,31 @@ sudo systemctl enable docker-compose-app // /etc/install.sh return `${installDocker}${installDockerCompose}${dockerOnStartup}`; } + +function setUpSwap(swapCountIn128MBChunks: number | undefined): string { + if (swapCountIn128MBChunks == null || swapCountIn128MBChunks <= 0) { + return `#!/bin/bash +echo "NOT setting up swap" +`; + } + swapCountIn128MBChunks = Math.round(swapCountIn128MBChunks); + + return `#!/bin/bash +# mounting should already be done +# sudo mount /dev/xvda2 /mnt + +# Create the swap file +sudo dd if=/dev/zero of=/swapfile bs=128M count=${swapCountIn128MBChunks.toString()} + +# permissions +sudo chmod 600 /swapfile + +# make it swap +sudo mkswap /swapfile +sudo swapon /swapfile + +# Add to fstab so swap persists after restarting +echo "\n/swapfile swap swap defaults 0 0\n" >> /etc/fstab +`; +} + diff --git a/test/use-swap.test.ts b/test/use-swap.test.ts new file mode 100644 index 0000000..875bcb9 --- /dev/null +++ b/test/use-swap.test.ts @@ -0,0 +1,37 @@ +import { App, Stack } from 'aws-cdk-lib'; +import * as cdk from 'aws-cdk-lib'; +import { Template } from 'aws-cdk-lib/assertions'; +import { dockerComposeFileAsString } from './docker-compose-file-as-string'; +import * as KissDockerCompose from '../src/index'; + +const mockApp = new App(); +const stack = new Stack(mockApp); + +// Supplying EC2Instance as an argument overrides / ignores other properties +// So we only need to provide this one thing to get the service to deploy with everything we want +const vpc = KissDockerCompose.VPC(stack, 'testing-stack-vpc'); +const role = KissDockerCompose.Ec2InstanceRole(stack, 'testing-stack-role'); +const instanceSecurityGroup = KissDockerCompose.InstanceSecurityGroup(stack, 'testing-stack-sg', vpc); +const ec2Instance = KissDockerCompose.EC2Instance(stack, 'testing-stack-ec2-instance', vpc, role, instanceSecurityGroup, [], cdk.aws_ec2.InstanceSize.SMALL, 'us-east-2', 'us-east-2', dockerComposeFileAsString, 10); + +new KissDockerCompose.KissDockerCompose(stack, 'testing-stack', { + dockerComposeFileAsString, + ec2Instance, +}); +const minimalConfigurationTemplate = Template.fromStack(stack); + +test('VPC should exist', () => { + minimalConfigurationTemplate.hasResource('AWS::EC2::VPC', {}); +}); + +test('Role should exist', () => { + minimalConfigurationTemplate.hasResource('AWS::IAM::Role', {}); +}); + +test('Security group should exist', () => { + minimalConfigurationTemplate.hasResource('AWS::EC2::SecurityGroup', {}); +}); + +test('EC2 Instance should exist', () => { + minimalConfigurationTemplate.hasResource('AWS::EC2::Instance', {}); +});