Skip to content

Instantly share code, notes, and snippets.

@markusl
Last active December 29, 2021 08:02
Show Gist options
  • Save markusl/cd1d9ab2c312b0aff18f2f1b19146a00 to your computer and use it in GitHub Desktop.
Save markusl/cd1d9ab2c312b0aff18f2f1b19146a00 to your computer and use it in GitHub Desktop.
How to run AWS macOS EC2 instance and automatically resize disk using AWS CDK
/**
To be used with https://aws.amazon.com/blogs/opensource/integrating-ec2-macos-workers-with-eks-and-jenkins/
*/
import {
aws_ec2 as ec2,
aws_eks as eks,
aws_iam as iam,
Stack,
StackProps,
CfnOutput,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';
export interface JenkinsWorkerProps extends StackProps {
cluster: eks.Cluster;
keyName: string;
publicKey: string;
instanceRole?: iam.IRole;
amiMap: Record<string, string>;
}
export class JenkinsWorker extends Stack {
constructor(scope: Construct, id: string, props: JenkinsWorkerProps) {
super(scope, id, props);
const securityGroup = new ec2.SecurityGroup(this, `${id}securityGroup`, {
vpc: props.cluster.vpc,
description: 'Allow ssh access to Jenkins instances from internal network',
allowAllOutbound: true
});
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(22), 'allow private ssh access');
const instance = new ec2.Instance(this, `${id}Mac1MetalInstance`, {
instanceType: new ec2.InstanceType('mac1.metal'),
machineImage: ec2.MachineImage.genericLinux(props.amiMap),
securityGroup,
role: props.instanceRole,
vpc: props.cluster.vpc,
keyName: props.keyName,
blockDevices: [
{
deviceName: '/dev/sda1',
volume: ec2.BlockDeviceVolume.ebs(256)
},
],
userDataCausesReplacement: true,
});
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-mac-instances.html#mac-instance-increase-volume
const resizeSh = Buffer.from(`PDISK=$(diskutil list physical external | head -n1 | cut -d" " -f1)
APFSCONT=$(diskutil list physical external | grep "Apple_APFS" | tr -s " " | cut -d" " -f8)
yes | sudo diskutil repairDisk $PDISK
sudo diskutil apfs resizeContainer $APFSCONT 0
`, 'binary').toString('base64');
// If there any errors here you can check /var/log/amazon/ec2/ec2-macos-init.log
instance.addUserData(
// Install Corretto Java (required by Jenkins)
'su - ec2-user -c "/usr/local/bin/brew install --cask corretto"',
// iOS builds require this
`su - ec2-user -c "echo 'export LANG=en_US.UTF-8' >> ~/.profile"`,
// Allow SSH access for eks-jenkins-ssh-key to be able to log in for installing XCode
`su - ec2-user -c "echo '${props.publicKey}' >> ~/.ssh/authorized_keys"`,
// Resize disk
`su - ec2-user -c "echo \"${resizeSh}\" | base64 --decode > resize.sh"`,
`su - ec2-user -c "sh resize.sh"`,
// Enable VNC https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-mac-instances.html#mac-instance-vnc
'/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -access -on -restart -agent -privs -all',
// Rest of the steps need to be done manually as per https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-mac-instances.html#mac-instance-vnc
);
const cfnInstance = instance.node.defaultChild as ec2.CfnInstance;
cfnInstance.addPropertyOverride('Tenancy', 'host');
new CfnOutput(this, 'MacOS Worker Private DNS name', {
value: instance.instancePrivateDnsName
});
// The private IP is configured in the Jenkins config file
new CfnOutput(this, 'MacOS Worker Private IP', {
value: instance.instancePrivateIp
});
}
}
new JenkinsWorker(app, 'JenkinsWorker', {
env: {
region,
},
keyName: 'eks-jenkins-ssh-key',
publicKey: 'ssh-rsa AAAAB3-.....x2j2baEa2O1VTNWGc= eks-jenkins-ssh-key-2',
cluster: primaryCluster.cluster,
instanceRole: s3bucket.role,
amiMap: {
'eu-central-1': 'ami-0ec2b8cc005c0a1d1', // macOS Monterey 12.0.1
// 'eu-central-1: 'ami-0fab661bd6dd419af', // macOS Big Sur 11.6.1
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment