diff --git a/.dockerignore b/.dockerignore index ba8f5ffed7..fc54fb0a69 100644 --- a/.dockerignore +++ b/.dockerignore @@ -22,6 +22,7 @@ bin /hack /LICENSES /local +/gen /pkg/test* @@ -35,3 +36,4 @@ bin !go.* !**/*.go +!.git \ No newline at end of file diff --git a/.github/workflows/components.yaml b/.github/workflows/components.yaml index c519473c20..9cf04be0c3 100644 --- a/.github/workflows/components.yaml +++ b/.github/workflows/components.yaml @@ -33,6 +33,8 @@ env: components: '["ocmcli", "helminstaller", "helmdemo", "subchartsdemo", "ecrplugin"]' IMAGE_PLATFORMS: 'linux/amd64 linux/arm64' PLATFORMS: 'windows/amd64 darwin/arm64 darwin/amd64 linux/amd64 linux/arm64' + BUILDX_CACHE_PUSH: ${{ github.ref == 'refs/heads/main' }} + BUILDX_CACHE_REF_BASE: ghcr.io/${{ github.repository }}/buildx-cache jobs: define-matrix: @@ -66,6 +68,14 @@ jobs: with: go-version-file: '${{ github.workspace }}/go.mod' cache: false + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Docker Login + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Get go environment for use with cache run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV @@ -95,6 +105,8 @@ jobs: VERSION=${{ inputs.version }} \ PLATFORMS="${{ env.PLATFORMS }}" \ IMAGE_PLATFORMS="${{ env.IMAGE_PLATFORMS }}" \ + BUILDX_CACHE_REF=${{ env.BUILDX_CACHE_REF_BASE }}:${{ matrix.component }} \ + BUILDX_CACHE_PUSH=${{ env.BUILDX_CACHE_PUSH }} \ make \ ctf descriptor describe - name: Upload CTF diff --git a/Dockerfile b/Dockerfile index 1a8f590786..77c00ef102 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,28 @@ -FROM golang:1.23-alpine3.20 AS build +FROM --platform=$BUILDPLATFORM golang:1.23-alpine3.20 AS build + +RUN apk add --no-cache make git WORKDIR /src -RUN go env -w GOMODCACHE=/root/.cache/go-build COPY go.mod go.sum *.go VERSION ./ ARG GO_PROXY="https://proxy.golang.org" ENV GOPROXY=${GO_PROXY} -RUN --mount=type=cache,target=/root/.cache/go-build go mod download +RUN go mod download COPY . . -RUN --mount=type=cache,target=/root/.cache/go-build \ - export VERSION=$(go run api/version/generate/release_generate.go print-rc-version) && \ - export NOW=$(date -u +%FT%T%z) && \ - go build -trimpath -ldflags \ - "-s -w -X ocm.software/ocm/api/version.gitVersion=$VERSION -X ocm.software/ocm/api/version.buildDate=$NOW" \ - -o /bin/ocm ./cmds/ocm/main.go + +ENV BUILD_FLAGS="-trimpath" + +# the GOARCH has not a default value to allow the binary be built according to the host where the command +# was called. For example, if we call make docker-build in a local env which has the Apple Silicon SO +# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, +# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. +RUN make bin/ocm GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} FROM gcr.io/distroless/static-debian12:nonroot@sha256:d71f4b239be2d412017b798a0a401c44c3049a3ca454838473a4c32ed076bfea -COPY --from=build /bin/ocm /usr/local/bin/ocm +COPY --from=build /src/bin/ocm /usr/local/bin/ocm # https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys LABEL org.opencontainers.image.description="Open Component Model command line interface based on Distroless" diff --git a/Makefile b/Makefile index 726de3d3f2..87542905e6 100644 --- a/Makefile +++ b/Makefile @@ -26,12 +26,14 @@ SOURCES := $(shell go list -f '{{$$I:=.Dir}}{{range .GoFiles }}{{$$I}}/{{.}} {{e GOPATH := $(shell go env GOPATH) NOW := $(shell date -u +%FT%T%z) -BUILD_FLAGS := "-s -w \ +LD_FLAGS := "-s -w \ -X ocm.software/ocm/api/version.gitVersion=$(EFFECTIVE_VERSION) \ -X ocm.software/ocm/api/version.gitTreeState=$(GIT_TREE_STATE) \ -X ocm.software/ocm/api/version.gitCommit=$(COMMIT) \ -X ocm.software/ocm/api/version.buildDate=$(NOW)" CGO_ENABLED := 0 +GOOS := $(shell go env GOOS) +GOARCH := $(shell go env GOARCH) COMPONENTS ?= ocmcli helminstaller demoplugin ecrplugin helmdemo subchartsdemo @@ -42,19 +44,19 @@ bin: mkdir -p bin bin/ocm: bin $(SOURCES) - CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/ocm ./cmds/ocm + CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(BUILD_FLAGS) -ldflags $(LD_FLAGS) -o bin/ocm ./cmds/ocm bin/helminstaller: bin $(SOURCES) - CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/helminstaller ./cmds/helminstaller + CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(BUILD_FLAGS) -ldflags $(LD_FLAGS) -o bin/helminstaller ./cmds/helminstaller bin/demo: bin $(SOURCES) - CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/demo ./cmds/demoplugin + CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(BUILD_FLAGS) -ldflags $(LD_FLAGS) -o bin/demo ./cmds/demoplugin bin/cliplugin: bin $(SOURCES) - CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/cliplugin ./cmds/cliplugin + CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(BUILD_FLAGS) -ldflags $(LD_FLAGS) -o bin/cliplugin ./cmds/cliplugin bin/ecrplugin: bin $(SOURCES) - CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/ecrplugin ./cmds/ecrplugin + CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(BUILD_FLAGS) -ldflags $(LD_FLAGS) -o bin/ecrplugin ./cmds/ecrplugin api: $(SOURCES) go build ./api/... diff --git a/components/helminstaller/Makefile b/components/helminstaller/Makefile index e6c8d43b1c..9dafc4da79 100644 --- a/components/helminstaller/Makefile +++ b/components/helminstaller/Makefile @@ -23,6 +23,14 @@ PLATFORM := $(shell go env GOOS)/$(shell g CACHE_DIR := $(shell go env GOCACHE) MOD_CACHE_DIR := $(shell go env GOMODCACHE) + +ifneq ($(BUILDX_CACHE_REF),) + ADDITIONAL_BUILDX_ARGS += --cache-from type=registry,ref=$(BUILDX_CACHE_REF) + ifeq ($(BUILDX_CACHE_PUSH),true) + ADDITIONAL_BUILDX_ARGS += --cache-to type=registry,ref=$(BUILDX_CACHE_REF) + endif +endif + CREDS ?= # Define the path to the binary OCM_BIN = $(REPO_ROOT)/bin/ocm @@ -48,7 +56,7 @@ BUILD_FLAGS := "-s -w \ -X ocm.software/ocm/api/version.buildDate=$(NOW)" CMDSRCS=$(shell find $(REPO_ROOT)/cmds/$(NAME) -type f) -OCMSRCS=$(shell find $(REPO_ROOT)/pkg -type f) $(REPO_ROOT)/go.* +OCMSRCS=$(shell find $(REPO_ROOT)/api -type f) $(REPO_ROOT)/go.* ifeq ($(MULTI),true) FLAGSUF = .multi @@ -89,7 +97,7 @@ $(GEN)/image.$(NAME): $(GEN)/.exists Dockerfile $(CMDSRCS) $(OCMSRCS) --build-arg CACHE_DIR=$(CACHE_DIR) \ --build-arg MOD_CACHE_DIR=$(MOD_CACHE_DIR) \ --build-arg EFFECTIVE_VERSION=$(EFFECTIVE_VERSION) \ - --build-arg GIT_TREE_STATE=$(GIT_TREE_STATE); \ + --build-arg GIT_TREE_STATE=$(GIT_TREE_STATE) $(ADDITIONAL_BUILDX_ARGS); \ @touch $(GEN)/image.$(NAME) push-image: @@ -108,7 +116,7 @@ $(GEN)/image.$(NAME).multi: $(GEN)/.exists Dockerfile $(CMDSRCS) $(OCMSRCS) --build-arg CACHE_DIR=$(CACHE_DIR) \ --build-arg MOD_CACHE_DIR=$(MOD_CACHE_DIR) \ --build-arg EFFECTIVE_VERSION=$(EFFECTIVE_VERSION) \ - --build-arg GIT_TREE_STATE=$(GIT_TREE_STATE); \ + --build-arg GIT_TREE_STATE=$(GIT_TREE_STATE) $(ADDITIONAL_BUILDX_ARGS); \ done @touch $(GEN)/image.$(NAME).multi diff --git a/components/ocmcli/Dockerfile b/components/ocmcli/Dockerfile deleted file mode 100644 index b17ec7e741..0000000000 --- a/components/ocmcli/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -# This Dockerfile is used by `make` via the Makefile - -FROM --platform=$BUILDPLATFORM gcr.io/distroless/static-debian12:nonroot@sha256:d71f4b239be2d412017b798a0a401c44c3049a3ca454838473a4c32ed076bfea - -ARG SUFFIX -ARG OCM_VERSION - -COPY gen/ocmcli/ocmcli.$SUFFIX /usr/local/bin/ocm - -# https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys -LABEL org.opencontainers.image.description="Open Component Model command line interface based on Distroless" -LABEL org.opencontainers.image.vendor="SAP SE" -LABEL org.opencontainers.image.licenses="Apache-2.0" -LABEL org.opencontainers.image.url="https://ocm.software/" -LABEL org.opencontainers.image.source="https://github.com/open-component-model/ocm" -LABEL org.opencontainers.image.title="ocm" -LABEL org.opencontainers.image.version="${OCM_VERSION}" -LABEL org.opencontainers.image.revision="${OCM_VERSION}" -LABEL org.opencontainers.image.documentation="https://github.com/open-component-model/ocm/blob/main/docs/reference/ocm.md" -LABEL org.opencontainers.image.base.name="gcr.io/distroless/static-debian12:nonroot" - -ENTRYPOINT ["/usr/local/bin/ocm"] -CMD ["version"] diff --git a/components/ocmcli/Makefile b/components/ocmcli/Makefile index 20915dab42..aa5174f443 100644 --- a/components/ocmcli/Makefile +++ b/components/ocmcli/Makefile @@ -31,6 +31,13 @@ ifeq ($(MULTI),true) FLAGSUF = .multi endif +ifneq ($(BUILDX_CACHE_REF),) + ADDITIONAL_BUILDX_ARGS += --cache-from type=registry,ref=$(BUILDX_CACHE_REF) + ifeq ($(BUILDX_CACHE_PUSH),true) + ADDITIONAL_BUILDX_ARGS += --cache-to type=registry,ref=$(BUILDX_CACHE_REF),mode=max + endif +endif + CREDS ?= # Define the path to the binary OCM_BIN = $(REPO_ROOT)/bin/ocm @@ -68,40 +75,35 @@ $(GEN)/build: $(GEN) $(GEN)/.exists $(CMDSRCS) $(OCMSRCS) @touch $(GEN)/build .PHONY: image -image: $(GEN)/image - -$(GEN)/image: $(GEN)/.exists Dockerfile $(GEN)/build +image: @PLATFORM_OS_OVERRIDE=$(PLATFORM_OS); \ if [ $$PLATFORM_OS_OVERRIDE == darwin ]; then \ echo; echo "Building linux instead of darwin as there's no native Docker platform for darwin"; echo; \ - docker buildx build -t $(IMAGE):$(VERSION) --platform linux/$(PLATFORM_ARCH) --file Dockerfile $(REPO_ROOT) \ - --build-arg OCM_VERSION=$(EFFECTIVE_VERSION) \ - --build-arg SUFFIX=$$(echo linux/$(PLATFORM_ARCH) | sed -e s:/:-:g); \ + docker buildx build -t $(IMAGE):$(VERSION) --platform linux/$(PLATFORM_ARCH) --file $(REPO_ROOT)/Dockerfile $(REPO_ROOT) \ + --label org.opencontainers.image.version=$(VERSION) \ + --label org.opencontainers.image.revision=$(VERSION) $(ADDITIONAL_BUILDX_ARGS); \ else \ echo; echo "Building for $(PLATFORM_OS)/$(ARCH)"; echo; \ - docker buildx build -t $(IMAGE):$(VERSION) --platform $(PLATFORM_OS)/$(PLATFORM_ARCH) --file Dockerfile $(REPO_ROOT) \ - --build-arg OCM_VERSION=$(EFFECTIVE_VERSION) \ - --build-arg SUFFIX=$$(echo $(PLATFORM_OS)/$(PLATFORM_ARCH) | sed -e s:/:-:g); \ + docker buildx build -t $(IMAGE):$(VERSION) --platform $(PLATFORM_OS)/$(PLATFORM_ARCH) --file $(REPO_ROOT)/Dockerfile $(REPO_ROOT) \ + --label org.opencontainers.image.version=$(VERSION) \ + --label org.opencontainers.image.revision=$(VERSION) $(ADDITIONAL_BUILDX_ARGS); \ fi - @touch $(GEN)/image .PHONY: image.multi -image.multi: $(GEN)/image.multi - -$(GEN)/image.multi: Dockerfile $(GEN)/build +image.multi: for i in $(IMAGE_PLATFORMS); do \ - tag=$$(echo $$i | sed -e s:/:-:g); \ - echo building platform $$i; \ - docker buildx build --load -t $(IMAGE):$(VERSION)-$$tag --platform $$i --file Dockerfile $(REPO_ROOT) \ - --build-arg OCM_VERSION=$(EFFECTIVE_VERSION) \ - --build-arg SUFFIX=$$tag; \ + tag=$$(echo $$i | sed -e s:/:-:g); \ + echo building platform $$i; \ + docker buildx build --load -t $(IMAGE):$(VERSION)-$$tag --platform $$i --file $(REPO_ROOT)/Dockerfile $(REPO_ROOT) \ + --build-arg OCM_VERSION=$(EFFECTIVE_VERSION) \ + --label org.opencontainers.image.version=$(VERSION) \ + --label org.opencontainers.image.revision=$(VERSION) $(ADDITIONAL_BUILDX_ARGS); \ done - @touch $(GEN)/image.multi .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(OCM_BIN) $(GEN)/.exists $(GEN)/build $(GEN)/image$(FLAGSUF) component-constructor.yaml $(CHARTSRCS) Makefile +$(GEN)/ctf: $(OCM_BIN) $(GEN)/.exists $(GEN)/build image$(FLAGSUF) component-constructor.yaml $(CHARTSRCS) Makefile @rm -rf "$(GEN)/ctf" $(OCM) add componentversions \ --create \