Docker中Golang主进程与Python子进程通信的最佳实践

huangapple go评论82阅读模式
英文:

Best practice on docker golang main process communicate with python subprocess

问题

我知道在使用Docker时的最佳实践是每个容器只有一个主进程,并且只有一条运行的CMD命令。

我的情况是我有一个Golang微服务,功能是通过Python子进程实现的。目前,主进程只接收API调用,然后在exec中调用Python子进程,并读取STDOUTSTDERR

我想优化架构,将Python作为一个服务(Flask)仅在Docker内的本地主机上运行。然后,我的主Golang进程可以使用RESTful的http调用与Python进程通信。

但这样会让两个服务在同一个Docker容器中运行,并且它们不是一个主进程和一个子进程。这样做是否会有实际上的问题?有什么想法吗?

感谢您的帮助。

英文:

I know that a best practice of using docker is to have only one main process in each container and only one CMD line running.

My case is I have a Golang micro service and the functionality are implemented in python subprocess. Currently the main process just take API calls then invoke the python subprocess in exec and read the STDOUT and STDERR.

I want to optimize the architecture like to run python as a service (Flask) only on localhost inside docker. Then my main Golang process can use restful http call to communicate with the python process.

But that will let 2 service running in a same docker and it's not a main process and a subprocess. Will that be practically bad, Any idea?

Appreciate on all helps.

答案1

得分: 2

通常情况下,当你有多个服务时,最佳实践是不将它们部署在一个容器中,建议将它们部署在多个容器中。

你可以使用docker-compose来帮助你:

Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。使用 Compose,你可以使用一个 YAML 文件来配置应用程序的服务。然后,通过一个命令,你可以根据配置创建和启动所有的服务。

针对你的场景,下面给出一个最简示例。

文件夹结构:

.
├── docker-compose.yaml
├── flask
│   ├── app.py
│   └── Dockerfile
└── go
    ├── app.go
    └── Dockerfile

docker-compose.yaml:

version: '3'
services:
  flask_service:
    build: flask

  go_service:
    build: go
    ports:
    - "9500:9500"
    depends_on:
    - flask_service

go/app.go:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
        url := "http://flask_service:9600"
        ret, err := http.Get(url)
        if err != nil {
                panic(err)
        }
        defer ret.Body.Close()

        body, err := ioutil.ReadAll(ret.Body)
        if err != nil {
                panic(err)
        }
        fmt.Fprintf(w, string(body))
}

func main() {
        http.HandleFunc("/", handler)
        http.ListenAndServe(":9500", nil)
}

go/Dockerfile:

FROM golang:latest as build

WORKDIR /go/app
COPY ./app.go .
RUN go mod init app; go mod tidy; go build

CMD ["/go/app/app"]

flask/app.py:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hey, we have Flask in a Docker container!'

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=9600)

flask/Dockerfile:

FROM python:alpine3.7

WORKDIR /app

RUN pip install flask

COPY . /app

ENTRYPOINT [ "python" ]
CMD [ "app.py" ]

执行:

$ docker-compose up
Creating network "20211203_default" with the default driver
Creating 20211203_flask_service_1 ... done
Creating 20211203_go_service_1    ... done
Attaching to 20211203_flask_service_1, 20211203_go_service_1

验证:

$ curl http://10.192.244.21:9500
Hey, we have Flask in a Docker container!

你可以看到我们访问了 9500 端口,该端口将请求路由到 golang 容器,然后 golang 容器将通过 API 调用 flask 服务容器,并最终获得由 flask 生成的内容 Hey, we have Flask in a Docker container!

英文:

Usually when you have multi service, the best practice is not to deploy them in one container, you are suggested to deploy them in multi containers.

You may use docker-compose to help you:

> Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.

For your scenario, give you a minimal example as next.

Folder structure:

.
├── docker-compose.yaml
├── flask
│   ├── app.py
│   └── Dockerfile
└── go
    ├── app.go
    └── Dockerfile

docker-compose.yaml:

version: '3'
services:
  flask_service:
    build: flask

  go_service:
    build: go
    ports:
    - "9500:9500"
    depends_on:
    - flask_service

go/app.go:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
        url := "http://flask_service:9600"
        ret, err := http.Get(url)
        if err != nil {
                panic(err)
        }
        defer ret.Body.Close()

        body, err := ioutil.ReadAll(ret.Body)
        if err != nil {
                panic(err)
        }
        fmt.Fprintf(w, string(body))
}

func main() {
        http.HandleFunc("/", handler)
        http.ListenAndServe(":9500", nil)
}

go/Dockerfile:

FROM golang:latest as build

WORKDIR /go/app
COPY ./app.go .
RUN go mod init app; go mod tidy; go build

CMD ["/go/app/app"]

flask/app.py:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hey, we have Flask in a Docker container!'

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=9600)

flask/Dockerfile:

FROM python:alpine3.7

WORKDIR /app

RUN pip install flask

COPY . /app

ENTRYPOINT [ "python" ]
CMD [ "app.py" ]

Execution:

$ docker-compose up
Creating network "20211203_default" with the default driver
Creating 20211203_flask_service_1 ... done
Creating 20211203_go_service_1    ... done
Attaching to 20211203_flask_service_1, 20211203_go_service_1

Verify:

$ curl http://10.192.244.21:9500
Hey, we have Flask in a Docker container!

You could see we visit 9500 port which will route the request to golang container, and the golang container will then call flask service container with api, and finally get the content Hey, we have Flask in a Docker container! which produced by flask.

huangapple
  • 本文由 发表于 2021年11月25日 09:34:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/70104869.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定