mirror of https://github.com/cirruslabs/tart.git
289 lines
11 KiB
Markdown
289 lines
11 KiB
Markdown

|
||
|
||
*Tart* is a virtualization toolset to build, run and manage macOS and Linux virtual machines on Apple Silicon.
|
||
Built by CI engineers for your automation needs. Here are some highlights of Tart:
|
||
|
||
* Tart uses Apple's own `Virtualization.Framework` for [near-native performance](https://browser.geekbench.com/v5/cpu/compare/14966395?baseline=14966339).
|
||
* Push/Pull virtual machines from any OCI-compatible container registry.
|
||
* Use Tart Packer Plugin to automate VM creation.
|
||
* Built-in CI integration.
|
||
|
||
*Tart* is already adopted by several automation services:
|
||
|
||
<p align="center">
|
||
<a href="https://cirrus-ci.org/guide/macOS/" target=_blank>
|
||
<img src="https://github.com/cirruslabs/tart/raw/main/Resources/Users/CirrusCI.png" height="65"/>
|
||
</a>
|
||
<a href="https://codemagic.io/" target=_blank>
|
||
<img src="https://github.com/cirruslabs/tart/raw/main/Resources/Users/Codemagic.png" height="65"/>
|
||
</a>
|
||
<a href="https://testingbot.com/" target=_blank>
|
||
<img src="https://github.com/cirruslabs/tart/raw/main/Resources/Users/TestingBot.png" height="65"/>
|
||
</a>
|
||
</p>
|
||
|
||
## Usage
|
||
|
||
Try running a Tart VM on your Apple Silicon device running macOS Monterey or later (will download a 25 GB image):
|
||
|
||
```shell
|
||
brew install cirruslabs/cli/tart
|
||
tart clone ghcr.io/cirruslabs/macos-monterey-base:latest monterey-base
|
||
tart run monterey-base
|
||
```
|
||
|
||

