需要帮助设置 Golang 的 Dockerfile。

huangapple go评论86阅读模式
英文:

Need help setting up golang dockerfile

问题

我正在遇到设置个人项目的Golang Dockerfile的困难。

项目结构如下:

Project
|
+-- log.go(包含main函数)
|
+-- go.mod
|      
+-- hash
   |  
   +-- hash.go

该应用程序每5秒打印一个随机哈希,并在其后附加时间戳。

文件内容如下:

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)
  }

我拼凑了以下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"]

然而,我一直收到以下错误(以及类似的错误):

   ------
    > [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

我已经在网上搜索了几个小时,试图解决这个问题,但我真的不明白出了什么问题。我怀疑在Dockerfile中处理依赖管理时做错了什么。

我提到我是Go的新手,并且这是我学习过程中的一部分。

请帮助我编写一个能够构建和运行的Dockerfile。

谢谢!

英文:

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!

答案1

得分: 2

这应该可以工作,下面是解释。

#构建阶段
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 .

#最终阶段
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"]

将Dockerfile放在项目中,这样你就不必在项目内克隆(没有意义)。

使用两阶段构建来获得一个干净的最终镜像。

使用与root不同的用户来运行最终的可执行文件。

不要暴露任何端口,因为你的应用程序没有监听任何端口。

使用ENTRYPOINT而不是CMD。这样你以后可以在docker run命令行中传递参数。

英文:

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.

答案2

得分: 1

你不需要执行go get github.com/postelniql/logger-output/hash命令:这是你本地源代码树的一部分,你已经拥有它了。但你需要确保将它COPY到你的镜像中。

你的Dockerfile的修改并不复杂,但是你的Dockerfile本身并不大:

FROM golang:1.19-alpine
WORKDIR /app
COPY go.mod go.sum ./    # 添加 `go.sum`
RUN go mod download      # 添加:下载外部依赖
# RUN apk add git        # 删除
# RUN go get github.com/postelniql/logger-output/hash  # 删除
COPY *.go ./
COPY hash/ hash/         # 添加
RUN go build -o /logger-output-app
EXPOSE 8080
CMD [ "/logger-output-app" ]

@Mihai的答案中的Dockerfile也可以工作,因为它也删除了go get your-own-application这一行。多阶段构建设置会从最终构建中删除Go工具链,因此你会得到一个更小的镜像,但它也更复杂,有点难以调试。

英文:

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.

huangapple
  • 本文由 发表于 2022年9月25日 16:31:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/73843059.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定