I'm having difficulties setting up a golang dockerfile for a personal project.
project structure is:
Project
|
-- log.go (contains main)
|
-- go.mod
|
-- hash
|
-- hash.go
The app prints a random hash every 5 seconds and appends a timestamp to it.
File contents:
log.go
package main
import (
"fmt"
"github.com/postelniql/logger-output/hash"
"time"
)
func log() string {
dt := time.Now()
hash := hash.NewSHA1Hash()
return dt.Format("01-02-2006T15:04:05.000Z") ": " hash
}
func main() {
fmt.Println(log())
tick := time.Tick(5000 * time.Millisecond)
for range tick {
fmt.Println(log())
}
}
go.mod:
module github.com/postelniql/logger-output
go 1.19
hash.go:
package hash
import (
"crypto/sha1"
"fmt"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func NewSHA1Hash(n ...int) string {
noRandomCharacters := 32
if len(n) > 0 {
noRandomCharacters = n[0]
}
randString := randomString(noRandomCharacters)
hash := sha1.New()
hash.Write([]byte(randString))
bs := hash.Sum(nil)
return fmt.Sprintf("%x", bs)
}
var characterRunes =
[]rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
// RandomString generates a random string of n length
func randomString(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = characterRunes[rand.Intn(len(characterRunes))]
}
return string(b)
}
I scraped together the following Dockerfile:
FROM golang:1.19-alpine
WORKDIR /app
COPY go.mod ./
RUN apk add git
RUN go get github.com/postelniql/logger-output/hash
COPY *.go ./
RUN go build -o /logger-output-app
EXPOSE 8080
CMD [ "/logger-output-app" ]
However I keep getting this error (and similar sort of errors):
------
> [6/8] RUN go get github.com/postelniql/logger-output/hash:
#10 2.105 go: github.com/postelniql/logger-output/hash: no matching versions for
query "upgrade"
------
executor failed running [/bin/sh -c go get github.com/postelniql/logger-
output/hash]: exit code: 1
I've searched the web for hours trying to fix this, I genuinely don't understand what's wrong with it. I suspect I'm doing something wrong when it comes to dependency management in the Dockerfile.
I mention I'm a noob in go and am coding this as part of my learning process.
Please help me write a dockerfile that builds and runs.
Thanks!
CodePudding user response:
This should work, explanation below.
#build stage
FROM golang:alpine AS builder
RUN apk add --no-cache git
WORKDIR /go/src/app
COPY . .
RUN go get -d -v ./...
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /go/bin/app -v .
#final stage
FROM alpine:latest
RUN addgroup -S app && adduser -S app -G app
COPY --from=builder --chown=app /go/bin/app /app
USER app
ENTRYPOINT ["/app"]
Place the Dockerfile in your project so that you don't have to clone the project inside (makes no sense).
Use 2-stage build to have a clean final image.
Use a different user than root to run the final binary.
Don't expose any port since your app is not listening on any port.
Use ENTRYPOINT instead of CMD. This way you can later pass arguments on the docker run
command line.
CodePudding user response:
You don't need to go get github.com/postelniql/logger-output/hash
: this is part of your local source tree and you have it locally. You do need to make sure you COPY
it into your image.
The changes in your Dockerfile aren't complicated, but your Dockerfile isn't that large to start with:
FROM golang:1.19-alpine
WORKDIR /app
COPY go.mod go.sum ./ # add `go.sum`
RUN go mod download # add: downloads external dependencies
# RUN apk add git # delete
# RUN go get github.com/postelniql/logger-output/hash # delete
COPY *.go ./
COPY hash/ hash/ # add
RUN go build -o /logger-output-app
EXPOSE 8080
CMD [ "/logger-output-app" ]
The Dockerfile in @Mihai's answer should work too, since it also deletes the go get your-own-application
line. The multi-stage build setup deletes the Go toolchain from the final build so you get a much smaller image out, but it's also more complex and a little harder to debug.