Is it a bad idea to set this environment variable to 0? From what I read, setting it to 1 means there should be a gcc compiler installed in the working system. Is this a correct interpretation? Why is it 1 by default?
I was trying to containerise my go application using the below docker file:
FROM golang:latest as builder
ENV GOOS=linux
COPY ./ /go/src/hello_world
WORKDIR /go/src/hello_world
RUN go build .
FROM alpine:latest
WORKDIR /usr/home
COPY --from=builder /go/src/hello_world/hello_world /usr/home
ENTRYPOINT ["./hello_world"]
This was giving me error but based on my findings I put ENV CGO_ENABLED=0 during build and it started working fine.
When is it required to be set to 1 and why did I have to explicitly set to 0 in my case?
P.S. I am very new to go so any resources on this would be appreciated.
With CGO_ENABLED=0 you got a staticaly-linked binary (see: https://en.wikipedia.org/wiki/Static_build) so it will run without any external dependencies (you can buld your dockers from 'scratch' image) Like that: https://github.com/s0rg/microapp/blob/master/Dockerfile
From what I read, setting it to 1 means there should be a gcc compiler installed in the working system. Is this a correct interpretation? Why is it 1 by default?
It doesn't actually mean you must have a gcc compiler available. It means a couple things. Some parts of the runtime like the dns resolver and user lookups use glibc so it will link against those if you use certain stdlib packages. There are some pure Go replacements that swap in if you disable cgo. But if you use any other 3rd party packages that do have cgo bindings to C then it would be expected that you have a compiler when you build. But you would find that out pretty quick if you disabled cgo and your project could no longer build those dependencies .
What it's saying you need to do is rebuild the library and runtime for linux-amd64. You can do that this way:
- Find the root of your Go installation (if you don't know where this is, running
which gomay help - the binary is often installed with the rest of the sources). cdinto thesrcdirectory- Run
GOOS=linux GOARCH=amd64 ./make.bash --no-clean(orGOOS=linux GOARCH=amd64 bash make.bash --no-cleanifmake.bashis not executable). This will rebuild the library and runtime using the specified OS and architecture.
Once you've done this, you can build a go package or binary for this architecture using GOOS=linux GOARCH=amd64 go build. You can follow the same instructions for other architectures and operating systems.
Edit (08/13/15):
As of Go 1.5, cross compiling is much easier. Since the runtime is written in Go, there's no need to set anything up in order to be able to cross-compile. You can now just run GOOS=<os> GOARCH=<arch> go build from a vanilla Go installation and it will work.
However, there's one exception to this. If you're using cgo, you'll still need to set stuff up ahead of time. And you'll need to inform the tooling that you want to enable cgo cross-compiling by setting the CGO_ENABLED environment variable to 1. So, to be precise:
cdinto thesrcdirectory of your Go installation (see the instructions above).- Run
CGO_ENABLED=1 GOOS=<os> GOARCH=<arch> ./make.bash --no-clean - Run
CGO_ENABLED=1 go buildto build your project. It is important that you specifyCGO_ENABLED=1even when you're compiling.
Following the above answer https://stackoverflow.com/a/27413148/3675575, I needed to set GOROOT_BOOTSTRAP to recompile my GO source tree:
GOROOT_BOOTSTRAP=/usr/lib/golang/ CGO_ENABLED=1 GOOS=linux GOARCH=386 ./make.bash --no-clean
(I'm using Fedora 23, so the GOROOT_BOOTSTRAP may vary in your operating system)
-
My project is a simple web API app which uses Docker.
-
I went though https://golang.org/cmd/go/ but didn't see any special case of
-installsuffix cgowhen usingCGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o ./build/api ./cmd/api.
Do we really need -installsuffix cgo when running go build inside go-alpine images?
Many things are only available as C libraries, and re-implementing that all in Go would be costly. cgo has its downsides, but it can be a good trade-off. Even the standard library uses it (net for DNS lookups, os/user for user lookups) because it doesn't re-implement 100% of the behaviour in Go.
Cross-compiling C code is still rather hard; you'll need the target architecture's C compiler and toolchain (e.g. CC=aarch64-linux-musl-gccgo build to build an arm64 binary). None of that is installed by default so for most people cgo simply won't work when cross-compiling; they need to take manual steps to set it up first.
cgo often isn't strictly required (like in the net and os/user packages), so disabling it by default seems the most user-friendly option.
But there are no such constraints on the native platform, and it's expected to work by default without any user setup; so why not enable it by default?
If you're running on an Alpine image, it is impossible to compile and run Go programs in Alpine images right away. You must disable CGO by setting the environment variable CGO_ENABLED to false (the default value is true).
You can do this either by:
- Adding
go env -w CGO_ENABLED=0like Robert mentions in his comment or, - Setting the env value prefixing it in the
gocommand, e.g.:CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -ldflags '-s -w' -tags lambda.norpc -o bin/<YOUR_FUNC>/bootstrap <YOUR_PATH>/main.go
See: https://megamorf.gitlab.io/2019/09/08/alpine-go-builds-with-cgo-enabled/
@LinPy Thank you for u help.
https://www.x-cellent.com/blog/cgo-bindings/
I solved the problem. But build takes a long time, about 10 minutes, and I'm still looking for a better solution.
Images Dockerfile : https://github.com/sillyhatxu/alpine-build
CopyFROM xushikuan/alpine-build:2.0 AS builder
ENV WORK_DIR=$GOPATH/src/github.com/sillyhatxu/mini-mq
WORKDIR $WORK_DIR
COPY . .
RUN go build -a -ldflags "-linkmode external -extldflags '-static' -s -w" -o main main.go
FROM xushikuan/alpine-build:1.0
ENV BUILDER_WORK_DIR=/go/src/github.com/sillyhatxu/mini-mq
ENV WORK_DIR=/app
ENV TIME_ZONE=Asia/Singapore
WORKDIR $WORK_DIR
RUN ln -snf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && echo $TIME_ZONE > /etc/timezone
RUN mkdir -p logs
RUN mkdir -p db
RUN mkdir -p data
COPY --from=builder $BUILDER_WORK_DIR/main $WORK_DIR
COPY --from=builder $BUILDER_WORK_DIR/config.conf $WORK_DIR
COPY --from=builder $BUILDER_WORK_DIR/db $WORK_DIR/db
COPY --from=builder $BUILDER_WORK_DIR/basic.db $WORK_DIR/data
ENTRYPOINT ./main -c config.conf
Build with the correct image
CopyFROM golang:1.18-alpine AS BUILDER
RUN apk add --no-cache gcc g++ git openssh-client
RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server