Внешние модули сборки и запуска¶
До выхода версии Hyperledger Fabric 2.0 процесс сборки и запуска чейнкодов был частью реализации однорангового узла и не мог быть просто изменен. Все чейнкоды, установленные на одноранговый узел, «собирались» по специфичной для языка программирования логике, жестко определенной в самом узле. В результате такого процесса сборки создается образ контейнера Docker, который запускается для выполнения чейнкода, подключенного к одноранговому узлу в качестве клиента.
Такой подход ограничивал реализацию чейнкодов только несколькими языками программирования, требовал, чтобы Docker был частью среды, в которой происходит развертывание, и не позволял запускать чейнкоды как долго работающие серверные процессы.
Начиная с версии Fabric 2.0 внешние модули сборки и запуска устраняют эти ограничения, позволяя операторам расширять
одноранговые узлы программами, которые могут собирать, запускать и обнаруживать чейнкоды. Для использования этой
возможности, необходимо создать свой собственный модуль сборки (buildpack), а затем включить его в раздел
externalBuilders
конфигурации однорангового узла в файле core.yaml, чтобы узел знал о наличии этого модуля. Далее
описаны детали этого процесса.
Обратите внимание, что если ни один из включенных в конфигурацию внешних модулей не может осуществить сборку пакета чейнкода, одноранговый узел попытается обработать этот пакет так, как будто он был создан стандартными инструментами упаковки Fabric, такими как команды CLI или функции SDK.
Примечание: Это расширенная функция, которая скорее всего потребует пользовательской сборки образа однорангового узла.
Например, далее в статье используются go
и bash
, которые не включены в текущий официальный образ fabric-peer
.
Модель внешнего модуля сборки¶
Внешние модули сборки и запуска чейнкодов Hyperledger Fabric в значительной степени основаны на модулях сборки Heroku (Buildpacks). Реализация этих модулей сборки - это просто набор программ или скриптов, которые превращают артефакты приложения в нечто, что можно запустить. Модель модуля сборки была адаптирована для пакетов чейнкода и расширена для поддержки выполнения и обнаружения чейнкодов.
API внешних модулей сборки и запуска¶
Внешний модуль сборки и запуска состоит из четырех программ или скриптов:
bin/detect
определяет, следует ли использовать данный модуль для сборки пакета чейнкода и его запуска.bin/build
преобразует пакет чейнкода в исполняемый чейнкод.bin/release
(опционально) предоставляет метаданные о чейнкоде одноранговому узлу.bin/run
(опционально) запускает чейнкод.
bin/detect
¶
Скрипт bin/detect
отвечает за определение того, стоит ли использовать данный модуль для сборки пакета чейнкода и его
запуска. Одноранговый узел вызывает detect
с двуми аргументами:
bin/detect CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR
При вызове detect
директория CHAINCODE_SOURCE_DIR
содержит исходный код чейнкода, а CHAINCODE_METADATA_DIR
- файл
metadata.json
из установленного на одноранговый узел пакета чейнкода. Директории CHAINCODE_SOURCE_DIR
и
CHAINCODE_METADATA_DIR
следует рассматривать как входные данные, доступные только для чтения. Если данный модуль
сборки должен быть применен к исходному пакету чейнкода, скрипт detect
должен вернуть код 0
; любой другой код
завершения будет означать, что модуль сборки не должен быть применен.
Ниже приведен пример простого скрипта detect
для чейнкода, написанного на языке go:
#!/bin/bash
CHAINCODE_METADATA_DIR="$2"
# use jq to extract the chaincode type from metadata.json and exit with
# success if the chaincode type is golang
if [ "$(jq -r .type "$CHAINCODE_METADATA_DIR/metadata.json" | tr '[:upper:]' '[:lower:]')" = "golang" ]; then
exit 0
fi
exit 1
bin/build
¶
Скрипт bin/build
отвечает за сборку, компиляцию или преобразование содержимого пакета чейнкода в артефакты, которые
могут быть использованы скриптами release
и run
. Одноранговый узел вызывает build
с тремя аргументами:
bin/build CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR BUILD_OUTPUT_DIR
При вызове build
директория CHAINCODE_SOURCE_DIR
содержит исходный код чейнкода, а CHAINCODE_METADATA_DIR
- файл
metadata.json
из установленного на одноранговый узел пакета чейнкода. BUILD_OUTPUT_DIR
- это директория, в которую
скрипт build
должен поместить артефакты, необходимые для скриптов release
и run
. Директории CHAINCODE_SOURCE_DIR
и CHAINCODE_METADATA_DIR
должны рассматриваться как доступные только для чтения, но директория BUILD_OUTPUT_DIR
доступна для записи.
При завершении работы build
с кодом 0
содержимое BUILD_OUTPUT_DIR
копируется в постоянное хранилище,
поддерживаемое одноранговым узлом; любой другой код завершения означает неуспешный вызов скрипта.
Ниже приведен пример простого скрипта build
для чейнкода, написанного на языке go:
#!/bin/bash
CHAINCODE_SOURCE_DIR="$1"
CHAINCODE_METADATA_DIR="$2"
BUILD_OUTPUT_DIR="$3"
# extract package path from metadata.json
GO_PACKAGE_PATH="$(jq -r .path "$CHAINCODE_METADATA_DIR/metadata.json")"
if [ -f "$CHAINCODE_SOURCE_DIR/src/go.mod" ]; then
cd "$CHAINCODE_SOURCE_DIR/src"
go build -v -mod=readonly -o "$BUILD_OUTPUT_DIR/chaincode" "$GO_PACKAGE_PATH"
else
GO111MODULE=off go build -v -o "$BUILD_OUTPUT_DIR/chaincode" "$GO_PACKAGE_PATH"
fi
# save statedb index metadata to provide at release
if [ -d "$CHAINCODE_SOURCE_DIR/META-INF" ]; then
cp -a "$CHAINCODE_SOURCE_DIR/META-INF" "$BUILD_OUTPUT_DIR/"
fi
bin/release
¶
Скрипт bin/release
отвечает за предоставление метаданных чейнкода одноранговому узлу. bin/release
является
необязательным. Если он отсутствует, этот шаг пропускается. Одноранговый узел вызывает release
с двумя аргументами:
bin/release BUILD_OUTPUT_DIR RELEASE_OUTPUT_DIR
При вызове release
директория BUILD_OUTPUT_DIR
содержит артефакты, созданные программой build
и рассматривается
как входные данные только для чтения. RELEASE_OUTPUT_DIR
- директория, в которую скрипт release
должен поместить
артефакты для использования одноранговым узлом.
После завершения работы release
одноранговому узлу доступно два типа метаданных из директории RELEASE_OUTPUT_DIR
:
- определение индексов CouchDB для базы данных состояния;
- информация о подключении к внешнему серверу чейнкода (
chaincode/server/connection.json
).
Если определение индексов CouchDB требуется чейнкодом, скрипт release
отвечает за их размещение в директории
statedb/couchdb/indexes
внутри RELEASE_OUTPUT_DIR
. Файлы с индексами должны иметь расширение .json
. Подробнее
об этом читайте в статье об использовании CouchDB в качестве базы данных состояния.
В случаях использования чейнкода как сервера release
отвечает за заполнение файла chaincode/server/connection.json
адресом сервера чейнкода и данными TLS, необходимыми для связи с ним. При предоставлении этой информации скрипт run
не
будет вызываться. Подробнее о сервере чейнкода вы можете прочитать на этой странице
Ниже приведен пример простого скрипта release
для чейнкода, написанного на языке go:
#!/bin/bash
BUILD_OUTPUT_DIR="$1"
RELEASE_OUTPUT_DIR="$2"
# copy indexes from META-INF/* to the output directory
if [ -d "$BUILD_OUTPUT_DIR/META-INF" ] ; then
cp -a "$BUILD_OUTPUT_DIR/META-INF/"* "$RELEASE_OUTPUT_DIR/"
fi
bin/run
¶
Скрипт bin/run
отвечает за запуск чейнкода. Одноранговый узел вызывает run
с двумя аргументами:
bin/run BUILD_OUTPUT_DIR RUN_METADATA_DIR
При вызове run
директория BUILD_OUTPUT_DIR
содержит артефакты, созданные программой build
, а в директории
RUN_METADATA_DIR
содержится файл с именем chaincode.json
, содержащий информацию, необходимую чейнкоду для
соединения с одноранговым узлом и регистрации на нем. Обратите внимание, что скрипт bin/run
должен рассматривать
содержимое директорий BUILD_OUTPUT_DIR
и RUN_METADATA_DIR
как входные данные только для чтения. В файле
chaincode.json
содержатся следующие ключи:
chaincode_id
: уникальный идентификатор, связанный с пакетом чейнкода.peer_address
: адрес в форматеhost:port
конечной точки сервера gRPCChaincodeSupport
, расположенного на одноранговом узле.client_cert
: сертификат клиента в кодировке PEM, созданный одноранговым узлом, который должен использоваться при установке соединения TLS между чейнкодом и одноранговым узлом.client_key
: ключ в кодировке PEM, созданный одноранговым узлом, который должен использоваться при уставновке соединения TLS между чейнкодом и одноранговым узлом.root_cert
: корневой сертификат в кодировке PEM для конечной точки сервера gRPCChaincodeSupport
, расположенного на одноранговом узле.mspid
: локальный mspid однорангового узла.
Когда run
завершает свою работу, одноранговый узел считает работу чейнкода завершенной. Если для чейнкода поступает
другой запрос, одноранговый узел пытается запустить еще один экземпляр чейнкода, снова вызвав run
. Содержимое файла
chaincode.json
не должно кэшироваться при каждом вызове.
Ниже приведен пример простого скрипта run
для чейнкода, написанного на языке go:
#!/bin/bash
BUILD_OUTPUT_DIR="$1"
RUN_METADATA_DIR="$2"
# setup the environment expected by the go chaincode shim
export CORE_CHAINCODE_ID_NAME="$(jq -r .chaincode_id "$RUN_METADATA_DIR/chaincode.json")"
export CORE_PEER_TLS_ENABLED="true"
export CORE_TLS_CLIENT_CERT_FILE="$RUN_METADATA_DIR/client.crt"
export CORE_TLS_CLIENT_KEY_FILE="$RUN_METADATA_DIR/client.key"
export CORE_PEER_TLS_ROOTCERT_FILE="$RUN_METADATA_DIR/root.crt"
export CORE_PEER_LOCALMSPID="$(jq -r .mspid "$RUN_METADATA_DIR/chaincode.json")"
# populate the key and certificate material used by the go chaincode shim
jq -r .client_cert "$RUN_METADATA_DIR/chaincode.json" > "$CORE_TLS_CLIENT_CERT_FILE"
jq -r .client_key "$RUN_METADATA_DIR/chaincode.json" > "$CORE_TLS_CLIENT_KEY_FILE"
jq -r .root_cert "$RUN_METADATA_DIR/chaincode.json" > "$CORE_PEER_TLS_ROOTCERT_FILE"
if [ -z "$(jq -r .client_cert "$RUN_METADATA_DIR/chaincode.json")" ]; then
export CORE_PEER_TLS_ENABLED="false"
fi
# exec the chaincode to replace the script with the chaincode process
exec "$BUILD_OUTPUT_DIR/chaincode" -peer.address="$(jq -r .peer_address "$ARTIFACTS/chaincode.json")"
Настройка внешний модулей сборки и запуска¶
Настройка одногрангового узла на использование внешних модулей сборки заключается в добавлении нового элемента в блок
конфигурации чейнкода externalBuilders в файле core.yaml
. Каждое определение внешнего модуля сборки должно включать
имя (используемое для логирования) и путь к директории, содержащей директорию bin
со скриптами модуля сборки.
Также при необходимости может быть указан список имен переменных окружения, которые будут передаваться из однорангового узла при вызове скриптов модуля сборки.
В следующем примере определены два внешних модуля сборки:
chaincode:
externalBuilders:
- name: my-golang-builder
path: /builders/golang
propagateEnvironment:
- GOPROXY
- GONOPROXY
- GOSUMDB
- GONOSUMDB
- name: noop-builder
path: /builders/binary
В этом примере реализация модуля сборки «my-golang-builder» расположена в директории /builders/golang
, а его скрипты
содержатся в /builders/golang/bin
. Когда одноранговый узел будет вызывать один и скриптов сборки, связанных с
«my-golang-builder», он будет передавать только значения переменных из списка propagateEnvironment
.
Примечания: следующие переменные всегда передаются внешним модулям сборки:
- LD_LIBRARY_PATH
- LIBPATH
- PATH
- TMPDIR
Если в блоке externalBuilders
конфигурации однорангового узла определены внешние модули сборки, узел будет в указанном
порядке поочередно вызывать скрипт bin/detect
каждого модуля, пока один из них не завершится успешно. Если ни один
из них не завершится успешно, одноранговый узел вернется к обычному процессу сборки образов Docker, реализованному
внутри узла. Это означает, что внешние модули сборки совершенно не обязательны.
В приведенном выше примере одноранговый узел сначала попытается использовать модуль сборки «my-golang-builder», затем модуль «noop-builder» и, наконец, свой внутренний процесс сборки.
Пакеты чейнкодов¶
В рамках нового жизненного цикла, представленного в Fabric 2.0, формат пакета чейнкода изменился с сериализованных
данных (protocol buffers) на архив tar, сжатый gzip. Пакеты чейнкода, созданные с помощью команды
peer lifecycle chaincode package
, используют этот новый формат.
Содержание пакета жизненного цикла чейнкода¶
Пакет жизненного цикла чейнкода содержит два файла. Первый файл, code.tar.gz
, представляет собой сжатый gzip архив
tar. В нем содержатся исходные артефакты чейнкода. В пакетах, созданных с помощью команд CLI однорангового узла, исходный
код чейнкода помещен в директорию src
, а метаданные чейнкода (например, индексы CouchDB) - в каталог META-INF
.
Второй файл, metadata.json
, представляет собой документ JSON с тремя ключами:
type
: тип чейкода (например, GOLANG, JAVA, NODE).path
: для чейнкода на go, путь к основному пакету чейнкода относительно GOPATH или GOMOD; не определен для других типов.label
: метка чейнкода, используемая при создании идентификатора пакета, по которому пакет чейнкода идентифицируется в новом процессе жизненного цикла.
Обратите внимание, что поля type
и path
используются только при сборках платформой docker.
Пакеты чейнкода и внешние модули сборки¶
Когда пакет чейнкода устанавливается на одноранговый узел, содержимое файлов code.tar.gz
и metadata.json
не
обрабатывается до вызова внешних модулей сборки, за исключением поля label
, которое используется новым процессом
жизненного цикла для вычисления идентификатора пакета. Это дает пользователям большую гибкость в том, как они
упаковывают исходный код и метаданные, которые будут обрабатываться внешними модулями сборки и запуска.
Например, можно создать пакет чейнкода, который содержит предварительно скомпилированную реализацию чейнкода в
code.tar.gz
и файл metadata.json
, позволяющий бинарному модулю сборки обнаружить пользовательский пакет, проверить
хеш-сумму бинарного файла и запустить программу как чейнкод.
Другим примером может быть пакет чейнкода, содержащий только определения индексов для базы данных состояния и данные,
необходимые внешнему модулю запуска для подключения к запущенному серверу чейнкода. В этом случае процесс build
просто
извлечет метаданные, а процесс release
предоставит их одноранговому узлу.
Единственным требованием является то, что code.tar.gz
может содержать только обычные файлы и каталоги, и что они не
могут содержать пути, которые приведут к записи файлов вне логического корня пакета чейнкода.