Open Anunayj opened 3 years ago
This Dockerfile can be used to automatically make builds using GitHub Actions, though I'm unsure how I should deal with the dependencies part, Should I export that as a Image and keep it on Dockerhub (and use FROM anunayj/go-alpine-unbound) or should I keep it like this and let the cache do it's job. (GitHub Actions evicts cache after 7 days of inactivity).
Also I have no idea what was causing the problems compiling earlier when i was using a lxd container. I guess I installed unbound from apk and then built it from source causing a unholy mess. I really feel like Alpine packagers should include static library (.a) for libraries in their -dev packages. Specially considering libmusl is used for static binaries, and their distribution is one of they few that implements libmusl.
Alternatively to save time/or if you are lazy to compile openssl this can be used. (Remember you will basically be trusting me to have shipped a exploit-free version of unbound library)
FROM anunayj/golang-libunbound@sha256:4db0797175be0d38f0a65f81517d1862a72c745cfb42d53b09aed477f00d6e5d as builder
#Install Dependendencies
WORKDIR /tmp/dane
COPY go.mod /tmp/dane/go.mod
RUN go mod download
#Will allow caching dependencies in layers.
COPY . /tmp/dane/
WORKDIR /tmp/dane/cmd/letsdane
#Build Static
RUN go build -tags unbound --ldflags '-extldflags "-lunbound -lssl -lcrypto -static"'
FROM scratch
COPY --from=builder /tmp/dane/cmd/letsdane/letsdane /
ENTRYPOINT [ "letsdane" ]
Sources for intermediate image here https://gist.github.com/Anunayj/f58463793ef3902eb4d0f4a24ce8b875
I have no idea how one would go about compiling for windows and mac, go does allow you to specify to build for windows
or darwin
, but how would that work with unbound? GitHub actions does provide both windows and macOS images to run stuff on which can be used to make binaries, but I don't have a MacOS machine to test stuff on, I'll try messing about on my windows machine later.
P.S. We really need a Windows subsystem for Linux haha.
Also are https://www.openssl.org/source/openssl-1.1.1j.tar.gz and https://www.nlnetlabs.nl/downloads/unbound/unbound-1.13.1.tar.gz updated with appropriate security fixes if there is one?
Should I export that as a Image and keep it on Dockerhub (and use FROM anunayj/go-alpine-unbound) or should I keep it like this and let the cache do it's job. (GitHub Actions evicts cache after 7 days of inactivity).
Building static binaries isn't a frequent process if it's only done for every release. It's okay to leave it to build from source even if takes a bit of time. It's unfortunate that alpine doesn't include *.a
libs. For openssl it seems there is a package on alpine openssl-libs-static
which i found here https://pkgs.alpinelinux.org/package/edge/main/x86/openssl-libs-static. It could save time if we did apk add openssl-dev openssl-libs-static
instead it of building openssl (i didn't test this)
I have no idea how one would go about compiling for windows and mac, go does allow you to specify to build for windows or darwin, but how would that work with unbound? GitHub actions does provide both windows and macOS images to run stuff on which can be used to make binaries, but I don't have a MacOS machine to test stuff on, I'll try messing about on my windows machine later.
Unbound is an optional dependency so letsdane can be built on most OSs with just go build
(assuming the user has a validating resolver like hsd).
building on macOS with unbound is pretty simple (shared libs)
brew install unbound
git clone ...
go build -tags unbound
To bundle unbound in the same binary, I built it this way (on MBP running Big Sur). I just installed unbound using brew
(so it's built with some other dependencies that we probably don't need like nghttp2) but here's a quick way to build it:
macos prefers dynamic libraries so if there is a dynamic lib and a static lib in the same directory it will pick the dynamic one. So I specified the path for each .a
lib
CGO_LDFLAGS="/usr/local/opt/unbound/lib/libunbound.a \
/usr/local/opt/openssl/lib/libssl.a \
/usr/local/opt/openssl/lib/libcrypto.a \
/usr/local/opt/nghttp2/lib/libnghttp2.a \
/usr/local/opt/libevent/lib/libevent.a" go build -tags unbound
it's not clear to me yet if that's the best way to do it.
Also are https://www.openssl.org/source/openssl-1.1.1j.tar.gz and https://www.nlnetlabs.nl/downloads/unbound/unbound-1.13.1.tar.gz updated with appropriate security fixes if there is one?
Those are links to the latest stable versions. They must be updated if new versions come up. Unbound includes a link for latest version https://nlnetlabs.nl/downloads/unbound/unbound-latest.tar.gz which is always updated (but this probably wouldn't be very stable if they include a new dependency or change something that affects compatibility)
Building static binaries isn't a frequent process if it's only done for every release. It's okay to leave it to build from source even if takes a bit of time. It's unfortunate that alpine doesn't include *.a libs. For openssl it seems there is a package on alpine openssl-libs-static which i found here https://pkgs.alpinelinux.org/package/edge/main/x86/openssl-libs-static. It could save time if we did apk add openssl-dev openssl-libs-static instead it of building openssl (i didn't test this)
Just tested it, and it works, updated the dockerfile.
I tried making binaries for macos using this command
C_INCLUDE_PATH="$(brew --prefix)/include" LIBRARY_PATH="$(brew --prefix)/lib" CGO_LDFLAGS="$(brew --prefix)/lib/libunbound.a \
$(brew --prefix)/lib/libssl.a \
$(brew --prefix)/lib/libcrypto.a \
$(brew --prefix)/lib/libnghttp2.a \
$(brew --prefix)/lib/libevent.a" go build -tags unbound ./cmd/letsdane
but seems like it still dynamically linked the binary?
linux-vdso.so.1 (0x00007fff935e3000)
libunbound.so.8 => not found
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5da032b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5da0139000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5da035f000)
if I use
C_INCLUDE_PATH="$(brew --prefix)/include" CGO_LDFLAGS="$(brew --prefix)/lib/libunbound.a \
$(brew --prefix)/lib/libssl.a \
$(brew --prefix)/lib/libcrypto.a \
$(brew --prefix)/lib/libnghttp2.a \
$(brew --prefix)/lib/libevent.a" go build -tags unbound ./cmd/letsdane
I get
go: downloading github.com/buffrr/hsig0 v0.0.0-20200928223456-eca10c3b5481
go: downloading github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0
go: downloading github.com/miekg/dns v1.1.31
go: downloading golang.org/x/net v0.0.0-20190923162816-aa69164e4478
go: downloading golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
go: downloading golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe
go: downloading github.com/miekg/unbound v0.0.0-20180419064740-e2b53b2dbcba
# github.com/miekg/unbound
/usr/bin/ld: cannot find -lunbound
collect2: error: ld returned 1 exit status
Error: Process completed with exit code 2.
Static Binaries for each platform can be built using:
Linux
Static Binaries for Linux can be made using the following Dockerfile (or running the commands in Dockerfile manually).
Use
DOCKER_BUILDKIT=1 docker build -f static.Dockerfile -o build/ .
to export the binary into build directory.Running this first time can take >500 seconds (Mostly because of all the compiling that needs to be done for
unbound
andopenssl
), The Image layer can be exported to Dockerhub and used repeatedly if necessary. Subsequent builds should take <100 seconds.Todo: