логотип PurpleSchool
логотип PurpleSchool

Создание Go-приложений и Kubernetes

Автор

Олег Марков

Введение

Современная разработка программного обеспечения все чаще использует контейнеризированные приложения и масштабируемые оркестрационные решения. Go остается одним из самых популярных языков для написания микросервисов и сервисных приложений благодаря скорости, компактности бинарных файлов и простоте параллельных вычислений. Kubernetes, в свою очередь, стал стандартом де-факто для управления развертыванием и масштабированием таких приложений.

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

Разработка Go-приложения для Kubernetes

Базовая структура Go-приложения

При разработке сервиса для работы в Kubernetes важно помнить о следующих особенностях:

  • Приложение должно быть самодостаточным (stateless), если только не требуется хранить состояние;
  • Логи рекомендуется выводить в стандартный поток вывода (stdout), чтобы их мог собирать Kubernetes;
  • Важно предусмотреть реакцию на сигналы завершения, чтобы ваше приложение корректно завершалось по требованию Kubernetes.

Давайте создадим базовый HTTP сервер на Go:

package main

import (
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, Kubernetes!"))
    })

    srv := &http.Server{
        Addr:    ":8080",
        Handler: mux,
    }

    // Канал для перехвата сигнала завершения работы (например, kill, SIGTERM)
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, syscall.SIGTERM, syscall.SIGINT)

    go func() {
        log.Println("Starting server on :8080")
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("ListenAndServe error: %v", err)
        }
    }()

    <-stop // Ждём сигнала завершения

    log.Println("Server is shutting down...")
    // Здесь можно добавить код для graceful shutdown, если нужно
}

В этом примере сервер выводит приветствие и завершится по сигналу от Kubernetes. Логи пишутся в стандартный вывод, что упрощает мониторинг.

Контейнеризация приложения

Kubernetes работает с контейнерами — чаще всего с Docker. Для деплоймента приложения на Go вам потребуется собрать исполняемый файл и описать способ его упаковки в Docker-образ.

Пример простого Dockerfile для Go-приложения:

# Используем официальный образ Golang для сборки
FROM golang:1.21-alpine AS build

# Добавляем исходники
WORKDIR /app
COPY . .

# Копилируем бинарник для Linux и отключаем CGO
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

# Минимальный образ для запуска
FROM alpine:3.18

# Копируем бинарник из билдер-образа
COPY --from=build /app/main /main

# Запускаем приложение
ENTRYPOINT ["/main"]
  • Первый этап собирает бинарник внутри официального образа Golang.
  • Второй этап создает минимальный контейнер для запуска — используем маленький alpine, что экономит место и уменьшает возможные уязвимости.

Соберите образ командой:

docker build -t my-go-app:latest .

Публикация контейнера в реестр

Чтобы Kubernetes мог скачать ваш образ, поместите его в публичный или приватный docker registry (например, DockerHub, GitHub Container Registry, Google Container Registry и т.д.). Пример для DockerHub:

docker tag my-go-app:latest yourdockerhubusername/my-go-app:latest
docker push yourdockerhubusername/my-go-app:latest

Следите за приватностью: если репозиторий не публичный — настройте Kubernetes на доступ к нему (секреты).

Деплой в Kubernetes

Базовые сущности Kubernetes

Для деплоя приложения потребуется создать несколько объектов:

  • Deployment — управляет ReplicaSet и обновлением подов;
  • Service — проксирует и балансирует трафик к вашим подам;
  • ConfigMap/Secret — передают параметры конфигурации и секреты (по необходимости).

Пример манифеста Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-app
spec:
  replicas: 3 # Количество экземпляров приложения
  selector:
    matchLabels:
      app: go-app
  template:
    metadata:
      labels:
        app: go-app
    spec:
      containers:
      - name: go-app
        image: yourdockerhubusername/my-go-app:latest
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 3
        livenessProbe:
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 10

Здесь:

  • replicas — количество одновременно работающих подов;
  • probes — проверки готовности и живости; они позволяют Kubernetes перезапускать приложение при сбоях или понять, когда оно готово принимать трафик.

Service для доступа к приложению

apiVersion: v1
kind: Service
metadata:
  name: go-app-service
spec:
  selector:
    app: go-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: ClusterIP # можно заменить на NodePort или LoadBalancer, если нужен внешний доступ

Этот сервис позволит другим подам обращаться к вашему приложению по имени go-app-service. Для внешнего доступа меняется type.

Применение манифестов

Сохраните манифесты в yaml-файлы. Применяйте их командой:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

Проверьте статус с помощью:

kubectl get pods
kubectl get deployments
kubectl get svc

Работа с конфигами и секретами

Go-приложения часто используют переменные окружения для настройки. Для их передачи через Kubernetes служат ConfigMap и Secret.

Пример ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: go-app-config
data:
  GREETING: "Hello from ConfigMap!"

Использование переменных в Deployment

...
        env:
        - name: GREETING
          valueFrom:
            configMapKeyRef:
              name: go-app-config
              key: GREETING
...

Внутри приложения можно получить значение обычным способом:

greeting := os.Getenv("GREETING")

Масштабирование приложения

Масштабируйте приложение командой:

