项目作者: crazy-max

项目描述 :
Cross compilation helper for GoReleaser
高级语言: Go
项目地址: git://github.com/crazy-max/goreleaser-xx.git
创建时间: 2021-03-04T23:00:30Z
项目社区:https://github.com/crazy-max/goreleaser-xx

开源协议:MIT License

下载


goreleaser-xx

GitHub release
Build Status
Docker Stars
Docker Pulls
Go Report Card

⚠️ Abandoned project

This project is not maintained anymore and is abandoned. Feel free to fork and
make your own changes if needed.

About

goreleaser-xx is a small CLI wrapper for GoReleaser
and available as a lightweight and multi-platform scratch Docker image
to ease the integration and cross compilation in a Dockerfile for your Go
projects.

Building yasu with goreleaser-xx


Features

  • Handle --platform in your Dockerfile for multi-platform support
  • Build into any architecture
  • Handle C and C++ compilers (CGO)
  • Translation of platform ARGs in the global scope into Go compiler’s target
  • Auto generation of .goreleaser.yml config based on target architecture
  • Demo projects

Image

Registry Image
Docker Hub crazymax/goreleaser-xx
GitHub Container Registry ghcr.io/crazy-max/goreleaser-xx

Following platforms for this image are available:

  1. $ docker run --rm mplatform/mquery crazymax/goreleaser-xx:latest
  2. Image: crazymax/goreleaser-xx:latest (digest: sha256:c65c481c014abab6d307b190ddf1fcb229a44b6c1845d2f2a53bd06dc0437cd7)
  3. * Manifest List: Yes (Image type: application/vnd.docker.distribution.manifest.list.v2+json)
  4. * Supported platforms:
  5. - linux/386
  6. - linux/amd64
  7. - linux/arm/v5
  8. - linux/arm/v6
  9. - linux/arm/v7
  10. - linux/arm64
  11. - linux/ppc64le
  12. - linux/riscv64
  13. - linux/s390x

CLI

  1. docker run --rm -t crazymax/goreleaser-xx:latest goreleaser-xx --help
Flag Env var Description
--debug DEBUG Enable debug (default false)
--git-ref GIT_REF The branch or tag like refs/tags/v1.0.0 (default to your working tree info)
--goreleaser GORELEASER_PATH Set a specific GoReleaser binary to use (default goreleaser)
--config GORELEASER_CONFIG Load GoReleaser configuration from file
--go-binary GORELEASER_GOBINARY Set a specific go binary to use when building (default go)
--name GORELEASER_NAME Project name
--dist GORELEASER_DIST Dist folder where artifact will be stored
--artifacts GORELEASER_ARTIFACTS Types of artifact to create (archive, bin) (default archive)
--main GORELEASER_MAIN Path to main.go file or main package (default .)
--flags GORELEASER_FLAGS Custom flags templates
--asmflags GORELEASER_ASMFLAGS Custom asmflags templates
--gcflags GORELEASER_GCFLAGS Custom gcflags templates
--ldflags GORELEASER_LDFLAGS Custom ldflags templates
--tags GORELEASER_TAGS Custom build tags templates
--files GORELEASER_FILES Additional files/template/globs you want to add to the archive
--replacements GORELEASER_REPLACEMENTS Replacements for GOOS and GOARCH in the archive/binary name
--envs GORELEASER_ENVS Custom environment variables to be set during the build
--pre-hooks GORELEASER_PRE_HOOKS Hooks which will be executed before the build
--post-hooks GORELEASER_POST_HOOKS Hooks which will be executed after the build
--snapshot GORELEASER_SNAPSHOT Run in snapshot mode
--checksum GORELEASER_CHECKSUM Create checksum (default true)

Usage

In order to use it, we will use the docker buildx command in the following
examples. Buildx is a Docker component that
enables many powerful build features. All builds executed via buildx run with
Moby BuildKit builder engine.

Minimal

