{"id":21204785,"url":"https://github.com/leslieleung/go-multiplatform-docker","last_synced_at":"2025-07-04T09:05:37.702Z","repository":{"id":49341224,"uuid":"517274804","full_name":"LeslieLeung/go-multiplatform-docker","owner":"LeslieLeung","description":"A demo on how to build go multiplatform binaries and publish to release and DockerHub with GitHub Actions.","archived":false,"fork":false,"pushed_at":"2023-10-31T18:05:25.000Z","size":36,"stargazers_count":36,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-05T11:51:14.232Z","etag":null,"topics":["cicd","docker","github-actions","golang","multiplatform"],"latest_commit_sha":null,"homepage":"","language":"Makefile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LeslieLeung.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-24T09:03:47.000Z","updated_at":"2024-11-05T05:27:12.000Z","dependencies_parsed_at":"2024-11-20T20:40:26.047Z","dependency_job_id":"9a4bd1f1-a8c1-4beb-9cc9-5123e1892ddf","html_url":"https://github.com/LeslieLeung/go-multiplatform-docker","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/LeslieLeung/go-multiplatform-docker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeslieLeung%2Fgo-multiplatform-docker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeslieLeung%2Fgo-multiplatform-docker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeslieLeung%2Fgo-multiplatform-docker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeslieLeung%2Fgo-multiplatform-docker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LeslieLeung","download_url":"https://codeload.github.com/LeslieLeung/go-multiplatform-docker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeslieLeung%2Fgo-multiplatform-docker/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263480868,"owners_count":23473164,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cicd","docker","github-actions","golang","multiplatform"],"created_at":"2024-11-20T20:40:13.351Z","updated_at":"2025-07-04T09:05:37.676Z","avatar_url":"https://github.com/LeslieLeung.png","language":"Makefile","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-multiplatform-docker\n\n[![build](https://github.com/LeslieLeung/go-multiplatform-docker/actions/workflows/build.yml/badge.svg)](https://github.com/LeslieLeung/go-multiplatform-docker/actions/workflows/build.yml)\n\nEnglish | [简体中文](doc/README.md)\n\n\u003e For a updated version that uses GoReleaser, you should checkout [LeslieLeung/gin-application-template](https://github.com/LeslieLeung/gin-application-template).\n\nA demo on how to build go multiplatform binaries and publish to release and DockerHub with GitHub Actions.\n\n## Why this exists?\n\nAs a software developer, it is not necessary to spend a lot of time repeating the same labor. This should be a high-level automation process. \nIn the process of releasing software, there are some points that could be a pain in the ass:\n\n- build binaries for multiple OSs and architectures\n- might have to build a suitable build environment for cross-platform compiling\n- complicated release procedures\n\nSure, some of these inconveniences have been eliminated\n\n- Golang supports cross-platform compiling out-of-the-box\n- use Docker or VM\n- use scripts\n\nHowever, it's not \"automatic\" enough. Using GitHub Actions, it can gracefully solve these problems, making developers more focus on the actual development.\n\n## Prerequisites\n\nThis passage assumes you are familiar with Golang,git and Docker, and know a little about GitHub Actions.\n\n## Let's begin!\n\nThere are two goals in this passage\n\n- Build multiplatform binaries for a Golang Program and release it to GitHub Releases\n- Build multiplatform binaries for a Golang Program and release it to DockerHub\n\n### Writing a simple Golang program\n\nThe Golang program is just for testing on different OSs and architectures, so a very simple program should do the trick. We will use a Hello World here.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, World!\")\n}\n```\n\nRun it in the terminal, and you will see the following.\n\n```bash\n\u003e go run main.go\nHello, World!\n```\n\nLooking good, now let's build an executable binary.\n\n```bash\n\u003e go build -o hello main.go\n\n```\n\nThis command outputs nothing, means it ran successfully without any errors. In the world of command lines, no news is good news.\n\nWe shall see a `hello` executable file under current directory（In Windows, it might look like `hello.exe`）。Let's run it.\n\n```bash\n\u003e ./hello\nHello, World!\n```\n\nGreat, it has the same result as `go run main.go`.\n\n\u003e ### Takeaways：\n\u003e Using `go build`, you can build an executable binary for a Golang program.\n\n### Building multiplatform binary executables\n\nRemember that on Windows, `go build` would produce a `.exe` file? It's worth mentioning that Golang's support for multiplatform compiling ability.\n It can produce binary executables for different platforms without any extra efforts.\n\nAssuming you are using macOS for development, you can build a binary executable for Windows with the following command\n\n```bash\n\u003e CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o hello_windows_amd64.exe main.go\n\n```\n\nThere would be a  `hello_windows_amd64.exe` file under current directory, copy it to a Windows machine a run it.\n\n### Build multiplatform binaries for a Golang Program and release it to GitHub Releases\n\nBefore you start, you might have a look at this repo's [Releases](https://github.com/LeslieLeung/go-multiplatform-docker/releases)\n\n![](http://img.ameow.xyz/20220724180813.png)\n\nYou might find for each target platform, there is a corresponding `tar.gz` or `zip` file with a `md5` checksum. Inside the compressed file, there is a binary executable file, `LISENCE` and `README.md`.\n\nThis is quite simple with GitHub Actions, an action would do all the trick. See [wangyoucao577/go-release-action](https://github.com/wangyoucao577/go-release-action) .\n\nIt's really easy to use.\n\n```yaml\nname: build\n\non:\n  release:\n    types: [created] # trigger when a release is created\n\njobs:\n  build-go-binary:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        goos: [linux, windows, darwin] # the required OSs\n        goarch: [amd64, arm64] # the required architectures\n        exclude: # exclude some OSs and architectures\n          - goarch: arm64\n            goos: windows\n    steps:\n      - uses: actions/checkout@v3\n      - uses: wangyoucao577/go-release-action@v1.30\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }} # a pre-defined secret to add files to Release\n          goos: ${{ matrix.goos }}\n          goarch: ${{ matrix.goarch }}\n          goversion: 1.18 # the required Go version\n          binary_name: \"hello\" # the name of the binary executable\n          extra_files: LICENSE README.md # the extra files to add to the release\n```\n\nWhen you finish writing a version and ready to release, all you have to do is to tag the commit, say `v0.0.2`, the push it to GitHub.\nIn `Releases` page, click `Draft a new release`, choose the tag, then click on `Publish release` in the bottom.\n\nThen we can dive into `Actions` page, we should see a `workflow` running. When it's done, go back to `Releases` , and there is your release files.\n\n\u003e ### Takeaway：\n\u003e With GitHub Actions, you can automate compiling, packaging and releasing binary executables to Release. \n\n### Build multiplatform binaries for a Golang Program and release it to DockerHub\n\nAs mentioned before, the easiest way to run a Golang program is to compile it to a binary executable file, then run it.\nThis doesn't even need a Golang environment on the actual machine.\n\nTherefore, if you are to pack a Golang program into a Docker image, you only need a minimal Linux system and copy the binary executable into it.\n\nWith that in mind, we should be able to write this Dockerfile.\n\n```dockerfile\nFROM alpine:3.15.5\nCOPY hello /usr/local/bin/hello\nRUN chmod +x /usr/local/bin/hello\n```\n\nWe should validate our idea. (Notice: The following code only works on Linux. On macOS and Windows it would not run for the \ncompiled binary doesn't match the Docker image's target system and architecture.)\n\n```bash\n\u003e docker build -t hello .\n...(a lot of logs)\n\u003e docker run -it --rm hello\n\u003e hello\nHello, world!\n```\n\nThere it goes! (Or you might fail if you didn't bother to look at the notice before.)\n\nSuccess or not, you should learn that we should just compile binary executables for different platforms, and then we can build the \ncorresponding Docker images.\n\n#### Makefile Magic\n\nAs is mentioned earlier, a `go build` with arguments can produce binary executables for different platforms. But we might have various platforms and \narchitectures, that's where `Makefile` comes into play.\n\nLet's write a simple `Makefile` assigning different commands to build different platforms. Considering that we only need\n`linux/amd64` and `linux/arm64` for our Docker image, we only need the following lines.\nIf you need a makefile that can run locally and build all the possible platforms, you can refer to the `Makefile` in this repo.\n\n```makefile\nall: build-linux-amd64 build-linux-arm64\n\nbuild-linux-amd64:\n\tmkdir -p build\n\tCGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o build/hello_linux_amd64 main.go\n\nbuild-linux-arm64:\n\tmkdir -p build\n\tCGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o build/hello_linux_arm64 main.go\n```\n\nIt's worth mentioning that the fist rule `all` is the default rule. When you run `make`, it will run the targets it assigned.\n`mkdir -p build` ensures that the output directory exists.\n\nIf you use macOS or Linux, you can try running `make`, it would create a `build` directory and put the binary executables into it.\n\n#### Environment Variables in Dockerfile\n\nIf you failed in the former test, it is because that the wrong binary executable was packaged into the docker file. Therefore, \nour dockerfile should know which version of binary executable it should grab.\n\nYou might find in the previous Makefile, I used different suffixes for different platforms and architectures, like `hello_linux_amd64`.\nNow, we should make Dockerfile grab the correct binary executable judging from its target platform and architecture.\n\nLet's modify the former Dockerfile to make it look like this.\n\n```dockerfile\nFROM alpine:3.15.5\nARG TARGETOS\nARG TARGETARCH\nCOPY build/hello_${TARGETOS}_${TARGETARCH} /usr/local/bin/hello\nRUN chmod +x /usr/local/bin/hello\n```\n\n`TARGETOS` and `TARGETARCH` is Automatic platform ARGs, but you have to use the `ARG` command to claim that you need them.\nWith `COPY`, we copied the corresponding binary executable to /usr/local/bin and gave it executes permission. So user can run our program with `hello`.\n\nIf you failed in the former test, you might try it now.\n\n#### Writing GitHub Actions\n\nTo this point, we've cleared all the hurdles, but we still have to write a GitHub Actions workflow to automate the process.\n\nThere is no need to create a new Action, we can just add a job to the former one.\n\n```yaml\nbuild-docker-image:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: docker/metadata-action@v4\n        id: meta\n        with:\n          images: leslieleung/hello\n      - uses: actions/setup-go@v3\n        with:\n          go-version: 1.18\n      - uses: docker/setup-qemu-action@v2\n      - uses: docker/setup-buildx-action@v2\n      - uses: docker/login-action@v2\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }} # REMEMBER to add the secret in secrets\n          password: ${{ secrets.DOCKERHUB_PASSWORD }}\n      - run: make\n      - uses: docker/build-push-action@v3\n        with:\n          context: .\n          platforms: linux/arm64,linux/amd64 # required platforms\n          push: true\n          tags: ${{ steps.meta.outputs.tags }}\n```\n\nRelease a version as mentioned before, then you can see your images on Dockerhub. You shall see `linux/amd64` and `linux/arm64`.\n\n![](http://img.ameow.xyz/20220724185319.png)\n\nThere you go, well done!\n\n## Other good stuffs\n\nAccording to the replies on my post on v2ex (see [关于 Golang 多平台打包发布这件事..](https://v2ex.com/t/868435) ), there are two\nother solutions.\n\n- [GoReleaser](https://goreleaser.com/) : Provides the ability to compile cross-platform and build Docker images. Super cool tool with a free and a paid Pro version.\n- [gox](https://github.com/mitchellh/gox) : Provides the ability to compile cross-platform in parallel.\n\ngox can provide us a parallel compile, so let's look into it here.\n\n### Accelerate your release with gox\n\nUpon checking out gox's documentation, it's quite easy-to-use. Let's add the following lines to the Makefile.\n\n```makefile\ngox-linux:\n\tgox -osarch=\"linux/amd64 linux/arm64\" -output=\"build/hello_{{.OS}}_{{.Arch}}\"\n\ngox-all:\n\tgox -osarch=\"darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 windows/amd64\" -output=\"build/hello_{{.OS}}_{{.Arch}}\"\n```\n\nNow, run `make gox-linux` or `make gox-all` should do all the magic.\n\nAlso, we have to modify our `build.yml`.\n\n```yaml\nbuild-docker-image:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: docker/metadata-action@v4\n        id: meta\n        with:\n          images: leslieleung/hello\n      - uses: actions/setup-go@v3\n        with:\n          go-version: 1.18\n      - uses: docker/setup-qemu-action@v2\n      - uses: docker/setup-buildx-action@v2\n      - uses: docker/login-action@v2\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_PASSWORD }}\n      - run: go install github.com/mitchellh/gox@latest # setup gox\n      - run: make gox-linux\n      - uses: docker/build-push-action@v3\n        with:\n          context: .\n          platforms: linux/arm64,linux/amd64\n          push: true\n          tags: ${{ steps.meta.outputs.tags }}\n```\n\n## FAQ\n\n### Failed to publish to Release due to permission issue\n\nSee [link](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#setting-the-permissions-of-the-github_token-for-your-repository)。\n\nSolution: add the following to `build.yml` .\n\n```yaml\nname: build\n\non:\n  release:\n    types: [created]\n    \npermissions: # ADD ME\n  contents: write # ADD ME\n\njobs:\n  build-go-binary:\n    runs-on: ubuntu-latest\n...\n```\n\n## References\n\n[GitHub Action - Build and push Docker images](https://github.com/marketplace/actions/build-and-push-docker-images)\n\n[GNU make](https://www.gnu.org/software/make/manual/make.html)\n\n[Dockerfile reference](https://docs.docker.com/engine/reference/builder/#arg)\n\n[wangyoucao577/go-release-action](https://github.com/wangyoucao577/go-release-action)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleslieleung%2Fgo-multiplatform-docker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleslieleung%2Fgo-multiplatform-docker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleslieleung%2Fgo-multiplatform-docker/lists"}