From 9b15f32087e7a33f88e930d19def8f7e57a2a48d Mon Sep 17 00:00:00 2001 From: Rohan Verma Date: Mon, 25 Nov 2019 01:37:21 +0530 Subject: [PATCH] blog: Building Go Plugins inside Docker --- ...019-11-24-build-go-plugins-using-docker.md | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 content/blog/2019/2019-11-24-build-go-plugins-using-docker.md diff --git a/content/blog/2019/2019-11-24-build-go-plugins-using-docker.md b/content/blog/2019/2019-11-24-build-go-plugins-using-docker.md new file mode 100644 index 0000000..c80267d --- /dev/null +++ b/content/blog/2019/2019-11-24-build-go-plugins-using-docker.md @@ -0,0 +1,65 @@ ++++ +title = "Building Go Plugins inside Docker" +date = 2019-11-24T15:30:03+05:30 +draft = false +tags = ["golang", "docker"] +categories = ["tutorials"] +type = "post" +url = "blog/2019/11/15/building-go-plugins-using-docker" +author = "Rohan Verma" ++++ + +Using Go plugins in your projects comes with a lot of caveats. As of writing, +there hasn't been much development on the feature recently. The +[commit history](https://github.com/golang/go/commits/master/src/plugin/plugin.go) +shows us that the last commit happened nearly 2 years ago. On the gopher slack, +the sentiment, more or less, is that this is not a priority anymore. Along with +this, there are multiple issues that come up with maintaining projects that use +it: + +- The go version for both host and plugin should match exactly +- External dependencies should match +- Host and plugin `GOPATH` needs to exactly match while building +- Plugins cannot depend on interfaces or structs of the host + +To learn more you can refer [this issue](https://github.com/golang/go/issues/20481#issuecomment-326832200) detailing some of the problems with +go plugins + +It works well if the projects bundles all the plugins in its own source tree and +both the host and plugins are built together at the same time. But, that limits +the scope of the project. Externally maintained plugins are impossible to +build independent of the host program. + +To solve this, we can use Docker to build both the host program, the bundled plugins, +and the custom plugin together. Then this image can be distributed instead +of distributing the host and loading the plugins separately in production. + +```Dockerfile +FROM golang:1.12-alpine AS builder +RUN apk update && apk add gcc libc-dev make git +WORKDIR /myproject-plugin/ +# Clone and build myproject and myproject-plugin together +# prevent version conflict for go plugins +RUN git clone https://github.com/rhnvrm/myproject.git && \ + mkdir -p myproject/bundled_plugins/myplugin +# Load our custom plugin from disk +COPY ./myplugin.go ./myproject/bundled_plugins/myplugin/myplugin.go +# CGO_ENABLED=1 is required +ENV CGO_ENABLED=1 GOOS=linux +# `make build` builds the host program and bundled plugins +# `go build` our custom plugin +RUN cd myproject && \ + make deps && make build && \ + go build -ldflags="-s -w" -buildmode=plugin -o myplugin.prov \ + bundled_plugins/myplugin/myplugin.go + +FROM alpine:latest AS deploy +RUN apk --no-cache add ca-certificates +WORKDIR /myproject/ +# Copy the assets from the builder image +COPY --from=builder /myproject-plugin/myproject/myproject /myproject-plugin/myproject-plugin/myproject/smtp.prov /myproject-plugin/myproject/bundled1.prov /myproject-plugin/myproject/bundled2.prov /myproject-plugin/myproject/myplugin.prov ./ + +CMD ["./myproject", "--config", "/etc/myproject/config.toml", "--prov", "smtp.prov", "--prov", "bundled1.prov", "--prov", "bundled2.prov", "--prov", "myplugin.prov"] +``` + +This image can then be pushed and used where it needs to be deployed. \ No newline at end of file