Here is a minimal Dockerfile to build a Go project using goreleaser-xx:

  1. # syntax=docker/dockerfile:1
  2. FROM --platform=$BUILDPLATFORM crazymax/goreleaser-xx:latest AS goreleaser-xx
  3. FROM --platform=$BUILDPLATFORM golang:1.17-alpine AS base
  4. ENV CGO_ENABLED=0
  5. COPY --from=goreleaser-xx / /
  6. RUN apk add --no-cache git
  7. WORKDIR /src
  8. FROM base AS vendored
  9. RUN --mount=type=bind,source=.,rw \
  10. --mount=type=cache,target=/go/pkg/mod \
  11. go mod tidy && go mod download
  12. FROM vendored AS build
  13. ARG TARGETPLATFORM
  14. RUN --mount=type=bind,source=.,rw \
  15. --mount=type=cache,target=/root/.cache \
  16. --mount=type=cache,target=/go/pkg/mod \
  17. goreleaser-xx --debug \
  18. --name="myapp" \
  19. --dist="/out" \
  20. --ldflags="-s -w -X 'main.version={{.Version}}'" \
  21. --files="LICENSE" \
  22. --files="README.md"
  23. FROM scratch AS artifact
  24. COPY --from=build /out/*.tar.gz /
  25. COPY --from=build /out/*.zip /
  • FROM --platform=$BUILDPLATFORM ... command will pull an image that will
    always match the native platform of your machine (e.g., linux/amd64).
    BUILDPLATFORM is part of the ARGs in the global scope.
  • ARG TARGETPLATFORM is also an ARG in the global scope that will be set
    to the platform of the target that will default to your current platform or
    can be defined via the --platform flag
    of buildx so goreleaser-xx will be able to automatically build against
    the right platform.

More details about multi-platform builds in this @tonistiigi/faster-multi-platform-builds-dockerfile-cross-compilation-guide-part-1-ec087c719eaf">blog post.

As you can see goreleaser-xx CLI handles basic GoReleaser build customizations
with flags to be able to generate a temp and dynamic .goreleaser.yml configuration,
but you can also include your own GoReleaser YAML config.

Let’s run a simple build against the artifact target in our Dockerfile:

  1. # build and output content of the artifact stage that contains the archive in ./dist
  2. docker buildx build \
  3. --output "./dist" \
  4. --target "artifact" .
  5. $ tree ./dist
  6. ./dist
  7. ├── myapp_v1.0.0-SNAPSHOT-00655a9_linux_amd64.tar.gz
  8. └── myapp_v1.0.0-SNAPSHOT-00655a9_linux_amd64.tar.gz.sha256

Here linux/amd64 arch is used because it’s my current platform. If we want
to handle more platforms, we need to create a builder instance as building
multi-platform is currently only supported when using BuildKit with the
docker-container or kubernetes drivers.

  1. # create a builder instance
  2. $ docker buildx create --name "mybuilder" --use
  3. # now build for other platforms
  4. $ docker buildx build \
  5. --platform "linux/amd64,linux/arm64,linux/arm/v7,windows/amd64,darwin/amd64" \
  6. --output "./dist" \
  7. --target "artifact" .
  8. $ tree ./dist
  9. ./dist
  10. ├── darwin_amd64
  11. ├── myapp_v1.0.0-SNAPSHOT-00655a9_darwin_x86_64.tar.gz
  12. └── myapp_v1.0.0-SNAPSHOT-00655a9_darwin_x86_64.tar.gz.sha256
  13. ├── linux_amd64
  14. ├── myapp_v1.0.0-SNAPSHOT-00655a9_linux_x86_64.tar.gz
  15. └── myapp_v1.0.0-SNAPSHOT-00655a9_linux_x86_64.tar.gz.sha256
  16. ├── linux_arm64
  17. ├── myapp_v1.0.0-SNAPSHOT-00655a9_linux_arm64.tar.gz
  18. └── myapp_v1.0.0-SNAPSHOT-00655a9_linux_arm64.tar.gz.sha256
  19. ├── linux_arm_v7
  20. ├── myapp_v1.0.0-SNAPSHOT-00655a9_linux_armv7.tar.gz
  21. └── myapp_v1.0.0-SNAPSHOT-00655a9_linux_armv7.tar.gz.sha256
  22. └── windows_amd64
  23. ├── myapp_v1.0.0-SNAPSHOT-00655a9_windows_x86_64.tar.gz
  24. └── myapp_v1.0.0-SNAPSHOT-00655a9_windows_x86_64.tar.gz.sha256

Multi-platform image

We can enhance the previous example to also create a multi-platform image in
addition to the generated artifacts:

  1. # syntax=docker/dockerfile:1
  2. FROM --platform=$BUILDPLATFORM crazymax/goreleaser-xx:latest AS goreleaser-xx
  3. FROM --platform=$BUILDPLATFORM golang:1.17-alpine AS base
  4. ENV CGO_ENABLED=0
  5. COPY --from=goreleaser-xx / /
  6. RUN apk add --no-cache git
  7. WORKDIR /src
  8. FROM base AS vendored
  9. RUN --mount=type=bind,source=.,rw \
  10. --mount=type=cache,target=/go/pkg/mod \
  11. go mod tidy && go mod download
  12. FROM vendored AS build
  13. ARG TARGETPLATFORM
  14. RUN --mount=type=bind,source=.,rw \
  15. --mount=type=cache,target=/root/.cache \
  16. --mount=type=cache,target=/go/pkg/mod \
  17. goreleaser-xx --debug \
  18. --name="myapp" \
  19. --dist="/out" \
  20. --ldflags="-s -w -X 'main.version={{.Version}}'" \
  21. --files="LICENSE" \
  22. --files="README.md"
  23. FROM scratch AS artifact
  24. COPY --from=build /out/*.tar.gz /
  25. COPY --from=build /out/*.zip /
  26. FROM alpine AS image
  27. RUN apk --update --no-cache add ca-certificates openssl
  28. COPY --from=build /usr/local/bin/myapp /usr/local/bin/myapp
  29. EXPOSE 8080
  30. ENTRYPOINT [ "myapp" ]

As you can see, we have added a new stage called image. The artifact of each
platform is available with goreleaser-xx in /usr/local/bin/{{ .ProjectName }}{{ .Ext }}
(build stage) and will be included in your image stage via COPY --from=build
command.

Now let’s build, tag and push our multi-platform image with buildx:

  1. docker buildx build \
  2. --tag "user/myapp:latest" \
  3. --platform "linux/amd64,linux/arm64,linux/arm/v7" \
  4. --target "image" \
  5. --push .

windows/amd64 and darwin/amd64 platforms have been removed here
because alpine:3.14 does not support them.

With .goreleaser.yml

You can also use a .goreleaser.yml to configure your build:

  1. env:
  2. - GO111MODULE=auto
  3. gomod:
  4. proxy: true
  5. builds:
  6. - mod_timestamp: '{{ .CommitTimestamp }}'
  7. flags:
  8. - -trimpath
  9. ldflags:
  10. - -s -w
  11. nfpms:
  12. - file_name_template: '{{ .ConventionalFileName }}'
  13. homepage: https://github.com/user/hello
  14. description: Hello world
  15. maintainer: Hello <hello@world.com>
  16. license: MIT
  17. vendor: HelloWorld
  18. formats:
  19. - apk
  20. - deb
  21. - rpm
  1. # syntax=docker/dockerfile:1
  2. FROM --platform=$BUILDPLATFORM crazymax/goreleaser-xx:latest AS goreleaser-xx
  3. FROM --platform=$BUILDPLATFORM golang:1.17-alpine AS base
  4. ENV CGO_ENABLED=0
  5. COPY --from=goreleaser-xx / /
  6. RUN apk add --no-cache git
  7. WORKDIR /src
  8. FROM base AS vendored
  9. RUN --mount=type=bind,source=.,rw \
  10. --mount=type=cache,target=/go/pkg/mod \
  11. go mod tidy && go mod download
  12. FROM vendored AS build
  13. ARG TARGETPLATFORM
  14. RUN --mount=type=bind,source=.,rw \
  15. --mount=type=cache,target=/root/.cache \
  16. --mount=type=cache,target=/go/pkg/mod \
  17. goreleaser-xx --debug \
  18. --config=".goreleaser.yml" \
  19. --name="hello" \
  20. --dist="/out" \
  21. --main="." \
  22. --files="README.md"
  23. FROM scratch AS artifact
  24. COPY --from=build /out/*.tar.gz /
  25. COPY --from=build /out/*.zip /

CGO

Here are some examples to use CGO to build your project with goreleaser-xx:

crazy-max/goxx

https://github.com/crazy-max/goxx

  1. # syntax=docker/dockerfile:1
  2. FROM --platform=$BUILDPLATFORM crazymax/goreleaser-xx:latest AS goreleaser-xx
  3. FROM --platform=$BUILDPLATFORM crazymax/osxcross:11.3 AS osxcross
  4. FROM --platform=$BUILDPLATFORM crazymax/goxx:1.17 AS base
  5. COPY --from=osxcross /osxcross /osxcross
  6. COPY --from=goreleaser-xx / /
  7. ENV CGO_ENABLED=1
  8. RUN goxx-apt-get install --no-install-recommends -y git
  9. WORKDIR /src
  10. FROM base AS vendored
  11. RUN --mount=type=bind,source=.,rw \
  12. --mount=type=cache,target=/go/pkg/mod \
  13. go mod tidy && go mod download
  14. FROM vendored AS build
  15. ARG TARGETPLATFORM
  16. RUN --mount=type=cache,sharing=private,target=/var/cache/apt \
  17. --mount=type=cache,sharing=private,target=/var/lib/apt/lists \
  18. goxx-apt-get install -y binutils gcc g++ pkg-config
  19. RUN --mount=type=bind,source=.,rw \
  20. --mount=type=cache,target=/root/.cache \
  21. --mount=type=cache,target=/go/pkg/mod \
  22. goreleaser-xx --debug \
  23. --name="myapp" \
  24. --dist="/out" \
  25. --ldflags="-s -w -X 'main.version={{.Version}}'" \
  26. --files="LICENSE" \
  27. --files="README.md"
  28. FROM scratch AS artifact
  29. COPY --from=build /out/*.tar.gz /
  30. COPY --from=build /out/*.zip /

tonistiigi/xx

https://github.com/tonistiigi/xx

  1. # syntax=docker/dockerfile:1
  2. FROM --platform=$BUILDPLATFORM crazymax/goreleaser-xx:latest AS goreleaser-xx
  3. FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.1.2 AS xx
  4. FROM --platform=$BUILDPLATFORM golang:1.17-alpine AS base
  5. ENV CGO_ENABLED=1
  6. COPY --from=goreleaser-xx / /
  7. COPY --from=xx / /
  8. RUN apk add --no-cache clang git file lld llvm pkgconfig
  9. WORKDIR /src
  10. FROM base AS vendored
  11. RUN --mount=type=bind,source=.,target=/src,rw \
  12. --mount=type=cache,target=/go/pkg/mod \
  13. go mod tidy && go mod download
  14. FROM vendored AS build
  15. ARG TARGETPLATFORM
  16. RUN xx-apk add --no-cache gcc musl-dev
  17. # XX_CC_PREFER_STATIC_LINKER prefers ld to lld in ppc64le and 386.
  18. ENV XX_CC_PREFER_STATIC_LINKER=1
  19. RUN --mount=type=bind,source=.,rw \
  20. --mount=from=crazymax/osxcross:11.3,src=/osxsdk,target=/xx-sdk \
  21. --mount=type=cache,target=/root/.cache \
  22. --mount=type=cache,target=/go/pkg/mod \
  23. goreleaser-xx --debug \
  24. --go-binary="xx-go" \
  25. --name="myapp" \
  26. --dist="/out" \
  27. --ldflags="-s -w -X 'main.version={{.Version}}'" \
  28. --files="LICENSE" \
  29. --files="README.md"
  30. FROM scratch AS artifact
  31. COPY --from=build /out/*.tar.gz /
  32. COPY --from=build /out/*.zip /

Notes

CGO_ENABLED

By default, CGO is enabled in Go when compiling for native architecture and
disabled when cross-compiling. It’s therefore recommended to always set
CGO_ENABLED=0 or CGO_ENABLED=1 when cross-compiling depending on whether
you need to use CGO or not.

Build

Everything is dockerized and handled by buildx bake for an
agnostic usage of this repo:

  1. git clone https://github.com/crazy-max/goreleaser-xx.git goreleaser-xx
  2. cd goreleaser-xx
  3. # build docker image and output to docker with goreleaser-xx:local tag (default)
  4. docker buildx bake
  5. # build multi-platform image
  6. docker buildx bake image-all

Contributing

Want to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. If
you want to open a pull request, please read the contributing guidelines.

You can also support this project by becoming a sponsor on GitHub or by
making a Paypal donation to ensure this journey continues indefinitely!

Thanks again for your support, it is much appreciated! :pray:

License

MIT. See LICENSE for more details.