在docker容器中运行时,golang项目无法找到依赖项

时间:2016-03-15 03:31:29

标签: go docker

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

当我尝试在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

为什么构建步骤不能在/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 我更改了容器内的数据卷安装路径,以便在容器$ 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

3 个答案:

答案 0 :(得分:2)

实际上你已经成功运行了Go服务器。它没有挂,只是在等待连接。由于一些怪癖,没有输出:它没有尝试连接到数据库,并且缓存了日志记录语句。

尝试修改gateway.go main:

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-compose似乎缓冲标准输出直到换行符
  • 日志功能,如log.Print添加换行符,fmt.Print不
  • sql.Open无法连接数据库,请使用sql.Ping(参见wiki
  • 缺少MYSQL_SERVER_PASSWORD
  • 缺少mysql连接字符串的网络类型(请参阅examples
  • 启动mysql服务器
  • 需要创建新的或挂载现有数据库'sandbox'

希望有所帮助。

答案 1 :(得分:0)

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

第二 - 这是错误的@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/

答案 2 :(得分:0)

在我看来,这看起来主要的问题是你没有提前构建你的Go程序。看起来你已经把Go源文件放在Docker容器中了,你依靠go run来构建然后运行程序。

我猜你能做到吗?这就是脚本语言风格。

然而,我认为最有效的方法是提前构建Go应用程序。

(注意,以下我改编了现有的makefile代码,但实际上并没有运行它。)
例如,您可以像这样构建它:

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

然后,假设您不需要该容器中的其他内容,您可以使用Dockerfile构建Docker镜像,如:

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

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