github.com/thriqon/involucro@v1.1.3/README.md (about)

     1  
     2  # Involucro - Build and Deliver Software with Containers
     3  
     4  [![Build Status](https://travis-ci.org/involucro/involucro.svg?branch=master)](https://travis-ci.org/involucro/involucro)
     5  [![Build Status](https://semaphoreci.com/api/v1/thriqon/involucro/branches/master/badge.svg)](https://semaphoreci.com/involucro/involucro)
     6  [![Build status](https://ci.appveyor.com/api/projects/status/ice63amutmub3qqr/branch/master?svg=true)](https://ci.appveyor.com/project/JonasWeber/involucro/branch/master)
     7  [![Go Report Card](https://goreportcard.com/badge/github.com/involucro/involucro)](https://goreportcard.com/report/github.com/involucro/involucro)
     8  [![Gitter](https://badges.gitter.im/involucro/involucro.svg)](https://gitter.im/involucro/involucro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
     9  
    10  ## Demo
    11  
    12  [![asciicast](https://asciinema.org/a/37622.png)](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