使用Docker进行godep vendor。

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

godep vendor with docker

问题

我正在尝试使用供应商运行一个带有 Docker 容器的程序。
这是我的 Dockerfile:

  1. FROM golang:alpine
  2. EXPOSE 8080
  3. RUN mkdir /app
  4. ADD . /app/
  5. WORKDIR /app
  6. RUN go build -o myapp .
  7. CMD ["/app/myapp"]

这是我的 main.go:

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/http"
  6. "github.com/gorilla/mux"
  7. )
  8. func main() {
  9. r := mux.NewRouter()
  10. r.HandleFunc("/", Hello)
  11. http.Handle("/", r)
  12. fmt.Println("Starting up on 8080")
  13. log.Fatal(http.ListenAndServe(":8080", nil))
  14. }
  15. func Hello(w http.ResponseWriter, req *http.Request) {
  16. fmt.Fprintln(w, "Hello world!")
  17. }

我正在使用 godep 进行库的供应,它在我的本地机器上工作正常,但是当我尝试使用 Docker 运行它时,出现以下错误:

  1. main.go:8:2: cannot find package "github.com/gorilla/mux" in any of:
  2. /usr/local/go/src/github.com/gorilla/mux (from $GOROOT)
  3. /go/src/github.com/gorilla/mux (from $GOPATH)

我不明白缺少了什么。

英文:

I'm trying to run a docker container with vendor.
This is my Dockerfile

  1. FROM golang:alpine
  2. EXPOSE 8080
  3. RUN mkdir /app
  4. ADD . /app/
  5. WORKDIR /app
  6. RUN go build -o myapp .
  7. CMD ["/app/myapp"]

and my main.go

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/http"
  6. "github.com/gorilla/mux"
  7. )
  8. func main() {
  9. r := mux.NewRouter()
  10. r.HandleFunc("/", Hello)
  11. http.Handle("/", r)
  12. fmt.Println("Starting up on 8080")
  13. log.Fatal(http.ListenAndServe(":8080", nil))
  14. }
  15. func Hello(w http.ResponseWriter, req *http.Request) {
  16. fmt.Fprintln(w, "Hello world!")
  17. }

I'm using godep for vendoring libs, it's working in my local machine, but when i'm trying to run it with docker with :

  1. docker build -t myapp-img .
  2. docker run -p 8080:8080 --name myapp-cnt myapp-img

I have the following error :

  1. main.go:8:2: cannot find package "github.com/gorilla/mux" in any of:
  2. /usr/local/go/src/github.com/gorilla/mux (from $GOROOT)
  3. /go/src/github.com/gorilla/mux (from $GOPATH)

I don't understand what is missing.

答案1

得分: 4

错误是正确的。它告诉你一个有抱负的Gopher需要的一切。

我假设你已经将Gorilla Mux复制到了你本地机器上的应用程序的/vendor目录中,就像这样:

  1. ./main.go # 这是你要复制的myapp代码
  2. ./vendor/github.com/gorilla/mux # 用于供应商,这个必须存在

如果你想了解更多关于供应商的信息,请参阅我在这里的热门答案:

https://stackoverflow.com/questions/37237036/how-should-i-use-vendor-in-go-1-6/37238226#37238226

现在,假设你已经完成了上述操作,要修复这个错误...

在构建之前,Gopher需要设置一个有效的$GOPATH。这在你的Dockerfile中缺失了。

  1. FROM golang:1.7-alpine
  2. EXPOSE 8080
  3. # 设置GOPATH和相关内容
  4. #
  5. # 从技术上讲,你不必执行这三个命令,因为
  6. # golang:alpine镜像实际上使用相同的目录结构,并且
  7. # 已经将$GOPATH设置为相同的结构。你可以只是
  8. # 删除这两行,下面的所有内容应该继续工作。
  9. #
  10. # 但是,为了确保我的正确构建路径,
  11. # 以防我尝试不同的Docker构建镜像或者
  12. # 以防最新的镜像更改了结构(你应该使用
  13. # 标签来锁定你使用的Go版本 - 注意我
  14. # 将你锁定到了docker镜像golang:1.7-alpine,因为那是
  15. # 你当前使用的最新版本,带有错误修复)。
  16. #
  17. RUN mkdir -p /go/src \
  18. && mkdir -p /go/bin \
  19. && mkdir -p /go/pkg
  20. ENV GOPATH=/go
  21. ENV PATH=$GOPATH/bin:$PATH
  22. # 现在将你的应用程序复制到正确的构建路径
  23. RUN mkdir -p $GOPATH/src/app
  24. ADD . $GOPATH/src/app
  25. # 现在应该能够构建了
  26. WORKDIR $GOPATH/src/app
  27. RUN go build -o myapp .
  28. CMD ["/go/src/app/myapp"]

这是它的工作原理...

  1. $ tree
  2. .
  3. ├── Dockerfile
  4. ├── main.go
  5. └── vendor
  6. └── mydep
  7. └── runme.go

