запустить флягу и сервер golang в докере

avatar
Julia.T
8 августа 2021 в 16:44
288
2
0

Я пытаюсь запустить веб-сервер go и сервер flask в одном контейнере Docker. У меня есть 1 файл Docker для создания фляжного приложения. Как я могу обновить Dockerfile, чтобы создать контейнер для запуска Python и Golang.

Папка проекта

  • pyfolder /app.py, Dockerfile
  • main.go

main.go

package main

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

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("func called")
}

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

app.py

from flask import Flask
import os

app = Flask(__name__)

@app.route("/")
def hello():
    return "Flask inside Docker!!"


if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True,host='0.0.0.0',port=port)

Файл Docker

FROM python:3.6

COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
ENTRYPOINT ["python"]
CMD ["app.py"]
Источник
The Fool
8 августа 2021 в 16:51
2

Вам нужно установить golang в образ python или python в образ golang. Тем не менее, это большой антипаттерн. Рассмотрите возможность запуска каждого из них в своем собственном контейнере.

Ответы (2)

avatar
David Maze
8 августа 2021 в 20:13
3

Поскольку у вас есть две отдельные программы, вы обычно запускаете их в двух контейнерах с двумя отдельными образами. В обоих случаях вы можете использовать базовый файл Dockerfile для соответствующих языков:

.
# pyfolder/Dockerfile
FROM python:3.6
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt .
COPY . .
EXPOSE 5000
CMD ["./app.py"]
# ./Dockerfile
FROM golang:1.16-alpine AS build
COPY go.mod go.sum .
RUN go mod download
COPY main.go .
RUN go build -o main main.go

FROM alpine
COPY --from=build /go/main /usr/bin/main
EXPOSE 8080
CMD ["main"]

Вы вообще не обсуждаете, почему у вас есть два контейнера или как они взаимодействуют. Вы часто захотите, чтобы контейнеры вообще не имели локального состояния, если они могут им управлять, и обменивались данными только через сетевые интерфейсы, такие как HTTP. Это означает, что вам понадобится какой-то способ настроить сетевой адрес, который одна служба использует для вызова другой, поскольку работа в локальной среде разработки будет отличаться от работы в контейнерах (по сравнению с развертыванием в облаке и работой в Kubernetes). vs....) Переменная окружения была бы типичным подходом; скажем, код Go должен вызывать код Python:

url := os.Getenv("PYAPP_URL")
if url == "" {
        url = "http://localhost:8080"
}
resp, err := http.Get(url)

Обычным инструментом для одновременного запуска нескольких контейнеров является Docker Compose. Это не единственный инструмент, но он является стандартной частью экосистемы Docker и проще, чем многие альтернативы. Вы должны написать файл YAML с описанием двух контейнеров:

.
version: '3.8'
services:
  pyapp:
    build: ./pyfolder
  server:
    build: . # (the directory containing the Go code and its Dockerfile)
    environment:
      - PYAPP_URL=http://pyapp:5000
    ports:
      - '8080:8080'
    depends_on:
      - pyapp

Запуск docker-compose up --build создаст два образа и запустит два контейнера.

Charlie Gildawie
9 августа 2021 в 18:13
0

++, где работает контейнер, часто упускается из виду при принятии решения о том, как создавать ваши образы. Допустим, вы используете k8s, вы можете использовать этот подход и объединить оба контейнера в один и тот же pod -- таким образом, оба контейнера будут доступны друг другу на локальном хосте. вы бы определили сопоставление портов для модуля, которое предоставляет один (или оба из них) на разных портах другим модулям, работающим в k8s.

David Maze
9 августа 2021 в 18:41
0

В Kubernetes вы обычно запускаете эти два контейнера в отдельных развертываниях с отдельной службой для каждого, и они могут использовать имена служб в качестве имен хостов; два контейнера в одном поде обычно не являются лучшей практикой.

Charlie Gildawie
10 августа 2021 в 17:23
0

совершенно мог != должен.

avatar
mep
8 августа 2021 в 17:22
-1

Вы сможете выполнить это, используя многоэтапную сборку в файле Docker.

Сначала переместите Dockerfile в корневой каталог рядом с main.go.

Затем измените файл Docker на

.
# grab the golang image
FROM golang:1.16
WORKDIR .
RUN go build -o app .

# python portion
FROM python:3.6
WORKDIR /app
# copy the go binary from stage 0
COPY --from=0 app ./
# start the go binary
CMD ["sh", "app"]
# start python
RUN pip install -r requirements.txt
ENTRYPOINT ["python"]
CMD ["app.py"]

Я действительно думаю, что Дурак прав, предлагая разделить их на два разных контейнера. Я бы посмотрел на docker-compose вместо использования многоэтапной сборки для этого использования.

Справочник по многоэтапной сборке Docker

The Fool
8 августа 2021 в 17:42
0

Если вы собираете go in muti staging, вы должны статически связать свои зависимости. Особенно для веб-сервера это, вероятно, требуется. Что-то вроде этого флага сборки -ldflags '-linkmode external -w -extldflags "-static"'.

David Maze
8 августа 2021 в 18:00
1

У вас не может быть двух CMD на одном изображении (или, точнее, только последний имеет эффект). ENTRYPOINT ["python"] не очень удачный паттерн и делает его излишне неудобным для docker run your-image ./app для запуска бинарного файла Go.

mh-cbon
8 августа 2021 в 20:51
0

@TheFool, можете ли вы поделиться ссылкой с более глубокими объяснениями и примерами? Для моего собственного понимания.

The Fool
9 августа 2021 в 06:27
1

@ mh-cbon Я не знаю конкретного руководства для этого. Но я знаю по опыту, что мне нужно делать это большую часть времени, когда сборка идет в одном образе и запускает его в другом. Некоторые зависимости, особенно сетевой стек, используются динамически, это означает, что go предполагает, что они находятся в системе, в которой вы запускаете свой двоичный файл. Если их нет в системе, у вас проблемы. Насколько я понимаю, статическое связывание гарантирует, что эти зависимости будут скомпилированы в сам двоичный файл. Возможно это: coderhelper.com/questions/62817082/…

The Fool
9 августа 2021 в 06:34
0

Это не обязательно. Я могу представить, что образ python поставляется с необходимыми зависимостями, поскольку python написан на c. Но может случиться так, что вы столкнетесь с проблемой. Много раз при использовании alpine в качестве конечного изображения.

The Fool
9 августа 2021 в 06:41
0

Здесь кто-то делает это со скретч-образом gist.github.com/PurpleBooth/ec81bad0a7b56ac767e0da09840f835a Здесь кто-то написал об этом статью weastur.medium.com/go-and-static-linking-472936

mh-cbon
9 августа 2021 в 08:37
0

да, теперь я понимаю. Я согласен. I need to do this most of the time when building go in one image and run it in another one