Slide 1

Slide 1 text

Continuous Integration for the Rest of Us Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 2

Slide 2 text

Structure of this Talk — Requirements — CI Orchestrators — Virtualization vs Bare Metal — Configuration Management Tools Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 3

Slide 3 text

whoami — Peter Steinberger — Founder @ PSPDFKit — @steipete on Twitter — https://steipete.com/speaking — https://pspdfkit.com/blog/ 2020/continuous-integration- for-small-ios-macos-teams Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 4

Slide 4 text

Our Requirements — 50 people — 1,5 MLOC codebase — 25m compile (6-core MacMini) — 10 Concurrent Builds — Multi-Platform Support — Integration with GitHub PRs — First-class container/Docker support — Pipeline support (parallel steps, artifact support) — Great UI Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 5

Slide 5 text

Types of CI Solutions — Full-Featured, closed (Manage Pipelines & Run Builds) — Full-Featured + optional self-hosted — Orchestrators (Manage Pipelines & self-hosted runners) Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 6

Slide 6 text

Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 7

Slide 7 text

Jenkins Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 8

Slide 8 text

Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 9

Slide 9 text

Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 10

Slide 10 text

Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 11

Slide 11 text

TeamCity Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 12

Slide 12 text

Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 13

Slide 13 text

Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 14

Slide 14 text

Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 15

Slide 15 text

Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 16

Slide 16 text

Virtualized Hardware — macOS must run on Mac hardware — virtualization on PC works but is against Apple EULA — Apple doesn't sell server hardware Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 17

Slide 17 text

Virtualizing macOS — VMware vSphere (VMware Hypervisor) — Orka (MacStadium, KVM Hypervisor) — Anka (Veertu, Apple Hypervisor) Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 18

Slide 18 text

Virtualizing macOS — Performance — Bugs — Compatibility Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 19

Slide 19 text

Virtualizing macOS: Pricing — Anka: $600/core/year. 10 Mac minis * 6 cores = $36k/year — Orka: starting at $18k/year. Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 20

Slide 20 text

Bare Metal Mac Hardware Intel Mac mini (6-core 3.2 GHz, 32 GB RAM, 512 GB SSD) Retails at $1,899 Geekbench Score: 1100/5465 — MacWeb: $1,680/year — MacStadium: $2,148/year — Flow: $5,400/year — Amazon AWS: $9,487/year Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 21

Slide 21 text

Bare Metal Apple Silicon Apple M1 Mac mini (16 GB RAM, 1TB SSD) Retails at $1,299 Geekbench Score: 1705/7379 — MacWeb: $1,680/year — MacStadium: $1,788/year Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 22

Slide 22 text

Apple Silicon woes — iOS 14 Simulator is arm64; iOS 13 and below uses Intel (via Rosetta 2) — Simulator leaks resources, machines need to be rebooted from time to time — WebKit code crashes on iOS < 14 in bmalloc::HeapConstants::HeapConstants2 — We found architecture specific bugs in our codebase! 2 https://steipete.com/posts/apple-silicon-mac-mini-for-ci Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 23

Slide 23 text

Detect Rose!a 2 let NATIVE_EXECUTION = Int32(0) let EMULATED_EXECUTION = Int32(1) let UNKNOWN_EXECUTION = -Int32(1) /// Test if the process runs natively or under Rosetta private func processIsTranslated() -> Int32 { let key = "sysctl.proc_translated" var ret = Int32(0) var size: Int = 0 sysctlbyname(key, nil, &size, nil, 0) let result = sysctlbyname(key, &ret, &size, nil, 0) if result == -1 { if errno == ENOENT { return 0 } return -1 } return ret } Terminal: sysctl -in sysctl.proc_translated Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 24

Slide 24 text

What about the Mac Pro? 2.5GHz 28-core Intel Xeon. 192GB RAM. 8TB storage. Retails $19,099 Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 25

Slide 25 text

Automatic Machine Setup Requirement: Nodes need to have the same configuration Solution: Configuration Management Tools Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 26

Slide 26 text

