diff --git a/Jenkinsfile b/Jenkinsfile index 6c972975c..01cdd37b2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -49,6 +49,7 @@ try { } stage('Cleanup') { + sh 'make clean' sh 'make prune PRUNE_KEEP_CACHED=48 PRUNE_KEEP_ORPHANS=48' deleteDir() } @@ -59,7 +60,7 @@ catch (Exception e) { echo 'Failure encountered' node("ec2-stateful") { - echo 'Cleaning up workspace' + sh 'make clean' sh 'make prune PRUNE_KEEP_CACHED=48 PRUNE_KEEP_ORPHANS=48' deleteDir() } diff --git a/Makefile b/Makefile index dcb5c0ff6..58c9f7b1f 100644 --- a/Makefile +++ b/Makefile @@ -161,6 +161,8 @@ vendor: go.vendor clean: go.clean @rm -fr $(WORKDIR) $(RELEASE_DIR) $(BIN_DIR) + @$(MAKE) release.cleanup + @$(MAKE) -C images clean distclean: go.distclean clean @rm -fr $(DOWNLOADDIR) @@ -173,17 +175,18 @@ cross.build.platform.%: cross.parallel: $(foreach p,$(PLATFORMS), cross.build.platform.$(p)) -cross: +build.all: @$(MAKE) go.init @$(MAKE) go.validate @$(MAKE) cross.parallel -release: cross - @$(MAKE) -C images cross +release: build.all + @$(MAKE) -C images build.all + @$(MAKE) release.build publish: ifneq ($(filter master alpha beta stable, $(CHANNEL)),) - @$(MAKE) -C images push + @$(MAKE) release.publish else @echo skipping publish. invalid channel "$(CHANNEL)" endif @@ -199,7 +202,7 @@ prune: @$(MAKE) -C images prune .PHONY: build.common cross.build cross.parallel -.PHONY: dev build install test check vet fmt vendor clean distclean cross images release publish promote prune +.PHONY: dev build build.all install test check vet fmt vendor clean distclean release publish promote prune # ==================================================================================== # Help @@ -210,13 +213,12 @@ help: @echo '' @echo 'Targets:' @echo ' build Build source code for host platform.' - @echo ' cross Build source code for all platforms.' + @echo ' build.all Build source code for all platforms.' @echo ' Best done in the cross-build container' @echo ' due to cross compiler dependencies.' @echo ' check Runs unit tests.' @echo ' clean Remove all files that are created ' @echo ' by building.' - @echo ' images Builds container images for host platform.' @echo ' distclean Remove all files that are created ' @echo ' by building or configuring.' @echo ' fmt Check formatting of go sources.' diff --git a/build/common.sh b/build/common.sh index 69937930c..9f8153914 100644 --- a/build/common.sh +++ b/build/common.sh @@ -20,7 +20,7 @@ host=$(hostname) rootdir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd -P) host_hash=`echo ${host}-${rootdir} | sha256sum | cut -c1-8` build_registry=build-${host_hash} -container_image=${build_registry}/cross-build +container_image=${build_registry}/cross-build-amd64 container_volume=cross-build-volume rsync_port=10873 diff --git a/build/makelib/release.mk b/build/makelib/release.mk index 14063a2da..7f1420771 100644 --- a/build/makelib/release.mk +++ b/build/makelib/release.mk @@ -52,7 +52,7 @@ GITHUB_USER ?= rook GITHUB_REPO ?= rook # Optional. Docker registry to publish to -RELEASE_REGISTRY ?= quay.io +RELEASE_REGISTRY ?= quay.io/rook # Optional. S3 bucket to publish artifacts to AWS_DEFAULT_REGION ?= us-east-1 diff --git a/build/release/containers.sh b/build/release/containers.sh index 2d88da7b8..a562c32b8 100755 --- a/build/release/containers.sh +++ b/build/release/containers.sh @@ -3,7 +3,18 @@ scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source ${scriptdir}/common.sh -registry=${RELEASE_REGISTRY}/ +build_registry=${BUILD_REGISTRY} +registry=${RELEASE_REGISTRY} + +get_build_image_name() { + local os=$1 + local arch=$2 + local repo=$3 + + local image=${repo}-${arch}:latest + + echo ${build_registry}/${image} +} get_image_name() { local os=$1 @@ -11,12 +22,22 @@ get_image_name() { local repo=$3 local version=$4 - local tag=${repo}-${arch}:${version} + local image=${repo}-${arch}:${version} if [[ ${arch} == "amd64" ]]; then - tag=${repo}:${version} + image=${repo}:${version} fi - echo ${tag} + echo ${registry}/${image} +} + +build_image() { + local os=$1 + local arch=$2 + local repo=$3 + + local build_image=$(get_build_image_name $os $arch $repo) + local image=$(get_image_name $os $arch $repo ${RELEASE_VERSION}) + docker tag ${build_image} ${image} } build() { @@ -25,22 +46,22 @@ build() { [[ ${os} == "linux" ]] || return 0 - make -C ${scriptdir}/../../images cross PLATFORMS=${arch} VERSION=${RELEASE_VERSION} + build_image $os $arch rookd } -publish_artifact() { +publish_image() { local os=$1 local arch=$2 local repo=$3 - local name=${registry}$(get_image_name $os $arch $repo ${RELEASE_VERSION}) + local name=$(get_image_name $os $arch $repo ${RELEASE_VERSION}) echo pushing docker container ${name} docker push ${name} # we will always tag master builds as latest. i.e. auto-promote master if [[ "${RELEASE_CHANNEL}" == "master" ]]; then - local dst=${registry}$(get_image_name $os $arch $repo master-latest) + local dst=$(get_image_name $os $arch $repo master-latest) echo pushing docker container ${dst} docker tag ${name} ${dst} docker push ${dst} @@ -53,22 +74,21 @@ publish() { [[ ${os} == "linux" ]] || return 0 - publish_artifact $os $arch rook/rookd - publish_artifact $os $arch rook/rook - - # TODO: publish the toolbox for arm - [[ ${arch} == "amd64" ]] || return 0 - publish_artifact $os $arch rook/toolbox + publish_image $os $arch rookd +# disabled for now +# publish_image $os $arch rook +# [[ ${arch} == "amd64" ]] || return 0 +# publish_image $os $arch toolbox } -promote_artifact() { +promote_image() { local os=$1 local arch=$2 local repo=$3 - local src=${registry}$(get_image_name $os $arch $repo ${RELEASE_VERSION}) - local dst1=${registry}$(get_image_name $os $arch $repo ${RELEASE_CHANNEL}-latest) - local dst2=${registry}$(get_image_name $os $arch $repo ${RELEASE_CHANNEL}-${RELEASE_VERSION}) + local src=$(get_image_name $os $arch $repo ${RELEASE_VERSION}) + local dst1=$(get_image_name $os $arch $repo ${RELEASE_CHANNEL}-latest) + local dst2=$(get_image_name $os $arch $repo ${RELEASE_CHANNEL}-${RELEASE_VERSION}) echo promoting container ${src} to ${dst1} and ${dst2} docker pull ${src} @@ -84,12 +104,12 @@ promote() { [[ ${os} == "linux" ]] || return 0 - promote_artifact $os $arch rook/rookd - promote_artifact $os $arch rook/rook - promote_artifact $os $arch rook/toolbox + promote_image $os $arch rookd +# promote_image $os $arch rook +# promote_image $os $arch toolbox } -cleanup_artifact() { +cleanup_image() { local os=$1 local arch=$2 local repo=$3 @@ -100,7 +120,7 @@ cleanup_artifact() { ${RELEASE_CHANNEL}-latest \ ${RELEASE_CHANNEL}-${RELEASE_VERSION} \ ; do - img=${registry}$(get_image_name $os $arch $repo ${t}) + img=$(get_image_name $os $arch $repo ${t}) if [[ -n "$(docker images -q ${img} 2> /dev/null)" ]]; then echo removing docker image ${img} docker rmi ${img} || true @@ -113,9 +133,9 @@ cleanup() { local arch=$2 [[ ${os} == "linux" ]] || return 0 - cleanup_artifact $os $arch rook/rookd - cleanup_artifact $os $arch rook/rook - cleanup_artifact $os $arch rook/toolbox + cleanup_image $os $arch rookd +# cleanup_image $os $arch rook +# cleanup_image $os $arch toolbox } action=$1 diff --git a/build/run b/build/run index 9d6ad05c3..01c7a1e94 100755 --- a/build/run +++ b/build/run @@ -27,7 +27,7 @@ fi # build the the container if we've not done so already if [[ -z "$(docker images -q ${container_image})" ]]; then echo ==== building the cross-build container \(this could take minutes the first time\) - make_cmd="make --no-print-directory -C ${scriptdir}/../images cross-build PULL=0" + make_cmd="make --no-print-directory -C ${scriptdir}/../images cross-build.amd64 PULL=0" make_output=$($make_cmd 2>&1) || { cat <&2 === cross build image failed for ${container_image} diff --git a/images/Makefile b/images/Makefile index 236ac75cb..d977fc87b 100644 --- a/images/Makefile +++ b/images/Makefile @@ -12,40 +12,36 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: all build push clean -all: build - include image.mk PLATFORMS ?= amd64 arm arm64 +PLATFORM_IMAGES ?= rookd +HOST_IMAGES ?= cross-build -.PHONY: cross-build -cross-build: - @$(MAKE) -C base GOARCH=amd64 - @$(MAKE) -C cross-build-gnu - @$(MAKE) -C cross-build-go - @$(MAKE) -C cross-build +# ==================================================================================== +# Image Builds -build.%: - @$(MAKE) -C base build GOARCH=$* - @$(MAKE) -C rookd build GOARCH=$* +base.%: + @$(MAKE) -C base GOARCH=$* -build: - @$(MAKE) -C base GOARCH=amd64 - @$(MAKE) -C cross-build-gnu - @$(MAKE) build.$(GOARCH) +cross-build-gnu.%: base.% + @$(MAKE) -C cross-build-gnu GOARCH=$* -push.%: - @$(MAKE) -C rookd push GOARCH=$* -push: $(foreach p,$(PLATFORMS), push.$(p)) +cross-build-go.%: cross-build-gnu.% + @$(MAKE) -C cross-build-go GOARCH=$* -clean: clean.build +cross-build.%: cross-build-go.% + @$(MAKE) -C cross-build GOARCH=$* -cross.all: $(foreach p,$(PLATFORMS), build.$(p)) -cross: - @$(MAKE) -C base GOARCH=amd64 - @$(MAKE) -C cross-build-gnu - @$(MAKE) cross.all +ceph-build.%: cross-build-gnu.$(GOHOSTARCH) + @$(MAKE) -C ceph-build GOARCH=$* + +rookd.%: ceph-build.% base.% + @$(MAKE) -C rookd GOARCH=$* + +build.all: $(foreach p,$(PLATFORMS), $(foreach i,$(PLATFORM_IMAGES), $(i).$(p))) $(foreach i,$(HOST_IMAGES), $(i).$(GOHOSTARCH)) + +build.images: $(foreach i,$(PLATFORM_IMAGES) $(HOST_IMAGES), $(i).$(GOHOSTARCH)) # ==================================================================================== # Help @@ -56,9 +52,9 @@ help: @echo '' @echo 'Targets:' @echo ' build Build images for the host platform.' + @echo ' build.all Build images for all platforms.' @echo ' clean Remove all images created from the' @echo ' current build.' - @echo ' cross Build images for all platforms.' @echo ' prune Prunes orphaned and cached images at the.' @echo ' host level.' @echo ' push Pushes public images to registry.' diff --git a/images/base/Dockerfile.rootfs-build b/images/base/Dockerfile.rootfs-builder similarity index 100% rename from images/base/Dockerfile.rootfs-build rename to images/base/Dockerfile.rootfs-builder diff --git a/images/base/Makefile b/images/base/Makefile index 31e626aa3..182849b0e 100755 --- a/images/base/Makefile +++ b/images/base/Makefile @@ -12,54 +12,44 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: all build clean -all: build - include ../image.mk -# ==================================================================================== -# Build Options +# the final base image +IMAGE = $(BUILD_REGISTRY)/base-$(GOARCH) -REPO ?= base -IMAGE = $(BUILD_REGISTRY)/$(REPO)-$(GOARCH) +# the full OS image from which we generate a smaller rootfs +ROOTFS_BUILDER_IMAGE := $(BUILD_REGISTRY)/rootfs-builder-$(GOARCH) -# ==================================================================================== -# Build rootfs +# the smaller rootfs that will be cached in docker as an image. we use +# the image id of the builder in the image name to chain them, and ensure +# that when the rootfs builder images that this one is invalidated. +ROOTFS_IMAGE := $(BUILD_REGISTRY)/rootfs-$(GOARCH)-$$(docker images -q $(ROOTFS_BUILDER_IMAGE)) -ROOTFS_BUILD_IMAGE := $(BUILD_REGISTRY)/rootfs-build-$(GOARCH) -ROOTFS_IMAGE := $(HOST_REGISTRY)/rootfs-$(GOARCH):$$(docker images -q $(ROOTFS_BUILD_IMAGE)) -ROOTFS_FILENAME = rootfs.tar +IMAGES = $(IMAGE) $(ROOTFS_BUILDER_IMAGE) $(ROOTFS_IMAGE) +CACHE_IMAGES = $(IMAGES) TEMP := $(shell mktemp -d) -CLEAN_IMAGES += $(IMAGE) $(ROOTFS_BUILD_IMAGE) - -# NOTE: we check if docker build actually built anything (due to changes) -# by comparing the image id before and after calling docker build. If there -# were changes then we proceed with extracting the rootfs and creating the -# final image. This prevents uncessary builds of containers that use this base image. rootfs-build: - @echo === docker build $(ROOTFS_BUILD_IMAGE) - @cp Dockerfile.rootfs-build $(TEMP)/Dockerfile + @echo === docker build $(ROOTFS_BUILDER_IMAGE) + @cp Dockerfile.rootfs-builder $(TEMP)/Dockerfile @cd $(TEMP) && $(SED_CMD) 's|BASEIMAGE|$(OSBASEIMAGE)|g' Dockerfile - @docker build $(BUILD_BASE_ARGS) -t $(ROOTFS_BUILD_IMAGE) $(TEMP) - @[ -n "$$(docker images -q $(ROOTFS_IMAGE))" ] || $(MAKE) rootfs + @docker build $(BUILD_BASE_ARGS) -t $(ROOTFS_BUILDER_IMAGE) $(TEMP) +# lookup the rootfs image from the cache or make it if its not there + @$(MAKE) cache.lookup LOOKUP_IMAGE=$(ROOTFS_IMAGE) MISS_TARGET=rootfs rootfs: @echo === docker build $(ROOTFS_IMAGE) - @CID=`docker create $(ROOTFS_BUILD_IMAGE) /bin/bash` &&\ - docker export $$CID > $(TEMP)/$(ROOTFS_FILENAME) &&\ + @CID=`docker create $(ROOTFS_BUILDER_IMAGE) /bin/bash` &&\ + docker export $$CID > $(TEMP)/rootfs.tar &&\ docker rm -f $$CID - @cp Dockerfile.rootfs $(TEMP)/Dockerfile @docker build $(BUILD_ARGS) -t $(ROOTFS_IMAGE) $(TEMP) @rm -fr $(TEMP) -build: rootfs-build +build.images: rootfs-build @echo === docker build $(IMAGE) @cp Dockerfile $(TEMP) @cd $(TEMP) && $(SED_CMD) "s|BASEIMAGE|$(ROOTFS_IMAGE)|g" Dockerfile @docker build $(BUILD_ARGS) -t $(IMAGE) $(TEMP) @rm -fr $(TEMP) - -clean: clean.images \ No newline at end of file diff --git a/images/ceph-build/Makefile b/images/ceph-build/Makefile index 3f93ab9ad..3f4de77aa 100644 --- a/images/ceph-build/Makefile +++ b/images/ceph-build/Makefile @@ -12,17 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: all build push -all: build - include ../image.mk -# ==================================================================================== -# Options - -# the git repo to build from +# the git repo and branch to build from CEPH_GIT_REPO ?= https://github.com/rook/ceph - CEPH_GIT_BRANCH ?= rook-luminous # the git commit hash to build @@ -40,23 +33,29 @@ $(error unsupported memory allocator $(CEPH_ALLOCATOR)) endif CEPH_CONFIG ?= $(GOARCH)-$(CEPH_ALLOCATOR)-$(CEPH_BUILD_TYPE) -BASEIMAGE := $(BUILD_REGISTRY)/cross-build-gnu -CEPH_BUILD_IMAGE := $(BUILD_REGISTRY)/ceph-build-$(CEPH_CONFIG) -CEPH_IMAGE := $(HOST_REGISTRY)/ceph-$(CEPH_CONFIG):$$(docker images -q $(CEPH_BUILD_IMAGE)) -CLEAN_IMAGES = $(CEPH_BUILD_IMAGE) CEPH_TARBALL = ceph-install.tar -TEMP := $(shell mktemp -d) CCACHE_DIR_HOST ?= $(HOME)/.ccache +CEPH_BUILDER_IMAGE := $(BUILD_REGISTRY)/ceph-builder-$(CEPH_CONFIG) +CEPH_BUILDER_BASEIMAGE := $(BUILD_REGISTRY)/cross-build-gnu-$(GOHOSTARCH) + +CEPH_IMAGE := $(BUILD_REGISTRY)/ceph-$(CEPH_CONFIG)-$$(docker images -q $(CEPH_BUILDER_IMAGE)) + +IMAGES = $(CEPH_BUILDER_IMAGE) $(CEPH_IMAGE) +CACHE_IMAGES = $(IMAGES) + + +TEMP := $(shell mktemp -d) + # ==================================================================================== # Targets -build: - @echo === docker build $(CEPH_BUILD_IMAGE) +build.images: + @echo === docker build $(CEPH_BUILDER_IMAGE) @cp -a . $(TEMP) - @cd $(TEMP) && $(SED_CMD) 's|BASEIMAGE|$(BASEIMAGE)|g' Dockerfile + @cd $(TEMP) && $(SED_CMD) 's|BASEIMAGE|$(CEPH_BUILDER_BASEIMAGE)|g' Dockerfile @docker build $(BUILD_ARGS) \ --build-arg ARCH=$(DEBIAN_ARCH) \ --build-arg CEPH_GIT_COMMIT=$(CEPH_GIT_COMMIT) \ @@ -65,17 +64,18 @@ build: --build-arg CEPH_ALLOCATOR=$(CEPH_ALLOCATOR) \ --build-arg CEPH_BUILD_TYPE=$(CEPH_BUILD_TYPE) \ --build-arg CROSS_TRIPLE=$(CROSS_TRIPLE) \ - -t $(CEPH_BUILD_IMAGE) \ + -t $(CEPH_BUILDER_IMAGE) \ $(TEMP) - @[ -n "$$(docker images -q $(CEPH_IMAGE))" ] || $(MAKE) ceph +# lookup the rootfs image from the cache or make it if its not there + @$(MAKE) cache.lookup LOOKUP_IMAGE=$(CEPH_IMAGE) MISS_TARGET=ceph ceph: - @echo === building ceph from $(CEPH_BUILD_IMAGE) + @echo === building ceph from $(CEPH_BUILDER_IMAGE) @docker run \ -i $(RUN_ARGS) \ --cidfile $(TEMP)/cid \ -v $(CCACHE_DIR_HOST):/root/.ccache \ - $(CEPH_BUILD_IMAGE) + $(CEPH_BUILDER_IMAGE) @docker cp `cat $(TEMP)/cid`:/build/$(CEPH_TARBALL) $(TEMP)/$(CEPH_TARBALL) @docker rm -f `cat $(TEMP)/cid` @docker import $(TEMP)/$(CEPH_TARBALL) $(CEPH_IMAGE) @@ -85,5 +85,3 @@ ceph: @CID=`docker create $(CEPH_IMAGE) /dev/null` &&\ docker export $$CID > $@ &&\ docker rm -f $$CID - -clean: clean.images \ No newline at end of file diff --git a/images/cross-build-gnu/Makefile b/images/cross-build-gnu/Makefile index 7dd6fde17..ee56f3e8a 100644 --- a/images/cross-build-gnu/Makefile +++ b/images/cross-build-gnu/Makefile @@ -12,31 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: all build clean -all: build - -# cross-build only supported on amd64 -override GOARCH := amd64 include ../image.mk -# ==================================================================================== -# Build Options +IMAGE = $(BUILD_REGISTRY)/cross-build-gnu-$(GOARCH) +IMAGES := $(IMAGE) +CACHE_IMAGES = $(IMAGES) -REPO ?= cross-build-gnu -IMAGE = $(BUILD_REGISTRY)/$(REPO) BASEIMAGE = $(BUILD_REGISTRY)/base-$(GOARCH) -# ==================================================================================== -# Build image - TEMP := $(shell mktemp -d) -CLEAN_IMAGES := $(IMAGE) -build: +build.images: @echo === docker build $(IMAGE) @cp -a . $(TEMP) @cd $(TEMP) && $(SED_CMD) 's|BASEIMAGE|$(BASEIMAGE)|g' Dockerfile @docker build $(BUILD_ARGS) -t $(IMAGE) $(TEMP) @rm -fr $(TEMP) - -clean: clean.images \ No newline at end of file diff --git a/images/cross-build-go/Makefile b/images/cross-build-go/Makefile index faaf2a303..1866e80e7 100644 --- a/images/cross-build-go/Makefile +++ b/images/cross-build-go/Makefile @@ -12,31 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: all build clean -all: build - -# cross-build only supported on amd64 -override GOARCH := amd64 include ../image.mk -# ==================================================================================== -# Build Options +IMAGE = $(BUILD_REGISTRY)/cross-build-go-$(GOARCH) +IMAGES := $(IMAGE) +CACHE_IMAGES = $(IMAGES) -REPO ?= cross-build-go -IMAGE = $(BUILD_REGISTRY)/$(REPO) -BASEIMAGE = $(BUILD_REGISTRY)/cross-build-gnu - -# ==================================================================================== -# Build image +BASEIMAGE = $(BUILD_REGISTRY)/cross-build-gnu-$(GOARCH) TEMP := $(shell mktemp -d) -CLEAN_IMAGES := $(IMAGE) -build: +build.images: @echo === docker build $(IMAGE) @cp -a . $(TEMP) @cd $(TEMP) && $(SED_CMD) 's|BASEIMAGE|$(BASEIMAGE)|g' Dockerfile @docker build $(BUILD_ARGS) -t $(IMAGE) $(TEMP) @rm -fr $(TEMP) - -clean: clean.images \ No newline at end of file diff --git a/images/cross-build/Makefile b/images/cross-build/Makefile index f96bba9d9..af855fd60 100644 --- a/images/cross-build/Makefile +++ b/images/cross-build/Makefile @@ -12,31 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: all build clean -all: build - -# cross-build only supported on amd64 -override GOARCH := amd64 include ../image.mk -# ==================================================================================== -# Build Options +IMAGE = $(BUILD_REGISTRY)/cross-build-$(GOARCH) +IMAGES := $(IMAGE) +CACHE_IMAGES = $(IMAGES) -REPO ?= cross-build -IMAGE = $(BUILD_REGISTRY)/$(REPO) -BASEIMAGE = $(BUILD_REGISTRY)/cross-build-go - -# ==================================================================================== -# Build image +BASEIMAGE = $(BUILD_REGISTRY)/cross-build-go-$(GOARCH) TEMP := $(shell mktemp -d) -CLEAN_IMAGES := $(IMAGE) -build: +build.images: @echo === docker build $(IMAGE) @cp -a . $(TEMP) @cd $(TEMP) && $(SED_CMD) 's|BASEIMAGE|$(BASEIMAGE)|g' Dockerfile @docker build $(BUILD_ARGS) -t $(IMAGE) $(TEMP) @rm -fr $(TEMP) - -clean: clean.images \ No newline at end of file diff --git a/images/image.mk b/images/image.mk index 4e8cdff29..95ee90660 100644 --- a/images/image.mk +++ b/images/image.mk @@ -16,12 +16,11 @@ SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) include $(SELF_DIR)/../build/makelib/cross.mk -# a registry that is scoped to the local host -HOSTNAME := $(shell hostname) -HOST_REGISTRY := host-$(shell echo $(HOSTNAME) | sha256sum | cut -c1-8) +CACHE_REGISTRY := cache # a registry that is scoped to the current build tree on this host ifeq ($(origin BUILD_REGISTRY), undefined) +HOSTNAME := $(shell hostname) ROOTDIR := $(shell cd $(SELF_DIR)/.. && pwd -P) BUILD_REGISTRY := build-$(shell echo $(HOSTNAME)-$(ROOTDIR) | sha256sum | cut -c1-8) endif @@ -84,81 +83,110 @@ export PULL BUILD_BASE_ARGS += $(BUILD_ARGS) +# ===================================================================================== +# Targets +# +.PHONY: all build publish clean +all: build + +build: build.images + @$(MAKE) cache.images + +push: push.images + +clean: clean.build + +prune: cache.prune + +clean.images: + @for i in $(IMAGES); do \ + if [ -n "$$(docker images -q $$i)" ]; then \ + for c in $$(docker ps -a -q --no-trunc --filter=ancestor=$$i); do \ + if [ "$$c" != "$(SELF_CID)" ]; then \ + echo stopping and removing container $${c} referencing image $$i; \ + docker stop $${c}; \ + docker rm $${c}; \ + fi; \ + done; \ + echo cleaning image $$i; \ + docker rmi $$i > /dev/null 2>&1 || true; \ + fi; \ + done + +# this will clean everything for this build +clean.build: + @echo === cleaning images for $(BUILD_REGISTRY) + @$(MAKE) clean.images IMAGES="$(shell docker images | grep -E '^$(BUILD_REGISTRY)/' | awk '{print $$1":"$$2}')" + +# ===================================================================================== +# Caching +# + +# NOTE: in order to reduce built time especially on jenkins, we maintain a cache +# of already built images. This cache contains images that can be used to help speed +# future docker build commands using docker's content addressable schemes. And also +# to avoid running builds like ceph when the contents have not changed. +# All cached images go in in a 'cache/' local registry and we follow an MRU caching +# policy -- keeping images that have been referenced around and evicting images +# that have to been referenced in a while (and according to a policy). Note we can +# not rely on the image's .CreatedAt date since docker only updates then when the +# image is created and not referenced. Instead we keep a date in the Tag. + # prune images that are at least this many hours old PRUNE_HOURS ?= 48 # prune keeps at least this many images regardless of how old they are -PRUNE_KEEP_CACHED ?= 24 -PRUNE_KEEP_ORPHANS ?= 24 +PRUNE_KEEP ?= 24 -CLEANUP_DATE := $(shell date -u --date="$(PRUNE_HOURS) hours ago" +"%Y-%m-%d %T %z UTC") +PRUNE_DRYRUN ?= 0 -# NOTE: docker rmi removes the last image when untagging. instead we switch the tag -# to a small dummy orphaning the original image and then call docker rmi. This approach -# avoids removing the last layer (and having to rebuild it) +CACHE_DATE_FORMAT := "%Y-%m-%d.%H%M%S.%N" +CACHE_PRUNE_DATE := $(shell date -u --date="$(PRUNE_HOURS) hours ago" +"$(CACHE_DATE_FORMAT)") +CACHE_TAG := $(shell date -u +"$(CACHE_DATE_FORMAT)") -DUMMY_IMAGE_BASE ?= tianon/true -DUMMY_IMAGE ?= $(HOST_REGISTRY)/dummy:latest +cache.lookup: + @IMAGE_NAME=$${LOOKUP_IMAGE#*/} ;\ + if [ -n "$$(docker images -q $(LOOKUP_IMAGE))" ]; then exit 0; fi; \ + if [ -z "$$(docker images -q $(CACHE_REGISTRY)/$${IMAGE_NAME})" ]; then \ + $(MAKE) $(MISS_TARGET); \ + else \ + docker tag $$(docker images -q $(CACHE_REGISTRY)/$${IMAGE_NAME}) $(LOOKUP_IMAGE); \ + fi; -clean.init: - @if [ -z "`docker images -q $(DUMMY_IMAGE)`" ]; then \ - docker pull $(DUMMY_IMAGE_BASE) > /dev/null 2>&1; \ - docker tag $(DUMMY_IMAGE_BASE) $(DUMMY_IMAGE) > /dev/null 2>&1; \ - docker rmi $(DUMMY_IMAGE_BASE) > /dev/null 2>&1; \ - fi - -do.orphan: clean.init - @for i in $(CLEAN_IMAGES); do \ - [ "$$i" != "$(DUMMY_IMAGE)" ] || continue; \ - for c in $$(docker ps -a -q --no-trunc --filter=ancestor=$$i); do \ - if [ "$$c" != "$(SELF_CID)" ]; then \ - echo stopping and removing container $${c} referencing image $$i; \ - docker stop $${c}; \ - docker rm $${c}; \ - fi; \ - done; \ - echo orphaning image $$i; \ - docker tag $(DUMMY_IMAGE) $$i > /dev/null 2>&1; \ - docker rmi $$i > /dev/null 2>&1; \ +cache.images: + @for i in $(CACHE_IMAGES); do \ + IMGID=$$(docker images -q $$i); \ + if [ -n "$$IMGID" ]; then \ + echo === caching image $$i; \ + CACHE_IMAGE=$(CACHE_REGISTRY)/$${i#*/}; \ + docker tag $$i $${CACHE_IMAGE}:$(CACHE_TAG); \ + for r in $$(docker images --format "{{.ID}}#{{.Repository}}:{{.Tag}}" | grep $$IMGID | grep $(CACHE_REGISTRY)/ | grep -v $${CACHE_IMAGE}:$(CACHE_TAG)); do \ + docker rmi $${r#*#}; \ + done; \ + fi; \ done -# this will clean all images in the variable CLEAN_IMAGES -clean.images: do.clean - -# this will clean everything for this build -clean.build: clean.init - @$(MAKE) do.orphan CLEAN_IMAGES="$(shell docker images | grep -E '^$(BUILD_REGISTRY)|$(REGISTRY)/' | awk '{print $$1":"$$2}')" - -# this will clean everything for this host regardless of prune policy -clean.all: clean.init - @$(MAKE) do.orphan CLEAN_IMAGES="$(shell docker images | grep -E '^$(BUILD_REGISTRY)|$(HOST_REGISTRY)|$(REGISTRY)/' | awk '{print $$1":"$$2}')" - -# prune removes old orphaned images and old cached images -prune: clean.build +# prune removes old cached images +cache.prune: @echo === pruning images older than $(PRUNE_HOURS) hours - @echo === keeping a minimum of $(PRUNE_KEEP_ORPHANS) orphaned images and $(PRUNE_KEEP_CACHED) cached images - @CLEAN_IMAGES="$(shell docker images --format "{{.CreatedAt}}#{{.Repository}}:{{.Tag}}" \ - | grep -E '$(HOST_REGISTRY)/' \ - | grep -v '$(DUMMY_IMAGE)' \ + @echo === keeping a minimum of $(PRUNE_KEEP) images + @EXPIRED=$$(docker images --format "{{.Tag}}#{{.Repository}}:{{.Tag}}" \ + | grep -E '$(CACHE_REGISTRY)/' \ | sort -r \ - | awk -v i=0 -v cd="$(CLEANUP_DATE)" -F "#" '{if ($$1 <= cd && i >= $(PRUNE_KEEP_CACHED)) print $$2; i++ }')" &&\ - $(MAKE) do.orphan CLEAN_IMAGES="$${CLEAN_IMAGES}" - @CLEAN_IMAGES="$(shell docker images -q -f dangling=true --format "{{.CreatedAt}}#{{.ID}}" \ - | sort -r \ - | awk -v i=0 -v cd="$(CLEANUP_DATE)" -F "#" '{if ($$1 <= cd && i >= $(PRUNE_KEEP_ORPHANS)) print $$2; i++ }')" &&\ - for i in $${CLEAN_IMAGES}; do \ - echo removing orphaned image $$i; \ - docker rmi $$i > /dev/null 2>&1; \ - done - -prune.all: + | awk -v i=0 -v cd="$(CACHE_PRUNE_DATE)" -F "#" '{if ($$1 <= cd && i >= $(PRUNE_KEEP)) print $$2; i++ }') &&\ + for i in $$EXPIRED; do \ + echo removing expired cache image $$i; \ + [ $(PRUNE_DRYRUN) = 1 ] || docker rmi $$i; \ + done @for i in $$(docker images -q -f dangling=true); do \ - echo removing orphaned image $$i; \ + echo removing danlging image $$i; \ docker rmi $$i > /dev/null 2>&1; \ done -# nukes all images -nuke: +# ===================================================================================== +# Debugging nukes all images +# +debug.nuke: @for c in $$(docker ps -a -q --no-trunc); do \ if [ "$$c" != "$(SELF_CID)" ]; then \ echo stopping and removing container $${c}; \ diff --git a/images/rookd/Dockerfile b/images/rookd/Dockerfile index 78ffdfd93..9d58ff5bb 100644 --- a/images/rookd/Dockerfile +++ b/images/rookd/Dockerfile @@ -14,37 +14,6 @@ FROM BASEIMAGE -ARG EXTRALIBS - -# install runtime dependencies for ceph and rookd -RUN BOOST_VERSION=1.62.0 && \ - DEBIAN_FRONTEND=noninteractive apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -yy -q --no-install-recommends \ - ca-certificates \ - libaio1 \ - libboost-context${BOOST_VERSION} \ - libboost-coroutine${BOOST_VERSION} \ - libboost-date-time${BOOST_VERSION} \ - libboost-iostreams${BOOST_VERSION} \ - libboost-program-options${BOOST_VERSION} \ - libboost-python${BOOST_VERSION} \ - libboost-random${BOOST_VERSION} \ - libboost-regex${BOOST_VERSION} \ - libboost-system${BOOST_VERSION} \ - libboost-thread${BOOST_VERSION} \ - libcurl3-gnutls \ - libexpat1 \ - libibverbs1 \ - libldap-2.4-2 \ - libnss3 \ - libpython2.7 \ - python-prettytable \ - python2.7-minimal \ - ${EXTRALIBS} && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade -y && \ - DEBIAN_FRONTEND=noninteractive apt-get autoremove -y && \ - DEBIAN_FRONTEND=noninteractive apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - # add the ceph binaries ADD ceph-install.tar / diff --git a/images/rookd/Dockerfile.base b/images/rookd/Dockerfile.base new file mode 100644 index 000000000..7b6bf7162 --- /dev/null +++ b/images/rookd/Dockerfile.base @@ -0,0 +1,46 @@ +# Copyright 2016 The Rook Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM BASEIMAGE + +ARG EXTRALIBS + +# install runtime dependencies for ceph and rookd +RUN BOOST_VERSION=1.62.0 && \ + DEBIAN_FRONTEND=noninteractive apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -yy -q --no-install-recommends \ + ca-certificates \ + libaio1 \ + libboost-context${BOOST_VERSION} \ + libboost-coroutine${BOOST_VERSION} \ + libboost-date-time${BOOST_VERSION} \ + libboost-iostreams${BOOST_VERSION} \ + libboost-program-options${BOOST_VERSION} \ + libboost-python${BOOST_VERSION} \ + libboost-random${BOOST_VERSION} \ + libboost-regex${BOOST_VERSION} \ + libboost-system${BOOST_VERSION} \ + libboost-thread${BOOST_VERSION} \ + libcurl3-gnutls \ + libexpat1 \ + libibverbs1 \ + libldap-2.4-2 \ + libnss3 \ + libpython2.7 \ + python-prettytable \ + python2.7-minimal \ + ${EXTRALIBS} && \ + DEBIAN_FRONTEND=noninteractive apt-get upgrade -y && \ + DEBIAN_FRONTEND=noninteractive apt-get autoremove -y && \ + DEBIAN_FRONTEND=noninteractive apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/images/rookd/Makefile b/images/rookd/Makefile index 57f69d516..e74049da8 100755 --- a/images/rookd/Makefile +++ b/images/rookd/Makefile @@ -12,26 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: all build push -all: build - include ../image.mk # ==================================================================================== # Image Build Options -REPO ?= rookd -IMAGE = $(REGISTRY)/$(REPO)-$(GOARCH):$(VERSION) -CLEAN_IMAGES = $(IMAGE) - -# ==================================================================================== -# Ceph Build Options - -CEPH_BUILD_TYPE ?= release -CEPH_ALLOCATOR ?= tcmalloc - -# ==================================================================================== -# Common Build Settings +ROOKD_IMAGE = $(BUILD_REGISTRY)/rookd-$(GOARCH) +ROOKD_BASE_IMAGE = $(BUILD_REGISTRY)/rookd-base-$(GOARCH) +IMAGES = $(ROOKD_IMAGE) $(ROOKD_BASE_IMAGE) +CACHE_IMAGES = $(ROOKD_BASE_IMAGE) BASEIMAGE = $(BUILD_REGISTRY)/base-$(GOARCH) @@ -40,6 +29,9 @@ TEMP := $(shell mktemp -d) # ==================================================================================== # Build Ceph +CEPH_BUILD_TYPE ?= release +CEPH_ALLOCATOR ?= tcmalloc + ifeq ($(CEPH_ALLOCATOR),tcmalloc) EXTRA_LIBS += libgoogle-perftools4 endif @@ -54,32 +46,27 @@ CEPH_TARBALL_FILENAME = ceph-install.tar CEPH_TARBALL = $(TEMP)/$(CEPH_TARBALL_FILENAME) $(CEPH_TARBALL): - @echo === building ceph for $(IMAGE) + @echo === building ceph for $(ROOKD_IMAGE) @$(MAKE) -C ../ceph-build GOARCH=$(GOARCH) CEPH_ALLOCATOR=$(CEPH_ALLOCATOR) CEPH_BUILD_TYPE=$(CEPH_BUILD_TYPE) $(CEPH_TARBALL) # ==================================================================================== # Build Rook -ROOKD = $(TEMP)/rookd - -$(ROOKD): - @echo === building rookd for $(IMAGE) - @cp ../../bin/linux_$(GOARCH)/rookd $@ - -# ==================================================================================== -# Build Final Image - -EXISTING_IMAGE_ID := $(shell docker images -q $(IMAGE)) - -build: $(CEPH_TARBALL) $(ROOKD) - @echo === docker build $(IMAGE) - @cp Dockerfile $(TEMP) +rookd-base-image: + @echo === docker build $(ROOKD_BASE_IMAGE) + @cp Dockerfile.base $(TEMP)/Dockerfile @cd $(TEMP) && $(SED_CMD) 's|BASEIMAGE|$(BASEIMAGE)|g' Dockerfile - @docker build $(BUILD_ARGS) --build-arg EXTRALIBS=$(EXTRA_LIBS) -t $(IMAGE) $(TEMP) - @docker rmi $(EXISTING_IMAGE_ID) > /dev/null 2>&1 || true + @docker build $(BUILD_ARGS) --build-arg EXTRALIBS=$(EXTRA_LIBS) -t $(ROOKD_BASE_IMAGE) $(TEMP) + +# since this is a leaf image avoid leaving around a lot of dangling images +# by removing the last build of the final rookd image +OLD_IMAGE_ID := $(shell docker images -q $(ROOKD_IMAGE)) + +build.images: rookd-base-image $(CEPH_TARBALL) + @echo === docker build $(ROOKD_IMAGE) + @cp Dockerfile $(TEMP) + @cp ../../bin/linux_$(GOARCH)/rookd $(TEMP) + @cd $(TEMP) && $(SED_CMD) 's|BASEIMAGE|$(ROOKD_BASE_IMAGE)|g' Dockerfile + @docker build $(BUILD_ARGS) -t $(ROOKD_IMAGE) $(TEMP) + @[ -z "$(OLD_IMAGE_ID)" ] || docker rmi $(OLD_IMAGE_ID) @rm -fr $(TEMP) - -push: - @docker push $(IMAGE) - -clean: clean.images \ No newline at end of file