Восстановление приложения golang в докере после изменения файла

Я создаю серверную часть golang с помощью gin и хочу настроить ее как службу в докере. Я хочу, чтобы при внесении изменений в код приложение перестраивалось с учетом этих изменений. Я пробовал использовать 2 пакета golang: github.com/cespare/reflex и github.com/cortesi/modd.

Для пакета cespare/reflex я обнаружил нерешенную проблему на GitHub: если вы используете плавное завершение работы для gin, который я использую, приложение не получает SIGTERM/SIGINT от рефлекса. Поэтому я перешел ко второму пакету. См. ниже:

Мой Dockerfile для бэкэнда golang:

FROM golang:1.22.5-alpine3.20 AS builder

WORKDIR /go/src/app

ENV GO111MODULE=on

RUN go install github.com/cortesi/modd/cmd/modd@latest

COPY go.mod .
COPY go.sum .

RUN go mod download

COPY . .

RUN go build -o ./run .

FROM alpine:3.20
RUN apk --no-cache add ca-certificates
WORKDIR /root/

COPY --from=builder /go/src/app/run .

EXPOSE 8080
CMD ["./run"]

Мой файл docker-compose.yaml частично:

services:
  goapp:
    build:
      context: ./src
      target: builder
    image: goapp
    [...]
    volumes:
      - ./src:/go/src/app
    command: modd -f .docker/modd.conf

Мой файл modd.conf:

**/*.go {
    prep: echo "file changed"
    prep: go build -o ./run .
    daemon +sigterm: ./run
}

Я также пытался добавить prep: pkill -f run || true в начало modd.conf, но он просто убивает контейнер.

При указанной выше конфигурации modd не обнаруживает никаких изменений, внесенных в код.

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

Контейнеры Docker обычно имеют изолированную файловую систему и не видят файлы на хосте; Можете ли вы использовать здесь простую цепочку инструментов Go без Docker? Go — компилируемый язык, и вам в любом случае придется пересобирать двоичный файл; достаточно ли docker-compose build; docker-compose up -d перестроить образ и контейнер?

David Maze 28.07.2024 21:57

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

iLaurian 28.07.2024 22:21

Помните, что контейнер сборки не будет доступен во время выполнения; вам понадобится набор инструментов go, установленный в окончательном образе, если вы хотите запустить go build. Один из этих инструментов может оказаться полезным.

Brits 29.07.2024 01:25

Есть ли особая причина не использовать docker Compose Watch?

Markus W Mahlberg 29.07.2024 07:28
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Kubernetes - это портативная, расширяемая платформа с открытым исходным кодом для управления контейнерными рабочими нагрузками и сервисами, которая...
Как создать PHP Image с нуля
Как создать PHP Image с нуля
Сегодня мы создадим PHP Image from Scratch для того, чтобы легко развернуть базовые PHP-приложения. Пожалуйста, имейте в виду, что это разработка для...
2
4
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Больше нет необходимости в сторонних приложениях. Начиная с версии docker compose 2.22.0 , вы можете просто использовать docker compose --watch.

По сути, вы даете команду докеру следить за различными файлами и папками и указываете ему, какие действия следует предпринять, если один из этих файлов или папок изменится.

Проект

Представьте себе простую настройку приложения следующим образом:

.
├── Dockerfile
├── app
│   ├── go.mod
│   └── main.go
├── docker-compose.yaml
└── resources
    └── sample.html

main.go

Мы пишем очень упрощенный веб-сервер:

package main

import (
    "flag"
    "log/slog"
    "net/http"
)

var bindAddress = flag.String("bind", ":8080", "HTTP server bind address")
var dir = flag.String("dir", "./", "Directory to serve")


// Do not use this code in production. There are security implications which are not mitigated for the sake of brevity. You have been warned!
func main() {
    flag.Parse()
    slog.Info("Starting server", "addr", *bindAddress, "dir", *dir)

    http.Handle("GET /files/", http.StripPrefix("/files/", http.FileServer(http.Dir(*dir))))
    err := http.ListenAndServe(*bindAddress, nil)
    if err != nil && err != http.ErrServerClosed {
        slog.Error("Failed to start server", "err", err)
    }
}

Примечание. НЕ используйте приведенный выше код в производстве. Существуют последствия для безопасности, которые не смягчаются ради краткости. Вы были предупреждены!

Важными частями являются docker-compose.yaml и Dockerfile.

Докерфайл

Сначала Dockerfile, чтобы мы поняли, что произойдет:

FROM golang:1.22-alpine3.20 AS builder
WORKDIR /app
ADD app/ .
RUN go build -o mycoolapp .

FROM alpine:3.20
COPY --from=builder /app/mycoolapp /usr/local/bin/mycoolapp
COPY resources/sample.html /usr/local/share/mycoolapp/sample.html
ENTRYPOINT [ "/usr/local/bin/mycoolapp" ]
CMD [ "-dir","/usr/local/share/mycoolapp/" ]

Итак, по сути, наш простой веб-сервер построен и будет считывать контент, который он обслуживает /usr/local/share/mycoolapp/, в сервисном контейнере.

docker-compose.yaml

services:
  my-service:
    image: my-service:latest
    build:
      context: .
      dockerfile: Dockerfile
    develop:
      watch:
        - action: sync
          path: resources/
          target: /usr/local/share/mycoolapp/
        - action: rebuild
          path: app/
    ports:
      - "8080:8080"
    environment:
      - MY_ENV_VAR=foo

Так что же происходит, когда мы «запускаем» этот файл компоновки (docker compose up --watch)?

  1. Если my-service:latest не существует на вашем компьютере, он встроен.
  2. Если файл изменен, добавлен или удален в resources, это будет отражено в Docker, синхронизирующем эти изменения с каталогом /usr/local/share/mycoolapp/ в сервисном контейнере, который является каталогом по умолчанию, из которого веб-сервер в нашем контейнере настроен для обслуживания файлов. Однако файлы не добавляются в образ.
  3. Если файл изменен, добавлен или удален в app, запускается полная перестройка, как если бы был вызван docker compose build.

Другие вопросы по теме