Александр Гольцман
Работа с Docker-контейнерами в Go
Docker — это инструмент контейнеризации, который позволяет упаковывать приложения и их зависимости в изолированные среды. В отличие от виртуальных машин, контейнеры используют ядро операционной системы, что делает их легче и быстрее.
Go — один из языков, который отлично сочетается с Docker. Компилируемые бинарные файлы, отсутствие необходимости в интерпретаторе и небольшой размер исполняемых файлов делают Go-приложения удобными для контейнеризации. В этой статье я покажу, как подготовить Go-приложение к запуску в контейнере, создавать оптимизированные Docker-образы и управлять контейнерами.
Почему контейнеризация важна?
Использование контейнеров дает несколько ключевых преимуществ:
- Изоляция — приложение работает в одном окружении независимо от операционной системы и установленных зависимостей.
- Портативность — контейнер можно запустить на любом сервере с Docker без дополнительных настроек.
- Масштабируемость — контейнеры легко управляются с помощью Kubernetes и других оркестраторов.
Теперь давайте посмотрим, как контейнеризировать Go-приложение.
Структура проекта
Прежде чем переходить к Docker, организуем структуру проекта. Пусть у нас есть простое HTTP-приложение:
/my-go-app
├── main.go
├── go.mod
├── go.sum
├── Dockerfile
Файл main.go
:
package main
import (
"fmt"
"net/http"
"os"
)
func handler(w http.ResponseWriter, r *http.Request) {
env := os.Getenv("APP_ENV")
fmt.Fprintf(w, "Приложение работает! Среда: %s", env)
}
func main() {
http.HandleFunc("/", handler)
port := "8080"
fmt.Println("Сервер запущен на порту", port)
http.ListenAndServe(":"+port, nil)
}
Теперь подготовим Dockerfile
для контейнеризации.
Создание Dockerfile
Файл Dockerfile
описывает процесс сборки контейнера. В нем указываются базовый образ, команды для установки зависимостей и инструкция для запуска приложения.
Вот базовый Dockerfile
для Go-приложения:
# Используем официальный образ Go
FROM golang:1.20 AS builder
# Устанавливаем рабочую директорию
WORKDIR /app
# Копируем файлы проекта
COPY . .
# Загружаем зависимости и собираем бинарник
RUN go mod tidy && go build -o app
# Используем минималистичный образ для финального контейнера
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/app .
# Задаем переменную окружения
ENV APP_ENV=production
# Запускаем приложение
CMD ["./app"]
Здесь используется многоэтапная сборка (multi-stage build):
- В первом этапе приложение компилируется в контейнере на основе
golang:1.20
. - Затем готовый бинарный файл копируется в легковесный образ
alpine
, что уменьшает размер контейнера.
Сборка и запуск контейнера
Теперь создадим Docker-образ и запустим контейнер.
Сборка образа
docker build -t my-go-app .
Флаг -t
задает имя образа (my-go-app
).
Запуск контейнера
docker run --rm -p 8080:8080 my-go-app
Флаг -p 8080:8080
пробрасывает порт, чтобы приложение было доступно локально.
Проверка работы контейнера
После запуска можно проверить работу сервиса:
curl http://localhost:8080
Оптимизация размера образа
Если приложение не использует динамические библиотеки, его можно упаковать в нулевой образ (scratch
), который не содержит ничего, кроме бинарного файла:
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go mod tidy && go build -o app
FROM scratch
COPY --from=builder /app/app .
CMD ["/app"]
Такой контейнер будет еще меньше, но в нем нет оболочки и утилит ОС, поэтому он подходит не для всех приложений.
Передача переменных окружения
Переменные окружения позволяют управлять конфигурацией без изменения кода.
В Dockerfile
можно задать их так:
ENV APP_ENV=production
При запуске контейнера можно передать переменные через флаг -e
:
docker run -e APP_ENV=development my-go-app
В Go их можно прочитать с помощью os.Getenv
:
env := os.Getenv("APP_ENV")
fmt.Println("Среда выполнения:", env)
Использование Docker Compose
Если приложение зависит от базы данных или других сервисов, удобнее использовать docker-compose.yaml
.
Пример для приложения с PostgreSQL:
version: '3'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- APP_ENV=production
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
ports:
- "5432:5432"
Запуск всех сервисов:
docker-compose up -d
Флаг -d
запустит контейнеры в фоновом режиме.
Удаление контейнеров и образов
Чтобы очистить систему от ненужных контейнеров и образов, используйте:
docker stop my-go-app
docker rm my-go-app
docker rmi my-go-app
Можно также удалить все неиспользуемые ресурсы:
docker system prune -a
Заключение
В этой статье я показал, как запустить Go-приложение в Docker-контейнере, оптимизировать его размер и работать с переменными окружения. Мы разобрали:
- Почему Go и Docker хорошо сочетаются.
- Как написать
Dockerfile
и создать контейнер. - Как минимизировать размер образа с
scratch
. - Как передавать переменные окружения.
- Как управлять зависимостями через
docker-compose
.
Использование Docker упрощает развертывание Go-приложений, делая их переносимыми и масштабируемыми.
Карта развития разработчика
Получите полную карту развития разработчика по всем направлениям: frontend, backend, devops, mobile