Docker для разработки Go с горячей перезагрузкой


Создание модуля Go

В Go 1.13 были введены модули. Это означает, что больше не нужно размещать все проекты в одно рабочее пространство Go.

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

Затем инициализируем репозиторий Git и создаем модуль Go.

git init git remote add origin [email protected]:Dirk94/go-docker.git go mod init github.com/dirk94/go-docker

В директории находится файл go.mod, который содержит все зависимости этого модуля, аналогично файлу package.json в разработке Node.

Создание API

Модуль установлен, пришло время для создания API.

Мы будем использовать пакет маршрутизации thegorilla/mux для API.

go get -u github.com/gorilla/mux

После выполнения команда добавится в качестве зависимости в файл go.mod.

Затем создаем основной файл Go commands/runserver.go.

package main import ( "fmt" "github.com/gorilla/mux" "net/http" ) func main() { r := mux.NewRouter() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome to this life-changing API.") }) fmt.Println("Server listening!") http.ListenAndServe(":80", r) }

Все, что делает API — это возвращает сообщение “Welcome to this life-changing API”.

Проверим, работает ли программа перед тем, как перейти к контейнерам Docker. Для запуска сервера используем команду go run.

go run commands/runserver.goServer listening!

API работает! ????

Установка Docker

Начнем с создания образа Docker для этого проекта, который содержит набор инструкций, сообщающих Docker, какую среду нужно создать.

FROM golang:latest WORKDIR /app COPY ./ /app RUN go mod download ENTRYPOINT go run commands/runserver.go

Используем образ golang:latest в качестве основы для этого нового пользовательского образа.

Копируем весь проект в директорию образа /app, а затем загружаем зависимости с помощью go mod download.

И, наконец, сообщаем Docker о запуске команды go run commands/runserver.go.

Для создания этого образа запускаем следующую команду:

docker build -t go-docker-image .

Теперь у нас есть инструкции по созданию образа Docker, которые необходимо запустить.

docker run go-docker-imageServer listening!

Сервер выполняет прослушивание в контейнере Docker, однако при переходе на localhost в браузере появляется сообщение об ошибке “Refused to connect”.

Происходит следующее: контейнер Docker прослушивает порт 80 на предмет входящих запросов, а операционная система хоста — нет. Таким образом, при отправке запроса GET на localhost он не находит работающий сервер.

Ниже представлена диаграмма с описанием проблемы:

Чтобы это исправить, нужно сопоставить порт 80 контейнеров с портом 80 хоста.

docker run -p 80:80 go-docker-image

Диаграмма теперь будет выглядеть следующим образом:

Теперь при переходе на localhost появляется сообщение “Welcome to this life-changing API”!

Изменение исходного кода

Нам необходимо внести некоторые изменения в API.

package main import ( "fmt" "github.com/gorilla/mux" "net/http" ) func main() { r := mux.NewRouter() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome to this life-changing API.\nIts the best API, its true, all other API's are fake.") }) fmt.Println("Server listening!") http.ListenAndServe(":80", r) }

Добавляем новую строку в API. Попробуем запустить новый контейнер Docker.

docker run -p 80:80 go-docker-image

Но при переходе на localhost мы видим то же самое сообщение.

Причина заключается в том, что образ Docker не изменился. Чтобы изменения вступили в силу, нам нужно перестроить образ.

docker build -t go-docker-image .docker run -p 80:80 go-docker-image

Теперь появляется обновленное сообщение:

Установка горячей перезагрузки

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

Мы будем использовать пакет Compile Daemon, который автоматически перестроит и перезапустит приложение Go при изменении любого из исходных файлов Go.

FROM golang:latest WORKDIR /app COPY ./ /app RUN go mod download RUN go get github.com/githubnemo/CompileDaemon ENTRYPOINT CompileDaemon --build="go build commands/runserver.go" --command=./runserver

Обновляем Dockerfile, чтобы загрузить пакет CompileDaemon.

Затем изменяем точку входа, чтобы запустить программу CompileDaemon. Указываем команду сборки и запуска программы, которые выполняются при каждом изменении файла Go.

Образ перестраивается при запуске:

docker build -t go-docker-image .

При запуске Docker добавляем флаг -v ~/projects/go-docker:/app. Он устанавливает директорию хоста go-docker в директорию /app контейнера Docker.

При каждом изменении в директории go-docker файлы в директории контейнера /app также изменяются.

Последняя команда представлена ниже. Обратите внимание, что путь -v не может быть относительным.

docker run -v ~/projects/go-docker:/app -p 80:80 go-docker-image

Во время запуска контейнера внесите изменения в исходный код, и вы увидите, что он автоматически обновляется. ????????

Использование Docker compose

Сейчас нам приходится писать очень длинную команду docker run -v ~/projects/go-docker:/app -p 80:80 go-docker-image для запуска контейнера.

Эта задача выполнима в подобном проекте, поскольку он содержит только один контейнер. Но предположим, что в проекте есть несколько контейнеров, которые нужно запустить. Выполнение всех команд docker run отнимет очень много сил.

Решение — Docker Compose. С помощью этого инструмента можно указать, какие контейнеры нужно запускать при запуске команды docker-compose.

Для установки создаем файл docker-compose.yml.

version: "3" services: go-docker-image: build: ./ ports: - '80:80' volumes: - ./:/app

Здесь указываем, что нужно создать образ go-docker-image. Образ должен быть собран с использованием Dockerfile в директории ./.

Сопоставляем порты и устанавливаем громкость — на этот раз можно использовать относительный путь.

Для запуска контейнеров, указанных в файле docker-compose.yml, запускаем docker-compose up.

Вот и все! Мы создали рабочий API в Docker, который автоматически перезагружается при изменении файлов! ????

Исходный код можно просмотреть здесь — https://github.com/dirk94/go-docker


Перевод статьи Dirk Hoekstra: Docker for Go Development with Hot Reload


Поделиться статьей:


Вернуться к статьям

Комментарии

    Ничего не найдено.