I have an AppEngine micro service setup in a monorepo, there is shared code between services so I've refactored to unify my go modules (they're really similar). The refactor works locally, builds and runs, and Goland compiles happily. My issue is that AppEngine deploy no longer works, receiving erorrs such as:
Error message: cmd/main.go:4:2: cannot find package "github.com/gin-gonic/gin" in any of:
/usr/local/go/src/github.com/gin-gonic/gin (from $GOROOT)
/layers/google.go.appengine_gopath/gopath/src/github.com/gin-gonic/gin (from $GOPATH)
cmd/main.go:5:2: cannot find package "mymodulename/customer/internal/mypkg" in any of:
/usr/local/go/src/mymodulename/customer/internal/cauth (from $GOROOT)
/layers/google.go.appengine_gopath/gopath/src/mymodulename/customer/internal/mypkg (from $GOPATH)
Original structure
> svc1
> cmd/main.go
> internal
>utils/shared.go
>mypkg
> go.mod
> app.yaml
> svc2
> cmd/main.go
> internal
>utils/shared.go
>mypkg
> go.mod
> app.yaml
After refactor
> svc1
> cmd/main.go
> internal
>mypkg
> app.yaml
> svc2
> cmd/main.go
> internal
>mypkg
> app.yaml
> internal (common shared stuff)
> utils/shared.go
go.mod
Key points are utils/shared.go was moved to outside of each service directory and go.mod were unified.
What I'm unclear on is whether AppEngine builds the go binary on my local machine when i run glcoud app deploy
or whether is bundles everything and runs it in cloud build.
- How does AppEngine deploy work?
- How do I get the AppEngine deploy to find my go.mod file?
- How are the dependencies bundled? (if it's running on CloudBuild surely it doesnt have access to private repos)
The solution I've reached for anyone else who has the same issue. A few truths seem to exist, though the docs are somewhat ambiguous about it. The docs say:
But this does not seem to be true, infact, nothing seems to be copied at all above the app.yaml file.
So the solution requires:
go mod edit
is used to tell the Go compiler to look locally rather than try and fetch via the internet.A bit about local imports
Go appears to look for everything first in the dependency cache / paths, but then entirely on the internet. If I created my local package using
go mod init shared
, its module name is 'shared'. To tell Go that you want to import locally rather using the internet, invokego mod edit -replace=shared=../../shared/
, you should see your go.mod gets a line likereplace shared => ../../shared
. If you're using Goland and it still isn't compiling, tryFile>Invalidate Caches/Restart...
A bit about vendoring
go mod vendor
in your go.mod folder will bundle all dependendies, including local ones so they can be deployed by AppEngine. This is also a good way to deal with private repos so you don't need to git Cloud Build access to your repo.