Существующие ограничения Go
Прежде чем начать использовать мониторинг приложений Go, убедитесь, что вы знаете об существующих ограничениях.
Поддержка ограничена официальными, стабильными версиями Go.
Поддержка Go ограничена:
- Официальные, стабильные релизы Go созданных с помощью набора инструментов Golang.
- Стабильные релизы Go с openssl-fips модификациями для поддержки Федеральных стандартов обработки информации (ЕдиныйАгент версии 1.295+).
ЕдиныйАгент не поддерживает двоичные файлы, созданные с использованием других наборов инструментов, таких как
- gccgo набор инструментов
Go поддерживает динамическое связывание стандартной библиотеки Go. Этот режим сборки используется редко, и ЕдиныйАгент не будет внедряться в приложения, созданные таким образом.
Пример
Рассмотрим следующее минималистичное приложение Go под названием GoMinimal.go
:
go install -buildmode=shared -linkshared std
go build -linkshared GoMinimal.go
ЕдиныйАгент отклонит полученный двоичный файл приложения.
Приложения, созданные с отключенными опциями -buildmode=pie
и CGO, не поддерживаются.
Это ограничение распространяется только на системы Linux.
Для libc
ЕдиногоАгента требуется сборка приложения с -buildmode=pie
и CGO_ENABLED=0
динамически связанным двоичным файлом приложения libc
, но без зависимости от системной библиотеки.
Пример и обходной путь
Рассмотрим следующее приложение Go под названием main.go
:
package main
import "fmt"
func main() {
fmt.Print("Enter text: ")
var input string
fmt.Scanln(&input)
fmt.Print(input)
}
Сборка приложения с помощью следующей команды приводит к созданию динамически связанного двоичного файла приложения, который не зависит от libc
, что требуется для ЕдиногоАгента:
CGO_ENABLED=0 go build -buildmode=pie main.go
В качестве обходного пути есть несколько вариантов:
- Удалить опцию
-buildmode=pie
, которая приводит к статически связанному приложению Go.CGO_ENABLED=0 go build main.go
- Используйте внешний компоновщик и не отключайте CGO (
CGO_ENABLED=1
по умолчанию).go build -ldflags="-linkmode=external" -buildmode=pie main.go
Приложения, загружающие плагины Go, не поддерживаются.
Плагин Go — это пакет, скомпилированный с использованием -buildmode=plugin
флага сборки для создания общего объектного файла. Этот режим сборки используется редко, и ЕдиныйАгент отключит глубокий мониторинг, когда приложение фактически загружает плагин Go.
Пакеты сторонних поставщиков не поддерживаются.
Go vendoring используется для включения локальных копий внешних зависимостей в репозиторий проекта. Этот подход использовался для закрепления версий сторонних пакетов перед модулем Go module была добавлена.
ЕдиныйАгент не будет отслеживать пакеты поставщиков. Например, службы gRPC поддерживаются только если вы используете модули Go или импортируете go-grpc напрямую, без использования системы управления зависимостями.
Возможные ограничения без таблицы символов
По умолчанию Go генерирует двоичные файлы приложения, содержащие таблицу символов.
В настоящее время нет известных ограничений для striped biners в Ключ-АСТРОМ. Однако мы не можем гарантировать, что все текущие функции продолжат работать в будущих версиях Go или что все функции, добавленные позже, будут поддерживаться в striped biners.
Поэтому мы рекомендуем вам собирать двоичные файлы Go, содержащие таблицу символов, и избегать использования параметров командной строки или внешних инструментов, которые могут ее подавить.
- Не используйте внешний инструмент
strip
(strip <Go binary>
). - Не компилируйте с
go build -ldflags="-s"
. Флаг-s
удаляет таблицу символов. - Не запускайте
go run <application>
. Эта редко используемая команда создает и запускает приложения на лету. Поскольку выходной файл приложения является временным (файл автоматически удаляется после завершения работы приложения), двоичный файл приложения не содержит таблицы символов.
В Ключ-АСТРОМ мониторинг stripped binaries включен по умолчанию. Однако вы можете отключить эту функцию для клиента, отключив Go stripped binaries на странице настроек функций ЕдиногоАгента.
Приложения, созданные с включенным отслеживанием -race
, не поддерживаются.
Приложение, созданное с помощью -race
флага, содержит встроенный data race detector. Этот режим сборки в основном используется в среде разработки, и ЕдиныйАгент не будет внедряться в приложения, созданные таким образом.
Профилирование стека создания потоков ОС отключено
ЕдиныйАгент не поддерживает predefined threadcreate
profile. Результаты профилирования создания потоков приложений Go, отслеживаемых ЕдинымАгентом, будут содержать только пустые трассировки стека.
Поддержка статически связанных двоичных файлов (только Linux)
ЕдиныйАгент версии 1.203+
До версии ЕдиногоАгента 1.203 статически связанные двоичные файлы не поддерживаются. Подробности см. ниже .
После включения статического мониторинга Go автоматическое внедрение для статически связанных двоичных файлов Go поддерживается ЕдинымАгентом, если
- Родительский процесс динамически связан. Это также относится к приложениям, работающим как полезная нагрузка контейнера. Пример В этом примере родительский процесс — это оболочка
/bin/sh
, которая запускает статически связанный двоичный файл Go. Следующий код запускает оболочку/bin/sh
и выполняет предоставленную команду./bin/sh -c '/StaticGoMinimal <optional app arguments>'
С помощью командыfile
можно проверить, является ли приложение динамически или статически связанным.$ file -L /bin/sh
/bin/sh: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked
$ file -L /StaticGoMinimal
/StaticGoMinimal: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked
- Полноценное внедрение Kubernetes Classic. Статически связанный двоичный файл Go работает как точка входа контейнера Docker. Пример
FROM alpine:3.11
COPY StaticGoMinimal /
ENTRYPOINT ["/StaticGoMinimal"]
Облачное внедрение полного стека
Автоматическое внедрение статически связанных приложений Go, работающих как точки входа контейнера, не поддерживается при использовании облачного развертывания с полным стеком внедрения в Kubernetes.
- Пример
Например, при развертывании полнофункционального внедрения в облаке следующий код запускает неподдерживаемое статически связанное приложение Go.
FROM alpine:3.11
COPY StaticGoMinimal /
ENTRYPOINT ["/StaticGoMinimal"]
Чтобы обойти это ограничение, можно изменить точку входа контейнера со статически связанного приложения Go на динамически связанное приложение, такое как оболочка или init
.
- Обходной путь при наличии оболочки
Применимо к образам контейнеров, которые уже содержат динамически связанный двоичный файл оболочки.
Изменяя контейнер entryproint со статически связанного приложения Go на динамически связанную оболочку, мы получаем следующий код, который запускает /bin/sh
и выполняет команду /StaticGoMinimal
.
FROM alpine:3.11
COPY StaticGoMinimal /
ENTRYPOINT ["/bin/sh", "-c", "'/StaticGoMinimal'"]
- Обходной путь, когда оболочка недоступна
Применимо к образам контейнеров, где оболочка недоступна.
Когда образ контейнера не содержит оболочку, например, в образах distroless, другой вариант - использовать минимальный init
двоичный файл, такой как tini. Добавив tini и изменив entryproint контейнера, мы получаем следующий код /StaticGoMinimal
, который выполняется, сохраняя правильную пересылку сигнала.
# syntax=docker/dockerfile:1
FROM gcr.io/distroless/base
COPY StaticGoMinimal /
ARG TINI_VERSION=v0.19.0
ADD --checksum=sha256:93dcc18adc78c65a028a84799ecf8ad40c936fdfc5f2a57b1acda5a8117fa82c --chmod=555 \
https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-amd64 /tini
ENTRYPOINT [ "/tini", "--" ]
CMD ["/StaticGoMinimal"]
Обратите внимание на директиву parser, указывающую синтаксис Dockerfile версии 1, которая требуется для использования опций --checksum
и --chmod
с ADD
. Без нее образ должен был бы предоставлять двоичный файл chmod
, чтобы его tini
можно было сделать исполняемым. Существует несколько вариантов tini для glibc и musl, а также архитектур amd64 и aarch64.
Ограничения
- Статические приложения Go, использующие cgo, не поддерживаются. ЕдиныйАгент отклоняет мониторинг статических двоичных файлов Go, использующих cgo и, следовательно, имеют статическую зависимость от системной библиотеки с libc. Это связано с тем, что статически связанная версия libc может конфликтовать с той, которая используется ЕдинымАгентом. Чтобы обойти это ограничение, вы можете построить приложение Go как динамически связанный исполняемый файл , который динамически связывается с libc. Это гарантирует, что и приложение Go, и ЕдиныйАгент будут использовать одну и ту же версию libc, которая доступна на хосте.
- Для статического мониторинга Go требуются
SYS_PTRACE
возможности контейнеров Docker. Эта возможностьSYS_PTRACE
включена по умолчанию для Docker 19.03.0+ и Linux Kernel 4.8+. Она позволяет системные вызовы между процессами, запущенными в контейнере, что является требованием для статического мониторинга Go. Это ограничение можно обойти для версий Docker ниже 19.03.0 или версий ядра Linux ниже 4.8, запустив контейнер сSYS_PTRACE
возможностью, как показано ниже.docker run --cap-add=SYS_PTRACE <container> ...
- Образы Docker, не предоставляющие системную библиотеку C, не поддерживаются. ЕдиныйАгент требует наличия системной библиотеки C на контролируемом хосте. Чтобы обойти это ограничение, можно изменить базовый образ контейнера на тот, который предоставляет системную библиотеку C. Примером образа Docker, который не предоставляет системную библиотеку C, является образ Scratch.
FROM scratch
COPY StaticGoMinimal /
CMD ["/StaticGoMinimal"]
Примерами образов, которые предоставляют библиотеку системы C, являются образ Alpine или различные distroless образыFROM alpine:3.11
COPY StaticGoMinimal /
CMD ["/StaticGoMinimal"]
Побочные эффекты
Файл proc/<pId>/exe
ссылается на исполняемый файл с именем oneagentdynamizer
вместо двоичного файла приложения Go, он содержится в процедуре Псевдофайловая система, которая предоставляет интерфейс к структурам данных ядра запущенных процессов. Это может привести к тому, что системные инструменты, такие как ps
или , top
будут отображать oneagentdynamizer
вместо имени двоичного файла Go в своих выходных данных.
Версии OneAgent без поддержки статического мониторинга
ЕдиныйАгент версии 1.201 и более ранних
До версии ЕдиногоАгента 1.203 статически связанные двоичные файлы не поддерживаются, а для внедрения в Linux требуется динамическая компоновка. В Windows такого ограничения нет.
Динамическое связывание автоматически применяется, когда приложение использует определенные стандартные пакеты библиотеки времени выполнения, например, net/http
. Во всех остальных случаях вы можете принудительно применить динамическое связывание с помощью -ldflags="-linkmode=external"
параметра командной строки. Обратите внимание, что отключение cgo, например, с помощью CGO_ENABLED=0
, не поддерживается, и ЕдиныйАгент отклонит полученный двоичный файл приложения.
Пример
- Рассмотрим следующее минималистичное приложение Go под названием
GoMinimal.go
:
package main
import "fmt"
func main() {
fmt.Print("Enter text: ")
var input string
fmt.Scanln(&input)
fmt.Print(input)
}
- В результате сборки приложения получается статически скомпонованный двоичный файл приложения:
$ go build GoMinimal.go
$ file GoMinimal
GoMinimal: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
- Вы можете реализовать динамическое связывание с помощью
-ldflags="-linkmode=external"
:
$ go build -ldflags="-linkmode=external" GoMinimal.go
$ file GoMinimal
GoMinimal: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32
Поддержка musl libc
Библиотека musl libc — это замена библиотеки glibc. Ключ-АСТРОМ поддерживает приложения Go на основе musl, например, созданные на Alpine Linux.
Есть одно дополнительное требование для сборки динамически связанного двоичного приложения. Вам следует использовать Go toolchain для alpine (golang:<version>-alpine) и добавить -ldflags="-linkmode=external"
(или добавьте -linkmode=external
к существующему -ldflags
) в командную строку сборки для принудительного использования системного компоновщика. Это не требуется для статически связанных приложений Go, отслеживаемых статическим мониторингом Go .
Хотя musl libc действительно очень близко имитирует функциональность glibc, между ними есть тонкие различия в поведении. Более того, Go официально не поддерживает Go toolchain на основе musl, что означает, что двоичные файлы Go toolchain нельзя загрузить с веб-сайта golang.org.
Кроме того, существует серьезная проблема с тем, как Go использует musl libc. Это ограничивает степень, в которой Ключ-АСТРОМ может поддерживать приложения на основе musl. Набор инструментов Go включает внутренний компоновщик, который генерирует двоичные файлы приложений на основе musl, которые неправильно инициализируют musl libc при запуске приложения. Эта проблема не позволяет Ключ-АСТРОМ контролировать эти приложения. В таком случае на соответствующей странице процесса приложения отображается следующее сообщение:
Активация глубокого мониторинга не удалась, Мониторинг двоичных файлов Go musl, созданных с помощью внутреннего компоновщика Go, не поддерживается
Если вы используете системный компоновщик для генерации двоичного файла приложения, он добавляет код запуска, который правильно инициализирует общие объекты. Кроме того, добавление -ldflags="-linkmode=external"
в командную строку сборки принудительно использует системный компоновщик. Полученный двоичный файл будет выполняться с правильно инициализированной libc, что позволяет Ключ-АСТРОМ контролировать такое приложение.
Пример
- Рассмотрим следующее минималистичное приложение Go под названием
GoMinimal.go
:
package main
import "fmt"
func main() {
fmt.Print("Enter text: ")
var input string
fmt.Scanln(&input)
fmt.Print(input)
}
- Следующий многоэтапный файл Docker создает действительный динамически связанный двоичный файл Go musl на этапе 1 и запускает приложение на этапе 2.
# --- Stage 1:
# Use Golang toolchain for alpine to build the application.
FROM golang:1.13.5-alpine as builder
RUN apk update && apk add gcc libc-dev
# Copy local code, for example, GoMinimal.go, to the container image.
COPY ./GoMinimal.go ./GoMinimal.go
# Build dynamically linked Go binary.
RUN go build -ldflags="-linkmode=external" GoMinimal.go
# or add '-linkmode=external' to existing ldflags:
# e.g.: go build -ldflags="-linkmode=external <other linker flags>" GoMinimal.go
# --- Stage 2:
# Use a Docker multi-stage build to create a lean production image.
FROM alpine:3.11
# Install ca-certificates and libc6-compat for Go programs to work properly.
RUN apk add --no-cache ca-certificates libc6-compat
# Copy the binary to the production image from the builder stage.
COPY --from=builder /go/GoMinimal /GoMinimal
# Run the application on container startup.
CMD ["/GoMinimal"]
- Создайте контейнер и запустите приложение:
docker build -t gominimal-alpine .
docker run --interactive gominimal-alpine