github.com/thriqon/involucro@v1.1.3/README.md (about) 1 2 # Involucro - Build and Deliver Software with Containers 3 4 [](https://travis-ci.org/involucro/involucro) 5 [](https://semaphoreci.com/involucro/involucro) 6 [](https://ci.appveyor.com/project/JonasWeber/involucro/branch/master) 7 [](https://goreportcard.com/report/github.com/involucro/involucro) 8 [](https://gitter.im/involucro/involucro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 9 10 ## Demo 11 12 [](https://asciinema.org/a/37622) 13 14 The code for the example is in `examples/hello_world_server/`. 15 16 ## Introduction 17 18 Building and delivering software is a complex task that can be made easier 19 with proper encapsulation: Containers. They are able to pack all required 20 dependencies (bitwise version controlled) so that you can release code with the 21 confidence that everything works the same way it worked on the developers machine. 22 23 The current default for building and packing software into containers is using 24 *Dockerfiles*<sup>[1](#trademarks)</sup> offered by the 25 [DockerĀ®](https://www.docker.com) software. This, however, has several 26 structural disadvantages: 27 28 * Build Container is the Deliverable Container 29 * Only one-dimensional caching of build steps 30 * No support for slimmed containers 31 * Unnecessary layers 32 33 Involucro [from Latin for 'envelope'] detaches the build process from the 34 deliverable container and re-establishes proper encapsulation in containers: 35 One Process, One Container. 36 37 ## Installation 38 39 From source: 40 41 $ go get github.com/involucro/involucro/cmd/involucro 42 $ $GOPATH/bin/involucro --version 43 44 As binary for Linux: 45 [involucro](https://github.com/involucro/involucro/releases/download/latest/involucro) 46 47 Or, for Windows: 48 [involucro.exe](https://github.com/involucro/involucro/releases/download/latest/involucro.exe) 49 [involucro32.exe](https://github.com/involucro/involucro/releases/download/latest/involucro32.exe) 50 51 And for Mac OSX: 52 [involucro.darwin](https://github.com/involucro/involucro/releases/download/latest/involucro.darwin) 53 54 ## Usage 55 56 Involucro is configured by a Lua script file. By default, it is looking for 57 `invfile.lua` in the current directory, but this can be overridden (see below). 58 59 A configuration file contains a set of tasks identified by a unique name. 60 These names can be specified when invoking `involucro` and are executed in the 61 order they are given. For example, `$ involucro build package` will run the 62 `build` and afterwards the `package` task. A task can be created by invoking 63 `inv.task('<ID>')` in the configuration file. 64 65 For easy readability, the configuration file uses a fluent syntax to build the 66 tasks. The available methods are either modifying the next registered step, or 67 are registering a step. This type distinction is documented below for each 68 method. 69 70 **inv.task**`('<ID>')` (*modifier*) sets the task of the next registered step 71 to `<ID>`. It makes the methods `using`, `runTask`, and `wrap` available. 72 73 Each task consists of a list of steps that are run in the order they are given 74 in the file. There are different types of steps. Each step has one 75 *introductory* method made available from the task, a set of *modifying* 76 methods setting different properties of the step, and a final *registration* 77 method that registers these settings for execution. The current status can be 78 stored at any point into a variable and reused later. However, the steps are 79 strictly run in the order their registration method was called. 80 81 ### Run Step 82 83 A run step executes a Docker container. By default, the current working 84 directory is mounted as `/source` into the container which is also configured 85 to be the working directory of the process running in the container. It is 86 mainly used to transform source code using external processes such as compilers 87 into a different form. 88 89 **task.using**`('<IMAGE_ID>')` (*introductory*) starts off a run step by 90 specifying the repository name (optionally with tag) or the image ID of the 91 image to be run. Example: `task.using('gcc:4.9')`. 92 93 **runstep.withConfig**`(<TABLE>)` (*modifying*) sets the values in the Lua 94 table as configuration values for the Docker container. The values that can be 95 set here are only affecting the container itself, not how is connected with the 96 host. See *withHostConfig* for this. The options available are 97 [Config](https://godoc.org/github.com/fsouza/go-dockerclient#Config). The keys 98 are interpreted case insensitive. Example: `runstep.withConfig({Cmd = 99 {"/bin/echo", "Hello, World!"}})`. 100 101 **runstep.withHostConfig**`(<TABLE>)` (*modifying*) sets the values in the Lua 102 table as host configuration values. These values control the exact execution 103 semantics of the container from the hosts point of view. The available options 104 are documented here: 105 [HostConfig](https://godoc.org/github.com/fsouza/go-dockerclient#HostConfig). 106 Example: `runStep.withConfig({links = {"redis"}})`. 107 108 NOTE: By default, `involucro` binds the current directory as `/source`. If the 109 `Binds` key is set in the given table it overwrites this binding. `Involucro` 110 however interprets the given bindings and changes all relative source bindings 111 to absolute paths. This enables bindings such as `{binds = {"./dist:/data", 112 "/tmp:/tmp"}}`. 113 114 **runstep.withExpectation**`(<TABLE)` (*modifying*) registers expectations 115 towards the output and exit code of the process. By default, `involucro` 116 expects the process to exit cleanly with exit code `0`. Tests of executables 117 however may require expecting a process to fail. This can be set with the key 118 `code`: `runstep.withExpectation({code = 1})`. Similarly, an expectation 119 towards the output of the process on `stdout` and/or `stderr` can be registered 120 with regular expressions conforming to [Re2 121 syntax](https://github.com/google/re2/wiki/Syntax). Example: 122 `runstep.withExpectation({stdout = "Hello, World!\n"})`. 123 124 **runstep.run**(`'<CMD>'...`) (*registration*) registers the run step. The 125 arguments are used as the command-line arguments of the process being run. It 126 directly follows Docker semantics regarding process execution. Each argument is 127 used as a single argument for the process. Example: `runstep.run('/bin/echo', 128 'Hello, World!')`. Note that there is no wildcard expansion or variable 129 replacement if the arguments are not given to a shell, such as `/bin/sh`. 130 Example: `runstep.run('/bin/sh', '-c', 'echo *')`. 131 132 ### Wrap Step 133 134 A wrap step takes the contents of a directory and creates an image layer out of 135 it, optionally with a parent image layer and meta data. The resulting image can 136 be tagged into a repository with a tag name (or `latest`, if none is set). 137 138 **task.wrap**`('<SOURCE_DIR>')` (*introductory*) starts off a wrap step by 139 specifying the directory containing the files that are to be wrapped into an 140 image. It is also possible to use the current directory (`.`). Example: 141 `task.wrap('dist')`. 142 143 **wrapstep.at**`('<TARGET_DIR>')` (*modifying*) sets the directory in the resulting 144 image into which the files are copied. This can be used to put HTML files into 145 the location the web server in the parent image expects them to be. This 146 directory doesn't need to exist yet. Example: `wrapstep.at('/data')`. 147 148 **wrapstep.inImage**`('<PARENT_IMAGE>')` (*modifying*) causes the resulting image 149 to be a child of the image identified by the parameter. If this modification is 150 omitted the resulting image is parent-less. Example: 151 `wrapstep.inImage('nginx')`. 152 153 **wrapstep.withConfig**`(<TABLE>)` (*modifying*) sets configuration values similar 154 to the *withConfig* method of the run step above. This can be used to pre-set 155 an entrypoint or exposed ports. Example: `wrapstep.withConfig({exposedports = 156 {"80/tcp"}})`. 157 158 **wrapstep.as**`('<IMAGE_NAME>')` (*registration*) registers the step for 159 execution. The image constructed by the previous modifications is built and 160 tagged with the given name, which may include a registry designation. Example: 161 `wrapstep.as('app:latest')` 162 163 ### Runtask Step 164 165 As a convenience, it is possible to run another task as part of a task. This 166 emulates the conventional `all` task from `Makefile`s. Exceptionally, the 167 introductory method for this step is also the registration method. 168 169 **task.runTask**(`<ID>`) (*introductory registration*) registers a step that 170 executes the task with the given ID as part of the steps in this task. Example: 171 `inv.task('all').runTask('compile').runTask('package')`. 172 173 ### Tag Step 174 175 Sometimes, there should be two versions of the same image sharing the same 176 image ID, for example to have the `latest` tag equivalent to version `v2`. The 177 tag step helps in this case. 178 179 **task.tag**(`<NAME>`) (*introductory*) starts a tagging by setting the name of 180 the original image. This can be anything Docker accepts, including 181 `test/asd:v2`, but also actual image IDs. Example: `task.tag('test/asd')`. 182 183 **tagstep.as**(`<NAME>`) (*registration*) registers a step that tags the image 184 named in introductory method to the name given as parameter. Example: 185 `tagstep.as('test/asd')`. 186 187 ### Hook Step 188 189 Control files can change their behaviour during tasks with hooks, for example 190 to use the results of previous tasks with `io.lines`. 191 192 **task.hook**(`<FUNCTION>`) (*introductory registration*) registers a step 193 that, when taken, runs the given function. No arguments are passed, and any 194 return values are ignored. Example: `task.hook(function () print('in step') 195 end)`. 196 197 ### Push Step 198 199 Tagged images can be pushed to repositories where they can be pulled by other 200 users. This step may involve authentication, see below for details. 201 202 **task.push(`<NAME>`) (*introductory registration*) registers a step that, when 203 taken, pushes the image with the given name to a remote repository. Note that 204 the default Docker rules apply with regard to names: If a name starts with a 205 server address the image is pushed there, and if not Docker Hub is selected. 206 Example: `task.push('image:latest')` 207 208 ## Authentication 209 210 Pushes and pulls to a remote registry or to Docker Hub may be neccessary to be 211 authenticated. Involucro solves this by reading a JSON file in the home 212 directory of the current user called `.involucro`. This file (currently) only 213 contains information about authentication, but more uses may be introduced 214 later. 215 216 To configure username, password, and email place a file of the following form 217 into `$HOME/.involucro`: 218 219 ```json 220 { 221 "auths": [ 222 "https://USERNAME:PASSWORD@SERVER.COM/?email=EMAIL@EXAMPLE.COM" 223 ] 224 } 225 ``` 226 227 Multiple entries are possible, but only one per server. By definition, the 228 address for Docker Hub is `index.docker.io/v1/`, so the configuration for a 229 user *alice* with password *b0b* and email address *alice@devs.io* on Docker 230 Hub is: 231 232 ```json 233 { 234 "auths": [ 235 "https://alice:b0b@index.docker.io/v1/?email=alice@devs.io" 236 ] 237 } 238 ``` 239 240 Please keep this file hidden from any user except you as it contains the 241 password in plaintext! 242 243 ## Trademarks 244 245 DockerĀ® is a registered trademark of Docker, Inc. 246