Configuration Management Tools Script Name Script Store Scripting Language Ansible Playbooks Ansibe Galaxy YAML Chef Cookbooks Chef Supermarket Ruby Puppet Manifests Puppet Forge Puppet DSL (Ruby based) Salt Formulas Salt Stack Formulas YAML Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 27

Slide 27 text

Chef and Open Source Licensing Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 28

Slide 28 text

Microsoft’s Chef Cookbook: https://github.com/microsoft/macos-cookbook

Slide 29

Slide 29 text

Spotlight provides :spotlight default_action :set property :volume, String, name_property: true property :indexed, [true, false], default: true property :searchable, [true, false], default: true action_class do def state new_resource.indexed ? 'on' : 'off' end def search new_resource.searchable ? '' : '-d' end def volume_path(volume) volume == '/' ? volume : ::File.join('/Volumes', volume) end def target_volume volume_path(new_resource.volume) end def mdutil ['/usr/bin/mdutil'] end def desired_spotlight_state [state, target_volume, search] end end action :set do macosx_service 'metadata server' do service_name 'com.apple.metadata.mds' plist '/System/Library/LaunchDaemons/com.apple.metadata.mds.plist' action [:enable, :start] end execute "turn Spotlight indexing #{state} for #{target_volume}" do command mdutil + desired_spotlight_state.insert(0, '-i') not_if { MetadataUtil.new(target_volume).status_flags == desired_spotlight_state } end end Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 30

Slide 30 text

Spotlight // attributes/defaults.rb default['pspdfkit-ci-macos']['apfs_volume']['name'] = 'CI' default['pspdfkit-ci-macos']['apfs_volume']['mount_point'] = '/Volumes/CI' // recipes/default.rb spotlight apfs_volume['name'] do indexed false searchable false end Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 31

Slide 31 text

Disk Space // attributes/defaults.rb default['pspdfkit-ci-macos']['applications']['unneeded'] = %w( GarageBand iMovie Keynote Numbers Pages ) // recipes/default.rb node['pspdfkit-ci-macos']['applications']['unneeded'].each do |application| directory "delete #{application}" do path "/Applications/#{application}.app" recursive true action :delete end end Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 32

Slide 32 text

Screensaver execute 'disable login screensaver' do command "sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0" end execute 'disable ci user screensaver' do command "sudo defaults write /Users/#{admin_user_name}/Library/Preferences/com.apple.screensaver idleTime 0" end execute 'disable admin user screensaver' do command "sudo defaults write /Users/#{ci_user_name}/Library/Preferences/com.apple.screensaver idleTime 0" end Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 33

Slide 33 text

Xcode default['pspdfkit-ci-macos']['xcode-install']['version'] = '2.6.8' default['pspdfkit-ci-macos']['xcode']['versions'] = [ { version: '12.3', build_version: '12C33', }, ] default['pspdfkit-ci-macos']['xcode']['simulators'] = %w( iOS\ 12.0 iOS\ 12.1 iOS\ 12.2 iOS\ 12.4 iOS\ 13.0 iOS\ 13.1 iOS\ 13.2 iOS\ 13.3 iOS\ 13.4 iOS\ 13.5 iOS\ 13.6 iOS\ 13.7 iOS\ 14.0 iOS\ 14.1 iOS\ 14.2 ) Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 34

Slide 34 text

Chef Server vs Knife Zero Plugin: https://knife-zero.github.io bundle exec knife zero converge "name:macos-macstadium{number}" Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 35

Slide 35 text

Run Command on all Agents: bundle exec knife ssh "name:macos-*" "xcodebuild -version" Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 36

Slide 36 text

Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 37

Slide 37 text

Summary — Evaluated CI orchestrators & Buildkite — Managed vs Self-Hosted Runners — Virtualization vs Bare Metal — Configuration Management Tools & Chef Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete

Slide 38

Slide 38 text

Thanks! Peter Steinberger @steipete Continuous Integration for the Rest of Us — iOS Conf SG 2021 | Peter Steinberger — @steipete