diff --git a/.gitignore b/.gitignore index 37268f75..0f5b832f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ _book # Built images *.img +*.tar \ No newline at end of file diff --git a/cmd/eli/buildNodeCommand.go b/cmd/eli/buildNodeCommand.go index 1e45b684..69afd33b 100644 --- a/cmd/eli/buildNodeCommand.go +++ b/cmd/eli/buildNodeCommand.go @@ -3,6 +3,7 @@ package main import ( "fmt" "io" + "log" "os" "github.com/ernoaapa/eliot/pkg/cmd" @@ -18,7 +19,7 @@ var buildNodeCommand = cli.Command{ Usage: "Build node image", UsageText: `eli build node [options] [FILE | URL] - # Build default node image + # Build default node disk img -file eli build node # Create Linuxkit file but don't build it @@ -27,7 +28,7 @@ var buildNodeCommand = cli.Command{ # Build from custom config and unpack to directory mkdir dist - eli build node custom-linuxkit.yml | tar xv -C dist + eli build node custom-linuxkit.yml --format tar | tar xv -C dist `, Flags: []cli.Flag{ cli.BoolFlag{ @@ -42,22 +43,27 @@ var buildNodeCommand = cli.Command{ }, cli.StringFlag{ Name: "output", - Usage: "Target output file", - Value: "image.tar", + Usage: "Target output file. (default: eliot-os.tar or eliot-os.img)", }, cli.StringFlag{ Name: "type", Usage: "Target build type, one of Linuxkit output types", Value: "rpi3", }, + cli.StringFlag{ + Name: "format", + Usage: "Target output format. One of [tar, img] (default: img)", + Value: "img", + }, }, Action: func(clicontext *cli.Context) (err error) { var ( - source = clicontext.Args().First() - dryRun = clicontext.Bool("dry-run") - serverURL = clicontext.String("build-server") - outputFile = clicontext.String("output") - outputType = clicontext.String("type") + source = clicontext.Args().First() + dryRun = clicontext.Bool("dry-run") + serverURL = clicontext.String("build-server") + outputType = clicontext.String("type") + outputFormat = clicontext.String("format") + outputFile = getBuildOutputFile(outputFormat, clicontext.String("output")) uiline ui.Line linuxkit []byte @@ -93,7 +99,7 @@ var buildNodeCommand = cli.Command{ } uiline = ui.NewLine().Loadingf("Building Linuxkit image in remote build server...") - image, err := build.BuildImage(serverURL, outputType, linuxkit) + image, err := build.BuildImage(serverURL, outputType, outputFormat, linuxkit) if err != nil { uiline.Errorf("Failed to build Linuxkit image: %s", err) return errors.Wrap(err, "Failed to build Linuxkit image") @@ -110,3 +116,19 @@ var buildNodeCommand = cli.Command{ return nil }, } + +func getBuildOutputFile(format, outputFile string) string { + if outputFile != "" { + return outputFile + } + + switch format { + case "img": + return "eliot-os.img" + case "tar": + return "eliot-os.tar" + default: + log.Fatalf("Unknown output format %s, cannot resolve default output file", format) + return "" + } +} diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index d1dd6903..00992df4 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -22,7 +22,7 @@ * [eli delete pod](client.md#eli-delete-pod-pod-name) * [eli exec](client.md#eli-exec---container-id-pod-name----command) * [eli attach](client.md#eli-attach--i---container-id-pod-name) - * [eli build device](client.md#eli-build-device) + * [eli build device](client.md#eli-build-device---format-img--tar) * [Configuration](configuration.md) * [Pod Specification](configuration.md#pod-specification) * [Project Configuration](configuration.md#project-configuration) diff --git a/docs/client.md b/docs/client.md index a73fabcf..622bf615 100644 --- a/docs/client.md +++ b/docs/client.md @@ -280,16 +280,16 @@ Hello world! You can also give `-i` flag to hook up your stdin into the container, but watch out, if you for example press ^C (ctrl+c) to exit, you actually send kill signal to the process in the container which will stop the container. -## `eli build device` +## `eli build device [--format img | tar]` Easiest way to run Eliot in your device is to use [EliotOS](https://github.com/ernoaapa/eliot-os) which is minimal Operating System where's just minimal components installed to run Eliot and everything else run on top of the Eliot in containers. -With `eli build device` command you can build EliotOS image that you can just unpack to your device sdcard. +With `eli build device` command you can build EliotOS image that you can just write to your device sdcard. > Note: At the moment we support only RaspberryPi 3b, for other devices [see installation guide](installation.md) ```shell **[terminal] -**[prompt ernoaapa@mac]**[path ~]**[delimiter $ ]**[command eli build device > my-image.tar] +**[prompt ernoaapa@mac]**[path ~]**[delimiter $ ]**[command eli build device > my-image.img] ``` [EliotOS](https://github.com/ernoaapa/eliot-os) is built with [Linuxkit]([EliotOS](https://github.com/ernoaapa/eliot-os) and you can view the Linuxkit configuration with `--dry-run` flag. @@ -298,7 +298,7 @@ With `eli build device` command you can build EliotOS image that you can just un **[terminal] **[prompt ernoaapa@mac]**[path ~]**[delimiter $ ]**[command eli build device --dry-run] ✓ Resolved Linuxkit config! - ✓ Resolved output: image.tar! + ✓ Resolved output: image.img! kernel: image: linuxkit/kernel:4.9.72 cmdline: "console=tty0 console=ttyS0 console=ttyAMA0" @@ -374,7 +374,7 @@ If you want to customise the Linuxkit configuration before building **[terminal] **[prompt ernoaapa@mac]**[path ~]**[delimiter $ ]**[command eli build device --dry-run > custom-linuxkit.yml] # Edit the my-custom-linuxkit.yml -file... -**[prompt ernoaapa@mac]**[path ~]**[delimiter $ ]**[command eli build device custom-linuxkit.yml > custom-image.tar] +**[prompt ernoaapa@mac]**[path ~]**[delimiter $ ]**[command eli build device custom-linuxkit.yml > custom-image.img] ``` #### Shell piping @@ -400,7 +400,7 @@ files: ```shell **[terminal] **[prompt ernoaapa@mac]**[path ~]**[delimiter $ ]**[command sed -e "s/\MY-HOSTNAME/eliot-$(date +%s)/" custom-linuxkit.yml \ - | eli build device \ + | eli build device --format tar \ | tar xv -C /Volumes/raspberrypi3] ``` @@ -410,6 +410,6 @@ _Pretty handy, ain't it? :D_ #### How it works? Linuxkit doesn't support building arm images on x86, but RaspberryPi is arm based computer. -For building images, Eliot hosts [Linuxkit build server](https://github.com/ernoaapa/linuxkit-server) and when you execute `eli build device`, it sends the config to `build.eliot.run` server, which builds the image on arm server and send it back as tar package. +For building images, Eliot hosts [Linuxkit build server](https://github.com/ernoaapa/linuxkit-server) and when you execute `eli build device`, it sends the config to `build.eliot.run` server, which builds the image on arm server and send it back as either disk image (.img) or tar package (.tar). If you want to host and use your own build server, see the [Linuxkit build server documentation](https://github.com/ernoaapa/linuxkit-server) and pass `--build-server http://my-custom-build-server.com` flag to build the image in your own server. \ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md index 51698778..53db8aa0 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -23,15 +23,37 @@ There's three options for device installation ### EliotOS on RaspberryPI3 By far the easiest and most secure way to use Eliot is by using [EliotOS](eliotos.md). EliotOS is minimal Linux Operating System, built with [linuxkit](https://github.com/linuxkit/linuxkit), which contains only minimal components to run Eliot which are Linux kernel, `runc`, `containerd` and `eliotd` daemon. Check the [EliotOS](eliotos.md) section for more info. -`eli` provides [build command](client.md#eli-build-device) to build [EliotOS](eliotos.md) for RaspberryPI3 and install it to the sdcard. +`eli` provides [build command](client.md#eli-build-device) to build [EliotOS](eliotos.md) for RaspberryPI3 and install it to the sdcard. There's few different ways to do it, depending on your preferences. -1. Format sdcard as you would normally -2. Mount it to for example `/Volumes/rpi3` -3. Build image and unpack it to the directory `eli build device | tar xv -C /Volumes/rpi3` +#### a) Write image with Etcher +[Etcher](https://etcher.io/) is really handy desktop app for Win, Mac and Linux for writing img -files to sdcards. +1. Install [Etcher](https://etcher.io/) +2. Build image file `eli build device` +3. Start Etcher and select created `eliot-os.img` as the source and your sdcard drive as target + +### b) Write iamge with `dd` +If you're for example writing the image in headless server and you don't want to use any gui, you can write the image with `dd` + +**WARNING! With dd tool can overwrite any partition of your machine, for example your primary OS partition! Use only if you know what you do.** + +1. Connect your sdcard and resolve what device is the card (in this example it's `disk3`) +2. Unmount the disk (but keep connected) +3. Build img-file `eli build device` +4. Write to card `sudo dd bs=1m if=eliot-os.img of=/dev/rdisk3 conv=sync` + +#### c) Write disk manually +You can also build the disk manually, if none of above suite to you. + +1. Format sdcard as FAT32 and name it for example `rpi3` +2. Mount it to for example `/Volumes/rpi3` (Mac does this automatically) +3. Build image and unpack it to the sdcard `eli build device --format tar | tar xv -C /Volumes/rpi3` 4. Unmount the disk -5. Connect RaspberryPI with ethernet cable to same network with your laptop and power on! -6. In less than 10s you should see the device with command `eli get devices` -7. And that's it! ☺ + +#### Boot up! +Now just connect RaspberryPI with ethernet cable to same network with your laptop and power on! +In less than 10s you should see the device with command `eli get devices`. + +And that's it! ☺ Next step is to follow [getting started guide](getting_started.md#deploy-first-app) and deploy first app! diff --git a/pkg/cmd/build/utils.go b/pkg/cmd/build/utils.go index 33982aea..49d9c413 100644 --- a/pkg/cmd/build/utils.go +++ b/pkg/cmd/build/utils.go @@ -50,8 +50,8 @@ func ResolveLinuxkitConfig(source string) (linuxkit []byte, err error) { // BuildImage builds given Linuxkit config and returns the image as io.ReadClose or error // Note: you must call image.Close() -func BuildImage(serverURL, outputType string, config []byte) (io.ReadCloser, error) { - res, err := http.Post(fmt.Sprintf("%s/linuxkit/%s/build/%s", serverURL, "eli-cli", outputType), "application/yml", bytes.NewReader(config)) +func BuildImage(serverURL, outputType, outputFormat string, config []byte) (io.ReadCloser, error) { + res, err := http.Post(fmt.Sprintf("%s/linuxkit/%s/build/%s?output=%s", serverURL, "eli-cli", outputType, outputFormat), "application/yml", bytes.NewReader(config)) if err != nil { return nil, errors.Wrap(err, "Error while making request to Linuxkit build server") } diff --git a/pkg/cmd/build/utils_test.go b/pkg/cmd/build/utils_test.go index e4b933bc..13669259 100644 --- a/pkg/cmd/build/utils_test.go +++ b/pkg/cmd/build/utils_test.go @@ -57,7 +57,7 @@ func TestBuildImage(t *testing.T) { })) defer ts.Close() - image, err := BuildImage(ts.URL, "rpi3", exampleLinuxkitConfig) + image, err := BuildImage(ts.URL, "rpi3", "img", exampleLinuxkitConfig) assert.NoError(t, err) tar, err := ioutil.ReadAll(image) @@ -73,6 +73,6 @@ func TestBuildImageReturnErrorMessage(t *testing.T) { })) defer ts.Close() - _, err := BuildImage(ts.URL, "rpi3", exampleLinuxkitConfig) + _, err := BuildImage(ts.URL, "rpi3", "tar", exampleLinuxkitConfig) assert.True(t, strings.Contains(err.Error(), "This is the error")) }