Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed CI and local builds up #944

Merged
merged 18 commits into from
Jun 28, 2019
Merged

Speed CI and local builds up #944

merged 18 commits into from
Jun 28, 2019

Conversation

2opremio
Copy link
Contributor

@2opremio 2opremio commented Jun 26, 2019

This change speeds CI builds up by using a docker image (weaveworks/eksctl-build:deps-VERSION) as dependency-cache and CircleCI's caching system for caching go modules ($GOPATH/pkg/mod) and the go build artifacts (go env GOCACHE). Fixes #920

Dependencies don't change all that often, so caching them should save us a lot of time.

The change also speeds local builds and tests up since:

  1. We no longer need to generate code if it's not needed (there are proper file dependencies in place now)
  2. I disabled test coverage (it wasn't used) allowing go to cache test results (see
    cmd/go: coverage profile should be cached with tests golang/go#23565 )

Finally, the change makes building the eksctl-image faster since the local go caches are mounted when building.

CI build times are:

So, this change brings a ~66% speed improvement compared to master and a ~42% improvement compared to before go modules were introduced. Things will get even faster once #935 (comment) is addressed.

This change follows @errordeveloper's vision of keeping caching independent of the CI-system. It is inspired by this blog post and this Stackoverflow question.

For now the dependency-cache image needs to be manually pushed (which I did), just like it was done before with weaveworks/eksctl-build:latest, which isn't ideal doesn't worsen the current situation. I will automate it once https://github.com/weaveworks/corp/issues/350 is resolved.

PS: @errordeveloper FYI, using Docker images as a caching layer is a neat idea. However, Docker is not really made for this: the downsides (it took a couple of days to get it right, namely due to the file hashing invalidation and image pulling is slow in comparison with a caching-optimized storage) don't make it up for the upsides (having a CI-system-independent caching system). I think it would had taken me way less effort to use the CircleCI cache (see fluxcd/flux#2078 ). Well, at least I learned about layer caching in Docker ...

@2opremio 2opremio self-assigned this Jun 26, 2019
@2opremio 2opremio force-pushed the fons/build-cache branch 5 times, most recently from 1d71870 to d805939 Compare June 26, 2019 17:16
@2opremio 2opremio changed the title Fons/build cache Speed up CI builds Jun 26, 2019
@2opremio 2opremio changed the title Speed up CI builds Speed CI builds up Jun 26, 2019
@2opremio 2opremio removed their assignment Jun 26, 2019
@2opremio 2opremio force-pushed the fons/build-cache branch 4 times, most recently from 4f14ae9 to 25b4c8f Compare June 26, 2019 20:21
@errordeveloper
Copy link
Contributor

errordeveloper commented Jun 26, 2019

Awesome, thanks! I might not find the time tomorrow to look into the details, but happy to go ahead with this. I mostly want to look at it out of curiosity, please don't block on my review.

@2opremio
Copy link
Contributor Author

I've sprinkled the makefile with time invocations to see why the build/testing still takes so long. The plan is to remove it once we optimize it.

Makefile Show resolved Hide resolved
Makefile Show resolved Hide resolved
.gitignore Outdated Show resolved Hide resolved
Makefile Outdated
@# 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 0600 go.mod go.sum
chmod 0700 install-build-deps.sh
Copy link
Contributor

Choose a reason for hiding this comment

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

Alternatively, we could tar up the context and pass to docker via stdin, I've seen it done in LinuxKit. Just FYI.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you have a link?

Copy link
Contributor

Choose a reason for hiding this comment

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

No, LinuxKit has build system written in Go no.

But see the docs, there are multiple options of how you can pass the context.

@2opremio
Copy link
Contributor Author

2opremio commented Jun 27, 2019

The main bottlenecks in the build currently are:

  • Linting, which takes a ridiculous amount of time (2 minutes)
  • Code generation
  • Duplicated things. Due to buggy make rules, we generate the kubernetes code twice and call make build-integration-test twice. There are probably more duplicated things.

@2opremio
Copy link
Contributor Author

2opremio commented Jun 27, 2019

Update:

I have updated the PR to:

  1. Use CircleCI cache for persisting the project's build cache and modules, and a Docker image cache for the project dependencies. This simplifies the code (for instance, no need to generate dependencies) and brings a big performance boost.
  2. Improve the Makefiles rules. Now no code is generated if there is no need to.

We are now at a 4.5-minute build mark!

I have updated the PR description and measurements accordingly.

I know @errordeveloper is not going to like the use of CircleCI, but persisting Go's build cache and modules for changing source code can't really be done with Docker image caching (i.e. --cache-from) due to its layer-matching strictness (as soon as a single input source-file is off the whole cache is invalidated).

Duplicated things. Due to buggy make rules, we generate the kubernetes code twice and call make build-integration-test twice. There are probably more duplicated things.

This has been fixed

@errordeveloper @martina-if PTAL

@2opremio 2opremio force-pushed the fons/build-cache branch 7 times, most recently from 5da8e16 to ab4a508 Compare June 27, 2019 21:25
@2opremio 2opremio force-pushed the fons/build-cache branch 2 times, most recently from 4573bad to affba2f Compare June 28, 2019 10:56
Also, do not copy full sourcecode to buildcache container, since
it will cause caching to fail whenever the sourcecode changes
(we want to cache build dependencies).
It hasn't been needed for a long time https://golang.org/doc/go1.5#net

Also it was implicit when CGO_ENABLED=0 anyways
As a side-effect, I added a new build stage
Use ubuntu-1604:201903-01 because:
1. The default executor (ubuntu-1604:201903-01) uses Ubuntu 14.04, which reached
   EOL and Circle recommends ubuntu-1604:201903-01 (see
   https://circleci.com/docs/2.0/configuration-reference/#available-machine-images )
2. The default executor bundles Docker 17.09-ce which suffers from this bug,
   breaking caching: moby/moby#32816
It wasn't used and it prevents tests from being cached.

See golang/go#23565 for more details.
1. Use file targets instead of .PHONY ones when possible.

2. Avoid generating files if they are up to date

3. Use proper prerequisites
1. Remove PWD prefix for local dependencies (otherwise we need to specify the full path in the make targets)
2. Remove zz_generated.deepcopy.go from its prerequisites
@2opremio 2opremio changed the title Speed CI builds up Speed CI and local builds up Jun 28, 2019
@2opremio 2opremio merged commit 935f247 into master Jun 28, 2019
@2opremio 2opremio deleted the fons/build-cache branch June 28, 2019 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Speed CI up
3 participants