Push code to your containers - live!
Given a running container, this module will sync over any changes in the filesystem and perform the docker build within the container.
Note this module is not intended to be used directly, and instead provides a publc API for different frontends.
A notable frontend is balena-cli where it is used for live updates of local mode devices.
Given the following Dockerfile:
FROM debian
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY src/ src/
CMD node src/app.js
A change made to the package.json, for example
npm install --save express
will invalidate every step from
COPY package.json .
and cause a rebuild from there.
That would copy the new package.json into the container, run
npm install
, and move to the next stop. At the next step,
livepush would try to calculate of the files which have
changed, which should be synced into the container. Because
package.json
is not part of the src/
directory, nothing
will happen. After this the container will be restarted and
the CMD
step will run again.
We agree! Special case programs can be extremely fast, and livepush does not stop you from using them from within a container. To enable this, you can use live directives:
A live cmd, provided by the dev-cmd-live
direcitve, is the
command that gets executed in the container when this
container is running with livepush. It overrides the
existing CMD
in the Dockerfile. This is achieved with a
preprocess step on the Dockerfile.
FROM node
COPY package*.json ./
RUN npm install
#dev-cmd-live=webpack-dev-server
COPY ./src src
RUN npm run build
COPY nginx.conf .
CMD nginx
The above is a webpack based project which also describes how it should be run with livepush. Livepush will preprocess this Dockerfile to be the equivalent of:
FROM node
COPY package*.json ./
RUN npm install
CMD webpack-dev-server
COPY ./src src
COPY nginx.conf .
Now when this container is executed, the main process will be webpack-dev-server. Livepush will still copy in changed source files. Livepush will optionally restart the container based on a couple of rules:
- If the
COPY
step appears before the#dev-cmd-live
directive, livepush will restart the container after copying in a file which is specified in thatCOPY
step - If the
COPY
step appears after the#dev-cmd-live
directive, livepush will copy in the source file, but will not restart the container, and instead relies on the command specified by#dev-cmd-live
In this way, you can develop in a container, and have blazing fast restart speeds via the program of your choosing.
The behavior of a #dev-cmd-live
in a multistage image is
as follows:
- When the directive appears in the last stage, it is as described above.
- When the directive appears in any other stage, livepush will ignore any stages that follow.
For example:
FROM node AS build
COPY package*.json ./
RUN npm install
#dev-cmd-live=webpack-dev-server
COPY ./src src
RUN npm run build
FROM node
COPY --from=build /dist/app.js .
RUN nginx
will be preprocessed to:
FROM node AS build
COPY package*.json ./
RUN npm install
CMD webpack-dev-server
COPY ./src src
For this, you can use two other directives:
#dev-copy=
#dev-run=
These directives take exactly the same kind of arguments as their Dockerfile counterparts, but are only executed when the container is running as part of a livepush process.
Using these, it is possible to bring in any extra
dependencies that are useful when developing. For example,
you might choose to install webpack-dev-server using a
dev-run
directive to avoid specifying it inside your package.json.
static init({
dockerfileContent: string | Buffer,
context: string,
containerId: string,
stageImages: string[],
docker: Dockerode,
skipContainerRestart?: boolean,
}): Promise<Livepush>
Initialise a new Livepush instance with the dockerfile
content, the build context location on disk, the running
container ID, the IDs of the images created as part of a
possible multistage build ([]
for single stage
dockerfiles) and an initialised handle to a docker daemon
via Dockerode.
The skipContainerRestart
flag will stop livepush from
restarting the running container after performing a
livepush. This can be useful when the main process has some
kind of watch mode, for example webpack-dev-server
, or
node-supervisor
. Note that this is not necessary when
using the live directive.
performLivepush(
addedOrUpdated: string[],
deleted: string[],
): Promise<void> {
Provide the livepush instance with a list of files relative to the build context, and livepush will perfom any tasks necessary to get this code running remotely.
If a livepush process is already running, this will be cancelled, and the new one will start when the last executed command finishes (docker does not provide a way to cancel a command which is started by the api).
Can throw:
ContainerNotRunningError
- This is thrown when livepush tries to perform an action on any container that is no longer running.
cleanupIntermediateContainers();
For each stage in the Dockerfile which is not the final
stage, a container is created, to provide an environment in
which to copy any files and execute tasks. This function
will remove these containers. Note that once these
containers are removed, if performLivepush
is called
again, it will throw a ContainerNotRunningError
.
The livepush instance will emit events whilst performing a livepush. Note that these events are fully typed when using Typescript.
This function is called with an object { stageIdx: number, command: string }
and is called whenever a command is executed within a container. The
stageIdx
parameter represents the stage in the Dockerfile that this
executed in.
Whenever a command outputs data, this event will be called. The argument has the form:
{ stageIdx: number; output: CommandOutput }
where CommandOutput
has the structure:
{
data: Buffer;
isStderr: boolean;
}
When a command returns, this event will be called with the
following argument: { stageIdx: number; returnCode: number; command: string }
When a container is restarted this event is emitted with
argument { contianerId: string }
.
This event is emitted when an ongoing livepush process is cancelled.
- Add events for a livepush process starting and ending