Skip to content

Makefile flow#4554

Merged
jetstack-bot merged 3 commits intocert-manager:masterfrom
SgtCoDFish:maker
Dec 17, 2021
Merged

Makefile flow#4554
jetstack-bot merged 3 commits intocert-manager:masterfrom
SgtCoDFish:maker

Conversation

@SgtCoDFish
Copy link
Copy Markdown
Member

@SgtCoDFish SgtCoDFish commented Oct 26, 2021

Summary

This PR provides a make-based flow for building all cert-manager artifacts, with the intention of replacing bazel for deployments, with minimal changes. This isn't intended to fully remove bazel today, but instead to remove it for the development edit-build-run workflow and for cert-manager deployments, which are currently handled by cmrel.

Help for Reviewers

If you follow both "Comparison Against Old Releases" and "Building Everything + Signing" you should be able to easily compare an old bazel release and a "new" make release.

Comparison Against Old Releases

The goal here is that bin/release should contain everything needed for cmrel publish to be able to publish a release based on its contents, with minimal changes.

To compare bin/release with a previous release, the following may be helpful to check out an existing cert-manager release locally:

$ mkdir -p /tmp/maker/bzl
$ gsutil -m cp -r gs://cert-manager-release/stage/gcb/release/v1.6.0-beta.0-49914a057b39c887be0974c4657c095bd7724bc7 /tmp/maker/bzl/
$ ls /tmp/maker/bzl/v1.6.0-beta.0-49914a057b39c887be0974c4657c095bd7724bc7
...

Building Everything + Signing

Creating a full staged release includes signing the helm chart, which requires a GCP KMS key. I have a test one in my project and I can allowlist you to use it if you ask. Then, you should be able to run the following:

$ export CMREL_KEY="projects/jetstack-ashley-davis/locations/global/keyRings/testring/cryptoKeys/sha512key/cryptoKeyVersions/1"
# note you need to be allowlisted to sign using this test key! ask if you want that, or else you can create your own.
$ make -j8 -f make/Makefile staged-release

High Level Structure

The intention of this PR is that everything we need to stage a deployment can be built with exactly one command, including generating signatures. This build step should also be trivially run in parallel using make's -jN option.

$ make -j8 -f make/Makefile <target>
# lots of output...

The above command, starting from a clean repo with no bin/ dir but with a populated go build and module cache takes under 2 minutes to completely build and sign every artifact for a release when run on a developer laptop. The 2 minutes includes downloading and installing tools as dependencies (helm, cosign, etc).

Artifacts

Everything that's built is placed under bin/. Crucially, using make -f make/Makefile staged-release will create bin/release containing the same artifacts which bazel built, in the same format. In other words, bin/release should contain everything required to stage a complete release and side effect of this is that it should obsolete most of the logic in cmrel stage and allow a lot of cleanup there.

After this PR merges, cmrel stage will essentially become "clone repo, run make staged-release, upload to a bucket".

Notes / Differences from Bazel Artifacts

Lines prefixed with a ⚠️ denote functional changes which could affect others. Lines without a warning sign should be non-functional changes (e.g. a comment change)

Versioning

  • If HEAD is not a tag, a version like v1.6.0-67-gf4e2b2c3c will be generated using git describe --tags. This should uniquely identify practically all development builds.
    • The format is v<last-tag>-<N>-<commit-sha> where N is the number of commits since <last-tag>
    • This format is directly from git.
  • If HEAD is a tag, the tag will be used for the version.

Windows Client Binaries

  • We add a zip file for windows client binaries since tar.gz is less common on Windows
  • ⚠️ All windows client binaries now have a ".exe" extension

Helm Charts

  • We now write helm chart filenames using the correct version in the filename, rather than just naming the chart cert-manager.tgz. This more closely matches how helm expects chart filenames.
  • ⚠️ Helm charts are now packaged into cert-manager-manifests.tar.gz with their version in their filename
  • The helm chart signing being moved into the cert-manager repo means that it's possible to embed the artifacthub signKey annotation directly into the actual helm chart, which should improve the ArtifactHub UX. Previously this annotation was only added in our charts repo's index.yaml where it seemed to largely be ignored.

Signing

  • The make flow has support for signing helm charts (using cmrel as an installed standalone tool).
  • Includes a commented-out template for generating and signing a SHA256SUMS file automatically generated by the build process.
  • ⚠️ While not a breaking change, it's worth highlighting that the signing key information is currently hardcoded in a single file - deploy/charts/cert-manager/signkey_annotation.txt. This can obviously be improved later.

Containers

  • Containers are built with docker by default, but this is configurable through the CTR environment variable and both podman and nerdctl can be used as drop-in replacements.
  • ⚠️ When we build containers, the tag looks like cert-manager-controller-<arch>:<version> and doesn't include the registry (quay.io/...). This is to avoid creating a race condition if building containers in parallel. This will require a small change to cmrel publish, but seems worth to avoid this killing the ability to build containers in parallel.

