Skip to content

Commit

Permalink
Merge pull request #6 from seek-oss/build-args
Browse files Browse the repository at this point in the history
Support --build-arg options
  • Loading branch information
72636c authored Mar 14, 2019
2 parents 08fed75 + a76423c commit 8e0bf18
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 47 deletions.
113 changes: 75 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,90 +1,127 @@
# Docker ECR Cache
# Docker ECR Cache Buildkite Plugin

A [Buildkite plugin](https://buildkite.com/docs/agent/v3/plugins) to build and cache entire docker images in ECR.
[![GitHub Release](https://img.shields.io/github/release/seek-oss/docker-ecr-cache-buildkite-plugin.svg)](https://github.com/seek-oss/docker-ecr-cache-buildkite-plugin/releases)

This allows you to define a Dockerfile for your build-time dependencies without worrying about the time it
takes to build the image. It allows you to re-use entire docker images without worrying about layer caching, and/or pruning
layers as changes are made to your containers.
A [Buildkite plugin](https://buildkite.com/docs/agent/v3/plugins) to cache
Docker images in Amazon ECR.

An ECR repository to store the built docker image will be created for you, if one doesn't already exist.
This allows you to define a Dockerfile for your build-time dependencies without
worrying about the time it takes to build the image. It allows you to re-use
entire Docker images without worrying about layer caching, and/or pruning layers
as changes are made to your containers.

# Example
An ECR repository to store the built Docker image will be created for you, if
one doesn't already exist.

## Basic Usage
## Example

Dockerfile
```
### Basic usage

```dockerfile
FROM bash

RUN echo "my expensive build step"
```

```yml
```yaml
steps:
- command: 'echo wow'
plugins:
- seek-oss/docker-ecr-cache#v1.1.1
- docker#v2.0.0
- seek-oss/docker-ecr-cache#v1.1.3
- docker#v3.0.1
```
## Caching NPM Packages
### Caching npm packages
This plugin can be used to effectively cache `node_modules` between builds without worrying abbout
docker layer cache invalidation. You do this by hinting when the image should be re-built.
This plugin can be used to effectively cache `node_modules` between builds
without worrying about Docker layer cache invalidation. You do this by hinting
when the image should be re-built.

```dockerfile
FROM node:10-alpine
Dockerfile
```
FROM node:8
WORKDIR /workdir
COPY package.json package-lock.json /workdir
# this step downloads the internet
RUN npm install
```

```yml
```yaml
steps:
- command: 'npm test'
plugins:
- seek-oss/docker-ecr-cache#v1.1.1:
- seek-oss/docker-ecr-cache#v1.1.3:
cache-on:
- package-lock.json
- docker#v2.0.0
- docker#v3.0.1:
volumes:
- /workdir/node_modules
```

## Using Another Dockerfile
### Using another Dockerfile

It's possible to specify the Dockerfile to use by:

```yml
```yaml
steps:
- command: 'echo wow'
plugins:
- seek-oss/docker-ecr-cache#v1.1.1:
- seek-oss/docker-ecr-cache#v1.1.3:
dockerfile: my-dockerfile
- docker#v2.0.0
- docker#v3.0.1
```

## Specifying a target step
### Specifying a target step

A [multi-stage Docker build](https://docs.docker.com/develop/develop-images/multistage-build/) can be used to reduce an application container to just its runtime dependencies.
However, this stripped down container may not have the environment necessary for running CI commands such as tests or linting.
Instead, the `target` property can be used to specify an intermediate build stage to run commands against:
A [multi-stage Docker build] can be used to reduce an application container to
just its runtime dependencies. However, this stripped down container may not
have the environment necessary for running CI commands such as tests or linting.
Instead, the `target` property can be used to specify an intermediate build
stage to run commands against:

```yml
[multi-stage docker build]: https://docs.docker.com/develop/develop-images/multistage-build/

```yaml
steps:
- command: 'cargo test'
plugins:
- seek-oss/docker-ecr-cache#v1.1.1:
- seek-oss/docker-ecr-cache#v1.1.3:
target: build-deps
- docker#v2.0.0
- docker#v3.0.1
```

# Tests
### Specifying build args

[Build-time variables] are supported, either with an explicit value, or without
one to propagate an environment variable from the pipeline step:

To run the tests of this plugin, run
```sh
docker-compose run --rm tests
[build-time variables]: https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg

```dockerfile
FROM bash
ARG ARG_1
ARG ARG_2
RUN echo "${ARG_1}"
RUN echo "${ARG_2}"
```

```yaml
steps:
- command: 'echo amaze'
env:
ARG_1: wow
plugins:
- seek-oss/docker-ecr-cache#v1.1.3:
build-args:
- ARG_1
- ARG_2=such
- docker#v3.0.1
```

# License
## License

MIT (see [LICENSE](LICENSE))
55 changes: 50 additions & 5 deletions hooks/pre-command
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,53 @@ upsert_ecr() {
fi
}

read_build_args() {
read_list_property 'BUILD_ARGS'
for arg in ${result[@]+"${result[@]}"}; do
build_args+=('--build-arg' "${arg}")
done
}

# read a plugin property of type [array, string] into a Bash array. Buildkite
# exposes a string value at BUILDKITE_PLUGIN_{NAME}_{KEY}, and array values at
# BUILDKITE_PLUGIN_{NAME}_{KEY}_{IDX}.
read_list_property() {
local base_name="BUILDKITE_PLUGIN_DOCKER_ECR_CACHE_${1}"

result=()

if [[ -n ${!base_name:-} ]]; then
result+=("${!base_name}")
fi

while IFS='=' read -r item_name _; do
if [[ ${item_name} =~ ^(${base_name}_[0-9]+) ]]; then
result+=("${!item_name}")
fi
done < <(env | sort)
}

compute_tag() {
local docker_file="$1"
local sums

sums="$(sha1sum "${docker_file}")"

while IFS='=' read -r name _ ; do
if [[ ${name} =~ ^(BUILDKITE_PLUGIN_DOCKER_ECR_CACHE_CACHE_ON_[0-9]+) ]] ; then
sums="${sums}$(sha1sum "${!name}")"
read_list_property 'BUILD_ARGS'
for arg in ${result[@]+"${result[@]}"}; do
# include underlying environment variable
if [[ ${arg} != *=* ]]; then
arg+="=${!arg:-}"
fi
done < <(env | sort)

sums+="$(echo "${arg}" | sha1sum)"
done

read_list_property 'CACHE_ON'
for file in ${result[@]+"${result[@]}"}; do
sums+="$(sha1sum "${file}")"
done

echo "${sums}" | sha1sum | cut -c-7
}

Expand All @@ -52,9 +88,18 @@ if [[ -n ${BUILDKITE_PLUGIN_DOCKER_ECR_CACHE_TARGET:-} ]]; then
target_args+=('--target' "${BUILDKITE_PLUGIN_DOCKER_ECR_CACHE_TARGET}")
fi

build_args=()
read_build_args

if ! docker pull "${image}:${tag}"; then
echo '--- Building image'
docker build . --file "${docker_file}" --tag "${image}:${tag}" "${target_args[@]}" || exit 1
docker build \
--file "${docker_file}" \
--tag "${image}:${tag}" \
${build_args[@]+"${build_args[@]}"} \
${target_args[@]+"${target_args[@]}"} \
. || exit 1

docker tag "${image}:${tag}" "${image}:latest"

echo "--- Pushing tag ${tag}"
Expand Down
10 changes: 6 additions & 4 deletions plugin.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
name: docker-ecr-cache
description: Plugin for building and caching images to AWS ECR
name: Docker ECR Cache
description: Cache Docker images in Amazon ECR
author: https://github.com/seek-oss
requirements:
- docker
configuration:
properties:
build-args:
type: [array, string]
cache-on:
type: [array, string]
dockerfile:
type: string
cache-on:
type: array
ecr-name:
type: string
target:
Expand Down

0 comments on commit 8e0bf18

Please sign in to comment.