В продолжение предыдущей статьи контейнеризируем проект Go и создадим прокси-сеть с Envoy.

Контейнеризация приложения  —  это процесс преобразования приложения и всех его компонентов в пакет или контейнер с использованием платформы Docker. Контейнер Docker определяется как компактное, перемещаемое и автономное пространство, в котором приложение выполняется без воздействия внешней среды.

Dockerfile

FROM golang:1.23-alpine AS builder

RUN apk update && apk add --no-cache git

ENV GO111MODULE=on \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64

WORKDIR /app

COPY go.mod go.sum ./

RUN go mod download

COPY . .

RUN go build -o main .

FROM alpine:latest

WORKDIR /app

COPY --from=builder /app/main .

EXPOSE 9090

EXPOSE 9000

CMD ["./main"]

Этим Dockerfile создается многоэтапная сборка для приложения Go, интегрированного с прокси-сервером Envoy.

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

На втором настраивается прокси-сервер Envoy, в контейнер копируется конфигурационный файл envoy.yaml.

На заключительном этапе для запуска скомпилированного бинарника Go используется минимальный образ Alpine Linux, при этом приложение копируется из этапа builder.

Для трафика приложения и прокси-сервера контейнером предоставляются порты 9090, 9000 и 5209 со стандартным набором команд для выполнения приложения Go.

Docker Compose

services:
grpc-example:
build:
context: ./
dockerfile: Dockerfile
container_name: grpc-example
ports:
- "9090:9090" # HTTP-сервер на Gin
- "9000:9000" # gRPC сервер
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- db
restart: always

envoyproxy-grpc-example:
build:
context: ./
dockerfile: Dockerfile-envoy
container_name: envoy-grpc-example
ports:
- "5209:5209"
extra_hosts:
- "host.docker.internal:host-gateway"
restart: always

db:
image: postgres:15
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: admin123
POSTGRES_DB: learnInternLen
ports:
- "5432:5432"
volumes:
- ./db:/docker-entrypoint-initdb.d/

Этим файлом Docker Compose определяется многоконтейнерная структура с тремя службами: grpc-example, envoyproxy-grpc-example и db.

Первой службой создается gRPC и HTTP-сервер на Go из Dockerfile, предоставляются порты 9090 и 9000 соответственно, она зависит от службы PostgreSQL db.

Второй создается прокси-сервер Envoy из отдельного Dockerfile-envoy, предоставляется порт 5209 для взаимодействия с прокси-сервером.

У обеих служб имеется конфигурация extra_hosts для взаимодействия с хост-машиной, они автоматически перезапустятся при сбое.

Службой db используется официальный образ PostgreSQL 15 с переменными среды для конфигурирования базы данных и скриптом инициализации, подключаемым из локального каталога ./db. База данных PostgreSQL доступна через порт 5432.

Конфигурация Envoy

Dockerfile-envoy

FROM envoyproxy/envoy-dev:latest
COPY ./envoy.yaml /etc/envoy/envoy.yaml

EXPOSE 5209
CMD /usr/local/bin/envoy -c /etc/envoy/envoy.yaml -l trace --log-path /tmp/envoy_info.log

Для наглядности, модульности и сопровождаемости обычно используется отдельный dockerfile. Им определяется структура контейнера Envoy на основе образа envoyproxy/envoy-dev:latest и копируется пользовательский конфигурационный файл envoy.yaml из локальной машины в каталог контейнера /etc/envoy/.

В Dockerfile предоставляется порт 5209 для входящего трафика и задается стандартная команда CMD для запуска Envoy с указанным конфигурационным файлом /etc/envoy/envoy.yaml.

envoy.yaml

static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 5209 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: "*"
routes:
- match:
prefix: "/"
route:
cluster: grpc_service
http_filters:
- name: envoy.grpc_web
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: grpc_service
connect_timeout: 0.25s
type: LOGICAL_DNS
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options: {}
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: grpc_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: grpc-example
port_value: 9000

Этим файлом Envoy конфигурируется как прокси-сервер HTTP, которым через порт 5209 прослушивается входящий трафик. Им же настраивается фильтр диспетчера HTTP-подключений для обработки запросов с маршрутизацией, определенной для всех доменов * с префиксом / для перенаправления трафика в серверную службу gRPC grpc_service.

Служба gRPC определяется в разделе clusters при помощи DNS-разрешения LOGICAL_DNS для направления трафика в службу grpc_example, запускаемую на порту 9000.

В файле также содержится фильтр HTTP маршрутизатора для управления HTTP-запросами. При маршрутизации используется политика циклической балансировки нагрузки для серверной службы.

Сборка контейнера

Настроив все, собираем и запускаем контейнер такими командами:

docker-compose build
docker-compose up

Вот результат:

Консольный вывод

Тестируем сеть Envoy, отправляя на localhost:5209 gRPC-запрос:

Тестирование Envoy при помощи BloomRPC

Заключение

Процесс контейнеризации приложения Go состоит из различных аспектов, в том числе создания ориентированной на взаимодействия архитектуры, особенно для микросервисных систем.

Комбинированием Docker, Go и Envoy службы легко оркестрируются и развертываются, чем обеспечивается стабильное и предсказуемое расширение.

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

Конфигурацией envoy.yaml также предоставляется функционал маршрутизации запросов в серверные службы, такие как написанные на Go серверы gRPC. Этим повышаются масштабируемость, безопасность и гибкость.

Кроме того, упрощаются развертывание и конфигурирование сложных сетевых задач, таких как разрешение DNS-запросов или осуществление трафика.

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

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Izzan Alfadhil: Dockerize a GO Project with Envoy

Предыдущая статьяФункциональное программирование Java: элегантное применение Predicate и Function
Следующая статьяC++: подробное руководство по циклам for с векторами