简体   繁体   中英

Multiple go files in Docker build

I'm building a Dockeried app where I split the go file into two files.

When attempting to run it I get the following error:

# command-line-arguments 
./server.go:86:63: undefined: indexHandler

The indexHandler works fine when located in server.go but I get the error the it is located in handlers.go.

Any suggestions?

//server.go
package main

import (
    "database/sql"
    "fmt"
    "log"
    "net"
    "net/http"
    "os"
    "os/exec"
    "strconv"
    "strings"

    _ "github.com/go-sql-driver/mysql"
    "github.com/gorilla/mux"
    "github.com/jimlawless/whereami"
    "github.com/rs/cors"
)

type FileSystem struct {
    fs http.FileSystem
}

type dbConnection struct {
    conn *sql.DB
}

var dbx dbConnection
var Config Configs

type Configs struct {
    cookieName     string
    cookieValue    string
    cookieMaxAge   int
    cookieHTTPOnly bool
    cookiePath     string
    domain         string
    port           string
    apiKey         string
    apiVersion     string
    apiPath        string
    protocol       string
}

func setConfig() {
    Config = Configs{}
    Config.cookieName = os.Getenv("COOKIE_NAME")
    Config.cookieValue = os.Getenv("COOKIE_VALUE")
    age, err := strconv.Atoi(os.Getenv("COOKIE_MAX_AGE"))
    if err != nil {
        log.Println(whereami.WhereAmI(), err.Error())
    }
    Config.cookieMaxAge = age

    Config.cookieHTTPOnly, err = strconv.ParseBool(os.Getenv("COOKIE_HTTP_ONLY"))
    if err != nil {
        log.Println(whereami.WhereAmI(), err.Error())
    }

    Config.cookiePath = os.Getenv("COOKIE_PATH")
    Config.domain = os.Getenv("DOMAIN")
    Config.port = os.Getenv("PORT")
    Config.apiKey = os.Getenv("APP_KEY")
    Config.apiVersion = os.Getenv("API_VERSION")
    Config.apiPath = os.Getenv("API_PATH")
    Config.protocol = os.Getenv("PROTOCOL")
}

func main() {
    defer recoverPanic()
    setConfig()
    //db()
    fmt.Println(Config)
    target := Config.protocol + Config.domain + Config.port
    corsOpts := cors.New(cors.Options{
        AllowedOrigins: []string{target}, //you service is available and allowed for this base url
        AllowedMethods: []string{
            http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete, http.MethodOptions, http.MethodHead,
        },
        AllowedHeaders: []string{
            "*", //or you can your header key values which you are using in your application
        },
    })

    router := mux.NewRouter()
    router.HandleFunc(Config.apiPath+Config.apiVersion+"/index", indexHandler).Methods("GET")
    router.PathPrefix("/").Handler(http.FileServer(http.Dir("./")))
    http.ListenAndServe(Config.port, corsOpts.Handler(router))
}

/*
func indexHandler(w http.ResponseWriter, req *http.Request) {
    addCookie(w, Config.cookieName, Config.cookieValue)
    cookie, err := req.Cookie(Config.cookieName)
    if err != nil {
        log.Println(whereami.WhereAmI(), err.Error())
    }

    log.Println("Cookie: ", cookie)
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "hola")
}
*/
func addCookie(w http.ResponseWriter, name, value string) {
    cookie := http.Cookie{
        Name:     Config.cookieName,
        Value:    Config.cookieValue,
        Domain:   Config.domain,
        Path:     Config.cookiePath,
        MaxAge:   Config.cookieMaxAge,
        HttpOnly: Config.cookieHTTPOnly,
    }
    http.SetCookie(w, &cookie)
    log.Println("Cookie added")
}

func (fs FileSystem) Open(path string) (http.File, error) {
    f, err := fs.fs.Open(path)
    if err != nil {
        return nil, err
    }

    s, err := f.Stat()
    if s.IsDir() {
        index := strings.TrimSuffix(path, "/") + "/index.html"
        if _, err := fs.fs.Open(index); err != nil {
            return nil, err
        }
    }

    return f, nil
}

func db() error {
    db, err := sql.Open("mysql", "root:root@tcp(192.168.0.33:4200)/mysql")

    if err != nil {
        log.Print(err.Error())
    } else {
        log.Println("DB connected successfully")
    }
    defer db.Close()

    err = db.Ping()
    if err != nil {
        log.Println("Ping Error: " + err.Error())
    } else {
        dbx.conn = db
    }

    return err
}

func recoverPanic() {
    if rec := recover(); rec != nil {
        err := rec.(error)
        log.Println(whereami.WhereAmI(), err.Error())

        var l *net.TCPListener
        file, err := l.File()
        if err != nil {
            log.Println(whereami.WhereAmI(), err.Error())
        }

        path := os.Args
        args := []string{"-graceful"}

        cmd := exec.Command(path[0], args...)
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        cmd.ExtraFiles = []*os.File{file}

        err2 := cmd.Start()
        if err2 != nil {
            log.Println(whereami.WhereAmI(), err2.Error())
        } else {
            log.Println(whereami.WhereAmI(), "Restarted...")
        }
    }
}
//handlers.go
package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/jimlawless/whereami"
)

func indexHandler(w http.ResponseWriter, req *http.Request) {
    addCookie(w, Config.cookieName, Config.cookieValue)
    cookie, err := req.Cookie(Config.cookieName)
    if err != nil {
        log.Println(whereami.WhereAmI(), err.Error())
    }

    log.Println("Cookie: ", cookie)
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "hola")
}

The lines that are commented out are things that I have tried but failed.

#Dockerfile
FROM golang:alpine AS builder

RUN mkdir /app
RUN rm -f go.mod go.sum
RUN go mod init xyz.com
RUN rm -f $GOPATH/go.mod

ADD . /app/
WORKDIR /app
COPY ./handlers.go .
COPY ./server.go .
COPY ./favicon.ico .
COPY ./assets /assets
COPY ./go.mod . 
COPY ./go.sum .

RUN go mod download

COPY . .

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build $(ls -1 *.go)

# command-line-arguments
#./server.go:86:63: undefined: indexHandler

#RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .
#RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build $(ls -1 *.go)
#RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o server.go handlers.go
#RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server.go handlers.go
#RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build *.go

EXPOSE 9000
#stat /app/*.go: no such file or directory
#CMD ["go", "run", "/app/*.go"]

CMD ["go", "run", "/app/server.go"]

The issue is with your Dockerfile, specifically the CMD (last line).

I tested this, and it worked..

# ~ Dockerfile ~
# ...
# CMD ["go", "run", "/app/server.go"] # <- Remove this
CMD ["go", "run", "."] # <- Add this

Edit: the reason this was happening is because you were specifically running server.go . Meaning, handlers.go was not being compiled with server.go , specifying the period tells go to build/run all files in the current directory. I'm not sure how you got it working with go run server.go locally (I could not get that to work, I had to use go run. )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM