【问题标题】:Access Go Api Hosted in Docker container访问托管在 Docker 容器中的 Go Api
【发布时间】:2020-08-17 07:57:29
【问题描述】:

我创建了一个包含 api 的 Go 后端服务器。在本地运行“运行服务器”时一切正常。然而,我在 docker 中运行它时确实遇到了问题。所以我创建了一个 Dockerfile 并在 networkmode 主机中运行 linux 容器,但无法在浏览器中访问 api。如果它工作正常,我应该能够看到来自http://localhost:8500/status 的 json 响应。所以我想我需要权限或添加标志或更多与安装相关的脚本。我一直在 docker 中测试不同的标志和端口,但无法识别问题。请参阅下面的代码、dockerfile 和命令。

注意:当我在 windows 上本地运行程序时,会弹出一个安全警告,也许这与问题有关?

我正在运行 docker desktop community v 2.2.0.5 stable。

API 代码:

import (
    "log"
    "net/http"
    conf "server/conf"

    "github.com/gorilla/mux"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)
var db *gorm.DB

// Middleware used to add correct permissions for all requests
func middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
        next.ServeHTTP(w, r)
    })
}

func StartApi(config conf.Config, _db *gorm.DB) {

log.Println("Start Api")
    db = _db

    router := mux.NewRouter()
    // Create 
    router.HandleFunc("/login", login).Methods("POST", "OPTIONS")
    router.HandleFunc("/network", createNetwork).Methods("POST", "OPTIONS")

    // Read 
    router.HandleFunc("/users/{networkName}", getUsers).Methods("GET", "OPTIONS")
    router.HandleFunc("/streams/{networkName}", getStreams).Methods("GET", "OPTIONS")
    router.HandleFunc("/status", showStatus).Methods("GET", "OPTIONS")

    log.Println("API started at port " + config.Backend.Api_port) // api port is stored in config
    log.Println(http.ListenAndServe(":"+config.Backend.Api_port, middleware(router)))

    log.Println("Api done!")  }

Dockerfile:

# Start from the latest golang base image
FROM golang:latest

WORKDIR /go/src/server

COPY ./src/server .

# Download packages
RUN go get . 

# Compile code
#RUN go build -o server
RUN go install server

# Expose ports
EXPOSE 8500
EXPOSE 8600

#ENTRYPOINT ./server
CMD ["go", "run", "server"]

Docker 撰写:

version : '3'

services:
  react:
    build: ./ReactFrontend/
    container_name: ReactFrontend
    tty: true
    ports:
    - 4000:3000

  backend:
    network_mode: host
    build: ./GoBackend/
    container_name: goserver
    ports:
    - 8500:8500
    - 8600:8600

Docker 命令:

docker run --net=host goserver

感谢您的帮助,

干杯!

【问题讨论】:

  • 您使用的是哪种 Docker 设置? (是 Docker 工具箱吗?)你能展示你的应用程序代码中绑定到网络套接字的部分吗?为什么需要主机网络或 tty?
  • 要跟进@DavidMaze 的评论,您确实需要提供有关 Docker 设置的更多信息(因为在 Windows 下可能有两种不同的方法),以及警告/错误/不需要的行为你观察。
  • 仅供参考,此答案中提到了在这种情况下可能发生的三个典型问题(在 Windows 上部署后端和浏览 http://localhost…):Not open web page on port 8080 when start tomcat inside Docker
  • 顺便说一句,@DavidMaze 提到,使用docker run --net=host 是一种不好的做法,因为它基本上会阻碍 Docker 提供的网络隔离。我建议您使用诸如docker-compose up 之类的命令。

标签: docker go


【解决方案1】:

所以我现在通过以下方式解决了它:

正如这里提到的: https://docs.docker.com/compose/networking/

添加到 docker-compose:

networks:
  default:
    external:
      name: database_default

这里提到:Access to mysql container from other container

我可以在后端以 :3306 的身份连接到数据库。

为了自动化这个过程,我创建了一个 .sh 脚本来处理容器启动时的额外设置配置步骤。但是,由于我在 config.yml 中的结构,仅使用“sed”命令很难更新,因此我创建了一个 python 程序来更新所有配置数据。 Dockerfile、docker-compose 文件、setup.sh 和 update_config.py 文件如下所示。

setup.sh:

#!/bin/bash
# Don't remove this!
# This file is used by dockerfile to replace configs

# Replace config on run
python3 update_config.py

# Start program
go run server

Dockerfile:

# Start from the latest golang base image
FROM golang:latest

WORKDIR /go/src/server

COPY ./src/server .

# Install python3 and yml compability
RUN apt-get update && apt-get install -y python3-pip
RUN python3 --version
RUN pip3 install PyYAML

# Download packages
RUN go get . 

# Compile code
#RUN go build -o server
RUN go install server

# Expose ports
EXPOSE 8500
EXPOSE 8600

# ENV
 ENV DB_HOST "mysql:3306"

#CHMOD setup
RUN chmod +x setup.sh

CMD ["./setup.sh"]

Docker 编写

version : '3'

services:
  react:
    build: ./ReactFrontend/
    container_name: ReactFrontend
    tty: true
    ports:
    - 4000:3000

  backend:
    build: ./GoBackend/
    container_name: GoBackend
    environment:
      DB_HOST: mysql:3306 # Name or IP of DB container!
    ports:
    - 8500:8500
    - 8600:8600

networks:
  default:
    external:
      name: database_default

update_config.py:

import yaml
import os

"""
DONT REMOVE
This file is used in the dockerfile!
"""

fname = "/go/src/server/config.yml"

stream = open(fname, 'r')
data = yaml.safe_load(stream)
stream.close()

# Add more updates here!
if os.environ.get('DB_HOST') is not None:
    data["database"]["ip"] = os.environ['DB_HOST']


# Updated data print
print("Updated Data", data)

# Write changes to config
stream = open(fname, 'w')
yaml.dump(data, stream)
stream.close()

如果我们只希望容器运行,现在可以使用的示例 docker 命令:

docker run -p 8500:8500 -p 8600:8600 --net database_default goserver

一切正常!我们正在避免使用不必要的主机网络模式!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多