Docker and Go: Containerizing Golang Applications from Scratch

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Docker и Go: полное руководство по контейнеризации Golang-приложений



Контейнеризация стала стандартом де-факто для развертывания современных приложений. Язык Go (Golang) идеально подходит для контейнерной среды: его скомпилированные бинарные файлы не требуют рантайма, а статическая линковка позволяет создавать минимальные образы Docker. В этой статье мы разберем процесс контейнеризации Go-приложений от написания Dockerfile до оптимизации размера итогового образа.



Почему Go и Docker — идеальная пара



Go компилируется в один статический бинарный файл, который не зависит от системных библиотек. Это означает, что для запуска Go-приложения в контейнере не нужно устанавливать Go Runtime, интерпретаторы или дополнительные зависимости. В результате вы получаете:



  • Минимальный размер образа — часто менее 10-15 МБ
  • Быстрый запуск — миллисекунды, а не секунды
  • Высокую безопасность — меньше компонентов = меньше уязвимостей
  • Простоту деплоя — один бинарный файл вместо множества скриптов и библиотек


Рассмотрим это на примере простого HTTP-сервера на Go.



Шаг 1: Создаем Go-приложение



Для начала напишем простое веб-приложение, которое будем контейнеризировать. Создайте файл main.go:



package main

import ( "fmt" "log" "net/http" "os")

func main() { port := os.Getenv("PORT") if port == "" { port = "8080" }

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Привет из контейнера Go! 🐳") })

log.Printf("Сервер запущен на порту %s", port) log.Fatal(http.ListenAndServe(":"+port, nil))}


Это минимальный HTTP-сервер, который слушает порт, заданный переменной окружения PORT (по умолчанию 8080).



Шаг 2: Многоэтапная сборка (Multi-stage build)



Для создания минимального образа Docker используется многоэтапная сборка. Первый этап — компиляция приложения, второй — создание финального образа только с бинарным файлом. Создайте Dockerfile:



# Этап 1: Сборка приложенияFROM golang:1.22-alpine AS builder

WORKDIR /app

# Копируем go.mod и go.sum для кэширования зависимостейCOPY go.mod go.sum ./RUN go mod download

# Копируем исходный кодCOPY . .

# Собираем статический бинарный файлRUN CGO_ENABLED=0 GOOS=linux go build -o /app/server .

# Этап 2: Финальный минимальный образFROM alpine:3.19

# Добавляем CA-сертификаты для HTTPSRUN apk --no-cache add ca-certificates

WORKDIR /root/

# Копируем бинарник из первого этапаCOPY --from=builder /app/server .

# Открываем портEXPOSE 8080

# Запускаем приложениеCMD ["./server"]


Обратите внимание на ключевые моменты:

  • golang:1.22-alpine — легковесный образ для сборки
  • CGO_ENABLED=0 — отключаем CGO для статической линковки
  • alpine:3.19 — минимальный Linux-образ (~5 МБ)
  • ca-certificates — нужны, если приложение использует HTTPS


Шаг 3: Сборка и запуск контейнера



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



# Сборка образаdocker build -t go-hello:latest .

# Запуск контейнераdocker run -d -p 8080:8080 --name go-app go-hello:latest

# Проверкаcurl http://localhost:8080# Вывод: Привет из контейнера Go! 🐳


Проверьте размер полученного образа:



docker images go-hello# REPOSITORY   TAG       IMAGE ID       CREATED          SIZE# go-hello     latest    abc123def456   10 seconds ago   14.2 MB


Всего 14.2 МБ — это ничтожно мало по сравнению с образами на Node.js (сотни МБ) или Python (десятки МБ).



Шаг 4: Оптимизация Dockerfile для продакшена

Blogs

Book Recommendations