cheapcoffee
cheapcoffee

Reputation: 19

Any risks to disable cgo to get golang:alpine working?

My goal is to compare two docker solutions for my golang app:

  1. use ubuntu as base image
  2. use golang:alpine as base image

My Dockerfile is quite straight-forward, similar to:

FROM ubuntu:20.04
# FROM golang:alpine for alpine based images

# myApp binary is pre-built before running docker build
COPY bin/myApp app/myApp
COPY myApp-config.json app/myApp-config.json

CMD MYAPP_CONFIG=app/myApp-config.json ./app/myApp

With alpine-based images, I hit the same issue here, where /app/myApp cannot be started due to missing CGO dynamic links in my generated image. I addressed it by disabling CGO during go build:

CGO_ENABLED=0

Since I'm quite new to docker, my questions are:

  1. Is there any risk disabling CGO? My understanding is that go build will fall back to native go implementation of CGO, but I don't know whether it has any hidden traps. My app does have critical dependency on net/http which seems to be requiring presence of CGO during runtime.
  2. It seems to be that alpine images are the defacto base image to use for golang, what is the standard way to deal with this CGO problem?

Thanks!

Upvotes: 0

Views: 1846

Answers (1)

colm.anseo
colm.anseo

Reputation: 22097

If your app is net/http based - then really the only consideration you may need to worry about is with DNS resolution.

TL;DR

The only gotchas you may see is in a kubernetes environment with a hostname ending in .local


With CGO_ENABLED=1 (the go build default) it will use the native OS's DNS resolver.

With CGO_ENABLED=0 used with scratch Docker builds - then Go's DNS resolver is used.

What's the difference? See the official Go docs:

The method for resolving domain names, whether indirectly with functions like Dial or directly with functions like LookupHost and LookupAddr, varies by operating system.

On Unix systems, the resolver has two options for resolving names. It can use a pure Go resolver that sends DNS requests directly to the servers listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C library routines such as getaddrinfo and getnameinfo.

By default the pure Go resolver is used, because a blocked DNS request consumes only a goroutine, while a blocked C call consumes an operating system thread. When cgo is available, the cgo-based resolver is used instead under a variety of conditions: on systems that do not let programs make direct DNS requests (OS X), when the LOCALDOMAIN environment variable is present (even if empty), when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, when the ASR_CONFIG environment variable is non-empty (OpenBSD only), when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the Go resolver does not implement, and when the name being looked up ends in .local or is an mDNS name.


Personally, I've built dozens of net/http based microservices running in kubernetes in scratch Docker containers with CGO_ENABLED=0 without issue.

Upvotes: 6

Related Questions