|
||
|
||
## CI Integration
|
||
|
||
Tart itself is only responsible for managing virtual machines, but we've built Tart support into a tool called Cirrus CLI
|
||
also developed by Cirrus Labs. [Cirrus CLI](https://github.com/cirruslabs/cirrus-cli) is a command line tool with
|
||
one configuration format to execute common CI steps (run a script, cache a folder, etc.) locally or in any CI system.
|
||
We built Cirrus CLI to solve "But it works on my machine!" problem.
|
||
|
||
Here is an example of a `.cirrus.yml` configuration file which will start a Tart VM, will copy over working directory and
|
||
will run scripts and [other instructions](https://cirrus-ci.org/guide/writing-tasks/#supported-instructions) inside the virtual machine:
|
||
|
||
```yaml
|
||
task:
|
||
name: hello
|
||
macos_instance:
|
||
# can be a remote or a local virtual machine
|
||
image: ghcr.io/cirruslabs/macos-monterey-base:latest
|
||
hello_script:
|
||
- echo "Hello from within a Tart VM!"
|
||
- echo "Here is my CPU info:"
|
||
- sysctl -n machdep.cpu.brand_string
|
||
- sleep 15
|
||
```
|
||
|
||
Put the above `.cirrus.yml` file in the root of your repository and run it with the following command:
|
||
|
||
```shell
|
||
brew install cirruslabs/cli/cirrus
|
||
cirrus run
|
||
```
|
||
|
||

|
||
|
||
[Cirrus CI](https://cirrus-ci.org/) already leverages Tart to power its macOS cloud infrastructure. The `.cirrus.yml`
|
||
config from above will just work in Cirrus CI and your tasks will be executed inside Tart VMs in our cloud.
|
||
|
||
**Note:** Cirrus CI only allows [images managed and regularly updated by us](https://github.com/orgs/cirruslabs/packages?tab=packages&q=macos).
|
||
|
||
### Retrieving artifacts from within Tart VMs
|
||
|
||
In many cases there is a need to retrieve particular files or a folder from within a Tart virtual machine.
|
||
For example, the below `.cirrus.yml` configuration defines a single task that builds a `tart` binary and
|
||
exposes it via [`artifacts` instruction](https://cirrus-ci.org/guide/writing-tasks/#artifacts-instruction):
|
||
|
||
```yaml
|
||
task:
|
||
name: Build
|
||
macos_instance:
|
||
image: ghcr.io/cirruslabs/macos-monterey-xcode:latest
|
||
build_script: swift build --product tart
|
||
binary_artifacts:
|
||
path: .build/debug/tart
|
||
```
|
||
|
||
Running Cirrus CLI with `--artifacts-dir` will write defined `artifacts` to the provided local directory on the host:
|
||
|
||
```bash
|
||
cirrus run --artifacts-dir artifacts
|
||
```
|
||
|
||
Note that all retrieved artifacts will be prefixed with the associated task name and `artifacts` instruction name.
|
||
For the example above, `tart` binary will be saved to `$PWD/artifacts/Build/binary/.build/debug/tart`.
|
||
|
||
## Virtual Machine Management
|
||
|
||
### Creating from scratch
|
||
|
||
Tart supports macOS and Linux virtual machines. All commands like `run` and `pull` work the same way regarding of the underlying OS a particular VM image has.
|
||
The only difference is how such VM images are created. Please check sections below for [macOS](#creating-a-macos-vm-image-from-scratch) and [Linux](#creating-a-linux-vm-image-from-scratch) instructions.
|
||
|
||
#### Creating a macOS VM image from scratch
|
||
|
||
Tart can create VMs from `*.ipsw` files. You can download a specific `*.ipsw` file [here](https://ipsw.me/) or you can
|
||
use `latest` instead of a path to `*.ipsw` to download the latest available version:
|
||
|
||
```shell
|
||
tart create --from-ipsw=latest monterey-vanilla
|
||
tart run monterey-vanilla
|
||
```
|
||
|
||
After the initial booting of the VM you'll need to manually go through the macOS installation process. As a convention we recommend creating an `admin` user with an `admin` password. After the regular installation please do some additional modifications in the VM:
|
||
|
||
1. Enable Auto-Login. Users & Groups -> Login Options -> Automatic login -> admin.
|
||
2. Allow SSH. Sharing -> Remote Login
|
||
3. Disable Lock Screen. Preferences -> Lock Screen -> disable "Require Password" after 5.
|
||
4. Disable Screen Saver.
|
||
5. Run `sudo visudo` in Terminal, find `%admin ALL=(ALL) ALL` add `admin ALL=(ALL) NOPASSWD: ALL` to allow sudo without a password.
|
||
|
||
#### Creating a Linux VM image from scratch
|
||
|
||
```bash
|
||
# Create a bare VM
|
||
tart create --linux ubuntu
|
||
|
||
# Install Ubuntu
|
||
tart run --disk focal-desktop-arm64.iso ubuntu
|
||
|
||
# Run VM
|
||
tart run ubuntu
|
||
```
|
||
|
||
After the initial setup please make sure your VM can be SSH-ed into by running the following commands inside your VM:
|
||
|
||
```shell
|
||
sudo apt update
|
||
sudo apt install -y openssh-server
|
||
sudo ufw allow ssh
|
||
```
|
||
|
||
### Configuring a VM
|
||
|
||
By default, a tart VM uses 2 CPUs and 4 GB of memory with a `1024x768` display. This can be changed with `tart set` command.
|
||
Please refer to `tart set --help` for additional details.
|
||
|
||
### Building with Packer
|
||
|
||
Please refer to [Tart Packer Plugin repository](https://github.com/cirruslabs/packer-plugin-tart) for setup instructions.
|
||
Here is an example of a template to build `monterey-base` local image based of a remote image:
|
||
|
||
```json
|
||
{
|
||
"builders": [
|
||
{
|
||
"name": "tart",
|
||
"type": "tart-cli",
|
||
"vm_base_name": "tartvm/vanilla:latest",
|
||
"vm_name": "monterey-base",
|
||
"cpu_count": 4,
|
||
"memory_gb": 8,
|
||
"disk_size_gb": 32,
|
||
"ssh_username": "admin",
|
||
"ssh_password": "admin",
|
||
"ssh_timeout": "120s"
|
||
}
|
||
],
|
||
"provisioners": [
|
||
{
|
||
"inline": [
|
||
"echo 'Disabling spotlight indexing...'",
|
||
"sudo mdutil -a -i off"
|
||
],
|
||
"type": "shell"
|
||
},
|
||
# more provisioners
|
||
]
|
||
}
|
||
```
|
||
|
||
Here is a [repository with Packer templates](https://github.com/cirruslabs/macos-image-templates) used to build [all the images managed by us](https://github.com/orgs/cirruslabs/packages?tab=packages&q=macos).
|
||
|
||
### Working with a Remote OCI Container Registry
|
||
|
||
For example, let's say you want to push/pull images to a registry hosted at https://acme.io/.
|
||
|
||
#### Registry Authorization
|
||
|
||
First, you need to log in and save credential for `acme.io` host via `tart login` command:
|
||
|
||
```shell
|
||
tart login acme.io
|
||
```
|
||
|
||
Credentials are securely stored in Keychain.
|
||
|
||
#### Pushing a Local Image
|
||
|
||
Once credentials are saved for `acme.io`, run the following command to push a local images remotely with two tags:
|
||
|
||
```shell
|
||
tart push my-local-vm-name acme.io/remoteorg/name:latest acme.io/remoteorg/name:v1.0.0
|
||
```
|
||
|
||
#### Pulling a Remote Image
|
||
|
||
You can either pull an image:
|
||
|
||
```shell
|
||
tart pull acme.io/remoteorg/name:latest
|
||
```
|
||
|
||
...or instantiate a VM from a remote image:
|
||
|
||
```shell
|
||
tart clone acme.io/remoteorg/name:latest my-local-vm-name
|
||
```
|
||
|
||
This invocation calls the `tart pull` implicitly (if the image is not being present) before doing the actual cloning.
|
||
|
||
## FAQ
|
||
|
||
<details>
|
||
<summary>How Tart is different from Anka</summary>
|
||
|
||
Under the hood Tart is using the same technology as Anka 3.0 so there should be no real difference in performance
|
||
or features supported. If there is some feature missing please don't hesitate to [create a feature request](https://github.com/cirruslabs/tart/issues).
|
||
|
||
Instead of Anka Registry, Tart can work with any OCI-compatible container registry.
|
||
|
||
Tart doesn't yet have an analogue of Anka Controller for managing long living VMs. Please take a look at [CI integration](#ci-integration)
|
||
section for an option to run ephemeral VMs for your needs.
|
||
</details>
|
||
|
||
<details>
|
||
<summary>Why Tart is free and open sourced?</summary>
|
||
|
||
Apple did all the heavy lifting with their `Virtualization.Framework` and it just felt right to develop Tart in the open.
|
||
Please consider [becoming a sponsor](https://github.com/sponsors/cirruslabs) if you find Tart saving a substantial amount of money on licensing and engineering hours for your company.
|
||
</details>
|
||
|
||
<details>
|
||
<summary>How to change VM's disk size?</summary>
|
||
|
||
You can choose disk size upon creation of a virtual machine:
|
||
|
||
```shell
|
||
tart create --from-ipsw=latest --disk-size=25 monterey-vanilla
|
||
```
|
||
|
||
For an existing VM please use [Packer Plugin](https://github.com/cirruslabs/packer-plugin-tart) which can increase
|
||
disk size for new virtual machines. Here is an example of [how to change disk size in a Packer template](https://github.com/cirruslabs/macos-image-templates/blob/fb0bcf68e0b093129136875c050205a66729b596/templates/base.pkr.hcl#L15).
|
||
</details>
|
||
|
||
<details>
|
||
<summary>VM location on disk</summary>
|
||
|
||
Tart stores all it's files in `~/.tart/` directory. Local images that you can run are stored in `~/.tart/vms/`.
|
||
Remote images are pulled into `~/.tart/vms/cache/OCIs/`.
|
||
</details>
|
||
|
||
<details>
|
||
<summary>Nested virtualization support?</summary>
|
||
|
||
Tart is limited by functionality of Apple's `Virtualization.Framework`. At the moment `Virtualization.Framework`
|
||
doesn't support nested virtualization.
|
||
</details>
|
||
|
||
<details>
|
||
<summary>Changing the default NAT subnet</summary>
|
||
|
||
To change the default network to `192.168.77.1`:
|
||
|
||
```
|
||
sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.vmnet.plist Shared_Net_Address -string 192.168.77.1
|
||
```
|
||
|
||
Note that even through a network would normally be specified as `192.168.77.0`, the [vmnet framework](https://developer.apple.com/documentation/vmnet) seems to treat this as a starting address too and refuses to pick up such network-like values.
|
||
|
||
The default subnet mask `255.255.255.0` should suffice for most use-cases, however, you can also change it to `255.255.0.0`, for example:
|
||
|
||
```
|
||
sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.vmnet.plist Shared_Net_Mask -string 255.255.0.0
|
||
```
|
||
</details>
|