-3

I want to build a tiny container image from scratch using Buildah to run a Go app. Apart from the app itself, what other libraries etc need to be included. I am thinking that glibc is needed - is there anything else?

So in summary, I think I am asking "what are all the external dependencies that a compiled Go app needs on Linux?"

Dave C
  • 7,729
  • 4
  • 49
  • 65
Bryon
  • 939
  • 13
  • 25
  • 3
    A compiled binary Go app is self-contained, so it has no dependency. If you use syscalls to load external libraries, or you open and read external files, then it will obviously need those, but other than that, nothing will be required. – icza Jul 30 '19 at 07:06
  • You might need these external files used by the Go standard packages: root certificates, time zone info. – Charlie Tumahai Jul 30 '19 at 07:20
  • 2
    The `ldd` command should tell you what shared libraries a dynamically linked executable needs. As already mentioned there may also be files referenced/needed (e.g. in /etc). – Dave C Jul 30 '19 at 12:41

3 Answers3

2

@Dave C gave the information to correctly answer this. Using ldd with the test app returned:

[bryon@localhost resttest]$ ldd restest
    linux-vdso.so.1 (0x00007fff139fe000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fbad6ce2000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fbad691f000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fbad6f02000)
[bryon@localhost resttest]$ 

So for those looking to build a minimal container with Buildah, the BASH script to generate it would look like this:

#!/bin/bash
#
# Run this shell script after you have run the command: "buildah unshare"
#
git clone https://github.com/bryonbaker/resttest.git
cd resttest
go build restest.go

container=$(buildah from scratch)
mnt=$(buildah mount $container)
mkdir $mnt/bin
mkdir $mnt/lib64
buildah config --workingdir /bin $container
buildah copy $container restest /bin/restest
buildah copy $container /lib64/libpthread.so.0 /lib64
buildah copy $container /lib64/libc.so.6 /lib64
buildah copy $container /lib64/ld-linux-x86-64.so.2 /lib64
buildah config --port 8000 $container
#
# This step is not working properly.
# Need to run with podman -p 8000:8000 --entrypoint /bin/restest restest:latest
buildah config --entrypoint /bin/restest $container
buildah commit --format docker $container restest:latest

This generates a 14MB container for a simple microservice! There are no additional files to be worrying about for vulnerabilities etc.

I have a small defect I can't work out on entrypoints so I am overriding the entrypoint on start, but to test it run:

podman -p8000:8000 --entrypoint /bin/restest restest:latest

Then just type the following in a Terminal session:

curl http://localhost:8000

So thanks Dave C!

Bryon
  • 939
  • 13
  • 25
1

I know this is quite late answer, but it does tell how to build the slimmiest image for Golang programs. It is based on the question Deployment using image from scratch fails to start

The trick is to build statically linked executable and place it into the empty image called scratch. The image contains just a single file, that exact executable. It is the smallest image possible.

Docker file:

FROM golang:latest as builder
# The Dockerfile expects the source code of the application
# to reside in ./src/ directory
COPY src /src

WORKDIR /src

# Build statically linked file and strip debug information
# The Dockerfile expects the `main` package to be at the root of the module
RUN CGO_ENABLED=0 go build -ldflags="-extldflags=-static -s -w" -o executable

# scratch is an empty image
FROM scratch
# If you need /bin/sh and a few utilities, uncomment
# the following line. It increases the image by 5.5 MB
# FROM alpine:latest

COPY --from=builder /src/executable /executable
# copy other files if needed

ENTRYPOINT ["/executable"]

The Dockerfile expects the source code to be in src directory

<project_root>
 |_ Dockerfile
 |_ src/
     |_ go.mod
     |_ package_main.go # file with `package main` and `func main()`
     |_ other source files

The command docker build ./ -t my-minimal-go produces the image named my-minimal-go:latest

To prove that it is the minimal image, save it to TAR and study the contents:

docker image save my-minimal-go:latest > my-minimal-go.tar
tar tf my-minimal-go.tar

The contents is something like

84ebda22f9b32043fdcb7bb70c559f0ee91cac60b4b92f1ce424662afec6d4b9.json
e622775ad65d50bc0b9f30e6ce58ee7670f752c63c3ca70caba4f9165efdca80/
e622775ad65d50bc0b9f30e6ce58ee7670f752c63c3ca70caba4f9165efdca80/VERSION
e622775ad65d50bc0b9f30e6ce58ee7670f752c63c3ca70caba4f9165efdca80/json
e622775ad65d50bc0b9f30e6ce58ee7670f752c63c3ca70caba4f9165efdca80/layer.tar
manifest.json
repositories

And to see the list of files in the image:

docker image save my-minimal-go:latest | tar x --wildcards '*layer.tar' -O | tar t

Output:

executable

Just a single file, the minimal image.

Pak Uula
  • 2,750
  • 1
  • 8
  • 13
  • That is a nice linker flag I was not aware of. That would remove the need for copying the two libraries for sure. The Docker from scratch is also cool. Thanks. – Bryon Jan 10 '23 at 09:19
-2

I am assuming you have included the app dependencies in your docker image.

You won't require any external dependency to build a docker image. Just base image from Go is sufficient to build and run on Linux machines.

# Start from the latest Go base image
FROM golang:latest

# Set the Current Working Directory inside the container
WORKDIR /app

# Copy go mod and sum files
COPY go.mod go.sum ./

# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download
Dave C
  • 7,729
  • 4
  • 49
  • 65
Yashish Dua
  • 11
  • 1
  • 1
  • 1
    This is an image to build the app, right? To just run it, it would not need anything except the resulting binary, I think. – Thilo Jul 30 '19 at 08:02
  • @Thilo that is correct. The binary is built externally. A simple microservice listening and sending on a TCP port. I just want to containerise it. Buildah has awesome features to build minimal images - but to do that you need to understand what types of dependencies you need to include. (Hence the question). – Bryon Jul 30 '19 at 08:40
  • This is a great answer, just not to the question that was asked. – Adrian Jul 30 '19 at 15:34