英文:
godep vendor with docker
问题
我正在尝试使用供应商运行一个带有 Docker 容器的程序。
这是我的 Dockerfile:
FROM golang:alpine
EXPOSE 8080
RUN mkdir /app
ADD . /app/
WORKDIR /app
RUN go build -o myapp .
CMD ["/app/myapp"]
这是我的 main.go:
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/", Hello)
http.Handle("/", r)
fmt.Println("Starting up on 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func Hello(w http.ResponseWriter, req *http.Request) {
fmt.Fprintln(w, "Hello world!")
}
我正在使用 godep 进行库的供应,它在我的本地机器上工作正常,但是当我尝试使用 Docker 运行它时,出现以下错误:
main.go:8:2: cannot find package "github.com/gorilla/mux" in any of:
/usr/local/go/src/github.com/gorilla/mux (from $GOROOT)
/go/src/github.com/gorilla/mux (from $GOPATH)
我不明白缺少了什么。
英文:
I'm trying to run a docker container with vendor.
This is my Dockerfile
FROM golang:alpine
EXPOSE 8080
RUN mkdir /app
ADD . /app/
WORKDIR /app
RUN go build -o myapp .
CMD ["/app/myapp"]
and my main.go
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/", Hello)
http.Handle("/", r)
fmt.Println("Starting up on 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func Hello(w http.ResponseWriter, req *http.Request) {
fmt.Fprintln(w, "Hello world!")
}
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 :
docker build -t myapp-img .
docker run -p 8080:8080 --name myapp-cnt myapp-img
I have the following error :
main.go:8:2: cannot find package "github.com/gorilla/mux" in any of:
/usr/local/go/src/github.com/gorilla/mux (from $GOROOT)
/go/src/github.com/gorilla/mux (from $GOPATH)
I don't understand what is missing.
答案1
得分: 4
错误是正确的。它告诉你一个有抱负的Gopher需要的一切。
我假设你已经将Gorilla Mux复制到了你本地机器上的应用程序的/vendor目录中,就像这样:
./main.go # 这是你要复制的myapp代码
./vendor/github.com/gorilla/mux # 用于供应商,这个必须存在
如果你想了解更多关于供应商的信息,请参阅我在这里的热门答案:
https://stackoverflow.com/questions/37237036/how-should-i-use-vendor-in-go-1-6/37238226#37238226
现在,假设你已经完成了上述操作,要修复这个错误...
在构建之前,Gopher需要设置一个有效的$GOPATH
。这在你的Dockerfile中缺失了。
FROM golang:1.7-alpine
EXPOSE 8080
# 设置GOPATH和相关内容
#
# 从技术上讲,你不必执行这三个命令,因为
# golang:alpine镜像实际上使用相同的目录结构,并且
# 已经将$GOPATH设置为相同的结构。你可以只是
# 删除这两行,下面的所有内容应该继续工作。
#
# 但是,为了确保我的正确构建路径,
# 以防我尝试不同的Docker构建镜像或者
# 以防最新的镜像更改了结构(你应该使用
# 标签来锁定你使用的Go版本 - 注意我
# 将你锁定到了docker镜像golang:1.7-alpine,因为那是
# 你当前使用的最新版本,带有错误修复)。
#
RUN mkdir -p /go/src \
&& mkdir -p /go/bin \
&& mkdir -p /go/pkg
ENV GOPATH=/go
ENV PATH=$GOPATH/bin:$PATH
# 现在将你的应用程序复制到正确的构建路径
RUN mkdir -p $GOPATH/src/app
ADD . $GOPATH/src/app
# 现在应该能够构建了
WORKDIR $GOPATH/src/app
RUN go build -o myapp .
CMD ["/go/src/app/myapp"]
这是它的工作原理...
$ tree
.
├── Dockerfile
├── main.go
└── vendor
└── mydep
└── runme.go
我的应用程序的源文件:
$ cat main.go
package main
import (
"fmt"
"mydep"
)
func main() {
fmt.Println(mydep.RunMe())
}
我的vendor/
文件夹中的依赖项:
$ cat vendor/mydep/runme.go
package mydep
// RunMe返回一个字符串,表示它已经工作!
func RunMe() string {
return "Dependency Worked!"
}
现在,构建并运行镜像:
$ docker build --rm -t test . && docker run --rm -it test
(snip)
Step 8 : WORKDIR $GOPATH/src/app
---> Using cache
---> 954ed8e87ae0
Step 9 : RUN go build -o myapp .
---> Using cache
---> b4b613f0a939
Step 10 : CMD /go/src/app/myapp
---> Using cache
---> 3524025080df
Successfully built 3524025080df
Dependency Worked!
注意最后一行打印的控制台输出,Dependency Worked!
。
它能够工作是因为:
- 你声明你正在使用供应商,这意味着你的应用程序代码的根目录中有一个名为
./vendor
的本地目录。 - 当你执行
ADD . /go/src/app
时,你也在将./vendor
本地目录复制到你的应用程序代码中。 - 你已经将文件复制到了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:
./main.go # this is your myapp code you are coping
./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.
FROM golang:1.7-alpine
EXPOSE 8080
# setup GOPATH and friends
#
# TECHNICALLY, you don't have to do these three cmds as the
# golang:alpine image actually uses this same directory structure and
# already has $GOPATH set to this same structure. You could just
# remove these two lines and everything below should continue to work.
#
# But, I like to do it anyways to ensure my proper build
# path in case I experiment with different Docker build images or in
# case the #latest image changes structure (you should really use
# a tag to lock down what version of Go you are using - note that I
# locked you to the docker image golang:1.7-alpine above, since that is
# the current latest you were using, with bug fixes).
#
RUN mkdir -p /go/src \
&& mkdir -p /go/bin \
&& mkdir -p /go/pkg
ENV GOPATH=/go
ENV PATH=$GOPATH/bin:$PATH
# now copy your app to the proper build path
RUN mkdir -p $GOPATH/src/app
ADD . $GOPATH/src/app
# should be able to build now
WORKDIR $GOPATH/src/app
RUN go build -o myapp .
CMD ["/go/src/app/myapp"]
Here it is working...
$ tree
.
├── Dockerfile
├── main.go
└── vendor
└── mydep
└── runme.go
The source file of my app:
$ cat main.go
package main
import (
"fmt"
"mydep"
)
func main() {
fmt.Println(mydep.RunMe())
}
My dependency in my vendor/
folder:
$ cat vendor/mydep/runme.go
package mydep
// RunMe returns a string that it worked!
func RunMe() string {
return "Dependency Worked!"
}
Now, build and run the image:
$ docker build --rm -t test . && docker run --rm -it test
(snip)
Step 8 : WORKDIR $GOPATH/src/app
---> Using cache
---> 954ed8e87ae0
Step 9 : RUN go build -o myapp .
---> Using cache
---> b4b613f0a939
Step 10 : CMD /go/src/app/myapp
---> Using cache
---> 3524025080df
Successfully built 3524025080df
Dependency Worked!
Note the last line that prints the output from console, Dependency Worked!
.
It works because:
- you stated you are using Vendoring, which means you have a local directory called
./vendor
in the root of your application code. - when you
ADD . /go/src/app
, you are also copying the./vendor
local to your application code. - 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).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论