Docker环境下Gin应用本地无法访问及调试失败问题求助
我使用Go语言和Gin框架开发Web应用,希望通过Docker容器运行并实现调试功能,但本地8080端口访问无响应,VS Code启动调试也报错。以下是我的配置和运行日志:
Dockerfile
FROM golang:1.21.6 WORKDIR /go/src/gitlab.com/main/server COPY go.mod . COPY go.sum . RUN go mod download RUN go install github.com/cosmtrek/air@latest RUN go install github.com/swaggo/swag/cmd/swag@latest RUN go install github.com/go-delve/delve/cmd/dlv@latest EXPOSE 2345 EXPOSE 80
docker-compose配置
version: "3.2" services: service-influxdb: image: go-time-series build: context: .. dockerfile: docker/Dockerfile command: air -c .air.toml volumes: - ../:/go/src/gitlab.com/main/server ports: - 8080:80 - 10000:2345 environment: - WEB_APP_VERSION=0.0.1 - WEP_APP_TITLE=Thori influx-DB - WEP_APP_DESCRIPTION=Micro service for the manage of the influx-db services - ENVIRONMENT=dev - HOST=localhost:8080 - INFLUX_URL=http://localhost:8086 - INFLUX_TOKEN=1234 - INFLUX_ORG=Abc - INFLUX_MINIMUN_DATE=1677-09-21 00:12:44 - INFLUX_MAXIMUN_DATE=2100-01-01 00:00:00 network_mode: host
VS Code调试配置
{ "version": "0.2.0", "configurations": [ { "name": "Debug in Docker", "type": "go", "request": "attach", "mode": "remote", "remotePath": "/go/src/gitlab.com/main/server", "port": 10000, "host": "127.0.0.1", "showLog": true, "trace": "log", "logOutput": "rpc" }, ] }
.air.toml配置
root = "." testdata_dir = "testdata" tmp_dir = "tmp" [build] args_bin = [] bin = "./tmp/main" full_bin = "dlv exec --accept-multiclient --headless --listen :2345 --api-version 2 ./tmp/main" pre_cmd = ["swag init -g ./cmd/main.go"] cmd = "go build -o ./tmp/main ./cmd/main.go" post_cmd = [] delay = 0 exclude_dir = ["assets", "tmp", "vendor", "testdata", "docs"] exclude_file = [] exclude_regex = ["_test.go"] exclude_unchanged = true follow_symlink = true include_dir = [] include_ext = ["go", "tpl", "tmpl", "html"] include_file = [] kill_delay = "0s" log = "build-errors.log" poll = false poll_interval = 0 rerun = false rerun_delay = 500 send_interrupt = false stop_on_error = false [color] app = "" build = "yellow" main = "magenta" runner = "green" watcher = "cyan" [log] main_only = false time = true [misc] clean_on_exit = true [screen] clear_on_rebuild = true keep_scroll = true
应用main函数代码
func main() { port := flag.Int("port", 80, "Listening port") flag.Parse() if config.Cfg.Environment == "prod" { gin.ForceConsoleColor() gin.SetMode(gin.ReleaseMode) } router := gin.Default() loadSwagger(router) loadAPI(router) router.Run(fmt.Sprintf(":%d", *port)) } func loadSwagger(router *gin.Engine) { // @securityDefinitions.apikey ApiKeyAuth // @in Header // @name Authorization docs.SwaggerInfo.Title = config.Cfg.WebAppTitle docs.SwaggerInfo.Version = config.Cfg.WebAppVersion docs.SwaggerInfo.Description = config.Cfg.WebAppDescription docs.SwaggerInfo.Host = config.Cfg.Host router.GET("/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) }
运行日志
docker-service-influxdb-1 | [21:07:26] mkdir /go/src/gitlab.com/main/server/tmp docker-service-influxdb-1 | [21:07:26] watching . docker-service-influxdb-1 | [21:07:26] watching app docker-service-influxdb-1 | [21:07:26] watching app/api docker-service-influxdb-1 | [21:07:26] watching app/api/handlers docker-service-influxdb-1 | [21:07:26] watching app/api/handlers/healthcheck docker-service-influxdb-1 | [21:07:26] watching app/config docker-service-influxdb-1 | [21:07:26] watching app/domain docker-service-influxdb-1 | [21:07:26] watching app/domain/models docker-service-influxdb-1 | [21:07:26] watching app/domain/ports docker-service-influxdb-1 | [21:07:26] watching app/domain/services docker-service-influxdb-1 | [21:07:26] watching app/repositories docker-service-influxdb-1 | [21:07:26] watching cmd docker-service-influxdb-1 | [21:07:26] watching docker docker-service-influxdb-1 | [21:07:26] !exclude docs docker-service-influxdb-1 | [21:07:26] !exclude tmp docker-service-influxdb-1 | [21:07:26] > swag init -g ./cmd/main.go docker-service-influxdb-1 | 2024/02/07 21:07:26 Generate swagger docs.... docker-service-influxdb-1 | 2024/02/07 21:07:26 Generate general API Info, search dir:./ docker-service-influxdb-1 | 2024/02/07 21:07:26 warning: failed to get package name in dir: ./, error: execute go list command, exit status 1, stdout:, stderr:no Go files in /go/src/gitlab.com/main/server docker-service-influxdb-1 | 2024/02/07 21:07:26 Generating models.HealthCheck docker-service-influxdb-1 | 2024/02/07 21:07:26 create docs.go at docs/docs.go docker-service-influxdb-1 | 2024/02/07 21:07:26 create swagger.json at docs/swagger.json docker-service-influxdb-1 | 2024/02/07 21:07:26 create swagger.yaml at docs/swagger.yaml docker-service-influxdb-1 | [21:07:26] building... docker-service-influxdb-1 | [21:07:27] running... docker-service-influxdb-1 | API server listening at: [::]:2345 docker-service-influxdb-1 | 2024-02-07T21:07:27Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
问题根源
network_mode: host 导致端口映射失效
当docker-compose设置network_mode: host时,容器会直接使用宿主机的网络栈,此时ports配置会被完全忽略。容器内应用监听的80端口直接暴露在宿主机的80端口,而非配置的8080;Delve监听的2345端口直接暴露在宿主机2345,而非10000,这就是VS Code调试连接失败的核心原因。应用监听地址限制
Gin默认的router.Run(":80")会监听localhost,如果不用host网络,容器外部无法访问这个地址,需要改为监听0.0.0.0来允许所有网卡的连接。环境变量拼写错误
docker-compose里的WEP_APP_TITLE和WEP_APP_DESCRIPTION是拼写错误,应为WEB_APP_TITLE和WEB_APP_DESCRIPTION,这会导致Swagger无法正确读取标题和描述配置。
修复方案
方案1:移除network_mode: host(推荐)
这是Docker容器的标准用法,通过端口映射实现外部访问:
- 修改docker-compose.yml,删除
network_mode: host配置 - 修正环境变量的拼写错误
- 修改main.go中的监听地址为
0.0.0.0:%d
修改后的docker-compose.yml:
version: "3.2" services: service-influxdb: image: go-time-series build: context: .. dockerfile: docker/Dockerfile command: air -c .air.toml volumes: - ../:/go/src/gitlab.com/main/server ports: - 8080:80 - 10000:2345 environment: - WEB_APP_VERSION=0.0.1 - WEB_APP_TITLE=Thori influx-DB - WEB_APP_DESCRIPTION=Micro service for the manage of the influx-db services - ENVIRONMENT=dev - HOST=localhost:8080 - INFLUX_URL=http://localhost:8086 - INFLUX_TOKEN=1234 - INFLUX_ORG=Abc - INFLUX_MINIMUN_DATE=1677-09-21 00:12:44 - INFLUX_MAXIMUN_DATE=2100-01-01 00:00:00
修改后的main.go监听代码:
router.Run(fmt.Sprintf("0.0.0.0:%d", *port))
方案2:保留network_mode: host
如果必须使用host网络,调整端口配置:
- 删除docker-compose中的
ports配置 - 修改VS Code调试配置中的
port为2345 - 直接访问宿主机的80端口来访问应用
修改后的VS Code launch.json:
{ "version": "0.2.0", "configurations": [ { "name": "Debug in Docker", "type": "go", "request": "attach", "mode": "remote", "remotePath": "/go/src/gitlab.com/main/server", "port": 2345, "host": "127.0.0.1", "showLog": true, "trace": "log", "logOutput": "rpc" } ] }
额外说明
日志中的no Go files in /go/src/gitlab.com/main/server警告是因为项目根目录没有Go文件,swag仍能正常生成文档,不影响应用运行,可忽略。
内容的提问来源于stack exchange,提问作者Diego L

