Почему Go и Kubernetes — это как арахисовое масло и джем

Если вы жили в пещере (или просто были очень заняты написанием кода), возможно, вы не знаете, что Go и Kubernetes практически созданы друг для друга. Быстрая компиляция Go, небольшой размер бинарных файлов и модель параллелизма на основе горутин делают его идеальным для микросервисов. Kubernetes, с другой стороны, является дирижёром вашего оркестра контейнеризированных приложений. Вместе они непобедимы. Но вот в чём дело: развёртывание приложения Go в Kubernetes — это не какое-то мистическое тёмное искусство, доступное только DevOps-волшебникам. На самом деле это довольно просто, если знать шаги. И именно это мы сегодня и рассмотрим.

Понимание предстоящего пути

Прежде чем углубиться в технические детали, позвольте мне обрисовать вам картину того, чего мы собираемся достичь. Мы возьмём простое приложение на Go, упакуем его в Docker, запустим в кластере Kubernetes и увидим, как оно масштабируется как по волшебству. Звучит хорошо? Отлично, приступим. Вот рабочий процесс, которому мы будем следовать:

graph LR A["Go Application"] -->|Docker| B["Container Image"] B -->|Docker Hub| C["Registry"] C -->|Pull| D["Kubernetes Cluster"] D -->|Deployment| E["Running Pods"] E -->|Service| F["Load Balanced Access"] F --> G["Your Users"]

Просто, элегантно и очень эффективно.

Предварительные условия: подготовка инструментария

Прежде чем начать работать молотками, давайте убедимся, что у вас есть нужные инструменты: Docker: вам нужно установить Docker, чтобы контейнеризировать ваше приложение на Go. Перейдите на docker.com и скачайте подходящую версию для вашей ОС. Kubectl: это интерфейс командной строки для Kubernetes. Думайте о нём как о пульте дистанционного управления для кластера Kubernetes. Minikube или Docker Desktop: для локальной разработки Minikube предоставляет лёгкий кластер Kubernetes. Docker Desktop также включает Kubernetes, если вы включите его в настройках. Аккаунт на Docker Hub: вам нужно место для хранения образов ваших контейнеров. Docker Hub бесплатен и идеально подходит для этого. Go SDK: очевидно. Если у вас ещё не установлен Go, скачайте его с golang.org.

Шаг 1: Создание вашего приложения на Go

Давайте начнём с простого приложения на Go, с которым мы сможем работать. Ничего лишнего — просто что-то, что докажет, что наше развёртывание действительно работает.

package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
hostname, _ := os.Hostname()
fmt.Fprintf(w, "Hello from Go! Pod: %s\n", hostname)
})
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Healthy and ready to go!\n")
})
log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}

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

Шаг 2: Контейнеризация вашего приложения на Go

Теперь самое интересное — мы собираемся контейнеризировать этого зверя. Создайте Dockerfile в корне вашего проекта:

# syntax=docker/dockerfile:1
FROM golang:1.19-alpine
WORKDIR /app
COPY go.mod ./
COPY go.sum ./
RUN go mod download
COPY *.go ./
RUN go build -o /main
EXPOSE 8080
CMD [ "/main" ]

Давайте разберём, что здесь происходит:

  • Мы начинаем с официального образа Go, построенного на Alpine Linux (потому что Alpine маленький, а мы любим маленькие вещи в контейнерах)
  • Устанавливаем рабочую директорию на /app
  • Копируем файлы модуля Go и загружаем зависимости
  • Копируем исходный код и собираем наше приложение
  • Открываем порт 8080 (это сообщает Kubernetes, какой порт ожидать)
  • Указываем команду для запуска при старте контейнера Теперь давайте соберём этот образ:
docker build -t <your-docker-username>/my-go-app:latest .

Замените <your-docker-username> на ваше фактическое имя пользователя на Docker Hub. Это важно, потому что когда Kubernetes будет извлекать образ, ему нужно знать, где его найти. Проверьте ваш образ локально, чтобы убедиться, что он работает:

docker run -it -p 8080:8080 <your-docker-username>/my-go-app:latest

Перейдите по адресу http://localhost:8080 в своём браузере, и вы должны увидеть ваше приветствие. Поздравляю, ваш образ Docker работает!

Шаг 3: Отправка в Docker Hub

Теперь нам нужно сделать этот образ доступным для нашего кластера Kubernetes. Сначала войдите в Docker Hub:

docker login

Затем отправьте ваш образ:

docker push <your-docker-username>/my-go-app:latest

Это может занять минуту или две в зависимости от вашей скорости интернета. Как только это будет сделано, ваш образ будет доступен для всего мира (или по крайней мере для вашего кластера Kubernetes).

Шаг 4: Настройка локального кластера Kubernetes

Здесь начинается магия. Мы собираемся создать локальный кластер Kubernetes с помощью Minikube. Если вы ещё не установили его, скачайте его с minikube. Запустите ваш кластер:

minikube start

Эта команда создаёт лёгкий кластер Kubernetes, который работает в виртуальной машине на вашем компьютере. Он идеально подходит для разработки и тестирования. Если вы предпочитаете использовать Docker Desktop, просто убедитесь, что Kubernetes включён в настройках. Проверьте, всё ли работает:

kubectl cluster-info

Вы должны увидеть информацию о своём кластере. Если вы получаете ошибку, убедитесь, что Minikube запущен.

Шаг 5: Создание манифестов Kubernetes

Теперь мы переходим к настоящему Kubernetes. Нам нужно описать, как мы хотим, чтобы наше приложение работало в кластере. Создайте файл с именем deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
name: my-go-app
spec:
replicas: 3
selector:
matchLabels:
app: my-go-app
template:
metadata:
labels:
app: my-go-app
spec:
containers:
- name: go-container
image: <your-docker-username>/my-go-app:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5

Этот манифест сообщает Kubernetes:

  • Создать Deployment (который управляет вашими подами)
  • Запустить 3 реплики вашего приложения (для высокой доступности)
  • Использовать ваш образ Docker из Docker Hub
  • Открыть порт 8080
  • Проверять конечную точку /health, чтобы убедиться, что под действительно жив и готов Теперь создайте манифест сервиса (service.yaml):
apiVersion: v1
kind: Service
metadata:
name: my-go-app-service
spec:
selector:
app: my-go-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer

Сервис — это то, как ваше приложение общается с внешним миром. Думайте о нём как о балансировщике нагрузки, который распределяет трафик по всем вашим подам.

Шаг 6: Развёртывание в Kubernetes

Вот и момент истины. Примените ваши манифесты к кластеру:

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

Проверьте, что ваше развёртывание работает:

kubectl get pods

Вы должны увидеть три работающих пода. Если они всё ещё создаются, подождите немного и попробуйте снова. Чтобы получить доступ к вашему приложению, получите конечную точку сервиса:

kubectl get service my-go-app-service

С Minikube вам может потребоваться запустить:

minikube service my-go-app-service

Это откроет ваше приложение в браузере. Вы должны увидеть приветствие от вашего приложения на Go!

Шаг 7: Масштабирование как босс

Одна из самых крутых особенностей Kubernetes — это то, как легко можно масштабировать. Хотите больше реплик? Просто обновите ваше развёртывание:

kubectl scale deployment my-go-app --replicas=5