在Docker容器中运行时,golang项目无法find依赖关系

我有这个golang沙箱项目: https : //github.com/cflynn07/golang-db-gateway-example

当我尝试在golang:1.6.0-alpine运行gateway/gateway.go golang:1.6.0-alpine

 ~/g/s/g/c/golang-db-gateway-example git:master ❯❯❯ docker-compose up gateway mysql_server is up-to-date Starting gateway Attaching to gateway gateway | gateway.go:7:2: cannot find package "github.com/go-sql-driver/mysql" in any of: gateway | /usr/local/go/src/github.com/go-sql-driver/mysql (from $GOROOT) gateway | /go/src/github.com/go-sql-driver/mysql (from $GOPATH) gateway | gateway.go:8:2: cannot find package "github.com/gorilla/mux" in any of: gateway | /usr/local/go/src/github.com/gorilla/mux (from $GOROOT) gateway | /go/src/github.com/gorilla/mux (from $GOPATH) gateway exited with code 1 

为什么构build步骤不能检测我的项目在/example/vendor文件夹内的依赖关系?

当我运行从我的主机操作系统go run gateway/gateway.go ,命令的作品。

目录结构(安装在容器内部/ example)

 ~/g/s/g/c/golang-db-gateway-example git:master ❯❯❯ tree -L 3 . ├── README.md ├── client │  └── client.go ├── docker-compose.yml ├── gateway │  └── gateway.go ├── glide.lock ├── glide.yaml ├── tmp └── vendor └── github.com ├── go-sql-driver └── gorilla 

相关文件:

泊坞窗,compose.yml

 mysql: container_name: mysql_server image: mysql:5.7.11 environment: - MYSQL_ROOT_PASSWORD=root ports: - 3306 gateway: container_name: gateway image: golang:1.6.0-alpine volumes: - ./:/example working_dir: /example/gateway command: go run gateway.go environment: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=sandbox links: - mysql 

网关/ gateway.go

 package main import ( "database/sql" "encoding/json" "fmt" _ "github.com/go-sql-driver/mysql" "github.com/gorilla/mux" "net/http" "os" ) var db *sql.DB func main() { r := mux.NewRouter() var e error db, e = sql.Open( "mysql", os.ExpandEnv("root:${MYSQL_SERVER_PASSWORD}@mysql_server:3306/${MYSQL_DATABASE}")) fmt.Print("error is", e) r.HandleFunc("/todos", getTodos).Methods("GET") http.ListenAndServe(":8080", r) fmt.Printf("gateway") } type todo struct{} func getTodos(w http.ResponseWriter, r *http.Request) { t := new(todo) s, _ := json.Marshal(t) w.Header().Set("Content-Type", "application/json; charset=UTF-8") fmt.Fprint(w, string(s)) } 

更新1我更改了容器内的数据卷装入path,以在容器$ GOPATH下安装项目

 mysql: container_name: mysql_server image: mysql:5.7.11 environment: - MYSQL_ROOT_PASSWORD=root ports: - 3306 gateway: container_name: gateway image: golang:1.6.0-alpine volumes: - ./:/go/src/github.com/cflynn07/golang-db-gateway-example working_dir: /go/src/github.com/cflynn07/golang-db-gateway-example command: go run gateway/gateway.go environment: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=sandbox links: - mysql 

不过现在docker似乎挂起:

 ~/g/s/g/c/golang-db-gateway-example git:master ❯❯❯ docker-compose up gateway ✱ mysql_server is up-to-date Recreating gateway Attaching to gateway 

其实你已经成功地运行了Go服务器。 它不挂,只是在等待连接。 由于一些怪癖,没有输出:它没有尝试连接到数据库,并且logging语句被缓冲。

尝试修改gateway.go主要:

 func main() { log.Println("Starting main...") conn := os.ExpandEnv("root:${MYSQL_SERVER_PASSWORD}@mysql_server:3306/${MYSQL_DATABASE}") var err error db, err = sql.Open("mysql", conn) if err != nil { log.Fatal(err) } log.Println("pinging", conn) if err := db.Ping(); err != nil { log.Fatal(err) } r := mux.NewRouter() r.HandleFunc("/todos", getTodos).Methods("GET") listen := ":8080" log.Printf("Listening on %s\n", listen) log.Fatal(http.ListenAndServe(listen, r)) } 

运行这个版本给出:

 $ docker-compose up gateway mysql_server is up-to-date Starting gateway Attaching to gateway gateway | 2016/03/15 10:58:05 Starting main... gateway | 2016/03/15 10:58:05 pinging root:@mysql_server:3306/sandbox gateway | 2016/03/15 10:58:05 default addr for network 'mysql_server:3306' unknown gateway | exit status 1 gateway exited with code 1 

你应该很好从那里去。 注意:

  • docker组成似乎缓冲标准输出,直到换行
  • 日志function如log.Print添加新行,fmt.Print不行
  • sql.Open不连接到数据库,使用sql.Ping(请参阅wiki )
  • MYSQL_SERVER_PASSWORD丢失
  • mysql连接string的networkingtypes丢失(请参阅示例 )
  • 也启动mysql服务器
  • 需要创build新的或挂载现有的数据库“沙盒”

希望有所帮助。

在我看来,这里的主要问题是你没有提前制定Go程序。 看起来你已经把Go源代码文件放在了Docker容器中,而且你依靠go run来构build并运行程序。

我猜你可以做到这一点? 这是非常脚本语言的风格。

但是,我认为最好的方式是提前构buildGo应用程序。

(注意,下面我修改了现有的makefile代码,但是我没有真正运行这个。)
例如,你可以像这样构build它:

 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -installsuffix netgo -o ./gateway/gateway ./gateway 

然后,假设你不需要该容器中的其他东西,你可以使用Dockerfile构buildDocker镜像,如下所示:

 FROM scratch ENTRYPOINT ["/gateway"] ADD ./gateway/gateway /gateway 

产生一个简单的小型(大约8 MB)容器,其中包含一个静态链接的可执行文件。

首先 – 需要更改${MYSQL_SERVER_PASSWORD}上的${MYSQL_ROOT_PASSWORD} ,因为环境只有MYSQL_ROOT_PASSWORDvariables。

其次 – 这是错误的@mysql_server:3306 ,正确的是@tcp(mysql_server:3306)能够通过TCP连接到MySQL。

 conn := os.ExpandEnv("root:${MYSQL_ROOT_PASSWORD}@tcp(mysql_server:3306)/${MYSQL_DATABASE}") 

所有的都会正常工作,唯一的问题是在运行主程序之前db初始化需要暂停。 有很多方法来解决这个问题这里有几个方法https://docs.docker.com/compose/startup-order/