Base Images

  • Adds a script for automatically updating base images, both distroless/base and distroless/static across all relevant arches.
  • All containers now use a distroless base image whose tag matches their arch (e.g. a s390x base for the s390x cert-manager containers). With bazel all containers used amd64, which never caused a problem with the distroless static images but would break if anyone tried to use dynamic or a debug distroless image on non-amd64 platforms.
  • Using distroless/base or distroless/static is now a configurable through a single env var (BASE_IMAGE_TYPE)

Binary Locations

Background: Bazel adds binaries to containers at a long unusual path, along with a symlink:

# taken from a layer in one of our webhook docker images
$ tree .
app
└── cmd
    └── webhook
        ├── webhook -> /app/cmd/webhook/webhook.runfiles/com_github_jetstack_cert_manager/cmd/webhook/webhook_/webhook
        └── webhook.runfiles
            └── com_github_jetstack_cert_manager
                ├── cmd
                │   └── webhook
                │       └── webhook_
                │           └── webhook
                └── external -> /app/cmd/webhook/webhook.runfiles

In other words, the actual binary is /app/cmd/webhook/webhook.runfiles/com_github_jetstack_cert_manager/cmd/webhook/webhook_/webhook and /app/cmd/webhook/webhook exists as a symlink to that binary.

  • ⚠️ The make version only adds the actual binary, this time at /app/cmd/webhook/webhook.
  • ⚠️ The make version doesn't add the external symlink seen in the tree above, either.

Licenses in Containers

  • ⚠️ The LICENSES file changed into a short string pointing people at our repo if they want to see licenses.
    • This is because LICENSES is 1.4MB on its own, which is absurdly wasteful for a file which nobody ever looks at or cares about.
    • This change alone shaves maybe ~3%-5% off the size of the cert-manager containers, basically for free.

Static manifests: cert-manager.yaml / cert-manager.crds.yaml

  • Some comments are different.
  • The static manifest now has the namespace resource at the top of the file rather than after the CRDs

Release Notes

/kind feature

Added a makefile based build workflow which doesn't depend on bazel

@SgtCoDFish SgtCoDFish marked this pull request as draft October 26, 2021 08:30
@jetstack-bot jetstack-bot added needs-kind Indicates a PR lacks a `kind/foo` label and requires one. dco-signoff: yes Indicates that all commits in the pull request have the valid DCO sign-off message. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. labels Oct 26, 2021
@jetstack-bot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: SgtCoDFish

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@jetstack-bot jetstack-bot added approved Indicates a PR has been approved by an approver from all required OWNERS files. do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Oct 26, 2021
@jetstack-bot jetstack-bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. and removed do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels Oct 29, 2021
Copy link
Copy Markdown
Contributor

@irbekrm irbekrm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've read through the scripts and I think in general this would be a huge improvement as it makes the build steps a lot less complex and I think that's important both because it will be easier to make changes in the future and because it will be less likely that bugs are introduced or scripts drift due to folks not really understanding them.

I agree with the approach in general, would like to play with these a bit more and think about any possible edge cases around ensuring that dependency etc changes are detected and understand the signing/sha generation a bit better. Also interested how this will fit into our e2e test setup

@maelvls
Copy link
Copy Markdown
Member

maelvls commented Nov 18, 2021

This looks great! I tried using nerdctl (containerd and buildkit both running rootless)

make -f make/Makefile CTR=nerdctl all-containers

It works as expected.

I think we should go on and have this PR merged and use that when releasing for 1.7.0-alpha.0.

Update: we were able to do "reproducible builds" using -trimpath and CGO_ENABLED=0:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath ./cmd/controller

