Skip to content

Instantly share code, notes, and snippets.

@vaab vaab/docker-update
Last active Oct 19, 2018

Embed
What would you like to do?
docker-update
#!/bin/bash
## Updates an existing image with given script coming from stdin.
##
exname=$(basename $0)
usage="$exname DOCKER_IMAGE
Update image with stdin instruction.
"
if [ -z "$1" ]; then
echo "Error: you should specify a parent image as first argument." >&2
echo "usage: $usage"
exit 1
fi
image="$1"
shift
DOCKER_VERSION=$(docker -v | sed -r 's/^[^0-9.]+([0-9.]+).*$/\1/g')
is_cached_code_same() {
local cmd
cmd="$@"
code="$(cat -)"
[ "$1" == "-c" ] || return 1
[ "$2" == "$code" ] || return 1
if echo "$code" | egrep "#\s*docker:\s*ALWAYS\s*" >/dev/null 2>&1; then
return 1
fi
return 0
}
DOCKER_INSPECT_CACHE_FORMAT='{{.Id}}{{"\x00"}}
{{.Parent}}{{"\x00"}}
{{if .Config}}{{range $p := .Config.Cmd}}{{$p}}{{"\x00"}}
{{end}}{{end}}{{"\x00"}}'
DOCKER_INSPECT_CACHE_FORMAT="$(echo "$DOCKER_INSPECT_CACHE_FORMAT" | tr -d "\n")"
export DOCKER_INSPECT_CACHE_FORMAT
##
# check_cache PARENT_IMAGE
#
# Checks if no already stored image has PARENT_IMAGE as parent and
# same code. If it founds such an image, it'll output its id in stdout
# and return 0 errlvl. Otherwise it'll return 1 errlvl.
check_cache() {
local image
image="$1"
shift
code="$(cat -)"
image_id=$(get_image_id "$image")
while read-0 id parent; do
cmd=()
while true; do
read-0 elt
if [ "$elt" ]; then
cmd=("${cmd[@]}" "$elt")
else
break
fi
done
if [ "$parent" != "$image_id" ]; then
continue
fi
if echo "$code" | is_cached_code_same "${cmd[@]}"; then
## not used "$id" as there is a spurious \n that is inserted by --format
echo $id
return 0
fi
done < <(docker inspect --format "$DOCKER_INSPECT_CACHE_FORMAT" $(docker images -qa))
return 1
}
docker_update() {
local image
image="$1"
shift
code=$(cat -)
## Saving CMD and ENTRYPOINT
save_cmd=$(docker inspect --format='{{json .Config.Cmd}}' "$image")
save_entrypoint=$(docker inspect --format='{{json .Config.Entrypoint}}' "$image")
## Checking cache in case already built.
if cached=$(echo "$code" | check_cache "$image"); then
echo "cached"
docker tag "$cached" "$image"
else
## Running code in container
container_id=$(docker run -d \
--entrypoint /bin/bash \
"$@" "$image" -c \
"$code"
)
if [ "$(docker wait "$container_id")" != "0" ]; then
echo "Update of image "$image" failed ! (container: $container_id)"
echo "=== code:"
echo "$code"
echo "=== logs:"
docker logs "$container_id"
exit 1
fi
docker commit --author "$exname" --message "$exname" \
"$container_id" "$image" >/dev/null &&
docker rm $container_id >/dev/null
echo "updated"
fi
## Final commit to restore CMD and ENTRYPOINT
docker build -t "$image" - <<EOF >/dev/null 2>&1
FROM $image
CMD $save_cmd
ENTRYPOINT $save_entrypoint
EOF
}
read-0() {
while [ "$1" ]; do
IFS=$'\0' read -r -d '' "$1" || return 1
shift
done
}
get_image_id() {
docker inspect --format '{{.Id}}' "$1"
}
docker_update "$image" "$@"
@caioariede

This comment has been minimized.

Copy link

caioariede commented Dec 26, 2015

Hey, thanks for the scripts. It's very useful to me. :)

I forked it to make some little changes:

  1. replaces sed with grep
  2. make it work with images without entrypoint

https://gist.github.com/caioariede/99dc77101289726754a1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.