diff --git a/.build_image_manifest b/.build_image_manifest new file mode 100644 index 0000000000..cdd352caa4 --- /dev/null +++ b/.build_image_manifest @@ -0,0 +1,4 @@ +100644 blob 7984bfe4b3e5bdc7e2838feb954b32e9339e05bc Dockerfile +100644 blob 068bde679a10599594b7bd3ac3520c27bf800239 go.mod +100644 blob bd834def28dee387369922821becd663308e80f2 go.sum +100755 blob 98e770c77cf3b03c65cb7b7818e5f24e980f9b11 install-build-deps.sh diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index e5842dd026..0000000000 --- a/.dockerignore +++ /dev/null @@ -1,9 +0,0 @@ -logo -site -Dockerfile -*.md -DCO -LICENSE.* -skaffold.yaml -eksctl -eksctl-integration-test diff --git a/.gitignore b/.gitignore index 14f0ab3cd5..be911f5c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,7 @@ integration/kubeconfig-* # Generated header file .license-header + +# Build image context and Docker Image ID file +.build_image_context +*.iid diff --git a/Dockerfile b/Dockerfile index ba3d3dc41a..7984bfe4b3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,48 @@ -FROM scratch -CMD eksctl -COPY --from=weaveworks/eksctl-builder:latest /out / +# Make sure to run the following commands after changes to this file are made: +# `make update-build-image-manifest && make push-build-image` + +# This digest corresponds to golang:1.12.6-alpine3.9 (when Alpine was pointing to 3.9.4) +FROM golang@sha256:39677a9dd517a8e5d514dff8e36fa46ecc3fb14618b970bfaf3100cb8fab9ba6 + +# Build-time dependencies +RUN apk add --no-cache \ + curl \ + git \ + make \ + bash \ + gcc \ + g++ \ + libsass-dev \ + musl-dev \ + && true + +WORKDIR /src +ENV CGO_ENABLED=0 +COPY install-build-deps.sh go.mod go.sum /src/ + +# Install all go dependencies and remove the go caches in a single step to reduce the image footprint +# (caches won't be used later on, we overwrite them by volume-mounting) +RUN ./install-build-deps.sh && \ + go install github.com/goreleaser/goreleaser && \ + go build github.com/kubernetes-sigs/aws-iam-authenticator/cmd/aws-iam-authenticator && \ + rm -rf /root/.cache/go-build /go/pkg/mod + + + +# Runtime dependencies. Build the root filesystem of the eksctl image at /out +RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/ +RUN apk add --no-cache --initdb --root /out \ + alpine-baselayout \ + busybox \ + ca-certificates \ + coreutils \ + git \ + libc6-compat \ + openssh \ + && true + +RUN mv ./aws-iam-authenticator /out/usr/local/bin/aws-iam-authenticator + +ENV KUBECTL_VERSION v1.11.5 +RUN curl --silent --location "https://dl.k8s.io/${KUBECTL_VERSION}/bin/linux/amd64/kubectl" --output /out/usr/local/bin/kubectl \ + && chmod +x /out/usr/local/bin/kubectl diff --git a/Dockerfile.deps b/Dockerfile.deps deleted file mode 100644 index a77a544f0b..0000000000 --- a/Dockerfile.deps +++ /dev/null @@ -1,48 +0,0 @@ -# Make sure to bump the version of EKSCTL_DEPENDENCIES_IMAGE if you make any changes -# to this file - -# This digest corresponds to golang:1.12.6-alpine3.9 (when Alpine was pointing to 3.9.4) -FROM golang@sha256:39677a9dd517a8e5d514dff8e36fa46ecc3fb14618b970bfaf3100cb8fab9ba6 - -# Build-time dependencies -RUN apk add --no-cache \ - curl \ - git \ - make \ - bash \ - gcc \ - g++ \ - libsass-dev \ - musl-dev \ - && true - -WORKDIR /src -ENV CGO_ENABLED=0 -COPY install-build-deps.sh go.mod go.sum /src/ - -# Install all go dependencies and remove the go caches in a single step to reduce the image footprint -# (caches won't be used later on, we overwrite them by volume-mounting) -RUN ./install-build-deps.sh && \ - go install github.com/goreleaser/goreleaser && \ - go build github.com/kubernetes-sigs/aws-iam-authenticator/cmd/aws-iam-authenticator && \ - rm -rf /root/.cache/go-build /go/pkg/mod - - - -# Runtime dependencies. Build the root filesystem of the eksctl image at /out -RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/ -RUN apk add --no-cache --initdb --root /out \ - alpine-baselayout \ - busybox \ - ca-certificates \ - coreutils \ - git \ - libc6-compat \ - openssh \ - && true - -RUN mv ./aws-iam-authenticator /out/usr/local/bin/aws-iam-authenticator - -ENV KUBECTL_VERSION v1.11.5 -RUN curl --silent --location "https://dl.k8s.io/${KUBECTL_VERSION}/bin/linux/amd64/kubectl" --output /out/usr/local/bin/kubectl \ - && chmod +x /out/usr/local/bin/kubectl diff --git a/Makefile b/Makefile index 5e93724f10..91eb728339 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,42 @@ built_at := $(shell date +%s) -git_commit := $(shell git describe --dirty --always) +git_commit = $(shell git describe --dirty --always) + git_toplevel := $(shell git rev-parse --show-toplevel) version_pkg := github.com/weaveworks/eksctl/pkg/version -# The dependencies version should be bumped every time the build dependencies are updated -EKSCTL_DEPENDENCIES_IMAGE ?= weaveworks/eksctl-build:deps-0.15 -EKSCTL_BUILDER_IMAGE ?= weaveworks/eksctl-builder:latest -EKSCTL_IMAGE ?= weaveworks/eksctl:latest +build_image_input := Dockerfile install-build-deps.sh go.mod go.sum + +# We use git object hashes for determining the input files used for any given build image +# E.g. given `weaveworks/eksctl-build:e6e8800773d3adf8e7999a23dcdb07414c66a4da` one can +# run `git show e6e8800773d3adf8e7999a23dcdb07414c66a4da` to get contents of `.build_image_manifest`, +# and `git show ` for each of the hashes in the manifest to determine contents of each of the +# files used in `$(build_image_input)` at the time. +build_image_tag = $(shell git ls-tree --full-tree @ -- .build_image_manifest | awk '{ print $$3 }') + +build_image_name = weaveworks/eksctl-build:$(build_image_tag) + +unique_tag = $(shell printf "%s-%s-%s" `git rev-parse @` $(build_image_tag) $(built_at)) + +intermidiate_container_name = eksctl-build-$(unique_tag) +intermediate_image_name = weaveworks/eksctl-intermediate:$(unique_tag) -GOBIN ?= $(shell echo `go env GOPATH`/bin) +eksctl_image_name ?= weaveworks/eksctl:latest + +gopath := $(shell go env GOPATH) +gocache := $(shell go env GOCACHE) + +docker_build := time docker build +# We should eventually switch to buildkit, as it has a many feature and cleaner output with timing info, +# but right now 'docker build' doesn't allow us to export build cache images, so we cannot use it yet +# docker_build := env DOCKER_BUILDKIT=1 $(docker_build) + +GOBIN ?= $(gopath)/bin + +ifeq ($(OS),Windows_NT) +TEST_TARGET=unit-test +else +TEST_TARGET=test +endif generated_code_aws_sdk_mocks := $(wildcard pkg/eks/mocks/*API.go) @@ -102,7 +130,7 @@ integration-test-container-pre-built: ## Run the integration tests inside a Dock --volume=$(HOME)/.aws:/root/.aws \ --volume=$(HOME)/.ssh:/root/.ssh \ --workdir=/usr/local/share/eksctl \ - $(EKSCTL_IMAGE) \ + $(eksctl_image_name) \ eksctl-integration-test \ -eksctl.path=/usr/local/bin/eksctl \ -eksctl.kubeconfig=/tmp/kubeconfig \ @@ -136,7 +164,7 @@ generate-all: $(all_generated_files) # generate-ami ## Re-generate all the autom .PHONY: check-all-generated-files-up-to-date check-all-generated-files-up-to-date: generate-all - git diff --quiet -- $(all_generated_files) || (git --no-pager diff $(all_generated_files); exit 1) + git diff --quiet -- $(all_generated_files) || (git --no-pager diff $(all_generated_files); echo "HINT: to fix this, run 'git commit $(all_generated_files) --message \"Update generated files\"'"; exit 1) pkg/addons/default/assets.go: pkg/addons/default/assets/* env GOBIN=$(GOBIN) time go generate ./$(@D) @@ -158,7 +186,7 @@ pkg/nodebootstrap/maxpods.go: deep_copy_helper_input := $(shell $(call godeps_cmd,./pkg/apis/...) | sed 's|$(generated_code_deep_copy_helper)||' ) $(generated_code_deep_copy_helper): $(deep_copy_helper_input) .license-header ## Generate Kubernetes API helpers time go mod download k8s.io/code-generator # make sure the code-generator is present - time env GOPATH="$$(go env GOPATH)" bash "$$(go env GOPATH)/pkg/mod/k8s.io/code-generator@v0.0.0-20190808180452-d0071a119380/generate-groups.sh" \ + time env GOPATH="$(gopath)" bash "$(gopath)/pkg/mod/k8s.io/code-generator@v0.0.0-20190808180452-d0071a119380/generate-groups.sh" \ deepcopy,defaulter _ ./pkg/apis eksctl.io:v1alpha5 --go-header-file .license-header --output-base="$(git_toplevel)" \ || (cat codegenheader.txt ; cat $(generated_code_deep_copy_helper); exit 1) @@ -174,34 +202,64 @@ site/content/usage/20-schema.md: $(call godeps,cmd/schema/generate.go) $(generated_code_aws_sdk_mocks): $(call godeps,pkg/eks/mocks/mocks.go) mkdir -p vendor/github.com/aws/ @# Hack for Mockery to find the dependencies handled by `go mod` - ln -sfn "$$(go env GOPATH)/pkg/mod/github.com/aws/aws-sdk-go@v1.23.15" vendor/github.com/aws/aws-sdk-go + ln -sfn "$(gopath)/pkg/mod/github.com/aws/aws-sdk-go@v1.23.15" vendor/github.com/aws/aws-sdk-go time env GOBIN=$(GOBIN) go generate ./pkg/eks/mocks ##@ Docker -ifeq ($(OS),Windows_NT) -TEST_TARGET=unit-test -else -TEST_TARGET=test -endif - -.PHONY: eksctl-deps-image -eksctl-deps-image: ## Create a cache image with dependencies - -time docker pull $(EKSCTL_DEPENDENCIES_IMAGE) - @# Pin dependency file permissions. - @# Docker uses the file permissions as part of the COPY hash, which can lead to cache misses - @# in hosts with different default file permissions (umask). - chmod 0700 install-build-deps.sh - chmod 0600 go.mod go.sum - time docker build --cache-from=$(EKSCTL_DEPENDENCIES_IMAGE) --tag=$(EKSCTL_DEPENDENCIES_IMAGE) -f Dockerfile.deps . +update_build_image_manifest = git ls-tree --full-tree @ -- $(build_image_input) > .build_image_manifest + +.PHONY: check-build-image-manifest-up-to-date +check-build-image-manifest-up-to-date: ## Update build image manifest and commits the changes + git diff --quiet -- $(build_image_input) || (git --no-pager diff $(build_image_input); exit 1) + $(update_build_image_manifest) + git diff --quiet -- .build_image_manifest || (git --no-pager diff .build_image_manifest; echo "HINT: to fix this, run 'make update-build-image-manifest'"; exit 1) + +.PHONY: update-build-image-manifest +update-build-image-manifest: ## Update build image manifest and commits the changes + $(update_build_image_manifest) + git commit --quiet .build_image_manifest --message 'Update build image manifest' + $(info build image name is $(build_image_name)) + +.PHONY: build-image +build-image: check-build-image-manifest-up-to-date ## Build the build image that has all of external dependencies + -docker pull $(build_image_name) + rm -rf .build_image_context + mkdir .build_image_context + cp $(build_image_input) .build_image_context/ + # git only ensures owner's perssions are set, it ignores group and other's permissions, + # we need to force permissions here to avoid cache misses + chmod go-wrx .build_image_context/* + $(docker_build) \ + --iidfile=.build_image.iid \ + --cache-from=$(build_image_name) \ + --tag=$(build_image_name) \ + .build_image_context/ + +.PHONY: push-build-image +push-build-image: build-image ## Push the build image to the registry + docker push $(file < .build_image.iid) + +.PHONY: intermediate-image +intermediate-image: build-image ## Build the intermediate image that has all artefacts + time docker run \ + --tty \ + --name=$(intermidiate_container_name) \ + --env=TEST_TARGET=$(TEST_TARGET) \ + --volume=$(git_toplevel):/src \ + --volume=$(gocache):/root/.cache/go-build \ + --volume=$(gopath)/pkg/mod:/go/pkg/mod \ + $(file < .build_image.iid) /src/eksctl-image-builder.sh \ + || (docker rm $(intermidiate_container_name) ; exit 1) + time docker commit $(intermidiate_container_name) $(intermediate_image_name) \ + && docker rm $(intermidiate_container_name) .PHONY: eksctl-image -eksctl-image: eksctl-deps-image## Create the eksctl image - time docker run -t --name eksctl-builder -e TEST_TARGET=$(TEST_TARGET) \ - -v "$(git_toplevel)":/src -v "$$(go env GOCACHE):/root/.cache/go-build" -v "$$(go env GOPATH)/pkg/mod:/go/pkg/mod" \ - $(EKSCTL_DEPENDENCIES_IMAGE) /src/eksctl-image-builder.sh || ( docker rm eksctl-builder; exit 1 ) - time docker commit eksctl-builder $(EKSCTL_BUILDER_IMAGE) && docker rm eksctl-builder - docker build --tag $(EKSCTL_IMAGE) . +eksctl-image: intermediate-image ## Build the eksctl image that has release artefacts and no build dependencies + printf 'FROM scratch\nCMD eksctl\nCOPY --from=%s /out /' $(intermediate_image_name) \ + | $(docker_build) \ + --iidfile=.eksctl_image.iid \ + --tag="$(eksctl_image_name)" - ##@ Release @@ -211,7 +269,7 @@ docker_run_release_script = docker run \ --env=CIRCLE_PROJECT_USERNAME \ --volume=$(CURDIR):/src \ --workdir=/src \ - $(EKSCTL_BUILDER_IMAGE) + $(intermediate_image_name) .PHONY: release-candidate release-candidate: eksctl-image ## Create a new eksctl release candidate diff --git a/go.mod b/go.mod index 3b3c09d7fb..068bde679a 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,5 @@ -// Make sure to bump the version of EKSCTL_DEPENDENCIES_IMAGE if you make any changes here +// Make sure to run the following commands after changes to this file are made: +// `make update-build-image-manifest && make push-build-image` module github.com/weaveworks/eksctl go 1.12 diff --git a/install-build-deps.sh b/install-build-deps.sh index 194add9896..98e770c77c 100755 --- a/install-build-deps.sh +++ b/install-build-deps.sh @@ -1,6 +1,7 @@ #!/bin/sh -eux -# Make sure to bump the version of EKSCTL_DEPENDENCIES_IMAGE if you make any changes here +# Make sure to run the following commands after changes to this file are made: +# `make update-build-image-manifest && make push-build-image` if [ -z "${GOBIN+x}" ]; then GOBIN="$(go env GOPATH)/bin"