kubectl scale deployment go-app --replicas=5

Kubernetes автоматически запустит новых подов до нужного количества.

Журналирование и отладка

Логирование

Kubernetes собирает стандартный вывод контейнеров. Для просмотра логов запущенного пода:

kubectl logs <pod_name>

Для постоянного слежения:

kubectl logs -f <pod_name>

Отладка и доступ к поду

Если нужно попасть внутрь контейнера для отладки:

kubectl exec -it <pod_name> -- /bin/sh

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

Проверка проб и обновлений

Если рестартов много — проверьте readinessProbe и livenessProbe:

  • Проверьте, что ваше приложение возвращает HTTP 200 на нужном порте и URL.
  • Убедитесь, что время и параметры инициализации соответствуют времени старта приложения.

Стратегии обновления

По умолчанию используется rolling update — без "выпадений" трафика:

  • Новые поды запускаются постепенно, старые завершаются после успешного старта новых.
  • Вы можете управлять стратегией обновления через параметры deployment, например, ускорив обновление или сделав его более безопасным для продакшна.

Рекомендации для production

  • Health Checks: Настроить readiness и liveness пробы.
  • Ресурсы: Указать лимиты по CPU и памяти в спецификации контейнера.
  • Строгая политика логирования: Не храните логи в файлах, выводите в stdout/stderr.
  • Graceful shutdown: Обрабатывайте SIGTERM для обеспечения корректного завершения работ сервиса.
  • CI/CD: Автоматизируйте построение образов, проверяйте шаблоны Kubernetes на ошибки, внедряйте тестирование.
  • Безопасность: Используйте секреты, ограничивайте права сервисных аккаунтов, минимизируйте используемые образы.

Итог

Создание и деплой Go-приложений в Kubernetes — это эффективный и масштабируемый способ разработки современных сервисов. Go отлично подходит для микросервисной архитектуры и работает с минимальными накладными расходами, а Kubernetes позволяет легко управлять жизненным циклом и масштабом ваших приложений. Используйте контейнеризацию, манифесты Kubernetes и лучшие практики для обеспечения устойчивой работы и простоты обновления ваших сервисов.

Частозадаваемые технические вопросы по теме и ответы на них

Вопрос 1: Как сделать так, чтобы Go-приложение правильно завершалось при обновлении пода в Kubernetes?

Ответ:
Добавьте обработку сигналов SIGTERM/SIGINT с помощью пакета os/signal. Kubernetes сначала отправляет контейнеру SIGTERM, а через некоторое время SIGKILL. В этот промежуток ваше приложение должно успеть завершить работу, закрыть соединения и освободить ресурсы.

Вопрос 2: Как передать секретные данные (например, пароли или токены) в приложение на Go внутри Kubernetes?

Ответ:
Используйте Kubernetes Secret. Описываете секрет как объект Secret с base64-кодированными значениями, а затем монтируете его как переменные окружения или файлы в под. Доступ в Go-приложении через os.Getenv или чтение файлов из определённой директории.

Вопрос 3: Почему мое приложение перезапускается в Kubernetes с ошибкой "CrashLoopBackOff"?

Ответ:
Проверьте, что приложение не завершает работу сразу после запуска, а остается "живым" — обычно это ожидание HTTP запросов или другой работы. Убедитесь, что корректно настроили probes, нет ошибок в настройках окружения, достаточной памяти и доступности зависимости.

Вопрос 4: Как работать с конфигурационными файлами в Go-приложении внутри контейнера?

Ответ:
Создайте ConfigMap и смонтируйте как volume или используйте переменные окружения. В Go используйте стандартные методы работы с файлами или получите значения через пакет os. Следите за путями — внутри контейнера они соответствуют расшаренной директории.

Вопрос 5: Как добавить внешний доступ к сервису, находящемуся в Kubernetes-кластере?

Ответ:
Измените Service на тип NodePort или LoadBalancer. NodePort делает порт доступным на всех нодах кластера. LoadBalancer подходит для облачных провайдеров — автоматически выделит внешний IP и пробросит порт. Пример:

type: LoadBalancer
ports:
- port: 80
  targetPort: 8080

Следите за настройками безопасности при публикации сервисов вовне.

Стрелочка влевоУстановка и настройка Kafka в Kubernetes

Постройте личный план изучения Kubernetes до уровня Middle — бесплатно!

Kubernetes — часть карты развития DevOps

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Kubernetes

Terraform и Kubernetes инфраструктура как кодНастройка и использование Runners в KubernetesНастройка и деплой PostgreSQL в KubernetesСравнение и интеграция Openshift и KubernetesПримеры интеграции GitHub Actions и KubernetesDeploy приложений в Kubernetes - пошаговое руководство для начинающих и не толькоКак настроить CD в KubernetesИнтеграция Ansible в KubernetesИнтеграция CI/CD с Jenkins и KubernetesИнтеграция Kubernetes с GitLab - Автоматизация CI CD в облачной инфраструктуреГайд по DevOps инструментам в KubernetesОсобенности платформы Deckhouse в Kubernetes
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Kubernetes и Helm

Антон Ларичев
AI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Микросервисы

Антон Ларичев
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий