diff --git a/Taskfile.yml b/Taskfile.yml index 6332255..ec31d77 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -66,15 +66,31 @@ tasks: sources: - ./**/*.go - build-image: - desc: Build a container image for the plugin + build-plugin-image: + desc: Build the operator container image for the plugin env: # renovate: datasource=git-refs depName=docker lookupName=https://github.com/purpleclay/daggerverse currentValue=main DAGGER_DOCKER_SHA: d7438770bfab8844a89c2923b9e2942e78de5239 cmds: - > GITHUB_REF= dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA} - build --dir . --platform linux/amd64 image > /dev/null + build --dir . --file containers/Dockerfile.plugin --platform linux/amd64 image > /dev/null + + build-sidecar-image: + desc: Build the sidecar container image for the plugin + env: + # renovate: datasource=git-refs depName=docker lookupName=https://github.com/purpleclay/daggerverse currentValue=main + DAGGER_DOCKER_SHA: d7438770bfab8844a89c2923b9e2942e78de5239 + cmds: + - > + GITHUB_REF= dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA} + build --dir . --file containers/Dockerfile.sidecar --platform linux/amd64 image > /dev/null + + build-images: + desc: Build the container images for the plugin + deps: + - build-plugin-image + - build-sidecar-image ci: desc: Run the CI pipeline @@ -84,7 +100,7 @@ tasks: - uncommitted - lint - go-test - - build-image + - build-images publish: desc: Build and publish a container image for the plugin @@ -99,7 +115,8 @@ tasks: - REGISTRY_USER - REGISTRY_PASSWORD vars: - IMAGE_NAME: ghcr.io/{{.GITHUB_REPOSITORY}}{{if not (hasPrefix "refs/tags/v" .GITHUB_REF)}}-testing{{end}} + PLUGIN_IMAGE_NAME: ghcr.io/{{.GITHUB_REPOSITORY}}{{if not (hasPrefix "refs/tags/v" .GITHUB_REF)}}-testing{{end}} + SIDECAR_IMAGE_NAME: ghcr.io/{{.GITHUB_REPOSITORY}}-sidecar{{if not (hasPrefix "refs/tags/v" .GITHUB_REF)}}-testing{{end}} # remove /merge suffix from the branch name. This is a workaround for the GitHub workflow on PRs, # where the branch name is suffixed with /merge. Prepend pr- to the branch name on PRs. IMAGE_VERSION: '{{regexReplaceAll "(\\d+)/merge" .GITHUB_REF_NAME "pr-${1}"}}' @@ -110,8 +127,13 @@ tasks: - > dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA} --registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD - build --dir . --platform linux/amd64 - publish --ref {{.IMAGE_NAME}} --tags {{.IMAGE_VERSION}} + build --dir . --file containers/Dockerfile.plugin --platform linux/amd64 --platform linux/arm64 + publish --ref {{.PLUGIN_IMAGE_NAME}} --tags {{.IMAGE_VERSION}} + - > + dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA} + --registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD + build --dir . --file containers/Dockerfile.sidecar --platform linux/amd64 --platform linux/arm64 + publish --ref {{.SIDECAR_IMAGE_NAME}} --tags {{.IMAGE_VERSION}} manifest: desc: Update the image in the Kustomization diff --git a/Dockerfile b/containers/Dockerfile.plugin similarity index 57% rename from Dockerfile rename to containers/Dockerfile.plugin index 31c9ae6..500c535 100644 --- a/Dockerfile +++ b/containers/Dockerfile.plugin @@ -5,27 +5,42 @@ ARG TARGETARCH WORKDIR /workspace # Copy the Go Modules manifests -COPY go.mod go.mod -COPY go.sum go.sum +COPY ../go.mod go.mod +COPY ../go.sum go.sum # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer RUN go mod download # Copy the go source -COPY cmd/instance/main.go cmd/instance/main.go -COPY api/ api/ -COPY internal/ internal/ +COPY ../cmd/operator/main.go cmd/operator/main.go +COPY ../api api/ +COPY ../internal internal/ # Build # 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 M1 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 CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/instance/main.go +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/operator/main.go # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details FROM gcr.io/distroless/static:nonroot + +ENV SUMMARY="CloudNativePG Barman plugin" \ + DESCRIPTION="Container image that provides the barman-cloud plugin" + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.display-name="$SUMMARY" \ + io.k8s.description="$DESCRIPTION" \ + name="CloudNativePG Barman plugin" \ + vendor="CloudNativePG Contributors" \ + url="https://cloudnative-pg.io/" \ + version="" \ + release="1" + WORKDIR / COPY --from=builder /workspace/manager . USER 65532:65532 diff --git a/containers/Dockerfile.sidecar b/containers/Dockerfile.sidecar new file mode 100644 index 0000000..6093f94 --- /dev/null +++ b/containers/Dockerfile.sidecar @@ -0,0 +1,54 @@ +# Sidecar +# The container needs to provide and build two components: +# * barman-cloud +# * instance plugin +# Both components are built before going into a distroless container + +# Build barman-cloud +# pip will build everything inside /usr/ since this is the case +# we should build and then copy every file into a destination that will +# then copy into the distroless container +FROM python:3.12-slim AS pythonbuilder +RUN apt-get update && \ + apt-get install -y postgresql-common build-essential && \ + /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y && \ + apt-get install -y libpq-dev && \ + pip install barman[azure,cloud,google,snappy]==3.11.1 setuptools +# Prepare a new /usr/ directory with the files we'll need in the final image +RUN mkdir /new-usr/ && \ + cp -r --parents /usr/local/lib/ /usr/lib/*-linux-gnu/ /usr/local/bin/ \ + /new-usr/ + +# Build instance +# This step builds a simple instance app that will manage and handle +# the barman-cloud commands inside the sidecar +FROM --platform=$BUILDPLATFORM golang:1.23.1 AS gobuilder +ENV CGO_ENABLED=0 +COPY .. /src +ARG TARGETOS +ARG TARGETARCH +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \ + GOOS=$TARGETOS GOARCH=$TARGETARCH go build -C /src -o /build/instance /src/cmd/instance/main.go + +# Joint process +# Now we put everything that was build from the origin into our +# distroless container +FROM gcr.io/distroless/python3-debian12:nonroot + +ENV SUMMARY="CloudNativePG Barman plugin" \ + DESCRIPTION="Container image that provides the barman-cloud sidecar" + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.display-name="$SUMMARY" \ + io.k8s.description="$DESCRIPTION" \ + name="CloudNativePG Barman plugin sidecar" \ + vendor="CloudNativePG Contributors" \ + url="https://cloudnative-pg.io/" \ + version="" \ + release="1" + +COPY --from=pythonbuilder /new-usr/* /usr/ +COPY --from=gobuilder /build/instance /usr/local/bin/instance +USER 26:26 +ENTRYPOINT ["/usr/local/bin/instance"] diff --git a/internal/cnpgi/operator/lifecycle.go b/internal/cnpgi/operator/lifecycle.go index 3c44eb7..56c3e75 100644 --- a/internal/cnpgi/operator/lifecycle.go +++ b/internal/cnpgi/operator/lifecycle.go @@ -85,6 +85,9 @@ func (impl LifecycleImplementation) LifecycleHook( Value: "/controller/wal-restore-spool", }, }, + Command: []string{ + "/usr/local/bin/instance", + }, }, true) if err != nil { return nil, err