英文:
go does not write file from container unless application is manually started from container
问题
我写了一个小的Go应用程序,它有两个功能:
- 处理 http://localhost:5000
- 每秒写入一条日志
这个应用程序在一个Docker容器中。你可以看到的日志记录器是我的,只是一个练习。应用程序已经启动。如果我使用curl命令访问 http://localhost:5000,我可以看到"Ciao, mondo!"。但是日志记录器没有启动。奇怪的是,如果我进入容器,并手动运行应用程序,日志记录器就开始记录了。我认为这可能是权限的问题。
以下是docker-compose文件:
version: "3.9"
services:
app:
container_name: 'go_docker_app'
build:
dockerfile: Dockerfile
context: .
volumes:
- ./logs:/app/logs
- .:/opt/app/api
ports:
- "5000:5000"
以下是main.go文件的内容:
package main
import (
"fmt"
"net/http"
"time"
"github.com/sensorario/gol"
)
func main() {
http.HandleFunc("/", HelloServer)
http.ListenAndServe(":5000", nil)
go forever()
select{}
}
func HelloServer(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Ciao, mondo!")
}
func forever() {
l := gol.NewCustomLogger("/app")
for {
l.Info(fmt.Sprintf("%v+\n", time.Now()))
time.Sleep(time.Second)
}
}
以下是Dockerfile的内容:
我尝试了多种解决方案。例如,从Dockerfile中创建logger.log文件。我不认为这是权限的问题,因为我没有收到任何错误信息。
FROM golang:1.17-alpine
RUN mkdir -p /app/logs
ADD . /app
WORKDIR /app
RUN go get -d -v ./...
RUN go install -v ./...
RUN go build -o /application
EXPOSE 5000
RUN touch /app/logs/logger.log
CMD ["/application"]
英文:
I've written a little golang application. It do two things:
- handle http://localhost:5000
- write a log each seconds
This application is inside a docker container. The logger you can see is mine, is just an exercise. Application start. If I curl http://localhost:5000 I can see "Ciao, mondo!". But the logger does not starts. The strange thing is that if I go into the container, and I run the application by hand. The logger start to log. I thought this can be a problem of permissions.
Here the docker-compose.
version: "3.9"
services:
app:
container_name: 'go_docker_app'
build:
dockerfile: Dockerfile
context: .
volumes:
- ./logs:/app/logs
- .:/opt/app/api
ports:
- "5000:5000"
Here the main.go file
package main
import (
"fmt"
"net/http"
"time"
"github.com/sensorario/gol"
)
func main() {
http.HandleFunc("/", HelloServer);
http.ListenAndServe(":5000", nil);
go forever()
select{}
}
func HelloServer(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Ciao, mondo!");
}
func forever() {
l := gol.NewCustomLogger("/app");
for {
l.Info(fmt.Sprintf("%v+\n", time.Now()));
time.Sleep(time.Second)
}
}
Here the Dockerfile
I've tried more solutions. For example creating logger.log from Dockerfile. I dont think is a problem of permissions because I have no errors.
FROM golang:1.17-alpine
RUN mkdir -p /app/logs
ADD . /app
WORKDIR /app
RUN go get -d -v ./...
RUN go install -v ./...
RUN go build -o /application
EXPOSE 5000
RUN touch /app/logs/logger.log
CMD ["/application"]
答案1
得分: 3
这是由于在你的goroutine之前运行了ListenAndServe
导致的。go forever()
从未执行,因此不会输出任何日志文件。
奇怪的是,如果我进入容器,手动运行应用程序,记录器就开始记录了。
我猜你在运行的容器上执行了命令,其中一个应用程序实例已经在运行,所以端口5000已经被占用。你没有进行任何错误处理,所以它跳过了错误并进入了forever()
函数。空的select{}
是不需要的,因为ListenAndServe
会“阻塞”程序:一个很好的解释可以在这里找到https://stackoverflow.com/a/44598343/14484111
func main() {
go forever()
http.HandleFunc("/", HelloServer);
// 添加错误验证
err := http.ListenAndServe(":5000", nil);
log.Fatal(err)
// 或者更简洁的写法
// log.Fatal(http.ListenAndServe(":5000", nil))
}
英文:
It's caused by running ListenAndServe
before your goroutine. go forever()
never execute, so it will not output any log file.
> The strange thing is that if I go into the container, and I run the application by hand. The logger start to log.
I assume that You exec on running container, where one instance of your app is alredy running so the Port 5000 is alredy taken. You don't have any error handling, so it skips it and go to the forever()
function. Empty select{}
won't be needed, coz ListenAndServe
will "block" the program: a nice explenation https://stackoverflow.com/a/44598343/14484111
func main() {
go forever()
http.HandleFunc("/", HelloServer);
// added error validating
err := http.ListenAndServe(":5000", nil);
log.Fatal(err)
// or shorter version
// log.Fatal(http.ListenAndServe(":5000", nil))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论