Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Deployment pipelines for your iOS / tvOS apps with Amazon EC2 Mac Instances

Deployment pipelines for your iOS / tvOS apps with Amazon EC2 Mac Instances

Continuous Integration and Continuous Deployment (CI/CD) allows development teams be agile and respond to rapid business changes. It is one of the mechanisms used to increase software quality. In the cloud, AWS customers are typically using managed services such AWS Code Pipeline and AWS CodeBuild to automate their CI/CD pipelines. But what about developers on the Mac platforms ? Those building iOS, tvOS or watchOS applications ? These typically require access to Apple machines running macOS to build, test and deploy the apps. In this talk you will learn how to combine these two worlds: orchestrate and automate your builds and test using AWS Code* services, while delegating the actual build and test to Amazon EC2 instances running macOS.


  1. D E V D AY

  2. © 2021, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Deployment pipelines for your iOS / tvOS apps with Amazon EC2 Mac Instances Sébastien Stormacq Principal Seveloper Advocate, AWS @sebsto
  3. ✅ ✅ ✅ ✅

  4. None
  5. ⁉ ‼ 💔

  6. None
  7. CI/CD Challenges for iOS

  8. Typical Solution #1 : Xcode Server

  9. None
  10. None
  11. None
  12. None
  13. Typical Solution #2 : macOS Workers nodes

  14. Automate the build process Have a macOS machine part of

    the workflow CI/CD Challenges for iOS
  15. Provisioning the hardware 1

  16. None
  17. Start a Mac EC2 Instance ➜ ~ aws --region $REGION

    ec2 allocate-hosts \ --instance-type mac1.metal \ --availability-zone us-east-2b \ --quantity 1 { "HostIds": [ "h-0bab92ca090bfec3f" ] }
  18. Start a Mac EC2 Instance ➜ ~ aws --region $REGION

    ec2 run-instances \ --instance-type mac1.metal \ --key-name your_key \ --placement HostId=h-0bab92ca090bfec3f \ --security-group-ids sg-01000000000000032 \ --image-id AWS_Or_Your_AMI_Id { "Groups": [], "Instances": [ { "AmiLaunchIndex": 0, "ImageId": "ami-019fd52485934f8bd", "InstanceId": "i-0883f109e7f9b025c", "InstanceType": "mac1.metal", "KeyName": "sst-aws", "LaunchTime": "2021-03-08T16:47:39+00:00", "Monitoring": { "State": "disabled" },
  19. AWS Cloud mac1 instance Amazon EC2 👩💻

  20. mac1 Pricing

  21. mac1 Savings Plans

  22. sudo passwd ec2-user sudo /System/Library/CoreServices/RemoteManagement/\ ARDAgent.app/Contents/Resources/kickstart \ -activate -configure -access

    -on \ -restart -agent -privs –all ssh -L 5900:localhost:5900 –C –N -i /path/my-key-pair.pem \ ec2-user@my-instance-public-dns-name open vnc://localhost:5900 mac1 EC2 Tips – VNC (optional) mac1 instance
  23. 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 mac1 EC2 Tips - EBS mac1 instance
  24. # Download and install Xcode from your private web site

    (or S3 bucket) curl -o xcode.xip https://your_private_web_server/apple/Xcode_12.4.xip xip --expand xcode.xip sudo mv Xcode.app /Applications # Download and install Xcode CLI (use your own S3 bucket / CloudFront distribution, the below will stop working at some point) curl -o xcode-cli.dmg https://your_private_web_server/apple/Command_Line_Tools_for_Xcode_12.4.dmg hdiutil mount ./xcode-cli.dmg sudo installer -pkg /Volumes/Command\ Line\ Developer\ Tools/Command\ Line\ Tools.pkg -target / hdiutil unmount /Volumes/Command\ Line\ Developer\ Tools/ sudo installer -pkg /Applications/Xcode.app/Contents/Resources/Packages/XcodeSystemResources.pkg -target / sudo installer -pkg /Applications/Xcode.app/Contents/Resources/Packages/CoreTypes.pkg -target / sudo installer -pkg /Applications/Xcode.app/Contents/Resources/Packages/MobileDevice.pkg -target / sudo installer -pkg /Applications/Xcode.app/Contents/Resources/Packages/MobileDeviceDevelopment.pkg -target / # it might take several minutes to display the license / to return. Try until it works sudo xcodebuild -license accept xcode-select -p mac1 EC2 Tips – CLI Install Xcode mac1 instance
  25. Mac1 EC2 Tips – Create Golden AMI REGION=us-east-2 # REPLACE

    THE IP ADDRESS IN THE COMMAND BELOW # Use the EC2 mac1 Instance Public IP EBS_VOLUME_ID=$(aws ec2 --region $REGION describe-instances --query 'Reservations[].Instances[?PublicIpAddress==``].BlockDeviceMappings[][] .Ebs.VolumeId' --output text) aws ec2 create-snapshot --region $REGION --volume-id $EBS_VOLUME_ID --description "macOS Big Sur Xcode" # AT THIS STAGE COPY THE SNAPSHOT_ID RETURNED BY THE PREVIOUS COMMAND # WAIT FOR THE SNAPSHOT TO COMPLETE, THIS CAN TAKES SEVERAL MINUTES SNAPSHOT_ID=<YOUR SNAPSHOT ID> aws ec2 register-image --region=$REGION --name "GOLD_macOS_BigSur_Xcode" -- description "macOS Big Sur Xcode Gold Image" --architecture x86_64_mac -- virtualization-type hvm --block-device-mappings DeviceName="/dev/sda1",Ebs=\{SnapshotId=$SNAPSHOT_ID,VolumeType=gp3\} --root-device- name "/dev/sda1"
  26. 2 Automated Builds

  27. Build and Archive xcodebuild clean build archive \ -workspace "$WORKSPACE"

    \ -scheme "$SCHEME" \ -archivePath "$ARCHIVE_PATH" \ -configuration "$CONFIGURATION"
  28. Code Signing

  29. Code Signing security create-keychain -p "${PASSWORD}" "${NAME}" security unlock-keychain -p

    "${PASSWORD}" "${NAME}" security list-keychains -s "${NAME}" "${OLD_KEYCHAIN_NAMES[@]}"
  30. Code Signing echo $S3_APPLE_DISTRIBUTION_CERT | base64 -d > $DIST_CERT security

    import "${DIST_CERT}" \ -P "${APPLE_DISTRIBUTION_KEY_PASSWORD}" \ -k "${KEYCHAIN_NAME}" \ -T /usr/bin/codesign \ -T /usr/bin/xcodebuild
  31. Code Signing

  32. Code Signing curl -o ~/AppleWWDRCA.cer \ https://developer.apple.com/certificationauthority/AppleWWDRCA.cer security import ~/AppleWWDRCA.cer

    -t cert -k "${KEYCHAIN_NAME}" \ -T /usr/bin/codesign -T /usr/bin/xcodebuild curl -o ~/AppleWWDRCAG3.cer \ https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer security import ~/AppleWWDRCAG3.cer -t cert -k "${KEYCHAIN_NAME}" \ -T /usr/bin/codesign -T /usr/bin/xcodebuild curl -o ~/DevAuthCA.cer \ https://www.apple.com/certificateauthority/DevAuthCA.cer security import ~/DevAuthCA.cer -t cert -k "${KEYCHAIN_NAME}” \ -T /usr/bin/codesign -T /usr/bin/xcodebuild
  33. Code Signing security set-key-partition-list \ -S apple-tool:,apple: \ -s \

    -k "${PASSWORD}" "${NAME}"
  34. Code Signing echo $S3_MOBILE_PROFILE | base64 -d > mobile.profile UUID=$(security

    cms -D -i mobile.profile \ -k "${KEYCHAIN_NAME}" | plutil -extract UUID xml1 -o - - | xmllint --xpath "//string/text()" -) mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" cp mobile.profile "$HOME/Library/MobileDevice/Provisioning Profiles/${UUID}.mobileprovision"
  35. Other Build Steps

  36. Amplify R E - C R E A T E

    A M P L I F Y C O N F I G U R A T I O N . J S O N /usr/local/bin/amplify pull \ --amplify $AMPLIFY \ --frontend $FRONTEND \ --providers $PROVIDERS \ --yes --region eu-central-1
  37. +1 Other Build Steps

  38. Increase Build Number +1 BUILD_NUMBER=`date +%Y%m%d%H%M%S` plutil -replace CFBundleVersion \

    -string $BUILD_NUMBER \ "./getting started/Info.plist"
  39. Other Build Steps

  40. Upload to iTunes Connect xcrun altool \ --upload-app \ -f

    "$(pwd)/build/$SCHEME.ipa" \ -t ios \ -u $APPLE_ID \ -p @env:APPLE_SECRET
  41. 3 Integrate in the pipeline

  42. AWS CodeBuild Swift Amazon Linux 2 AWS Cloud macOS +

    Xcode Gold AMI GitHub Xcode mac1 Instance 👩💻 Amazon EC2 ?
  43. Command Message (build.sh) Command Queue Amazon Simple Queue Service AWS

    CodeBuild Swift Amazon Linux 2 SQSProducer AWS Cloud macOS + Xcode Gold AMI GitHub Xcode Response Queue Result Message (stdout / stderr) mac1 Instance SQS Build Agent 👩💻 Amazon EC2 ./SQSProducer https://command.queue.url \ https://response.queue.url command.sh ./SQSBuildAgent https://command.queue.url
  44. SQS Build Agent S O U R C E C

    O D E
  45. 4 Integrate AWS Services

  46. IAM Permissions attached { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [

    "cloudformation:List*", "cloudformation:Describe*", "cloudformation:Get*", "cloudformation:Validate*", "cloudformation:Detect*", "amplify:List*", "amplify:Get*", "sqs:Receive*", "sqs:Send*", "sqs:DeleteMessage" ], "Resource": "*" }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": "secretsmanager:GetSecretValue", "Resource": [ "arn:aws:secretsmanager:REGION:ACCOU NT_ID:secret:amplify*", "arn:aws:secretsmanager:REGION:ACCOU NT_ID:secret:apple*" ] }
  47. Store your build secrets A W S S E C

    R E T S M A N A G E R aws secretsmanager create-secret \ --name apple-dist-certificatee \ --secret-binary fileb://./apple-dist.p12 aws secretsmanager create-secret \ --name apple-id \ --secret-string myemail@me.com
  48. Retrieve your build secrets AW S S E C R

    E T S M A N A G E R export APPLE_SECRET=$($AWS_CLI secretsmanager get-secret-value \ --secret-id $APPLE_SECRET_SECRET \ --query SecretString --output text) # These are base64 values, we will need to decode to a file when needed APPLE_CERT=$($AWS_CLI secretsmanager get-secret-value \ --secret-id $APPLE_DISTRIBUTION_CERT_SECRET \ --query SecretBinary --output text)
  49. Retrieve your build secrets A W S S E C

    R E T S M A N A G E R echo $APPLE_CERT | base64 -d > $DIST_CERT security import "${DIST_CERT}" \ -P "${KEY_PASSWORD}" \ -k "${KEYCHAIN_NAME}" \ -T /usr/bin/codesign \ -T /usr/bin/xcodebuild
  50. © 2021, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. End-to-End Demo
  51. ✅ ✅ ✅ ✅

  52. 1

  53. https://github.com/sebsto/amplify-ios-getting-started/tree/main/code

  54. 2

  55. 3

  56. 4

  57. None
  58. Your imagination 🧠 is the limit

  59. Go build !

  60. Thank you! © 2021, Amazon Web Services, Inc. or its

    affiliates. All rights reserved. Sébastien Stormacq @sebsto
  61. Please complete the session survey © 2021, Amazon Web Services,

    Inc. or its affiliates. All rights reserved.