@SgtCoDFish SgtCoDFish added kind/feature Categorizes issue or PR as related to a new feature. and removed needs-kind Indicates a PR lacks a `kind/foo` label and requires one. labels Nov 18, 2021
@jetstack-bot jetstack-bot added area/deploy Indicates a PR modifies deployment configuration size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Nov 24, 2021
@SgtCoDFish SgtCoDFish force-pushed the maker branch 6 times, most recently from af2f097 to bce89ca Compare November 29, 2021 22:49
Comment on lines +1 to +6
bin/*

!bin/server/**
!bin/scratch/cert-manager.license
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: this means "ignore everything in bin except these two paths", which are the only ones currently consumed by the Containerfile

@maelvls
Copy link
Copy Markdown
Member

maelvls commented Dec 2, 2021

The PR description is very good!!

After this PR merges, cmrel stage will essentially become "clone repo, run make staged-release, upload to a bucket".

Does it mean we are going to run make locally, and then upload bin/release a bucket manually with gsutil? If it is the case, shouldn't we have a make target upload-release for that?
Or are we going to be running some Cloud Build that will do that for us?

By the way, is there still a need for storing the staged artifacts to a bucket? Could we skip this step and upload the artifacts directly to the github release? And when we click "Publish", we have something that pushes these tarballs to quay.io?

@SgtCoDFish
Copy link
Copy Markdown
Member Author

SgtCoDFish commented Dec 2, 2021

The PR description is very good!!

Thanks 😁

After this PR merges, cmrel stage will essentially become "clone repo, run make staged-release, upload to a bucket".

Does it mean we are going to run make locally, and then upload bin/release a bucket manually with gsutil? If it is the case, shouldn't we have a make target upload-release for that? Or are we going to be running some Cloud Build that will do that for us?

I think that "upload-release" target should probably exist, yeah. I'll write it. All of this will run in Cloud Build for sure; that'll provide us all with centralized build logs, plus a stable but ephemeral build environment which can easily be defined in code.

By the way, is there still a need for storing the staged artifacts to a bucket? Could we skip this step and upload the artifacts directly to the github release? And when we click "Publish", we have something that pushes these tarballs to quay.io?

I think storing them in a bucket is good; it's a central source of truth (and also a backup) of all release artifacts and that's valuable I think. The uploading logic could be moved into the main cert-manager repo longer term - I think all of cmrel could happily move into this repo.

@SgtCoDFish
Copy link
Copy Markdown
Member Author

/test pull-cert-manager-e2e-v1-22

@SgtCoDFish
Copy link
Copy Markdown
Member Author

The e2e test failure is unrelated and caused by cert-manager/testing#611

@SgtCoDFish
Copy link
Copy Markdown
Member Author

SgtCoDFish commented Dec 3, 2021

Update: Working on adding the gcs upload + fixing containers atm, should have that finished soon

EDIT: Containers are now working as I intended them to. I've not done the google cloud upload, I might leave that for a separate PR just so this one has less in it. (Also gsutil isn't as trivial to install locally, so I was looking at other tools like rclone)

Copy link
Copy Markdown
Contributor

@JoshVanL JoshVanL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good from me. Just have a few things, most of them come down to file/dir structure/placement- slightly bikesheddy, but a good dir structure I think goes a long way. It is obviously a bit trickier atm with bazel still around and squatting all the good names.

Nice work 😄

@SgtCoDFish
Copy link
Copy Markdown
Member Author

Nice work

Thank you!

I think I've addressed all comments now; I didn't want to delve too deep into extending make help for all possible useful invocations because they appear across so many different files ATM. There has to be a better way of surfacing targets such as make tools; probably those helpful .PHONY targets should all be defined in the main Makefile...

Signed-off-by: Ashley Davis <ashley.davis@jetstack.io>
hash.sh returns just the sha256sum of its input file

checkhash.sh uses ha.sh to get the sha256sum of its first argument and
then validates that the checksum matches the value provided in its
second argument

hash.sh isn't currently fully portable since sha256sum isn't present
by default on macOS, but it provides a single point around which we can
do hashing to validate checksums

Signed-off-by: Ashley Davis <ashley.davis@jetstack.io>
Includes targets for:

- all "server" binaries, for all arches
- all containers for all server binaries for all arches
- all client binaries (kubectl plugin / cmctl) for all arches
- the cert-manager helm chart + signature
- the cert-manager static manifests + CRDs
- tools which bazel would download, with checksum verification
- (commented out) a signed SHA256SUM file for client binaries

Upgrades from the bazel flow include that:

- we use OS-specific base images rather than just using amd64 everywhere
- we easily add support for signing artifacts at build time
- we add ".exe" to the end of windows executables
- we add a zip file for windows executables, for easier consumption
- we concatenate YAML files more robustly
- staging a full release should be much faster
- hopefully, it's easier to change things!
- licenses are trimmed down to reduce bloat in images (the license
  bundle was 1.4MB in size alone)

Changes from the bazel flow include:

- containers no longer have a symlink to the binary at an unusual
  path, but instead just have the binary at a more predictable path
  (e.g. /app/cmd/webhook/webhook instead of
  /app/cmd/webhook/webhook.runfiles/com_github_jetstack_cert_manager/cmd/webhook/webhook_/webhook)

Signed-off-by: Ashley Davis <ashley.davis@jetstack.io>
@maelvls
Copy link
Copy Markdown
Member

maelvls commented Dec 17, 2021

/lgtm

🔥🎄

@jetstack-bot jetstack-bot added the lgtm Indicates that a PR is ready to be merged. label Dec 17, 2021
@jetstack-bot jetstack-bot merged commit 0b8eba6 into cert-manager:master Dec 17, 2021
@SgtCoDFish SgtCoDFish deleted the maker branch December 17, 2021 11:28
@SgtCoDFish SgtCoDFish mentioned this pull request Jan 5, 2022
30 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. area/deploy Indicates a PR modifies deployment configuration dco-signoff: yes Indicates that all commits in the pull request have the valid DCO sign-off message. kind/feature Categorizes issue or PR as related to a new feature. lgtm Indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants