Skip to content

Commit 4ccd409

Browse files
authored
Merge pull request #44 from AkihiroSuda/dev
refactor
2 parents 8db2baa + 7843fe2 commit 4ccd409

File tree

12 files changed

+213
-144
lines changed

12 files changed

+213
-144
lines changed

.github/workflows/release.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ jobs:
3939
Terminal 1:
4040
\`\`\`console
4141
[macOS]$ limactl start
42+
...
43+
INFO[0029] READY. Run `lima` to open the shell.
4244
\`\`\`
4345
4446
Terminal 2:

README.md

Lines changed: 90 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
[[⬇️ **Download]**](https://github.com/AkihiroSuda/lima/releases)
2+
[[📖**Getting started]**](#getting-started)
3+
[[**FAQs & Troubleshooting]**](#faqs--troubleshooting)
4+
15
# Lima: Linux virtual machines (on macOS, in most cases)
26

37
Lima launches Linux virtual machines with automatic file sharing, port forwarding, and [containerd](https://containerd.io).
@@ -17,9 +21,9 @@ It may work on NetBSD and Windows hosts as well.
1721

1822
✅ ARM on Intel
1923

20-
✅ ARM on ARM (untested)
24+
✅ ARM on ARM
2125

22-
✅ Intel on ARM (untested)
26+
✅ Intel on ARM
2327

2428
✅ Ubuntu guest
2529

@@ -77,49 +81,12 @@ For the usage of containerd and nerdctl (contaiNERD ctl), visit https://github.c
7781
### Requirements (Intel Mac)
7882
- QEMU v6.0.0 or later (`brew install qemu`)
7983

80-
81-
<details>
82-
<summary>
83-
Signing the binary (not needed for recent version of QEMU and macOS, in most cases)
84-
</summary>
85-
86-
<p>
87-
88-
If you have installed QEMU v6.0.0 or later on macOS 11, your binary should have been already automatically signed to enable HVF acceleration.
89-
90-
However, if you see `HV_ERROR`, you might need to sign the binary manually.
91-
92-
```bash
93-
cat >entitlements.xml <<EOF
94-
<?xml version="1.0" encoding="UTF-8"?>
95-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
96-
<plist version="1.0">
97-
<dict>
98-
<key>com.apple.security.hypervisor</key>
99-
<true/>
100-
</dict>
101-
</plist>
102-
EOF
103-
104-
codesign -s - --entitlements entitlements.xml --force /usr/local/bin/qemu-system-x86_64
105-
```
106-
107-
Note: **Only** on macOS versions **before** 10.15.7 you might need to add this entitlement in addition:
108-
109-
```
110-
<key>com.apple.vm.hypervisor</key>
111-
<true/>
112-
```
113-
114-
</p>
115-
</details>
116-
11784
### Requirements (ARM Mac)
11885

119-
- QEMU with `--accel=hvf` support, see https://gist.github.com/citruz/9896cd6fb63288ac95f81716756cb9aa
86+
- QEMU with `--accel=hvf` support, see https://gist.github.com/nrjdalal/e70249bb5d2e9d844cc203fd11f74c55
12087

12188
> **NOTE**
122-
> Lima is not tested on ARM Mac.
89+
> Lima is not regularly tested on ARM Mac.
12390
12491
### Install
12592

@@ -129,6 +96,22 @@ and extract it under `/usr/local` (or somewhere else).
12996
To install from the source, run `make && make install`.
13097

13198
### Usage
99+
100+
Terminal 1:
101+
```console
102+
[macOS]$ limactl start
103+
...
104+
INFO[0029] READY. Run `lima` to open the shell.
105+
```
106+
107+
Terminal 2:
108+
```console
109+
[macOS]$ lima uname
110+
Linux
111+
```
112+
113+
Detailed usage:
114+
132115
- Run `limactl start <INSTANCE>` to start the Linux instance.
133116
The default instance name is "default".
134117
Lima automatically opens an editor (`vi`) for reviewing and modifying the configuration.
@@ -156,7 +139,7 @@ Especially, the following data might be easily lost:
156139

157140
### Configuration
158141

159-
See [`./pkg/limayaml/default.TEMPLATE.yaml`](./pkg/limayaml/default.TEMPLATE.yaml).
142+
See [`./pkg/limayaml/default.yaml`](./pkg/limayaml/default.yaml).
160143

161144
The current default spec:
162145
- OS: Ubuntu 21.04 (Hirsute Hippo)
@@ -183,16 +166,41 @@ The current default spec:
183166

184167
### Help wanted
185168
:pray:
186-
- Test on ARM Mac
169+
- [Test on ARM Mac](https://github.com/AkihiroSuda/lima/issues/42)
187170
- Performance optimization
188-
- Homebrew
171+
- [Homebrew](https://github.com/AkihiroSuda/lima/issues/37)
189172
- More guest distros
190173
- Windows hosts
191174
- GUI with system tray icon (Qt or Electron, for portability)
192-
- VirtFS to replace the current reverse sshfs (work has to be done on QEMU repo)
175+
- [VirtFS to replace the current reverse sshfs (work has to be done on QEMU repo)](https://github.com/NixOS/nixpkgs/pull/122420)
193176
- [vsock](https://github.com/apple/darwin-xnu/blob/xnu-7195.81.3/bsd/man/man4/vsock.4) to replace SSH (work has to be done on QEMU repo)
194177

195178
## FAQs & Troubleshooting
179+
<!-- doctoc: https://github.com/thlorenz/doctoc -->
180+
181+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
182+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
183+
### Generic
184+
185+
- [Generic](#generic)
186+
- ["What's my login password?"](#whats-my-login-password)
187+
- ["Does Lima work on ARM Mac?"](#does-lima-work-on-arm-mac)
188+
- ["Can I run non-Ubuntu guests?"](#can-i-run-non-ubuntu-guests)
189+
- ["Can I run other container engines such as Podman?"](#can-i-run-other-container-engines-such-as-podman)
190+
- ["Can I run Lima with a remote Linux machine?"](#can-i-run-lima-with-a-remote-linux-machine)
191+
- ["Advantages compared to Docker for Mac?"](#advantages-compared-to-docker-for-mac)
192+
- [QEMU](#qemu)
193+
- ["QEMU crashes with `HV_ERROR`"](#qemu-crashes-with-hv_error)
194+
- ["QEMU is slow"](#qemu-is-slow)
195+
- [error "killed -9"](#error-killed--9)
196+
- [SSH](#ssh)
197+
- ["Port forwarding does not work"](#port-forwarding-does-not-work)
198+
- [error "field SSHPubKeys must be set"](#error-field-sshpubkeys-must-be-set)
199+
- [error "hostkeys_foreach failed: No such file or directory"](#error-hostkeys_foreach-failed-no-such-file-or-directory)
200+
- [error "failed to execute script ssh: [...] Permission denied (publickey)"](#error-failed-to-execute-script-ssh--permission-denied-publickey)
201+
- ["Hints for debugging other problems?"](#hints-for-debugging-other-problems)
202+
203+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
196204
### Generic
197205
#### "What's my login password?"
198206
Password is disabled and locked by default.
@@ -201,7 +209,7 @@ You have to use `limactl shell bash` (or `lima bash`) to open a shell.
201209
Alternatively, you may also directly ssh into the guest: `ssh -p 60022 -o NoHostAuthenticationForLocalhost=yes 127.0.0.1`.
202210

203211
#### "Does Lima work on ARM Mac?"
204-
Yes, it should work, but not tested on ARM.
212+
Yes, it should work, but not regularly tested on ARM.
205213

206214
#### "Can I run non-Ubuntu guests?"
207215
Fedora is also known to work, see [`./examples/fedora.yaml`](./examples/fedora.yaml).
@@ -211,7 +219,6 @@ An image has to satisfy the following requirements:
211219
- systemd
212220
- cloud-init
213221
- The following binaries to be preinstalled:
214-
- `curl`
215222
- `sudo`
216223
- The following binaries to be preinstalled, or installable via the package manager:
217224
- `sshfs`
@@ -230,17 +237,49 @@ the predecessor or Lima, provides similar features for remote Linux machines.
230237
e.g., run `sshocker -v /Users/foo:/home/foo/mnt -p 8080:80 <USER>@<HOST>` to expose `/Users/foo` to the remote machine as `/home/foo/mnt`,
231238
and forward `localhost:8080` to the port 80 of the remote machine.
232239

240+
#### "Advantages compared to Docker for Mac?"
241+
Lima is free software (Apache License 2.0), while Docker for Mac is not.
242+
Their [EULA](https://www.docker.com/legal/docker-software-end-user-license-agreement) even prohibits disclosure of benchmarking result.
243+
244+
On the other hand, [Moby](https://github.com/moby/moby), aka Docker for Linux, is free software, but Moby/Docker lacks several novel features of containerd, such as:
245+
- [On-demand image pulling (aka lazy-pulling, eStargz)](https://github.com/containerd/nerdctl/blob/master/docs/stargz.md)
246+
- [Running an encrypted container](https://github.com/containerd/nerdctl/blob/master/docs/ocicrypt.md)
247+
- Importing and exporting [local OCI archives](https://github.com/opencontainers/image-spec/blob/master/image-layout.md)
248+
233249
### QEMU
234250
#### "QEMU crashes with `HV_ERROR`"
235-
You have to add `com.apple.security.hypervisor` entitlement to `qemu-system-x86_64` binary.
236-
See [Getting started](#getting-started).
251+
If you have installed QEMU v6.0.0 or later on macOS 11 via homebrew, your QEMU binary should have been already automatically signed to enable HVF acceleration.
252+
253+
However, if you see `HV_ERROR`, you might need to sign the binary manually.
254+
255+
```bash
256+
cat >entitlements.xml <<EOF
257+
<?xml version="1.0" encoding="UTF-8"?>
258+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
259+
<plist version="1.0">
260+
<dict>
261+
<key>com.apple.security.hypervisor</key>
262+
<true/>
263+
</dict>
264+
</plist>
265+
EOF
266+
267+
codesign -s - --entitlements entitlements.xml --force /usr/local/bin/qemu-system-x86_64
268+
```
269+
270+
Note: **Only** on macOS versions **before** 10.15.7 you might need to add this entitlement in addition:
271+
272+
```
273+
<key>com.apple.vm.hypervisor</key>
274+
<true/>
275+
```
237276

238277
#### "QEMU is slow"
239-
- Make sure that HVF is enabled with `com.apple.security.hypervisor` entitlement. See [Getting started](#getting-started).
278+
- Make sure that HVF is enabled with `com.apple.security.hypervisor` entitlement. See ["QEMU crashes with `HV_ERROR`"](#qemu-crashes-with-hv_error).
240279
- Emulating non-native machines (ARM-on-Intel, Intel-on-ARM) is slow by design.
241280

242281
#### error "killed -9"
243-
- make sure qemu is codesigned, see [Getting started](#getting-started).
282+
- make sure qemu is codesigned, See ["QEMU crashes with `HV_ERROR`"](#qemu-crashes-with-hv_error).
244283
- if you are on macOS 10.15.7 or 11.0 or later make sure the entitlement `com.apple.vm.hypervisor` is **not** added. It only works on older macOS versions. You can clear the codesigning with `codesign --remove-signature /usr/local/bin/qemu-system-x86_64` and [start over](#getting-started).
245284

246285

cmd/lima-guestagent/daemon_linux.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@ import (
1616
)
1717

1818
var daemonCommand = &cli.Command{
19-
Name: "daemon",
20-
Usage: "run the daemon",
21-
ArgsUsage: "[SOCKET]",
19+
Name: "daemon",
20+
Usage: "run the daemon",
2221
Flags: []cli.Flag{
2322
&cli.StringFlag{
2423
Name: "socket",

docs/internal.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ An instance directory contains the following files:
88
- `cidata.iso`: cloud-init ISO9660 image. (`user-data`, `meta-data`, `lima-guestagent.Linux-<ARCH>`)
99
- `basedisk`: the base image
1010
- `diffdisk`: the diff image (QCOW2)
11-
- `qemu-pid`: PID of the QEMU
11+
- `qemu.pid`: PID of the QEMU
1212
- `ssh.sock`: SSH control master socket
1313
- `ga.sock`: Forwarded to `/run/user/$UID/lima-guestagent.sock`
1414
- `serial.log`: QEMU serial log, for debugging

examples/default.TEMPLATE.yaml

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/default.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../pkg/limayaml/default.yaml

pkg/guestagent/api/client/client.go

Lines changed: 5 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,10 @@ import (
77
"context"
88
"encoding/json"
99
"fmt"
10-
"io"
11-
"io/ioutil"
12-
"net"
1310
"net/http"
14-
"os"
1511

1612
"github.com/AkihiroSuda/lima/pkg/guestagent/api"
17-
"github.com/pkg/errors"
13+
"github.com/AkihiroSuda/lima/pkg/httpclientutil"
1814
)
1915

2016
type GuestAgentClient interface {
@@ -26,17 +22,10 @@ type GuestAgentClient interface {
2622
// NewGuestAgentClient creates a client.
2723
// socketPath is a path to the UNIX socket, without unix:// prefix.
2824
func NewGuestAgentClient(socketPath string) (GuestAgentClient, error) {
29-
if _, err := os.Stat(socketPath); err != nil {
25+
hc, err := httpclientutil.NewHTTPClientWithSocketPath(socketPath)
26+
if err != nil {
3027
return nil, err
3128
}
32-
hc := &http.Client{
33-
Transport: &http.Transport{
34-
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
35-
var d net.Dialer
36-
return d.DialContext(ctx, "unix", socketPath)
37-
},
38-
},
39-
}
4029
return NewGuestAgentClientWithHTTPClient(hc), nil
4130
}
4231

@@ -62,19 +51,11 @@ func (c *client) HTTPClient() *http.Client {
6251

6352
func (c *client) Info(ctx context.Context) (*api.Info, error) {
6453
u := fmt.Sprintf("http://%s/%s/info", c.dummyHost, c.version)
65-
req, err := http.NewRequest("GET", u, nil)
66-
if err != nil {
67-
return nil, err
68-
}
69-
req = req.WithContext(ctx)
70-
resp, err := c.HTTPClient().Do(req)
54+
resp, err := httpclientutil.Get(ctx, c.HTTPClient(), u)
7155
if err != nil {
7256
return nil, err
7357
}
7458
defer resp.Body.Close()
75-
if err := successful(resp); err != nil {
76-
return nil, err
77-
}
7859
var info api.Info
7960
dec := json.NewDecoder(resp.Body)
8061
if err := dec.Decode(&info); err != nil {
@@ -85,19 +66,11 @@ func (c *client) Info(ctx context.Context) (*api.Info, error) {
8566

8667
func (c *client) Events(ctx context.Context, onEvent func(api.Event)) error {
8768
u := fmt.Sprintf("http://%s/%s/events", c.dummyHost, c.version)
88-
req, err := http.NewRequest("GET", u, nil)
89-
if err != nil {
90-
return err
91-
}
92-
req = req.WithContext(ctx)
93-
resp, err := c.HTTPClient().Do(req)
69+
resp, err := httpclientutil.Get(ctx, c.HTTPClient(), u)
9470
if err != nil {
9571
return err
9672
}
9773
defer resp.Body.Close()
98-
if err := successful(resp); err != nil {
99-
return err
100-
}
10174
var ev api.Event
10275
dec := json.NewDecoder(resp.Body)
10376
for {
@@ -107,56 +80,3 @@ func (c *client) Events(ctx context.Context, onEvent func(api.Event)) error {
10780
onEvent(ev)
10881
}
10982
}
110-
111-
func readAtMost(r io.Reader, maxBytes int) ([]byte, error) {
112-
lr := &io.LimitedReader{
113-
R: r,
114-
N: int64(maxBytes),
115-
}
116-
b, err := ioutil.ReadAll(lr)
117-
if err != nil {
118-
return b, err
119-
}
120-
if lr.N == 0 {
121-
return b, errors.Errorf("expected at most %d bytes, got more", maxBytes)
122-
}
123-
return b, nil
124-
}
125-
126-
// HTTPStatusErrorBodyMaxLength specifies the maximum length of HTTPStatusError.Body
127-
const HTTPStatusErrorBodyMaxLength = 64 * 1024
128-
129-
// HTTPStatusError is created from non-2XX HTTP response
130-
type HTTPStatusError struct {
131-
// StatusCode is non-2XX status code
132-
StatusCode int
133-
// Body is at most HTTPStatusErrorBodyMaxLength
134-
Body string
135-
}
136-
137-
// Error implements error.
138-
// If e.Body is a marshalled string of api.ErrorJSON, Error returns ErrorJSON.Message .
139-
// Otherwise Error returns a human-readable string that contains e.StatusCode and e.Body.
140-
func (e *HTTPStatusError) Error() string {
141-
if e.Body != "" && len(e.Body) < HTTPStatusErrorBodyMaxLength {
142-
var ej api.ErrorJSON
143-
if json.Unmarshal([]byte(e.Body), &ej) == nil {
144-
return ej.Message
145-
}
146-
}
147-
return fmt.Sprintf("unexpected HTTP status %s, body=%q", http.StatusText(e.StatusCode), e.Body)
148-
}
149-
150-
func successful(resp *http.Response) error {
151-
if resp == nil {
152-
return errors.New("nil response")
153-
}
154-
if resp.StatusCode/100 != 2 {
155-
b, _ := readAtMost(resp.Body, HTTPStatusErrorBodyMaxLength)
156-
return &HTTPStatusError{
157-
StatusCode: resp.StatusCode,
158-
Body: string(b),
159-
}
160-
}
161-
return nil
162-
}

0 commit comments

Comments
 (0)