我的应用程序的源文件:

  1. $ cat main.go
  2. package main
  3. import (
  4. "fmt"
  5. "mydep"
  6. )
  7. func main() {
  8. fmt.Println(mydep.RunMe())
  9. }

我的vendor/文件夹中的依赖项:

  1. $ cat vendor/mydep/runme.go
  2. package mydep
  3. // RunMe返回一个字符串,表示它已经工作!
  4. func RunMe() string {
  5. return "Dependency Worked!"
  6. }

现在,构建并运行镜像:

  1. $ docker build --rm -t test . && docker run --rm -it test
  2. (snip)
  3. Step 8 : WORKDIR $GOPATH/src/app
  4. ---> Using cache
  5. ---> 954ed8e87ae0
  6. Step 9 : RUN go build -o myapp .
  7. ---> Using cache
  8. ---> b4b613f0a939
  9. Step 10 : CMD /go/src/app/myapp
  10. ---> Using cache
  11. ---> 3524025080df
  12. Successfully built 3524025080df
  13. Dependency Worked!

注意最后一行打印的控制台输出,Dependency Worked!

它能够工作是因为:

  1. 你声明你正在使用供应商,这意味着你的应用程序代码的根目录中有一个名为./vendor的本地目录。
  2. 当你执行ADD . /go/src/app时,你也在将./vendor本地目录复制到你的应用程序代码中。
  3. 你已经将文件复制到了Go构建工具所需的正确$GOPATH设置结构中,以便找到包(在这种情况下,是源代码根文件夹中的./vendor目录)。
英文:

The error is correct. It is telling you everything an aspiring Gopher needs.

I am going to assume that you have copied Gorilla Mux to your app's /vendor directory in your local machine, like so:

  1. ./main.go # this is your myapp code you are coping
  2. ./vendor/github.com/gorilla/mux # for vendoring, this must exist

If you want to learn more about vendoring, see my popular answer here:

https://stackoverflow.com/questions/37237036/how-should-i-use-vendor-in-go-1-6/37238226#37238226

Now, to fix that error assuming you have done the above...

A Gopher needs to set a valid $GOPATH before you can build. This is missing from your Dockerfile.

  1. FROM golang:1.7-alpine
  2. EXPOSE 8080
  3. # setup GOPATH and friends
  4. #
  5. # TECHNICALLY, you don't have to do these three cmds as the
  6. # golang:alpine image actually uses this same directory structure and
  7. # already has $GOPATH set to this same structure. You could just
  8. # remove these two lines and everything below should continue to work.
  9. #
  10. # But, I like to do it anyways to ensure my proper build
  11. # path in case I experiment with different Docker build images or in
  12. # case the #latest image changes structure (you should really use
  13. # a tag to lock down what version of Go you are using - note that I
  14. # locked you to the docker image golang:1.7-alpine above, since that is
  15. # the current latest you were using, with bug fixes).
  16. #
  17. RUN mkdir -p /go/src \
  18. && mkdir -p /go/bin \
  19. && mkdir -p /go/pkg
  20. ENV GOPATH=/go
  21. ENV PATH=$GOPATH/bin:$PATH
  22. # now copy your app to the proper build path
  23. RUN mkdir -p $GOPATH/src/app
  24. ADD . $GOPATH/src/app
  25. # should be able to build now
  26. WORKDIR $GOPATH/src/app
  27. RUN go build -o myapp .
  28. CMD ["/go/src/app/myapp"]

Here it is working...

  1. $ tree
  2. .
  3. ├── Dockerfile
  4. ├── main.go
  5. └── vendor
  6. └── mydep
  7. └── runme.go

The source file of my app:

  1. $ cat main.go
  2. package main
  3. import (
  4. "fmt"
  5. "mydep"
  6. )
  7. func main() {
  8. fmt.Println(mydep.RunMe())
  9. }

My dependency in my vendor/ folder:

  1. $ cat vendor/mydep/runme.go
  2. package mydep
  3. // RunMe returns a string that it worked!
  4. func RunMe() string {
  5. return "Dependency Worked!"
  6. }

Now, build and run the image:

  1. $ docker build --rm -t test . && docker run --rm -it test
  2. (snip)
  3. Step 8 : WORKDIR $GOPATH/src/app
  4. ---> Using cache
  5. ---> 954ed8e87ae0
  6. Step 9 : RUN go build -o myapp .
  7. ---> Using cache
  8. ---> b4b613f0a939
  9. Step 10 : CMD /go/src/app/myapp
  10. ---> Using cache
  11. ---> 3524025080df
  12. Successfully built 3524025080df
  13. Dependency Worked!

Note the last line that prints the output from console, Dependency Worked!.

It works because:

  1. you stated you are using Vendoring, which means you have a local directory called ./vendor in the root of your application code.
  2. when you ADD . /go/src/app, you are also copying the ./vendor local to your application code.
  3. you have copied your files into the proper $GOPATH setup structure required by the Go build tools to find packages (and in this case, the ./vendor directory within your source code's root folder).

huangapple
  • 本文由 发表于 2016年10月31日 19:02:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/40340860.html
匿名

发表评论

匿名网友

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

确定