Docker Alpine image with the Go toolchain.
This Docker image provides the Go toolchain built on Alpine Linux. It ships the official upstream Go release, downloaded from dl.google.com and verified against the Go release signatures at build time, rather than Alpine's go package — so the Go version is fixed independently of the Alpine release. Alpine 3.24 ships Go 1.26, and waiting for the next Alpine release to follow the six-month Go cadence would leave the image a full minor behind.
A C toolchain (gcc, musl-dev) and git are included, so go get, CGO_ENABLED=1 builds and go test -race all work without extending the image.
- Small footprint: compact image using Alpine Linux
- Go 1.27.0: pinned upstream release, updated independently of Alpine
- Cgo ready:
gccandmusl-devincluded, so cgo and the race detector work out of the box - Module aware:
gitfor VCS module paths, and a pre-created cache tree at/go - Non-root user: Enhanced security with dedicated golang user
- Volume mounting: Easy code and data access through
/app
# Pull the image
docker pull ragedunicorn/golang:latest
# Print the Go version (default command)
docker run --rm ragedunicorn/golang:latest
# Build the code in the current directory
docker run --rm -v "$(pwd):/app" ragedunicorn/golang:latest build ./...For development and building from source, see DEVELOPMENT.md.
The container uses go as the entrypoint, so any Go subcommand can be passed directly to the docker run command.
Linux/macOS:
# Using latest version
docker run --rm -v "$(pwd):/app" ragedunicorn/golang:latest [go-subcommand]
# Using exact version combination
docker run --rm -v "$(pwd):/app" ragedunicorn/golang:1.27.0-alpine3.24.1-1 [go-subcommand]Windows (PowerShell):
docker run --rm -v "${PWD}:/app" ragedunicorn/golang:latest [go-subcommand]docker run --rm ragedunicorn/golang:latest versiondocker run --rm -v "$(pwd):/app" ragedunicorn/golang:latest run main.go# The named volume keeps the module and build cache between runs, so
# dependencies are not re-downloaded and packages are not recompiled every
# time. A fresh volume is initialized owned by the golang user (the image
# pre-creates /go).
docker run --rm -v "$(pwd):/app" -v gocache:/go ragedunicorn/golang:latest build ./...docker run --rm -v "$(pwd):/app" -v gocache:/go ragedunicorn/golang:latest test ./...
# With the race detector (needs the bundled C toolchain)
docker run --rm -v "$(pwd):/app" -v gocache:/go ragedunicorn/golang:latest test -race ./...docker run --rm -v "$(pwd):/app" --entrypoint gofmt ragedunicorn/golang:latest -l .
docker run --rm -v "$(pwd):/app" -v gocache:/go ragedunicorn/golang:latest vet ./...docker run --rm -v "$(pwd):/app" -v gocache:/go ragedunicorn/golang:latest install golang.org/x/tools/cmd/stringer@latestdocker run -it --rm -v "$(pwd):/app" --entrypoint /bin/sh ragedunicorn/golang:latestThe image is Alpine based, so its C library is musl, not glibc. Cgo is enabled by default (the C toolchain is present), which means a default go build of a package that uses cgo produces a musl-linked binary that will not run on a glibc host such as Debian or Ubuntu.
For a fully static binary that runs anywhere, disable cgo:
docker run --rm -v "$(pwd):/app" -v gocache:/go \
-e CGO_ENABLED=0 \
ragedunicorn/golang:latest build -o app ./cmd/appIf you need a glibc-linked binary, build it in a glibc-based image instead — that is a base image choice, not something this image can switch at runtime.
g++ is not installed. The handful of cgo packages that need a C++ compiler can add it in a derived image (apk add --no-cache g++).
Note (Docker Desktop for Windows): overwriting existing files on a Windows bind mount can fail with
Operation not permittedfor the non-rootgolanguser. If your build writes into the mounted workspace, run as root and move the cache volume to the root GOPATH:docker run --rm -u root -v "${PWD}:/app" -v gocache-root:/go ragedunicorn/golang:latest build ./...
The Go environment is set explicitly in the image rather than derived from $HOME, so the toolchain works even when HOME is unset:
| Variable | Value | Notes |
|---|---|---|
GOPATH |
/go |
Pre-created and owned by the golang user |
GOMODCACHE |
/go/pkg/mod |
Downloaded modules |
GOCACHE |
/go/cache |
Build cache |
GOTOOLCHAIN |
local |
No implicit toolchain downloads |
Because the whole cache tree lives under GOPATH, a single named volume mounted at /go covers both the module cache and the build cache.
GOTOOLCHAIN=local means a go.mod requiring a newer Go than the image ships fails loudly instead of silently downloading another toolchain. Override it if you want the default upstream behaviour:
docker run --rm -v "$(pwd):/app" -v gocache:/go -e GOTOOLCHAIN=auto ragedunicorn/golang:latest build ./...go build stamps the VCS revision into the binary by default (-buildvcs=auto), which means it runs git against your mounted source tree. A bind mount belongs to the host user rather than to the golang user inside the container, and git normally refuses such a repository with detected dubious ownership, failing the build.
The image therefore marks every directory as safe (git config --system --add safe.directory '*'), so builds of a real checkout work unchanged and the revision is stamped as expected:
docker run --rm -v "$(pwd):/app" -v gocache:/go ragedunicorn/golang:latest build ./...
docker run --rm -v "$(pwd):/app" -v gocache:/go ragedunicorn/golang:latest version -m ./appPass -buildvcs=false if you would rather not stamp VCS information at all.
This repository includes Docker Compose configurations for easier usage and common Go workflows.
- Create an
appdirectory:
mkdir -p app-
Place your Go code in
app/ -
Run Go using docker compose:
docker compose run --rm golang build ./...
docker compose run --rm golang test ./...The examples/ directory contains a hello-world example:
# Run the hello world example
cd examples && docker compose run --rm hello-worldThe compose configuration supports:
GOLANG_VERSION: Specify the Go image version (default: latest)TERM: Terminal type for colored output
-
Custom Commands: Override the default command:
docker compose run --rm golang env GOVERSION
-
Development Mode: Use the development compose file for building locally:
docker compose -f docker-compose.dev.yml build docker compose -f docker-compose.dev.yml run --rm golang-dev
-
Persistent Settings: The repository includes a
.envfile with default settings:GOLANG_VERSION=latest
This image is a toolchain image. The usual pattern is to use it as a build stage and ship the resulting binary in a minimal runtime image:
FROM ragedunicorn/golang:latest AS build
WORKDIR /app
COPY --chown=golang:golang . .
RUN CGO_ENABLED=0 go build -o /go/bin/app ./cmd/app
FROM alpine:3.24.1
COPY --from=build /go/bin/app /usr/local/bin/app
ENTRYPOINT ["app"]To add packages to a derived image, switch users temporarily:
FROM ragedunicorn/golang:latest
USER root
RUN apk add --no-cache g++
USER golangThis project uses semantic versioning that matches the Docker image contents:
Format: {go_version}-alpine{alpine_version}-{build_number}
Examples:
1.27.0-alpine3.24.1-1- Go 1.27.0 on Alpine 3.24.1, build 11.27.0-alpine3.24.1-2- Rebuild of the same versions (fixes, optimizations)1.27.0- Bare Go version, tracking the most recent build of that releaselatest- Most recent stable release
For detailed release process and versioning guidelines, see RELEASE.md.
This project uses Renovate to automatically check for updates to:
- Alpine Linux base image version (all major, minor, and patch updates)
- The pinned Go release, tracked through the
GO_VERSIONbuild arg
Renovate runs weekly (every Monday) and creates pull requests when updates are available. Every Alpine reference is kept in sync from a single update: the FROM line, the org.opencontainers.image.base.name OCI label, and the Alpine version asserted in test/golang_metadata_test.yml are grouped into one pull request. The Go references are grouped the same way — the GO_VERSION build arg and the exact version asserted in test/golang_command_test.yml move together, so a bump never lands as a green build arg alongside a red test. Go patch releases are merged automatically; minor bumps are reviewed by hand, since Go supports only the last two minors and moving between them is a deliberate decision.
- Development Guide - Building, debugging, and contributing
- Testing Guide - Running and writing tests
- Release Process - Creating releases and versioning
MIT License
Copyright (c) 2026 Michael Wiesendanger
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.