Сегодня тренировался паковать своё игровое приложение (API часть) в докер-контейнер. Отправной точкой для изучения вопроса стала статья в блоге golang.org Deploying Go servers with Docker.

Покажу, как это работает у меня.

Сразу важный момент. В Го, даже если вы не используете удалённый репозиторий для хранения кода, рекомендуется размещать свой рабочий каталог так, как будто вы его используете. Это просто хорошая привычка, которая поможет избежать ряда проблем. Т.е. предлагается сразу размещать код в папке $GOPATH/src/github.com/user/projectName.

Я вёл свой домашний проект в папке $GOPATH/src/projectName и все вложенные пакеты были локальными с импортами вида import "projectName/packageName. При сборке контейнера получал ошибку local import in non-local package.

Для исправления пришлось забрать код с гитхаба командой go get, поменять импорты на import "github.com/user/projectName/packageName и сделать каталог src/github.com/user/projectName рабочим. Дальше всё пошло нормально.

Пример Dockerfile

Сборка образа для докера производится командой docker build -t appname .. Точка в конце команды предполагает запуск в вашей рабочей директории. В этой же директории должен лежать и файл Dockerfile.

Код моего Dockerfile выглядит так:

# Указываем из какого базового образа собираем наш.
# В данном случае будет выполнена сборка на основе debian-образа с Go последней версии.
# Go-код в полученном образе будет размещаться в папку /go (от корня).
FROM golang

# Моё приложение использует ряд переменных окружения, указываем их:
ENV API_BOLTDB_PATH='/data/bolt.db'
ENV API_JWT_SECRET='superSecretCode'
ENV API_HOSTNAME=':8080'

# Рабочий каталог, в него будет скопирован локальный код командой ADD и в нём же будут запущены все команды RUN
WORKDIR /go/src/github.com/zaffka/newwords

# Копируем локальный код в WORKDIR
ADD . .

# Запускаем необходимые для работы моего приложения команды
# Создаём каталог для хранения файла базы данных BoltDB
RUN mkdir /data

# Поскольку файл у меня будет лежать отдельно от остального кода, я на всякий случай выставил всем права на чтение-запись-запуск для папки /data
# возможно это и лишнее
RUN chmod -R 777 /data

# Скачиваем все зависимости, прописанные в нашем коде в секциях import
RUN go get -d -v

# Устанавливаем бинарный файл appname в /go/bin
RUN go install -v

# При запуске контейнера будет сразу же вызываться наш бинарник
ENTRYPOINT /go/bin/appname

# Открываем наружу порт, на котором приложение будет слушать запросы
EXPOSE 8080

Сборка образа и запуск контейнера

Вызываем docker build -t appname ..

Получаем что-то похожее Docker сборка Golang контейнера

Дальше запускаем наш контейнер docker run -d -p 8080:8080 dockerimagename.

Ключ -d означает, что запуск будет произведён в фоне, -p - проброс порта из контейнера в хост-машину.

Моё Go-приложение после этих шагов завелось и заработало без проблем на порту 8080. Но в этой картинке есть ложка дёгтя. Размер полученного образа получается больше 860 мегабайт, т.к. по сути содержит полноценную дебиан-систему внутри.

Разбираться, как уменьшить образ и разместить его, скажем, за nginx буду дальше по ходу обучения. Надеюсь, кому-то этой заметкой помог :)