2

I am using "github.com/confluentinc/confluent-kafka-go/kafka" in a very simple consumer. It's pretty much what confluent has as a kafka/go tutorial.

"go build ." and "go run ." succeed, "docker build ." does not.

The error is:

 > [builder 7/7] RUN go build -o /app/bin/main .:
#12 9.826 # gitlab.com/.....
#12 9.826 ./main.go:24:24: undefined: kafka.ConfigMap
#12 9.826 ./main.go:30:18: undefined: kafka.NewConsumer

Here is my Dockerfile:

FROM golang:1.20.2-alpine3.16 AS builder
RUN apk --update add git
WORKDIR /app
COPY go.mod go.sum /app/
RUN go mod download
COPY . .
RUN go build -o /app/bin/main .

FROM scratch
WORKDIR /app
COPY --from=builder /app/bin/main /app/bin/main
ENTRYPOINT ["/app/bin/main"]

I am at a loss as to why this happens, especially since it claims that some functions in the package are undefined. I have not redeclared "kafka" anywhere in my code.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Andy Troschke
  • 441
  • 1
  • 5
  • 13
  • I have successfully built with the same Dockerfile but using bullseye instead of alpine. The question as to why this failed/whats different still remains. – Andy Troschke May 04 '23 at 21:59

1 Answers1

4

As correctly pointed out by Zeke in the comments, Kafka binaries are included in the Kafka Go client, so check out the Update section where I demonstrate such scenario.

That's because you need the native (C/C++) librdkafka. dependencies in order to build it. That will imply in most cases having gcc available as well. That's the underlying Kakfa lib used by your code.

You also need to make go build aware of that. I've added and modified these two lines on your example and was able to build it.

# Add this
RUN apk add alpine-sdk 

# Change this
RUN GOOS=linux GOARCH=amd64 go build -tags musl -o /app/bin/main .

Functional example:

FROM golang:1.20.2-alpine3.16 AS builder
RUN apk add alpine-sdk 
RUN apk --update add git
WORKDIR /app
COPY . .
RUN go mod download

RUN GOOS=linux GOARCH=amd64 go build -tags musl -o /app/bin/main .

FROM scratch
WORKDIR /app
COPY --from=builder /app/bin/main /app/bin/main
ENTRYPOINT ["/app/bin/main"]

I've used this quickstart code and the build process was OK.

Update

As Zeke pointed out, Kafka already has the prebuilt binaries.

Breaking down the Dockerfile below:

  • gcc and musl-dev are required for compilation using the selected image.
  • go build -tags musl option for Alpine, as per the Kafka SDK docs.
  • -ldflags '-extldflags "-static"' will statically compile everything in a single binary, including the dependencies. This will include for example C std lib, and will keep the scratch image clean. If dynamic is chosen, then one has to add the dependencies to the scratch image section directly.

The Dockerfile which generated the image with ~10MB size:

FROM golang:1.20.4-alpine3.17 AS builder
RUN apk add --no-progress --no-cache gcc musl-dev
WORKDIR /build
COPY . .
RUN go mod download

RUN go build -tags musl -ldflags '-extldflags "-static"' -o /build/main

FROM scratch
WORKDIR /app
COPY --from=builder /build/main .
ENTRYPOINT ["/app/main"]

Integration with Kafka using test code was successful when running in my demo.

Evandro Pomatti
  • 13,341
  • 16
  • 97
  • 165
  • This did fix the build itself, but linked the executable which will make it not-executable using FROM scratch. I've changed FROM scratch to FROM alpine and added the same RUN apk add alpine-sdk to the runner for now which seems to fix it, but it increased my image size from 9 to 273MB, can you recommend a more elegant way? – Andy Troschke May 04 '23 at 22:36
  • 1
    The update did build an run the consumer fine, with this I've also built a producer in another gRPC service and they both work just as expected. Thanks! – Andy Troschke May 05 '23 at 00:23
  • This docker file including building librdkafka from source code. But the Go client has included a prebuilt librdkafka binary. According to https://github.com/confluentinc/confluent-kafka-go/blob/master/README.md#librdkafka, it seems that modify the Dockerfile in the question to replace `RUN go build -o /app/bin/main .` with `RUN go build -tags musl -o /app/bin/main .` should be enough. @AndyTroschke Can you have a try? – Zeke Lu May 05 '23 at 00:40
  • @ZekeLu it worked, but I guess static is needed to run using the scratch image? `RUN go build -tags musl -installsuffix cgo -ldflags '-extldflags "-static"' -o /app/bin/main`. Found this thread with different examples: https://github.com/confluentinc/confluent-kafka-go/issues/454. You should post an answer to be accepted as it is cleaner. – Evandro Pomatti May 05 '23 at 02:51
  • Thanks for the confirming! I'm not sure whether `-installsuffix cgo -ldflags '-extldflags "-static"'` is needed. Have you tried without these options? Regarding posting a new answer, since @EvandroPomatti's answer has more details, I think it's better to add this new information to his answer. – Zeke Lu May 05 '23 at 03:20
  • @ZekeLu I also think you should post an answer that includes an explanation of why the issue happened as your solution is cleaner (it should result in the same binary as well) If you did, I will accept it. – Andy Troschke May 05 '23 at 14:25
  • @AndyTroschke In fact I'm not sure whether it works or not. And I don't have an environment to test it. I just find that in the doc and am thinking that if it works, it should be cleaner. And reading your answer, it's obviously that you know better about it than me. So I hope that you can take a look at it and if it works, add it to your answer. Thank you! You did a good job! – Zeke Lu May 05 '23 at 14:31
  • 1
    Oh, I'm so sorry that I just noticed I mistaken Evandro for Andy, and Andy for Evandro. My bad!! But I think you both get my idea. Thank you all! – Zeke Lu May 05 '23 at 15:08
  • 1
    updated to use the prebuilt binaries, was able to run code with a local Kafka and confirm that the integration works accordingly, repo link at the end – Evandro Pomatti May 06 '23 at 00:11
  • That works for `gopkg.in/confluentinc/confluent-kafka-go.v1/kafka` but not for `github.com/confluentinc/confluent-kafka-go/v2/kafka` (not for me at least). CGO should be set to 1 as well, but it works with or without with v1 – Jerome May 25 '23 at 11:29
  • @Jerome in my demo I tested with V2 https://github.com/epomatti/go-kafka – Evandro Pomatti May 25 '23 at 12:54
  • @EvandroPomatti yep it works(forgot an import from v1 which conflicted), thanks a lot. – Jerome May 26 '23 at 08:40
  • @Jerome you scared me! glad it worked. – Evandro Pomatti May 26 '23 at 13:32