From db3d8f703b1b0c76c1b3fe0eee82cdeb1f293ee4 Mon Sep 17 00:00:00 2001 From: Eng Zer Jun Date: Thu, 10 Apr 2025 02:12:30 +0800 Subject: [PATCH 1/2] Optimize Docker build with bind mounts This commit further optimize the Docker builds on top of PR #92 with: 1. Add .dockerignore file to exclude non-source code files [1]. 2. Use Alpine image variant for build stage to reduce download size. golang:1.23.7-alpine is 200 MB smaller than golang:1.23.7 [2][3]. 3. Replace COPY instruction with RUN --mount=type=bind. Bind mounts do not add unnecessary layers to the cache [4][5]. [1]: https://docs.docker.com/build-cloud/optimization/#dockerignore-files [2]: https://hub.docker.com/layers/library/golang/1.23.7-alpine/images/sha256-333d4ba78773b3a3ae9cf2cff8962df56effc5c9481faa355f211abf2baf175c [3]: https://hub.docker.com/layers/library/golang/1.23.7/images/sha256-2087a99c3235972660b3d35c1564d9d1a3f639dcace9c790acbabc7e938d1570 [4]: https://docs.docker.com/build/building/best-practices/#add-or-copy [5]: https://docs.docker.com/build/cache/optimize/#use-bind-mounts Signed-off-by: Eng Zer Jun --- .dockerignore | 11 +++++++++++ Dockerfile | 24 ++++++++++++++---------- 2 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..8f302e7c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.github +.vscode +script +third-party +.dockerignore +.gitignore +**/*.yml +**/*.yaml +**/*.md +**/*_test.go +LICENSE diff --git a/Dockerfile b/Dockerfile index 05fe1ddd..bedb2ce1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,27 +1,31 @@ +FROM golang:1.23.7-alpine AS build ARG VERSION="dev" -FROM golang:1.23.7 AS build -# allow this step access to build arg -ARG VERSION # Set the working directory WORKDIR /build -RUN go env -w GOMODCACHE=/root/.cache/go-build +# Install git +RUN --mount=type=cache,target=/var/cache/apk \ + apk add git # Install dependencies -COPY go.mod go.sum ./ -RUN --mount=type=cache,target=/root/.cache/go-build go mod download +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=bind,source=go.mod,target=go.mod \ + --mount=type=bind,source=go.sum,target=go.sum \ + go mod download -COPY . ./ # Build the server -RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=${VERSION} -X main.commit=$(git rev-parse HEAD) -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ - -o github-mcp-server cmd/github-mcp-server/main.go +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + --mount=type=bind,target=. \ + CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=${VERSION} -X main.commit=$(git rev-parse HEAD) -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + -o /bin/github-mcp-server cmd/github-mcp-server/main.go # Make a stage to run the app FROM gcr.io/distroless/base-debian12 # Set the working directory WORKDIR /server # Copy the binary from the build stage -COPY --from=build /build/github-mcp-server . +COPY --from=build /bin/github-mcp-server . # Command to run the server CMD ["./github-mcp-server", "stdio"] From bc3a1cc136c5c511c8d2806ec25f916af7621a74 Mon Sep 17 00:00:00 2001 From: Eng Zer Jun Date: Fri, 11 Apr 2025 09:48:21 +0800 Subject: [PATCH 2/2] Remove `go mod download` step `go build` will automatically download module dependencies. In many cases, that is a much smaller set of modules than what is downloaded by `go mod download`. Size of GOMODCACHE with `go mod download: $ go clean -i -r -cache -modcache $ go mod download $ du -sh ~/go/pkg/mod 186M /home/jun/go/pkg/mod Size of GOMODCACHE with `go build`: $ go clean -i -r -cache -modcache $ CGO_ENABLED=0 go build -ldflags="-s -w" cmd/github-mcp-server/main.go go: downloading github.com/spf13/viper v1.20.1 go: downloading github.com/mark3labs/mcp-go v0.18.0 go: downloading github.com/google/go-github/v69 v69.2.0 go: downloading github.com/sirupsen/logrus v1.9.3 go: downloading github.com/spf13/cobra v1.9.1 go: downloading golang.org/x/sys v0.31.0 go: downloading github.com/spf13/afero v1.14.0 go: downloading github.com/fsnotify/fsnotify v1.8.0 go: downloading github.com/spf13/cast v1.7.1 go: downloading github.com/go-viper/mapstructure/v2 v2.2.1 go: downloading github.com/subosito/gotenv v1.6.0 go: downloading gopkg.in/yaml.v3 v3.0.1 go: downloading github.com/spf13/pflag v1.0.6 go: downloading github.com/pelletier/go-toml/v2 v2.2.3 go: downloading github.com/sagikazarmark/locafero v0.9.0 go: downloading golang.org/x/text v0.23.0 go: downloading github.com/google/uuid v1.6.0 go: downloading github.com/yosida95/uritemplate/v3 v3.0.2 go: downloading github.com/sourcegraph/conc v0.3.0 go: downloading github.com/google/go-querystring v1.1.0 $ du -sh ~/go/pkg/mod 80M /home/jun/go/pkg/mod Reference: https://stackoverflow.com/a/68172023/7902371 Signed-off-by: Eng Zer Jun --- Dockerfile | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index bedb2ce1..a759da70 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,13 +8,8 @@ WORKDIR /build RUN --mount=type=cache,target=/var/cache/apk \ apk add git -# Install dependencies -RUN --mount=type=cache,target=/go/pkg/mod \ - --mount=type=bind,source=go.mod,target=go.mod \ - --mount=type=bind,source=go.sum,target=go.sum \ - go mod download - # Build the server +# go build automatically download required module dependencies to /go/pkg/mod RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ --mount=type=bind,target=. \