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

Docker

Создание модуля 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.go
Server listening!
Docker для разработки Go с горячей перезагрузкой — IT-МИР. ПОМОЩЬ В IT-МИРЕ 2020

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-image
Server listening!

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

Docker для разработки Go с горячей перезагрузкой — IT-МИР. ПОМОЩЬ В IT-МИРЕ 2020

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

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

Docker для разработки Go с горячей перезагрузкой — IT-МИР. ПОМОЩЬ В IT-МИРЕ 2020

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

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

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

Docker для разработки Go с горячей перезагрузкой — IT-МИР. ПОМОЩЬ В IT-МИРЕ 2020

Теперь при переходе на 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 для разработки Go с горячей перезагрузкой — IT-МИР. ПОМОЩЬ В IT-МИРЕ 2020

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

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

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

Docker для разработки Go с горячей перезагрузкой — IT-МИР. ПОМОЩЬ В IT-МИРЕ 2020

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

Перестройка образа 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

Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming