ラズパイおうちKubernetesクラスタ上でHyperledger Fabricを動かす

前回の記事 [Kubernetes the hard way on Raspberry Pi - Qiita](https://qiita.com/nekia/items/18ce460960b1c7c046f4)で紹介したRaspberry PiによるおうちKubernetesクラスタ上にHyperledger Fabricを構築した話をお届けします。


# 動機

* Kubernetesを触って学ぶため
* メンテナをしているHyperledger ExplorerプロジェクトのHelm Chart対応やKubernetesへのデプロイ手順の検証にK8s上のHyperledger Fabric環境が必要なため

# Key takeaway

すごく固有な環境向けの話題になるのでニーズはなさそうですが、本記事を読むとわかることは以下の２点。

* Windows上で`arm64`アーキ向けのHyperledger Fabricを動かすのに必要なバイナリやDockerイメージの作り方
* 今回利用した`Kubernetes operator for Hyperledger Fabric`をラズパイ上で動かす方法
    * 本オペレータは、Argo WorkflowとHelm Chartで主に構成されており、Helm Chartのテンプレート等を本環境向けに修正するのが主な作業
* Kubernetesクラスタ上にHyperledger Fabricネットワークを立ち上げる際に遭遇した問題の解決方法

# 環境

## Kubernetesクラスタ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/b8b1ef40-b390-3602-8a95-e79fc29e8b36.png)

## Hyperledger Fabric

* Hyperledger Fabric v1.4
* 3 Org, 1 Peer per org
* [Kubernetes operator for Hyperledger Fabric](https://github.com/raftAtGit/hl-fabric-operator)を使って構築

## ワークスペース

* Ubuntu 18.04 on WSL2 in Windows 11

# 主な作業

今回利用させてもらった`Kubernetes operator for Hyperledger Fabric`は、`amd64`アーキテクチャのみサポートしているので、`arm64`アーキテクチャ向け対応という地味な作業が主になります。

ではスタートです。

# `ARM64`向けイメージをWindows上で動かす準備

基本的には、`ARM64`アーキ向けコンテナイメージをビルドする場合、`ARM64`環境で作業を行う必要があります。今回の場合、`ARM64`アーキであるラズパイが手元にあるので、その上で実施してもいいのですが、ラズパイ上のコンテナランタイムにDockerではなく、Containerdを利用しているので、わざわざイメージ作成目的で新たにDockerをセットアップするのも手間なので、`ARM64`アーキ向けコンテナイメージを作りました。
なお、バイナリについては、Hyperledger Fabricにおいて、その多くがGoで書かれており、Goは元からクロスコンパイルが可能なため、特にテクニックは必要なく、Makefileを読み解ければ、比較的に対応が可能です。

方法は簡単で、マシンエミュレータであるQEMUとbinfmtを利用します。以下の１度実行することで、以降`ARM64`向けのコンテナがWindows環境でも動かすことができます。

```
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
```
* 参考: [multiarch/qemu-user-static - Docker Image | Docker Hub](https://hub.docker.com/r/multiarch/qemu-user-static/)

ただし、以下のようなマルチアーキテクチャ向けにビルドされたコンテナを使いたいときは注意が必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/a50b613d-03ab-1dc9-5c4d-4dfcf6939daa.png)

この場合、Dockerがプラットフォームから自動的にどのアーキテクチャ向けのイメージをPullすればよいか判断するため、`lts-alpine3.14`のタグを指定しただけでは、プラットフォームと同じ`amd64`のイメージが使われてしまいます。

# Hyperledger Fabric各種コンテナイメージのARM64向けビルド

## baseos, baseimageの準備

今回、ARM64向けの`baseos`, `baseimage`のコンテナイメージは、有志が公開している以下のイメージを利用させてもらうことにしました（公開されているイメージがどのようなDockerfileに基づきビルドされ、何が含まれているか、の確認については自己責任でお願いします）。

* [Image Layer Details - busan15/fabric-baseimage:arm64-0.4.20 - sha256:5c69f19febf6359436f37e1cf5d5b7dea414ac378c4d16758c81e81a575d3ddb | Docker Hub](https://hub.docker.com/layers/busan15/fabric-baseimage/arm64-0.4.20/images/sha256-5c69f19febf6359436f37e1cf5d5b7dea414ac378c4d16758c81e81a575d3ddb)
* [Image Layer Details - busan15/fabric-baseos:arm64-0.4.20 - sha256:3509039646399c9b7b86420df118686afc16174cad3561b5731936e2fac0ebdc | Docker Hub](https://hub.docker.com/layers/busan15/fabric-baseos/arm64-0.4.20/images/sha256-3509039646399c9b7b86420df118686afc16174cad3561b5731936e2fac0ebdc)

## fabricレポジトリのMakefileおよびDockerfileの修正

Hyperledger Fabricのネットワーク構築に必要な各種コンテナイメージのx64向けビルドは、fabricのリポジトリにある[Makefile](https://github.com/hyperledger/fabric/blob/v1.4.9/Makefile)で手順が定義されています。またベースとなるDockerfileは、各イメージごとに以下のフォルダに`Dockerfile.in`として格納されており、前述の`Makefile`内から設定に応じた置換処理をした後、`Dockerfile`としてコピーして利用します。

まずは今回利用するバージョン`v1.4.9`のfabricリポジトリをチェックアウトします（今回利用するfabric operatorの手順がv1.4.9を向けに用意されているため。最新v1.4で動かないというわけではないです）。

```
cd ~
export GOPATH=$HOME/go
mkdir -p ~/go/src/github.com/hyperledger
cd ~/go/src/github.com/hyperledger
git clone https://github.com/hyperledger/fabric.git
cd fabric
git checkout v1.4.9
```

`Makefile`を以下の通り、修正します。

```diff
diff --git a/Makefile b/Makefile
index 946d53785..e3900cba7 100755
--- a/Makefile
+++ b/Makefile
@@ -59,21 +59,21 @@ PROJECT_NAME = hyperledger/fabric
 endif

 BUILD_DIR ?= .build

 EXTRA_VERSION ?= $(shell git rev-parse --short HEAD)
 PROJECT_VERSION=$(BASE_VERSION)-snapshot-$(EXTRA_VERSION)
 TWO_DIGIT_VERSION = $(shell echo $(BASE_VERSION) | cut -d '.' -f 1,2)

 PKGNAME = github.com/$(PROJECT_NAME)
 CGO_FLAGS = CGO_CFLAGS=" "
-ARCH=$(shell go env GOARCH)
+ARCH=arm64
 MARCH=$(shell go env GOOS)-$(shell go env GOARCH)

 # defined in common/metadata/metadata.go
 METADATA_VAR = Version=$(BASE_VERSION)
 METADATA_VAR += CommitSHA=$(EXTRA_VERSION)
 METADATA_VAR += BaseVersion=$(BASEIMAGE_RELEASE)
 METADATA_VAR += BaseDockerLabel=$(BASE_DOCKER_LABEL)
 METADATA_VAR += DockerNamespace=$(DOCKER_NS)
 METADATA_VAR += BaseDockerNamespace=$(BASE_DOCKER_NS)

@@ -230,41 +230,41 @@ $(BUILD_DIR)/%/chaintool: Makefile
 # directory so that subsequent builds are faster
 $(BUILD_DIR)/docker/bin/%: $(PROJECT_FILES)
        $(eval TARGET = ${patsubst $(BUILD_DIR)/docker/bin/%,%,${@}})
        @echo "Building $@"
        @mkdir -p $(BUILD_DIR)/docker/bin $(BUILD_DIR)/docker/$(TARGET)/pkg $(BUILD_DIR)/docker/gocache
        @$(DRUN) \
                -v $(abspath $(BUILD_DIR)/docker/bin):/opt/gopath/bin \
                -v $(abspath $(BUILD_DIR)/docker/$(TARGET)/pkg):/opt/gopath/pkg \
                -v $(abspath $(BUILD_DIR)/docker/gocache):/opt/gopath/cache \
                -e GOCACHE=/opt/gopath/cache \
-               $(BASE_DOCKER_NS)/fabric-baseimage:$(BASE_DOCKER_TAG) \
+               busan15/fabric-baseimage@sha256:5c69f19febf6359436f37e1cf5d5b7dea414ac378c4d16758c81e81a575d3ddb \
                go install -tags "$(GO_TAGS)" -ldflags "$(DOCKER_GO_LDFLAGS)" $(pkgmap.$(@F))
        @touch $@

 $(BUILD_DIR)/bin:
        mkdir -p $@

 changelog:
        ./scripts/changelog.sh v$(PREV_VERSION) v$(BASE_VERSION)

 $(BUILD_DIR)/docker/gotools/bin/protoc-gen-go: $(BUILD_DIR)/docker/gotools

 $(BUILD_DIR)/docker/gotools: gotools.mk
        @echo "Building dockerized gotools"
        @mkdir -p $@/bin $@/obj $(BUILD_DIR)/docker/gocache
        @$(DRUN) \
                -v $(abspath $@):/opt/gotools \
                -w /opt/gopath/src/$(PKGNAME) \
                -v $(abspath $(BUILD_DIR)/docker/gocache):/opt/gopath/cache \
                -e GOCACHE=/opt/gopath/cache \
-               $(BASE_DOCKER_NS)/fabric-baseimage:$(BASE_DOCKER_TAG) \
+               busan15/fabric-baseimage@sha256:5c69f19febf6359436f37e1cf5d5b7dea414ac378c4d16758c81e81a575d3ddb \
                make -f gotools.mk GOTOOLS_BINDIR=/opt/gotools/bin GOTOOLS_GOPATH=/opt/gotools/obj

 $(BUILD_DIR)/bin/%: $(PROJECT_FILES)
        @mkdir -p $(@D)
        @echo "$@"
        $(CGO_FLAGS) GOBIN=$(abspath $(@D)) go install -tags "$(GO_TAGS)" -ldflags "$(GO_LDFLAGS)" $(pkgmap.$(@F))
        @echo "Binary available as $@"
        @touch $@

 # payload definitions'

```

`docker-env.mk`を以下の通り、修正します。

```diff
diff --git a/docker-env.mk b/docker-env.mk
index 7846aabd7..9c9f67f60 100644
--- a/docker-env.mk
+++ b/docker-env.mk
@@ -56,7 +56,7 @@ DBUILD = docker build $(DOCKER_BUILD_FLAGS)
 BASE_DOCKER_NS ?= hyperledger
 BASE_DOCKER_TAG=$(ARCH)-$(BASEIMAGE_RELEASE)

-DOCKER_NS ?= hyperledger
+DOCKER_NS ?= nekia
 DOCKER_TAG=$(ARCH)-$(PROJECT_VERSION)
 PREV_TAG=$(ARCH)-$(PREV_VERSION)

```

`gotools.mk`を以下の通り、修正します。この修正は以下の情報に基づきます。

* [[FAB-18346] "make docker" is failing with Fabric 1.4.9 - Hyperledger JIRA](https://jira.hyperledger.org/browse/FAB-18346?attachmentViewMode=list
)
    * gotoolsのうちの１つ`manifest-tool`がエラーになる、かつ未使用なため削除
* [Install Mockery in docker · Issue #364 · vektra/mockery](https://github.com/vektra/mockery/issues/364
)
    * Mockeryのインストールでエラーになる件

```diff
diff --git a/gotools.mk b/gotools.mk
index c5f8d42bd..d9595863f 100644
--- a/gotools.mk
+++ b/gotools.mk
@@ -3,7 +3,7 @@
 #
 # SPDX-License-Identifier: Apache-2.0

-GOTOOLS = counterfeiter dep golint goimports protoc-gen-go ginkgo gocov gocov-xml misspell mockery manifest-tool
+GOTOOLS = counterfeiter dep golint goimports protoc-gen-go ginkgo gocov gocov-xml misspell mockery
 BUILD_DIR ?= .build
 GOTOOLS_GOPATH ?= $(BUILD_DIR)/gotools
 GOTOOLS_BINDIR ?= $(GOPATH)/bin
@@ -45,6 +45,11 @@ gotool.golint:
        @echo "Building golang.org/x/lint/golint -> golint"
        GOBIN=$(abspath $(GOTOOLS_BINDIR)) go install ./vendor/golang.org/x/lint/golint

+gotool.mockery:
+       $(eval TOOL = ${subst gotool.,,${@}})
+       @echo "Building github.com/vektra/mockery -> mockery"
+       GOPATH=$(abspath $(GOTOOLS_GOPATH)) GO111MODULE=on GOBIN=$(abspath $(GOTOOLS_BINDIR)) go get ${go.fqp.${TOOL}}
+
 # Lock to a versioned dep
 gotool.dep: DEP_VERSION ?= "v0.5.1"
 gotool.dep:
```

各`Dockerfile.in`を以下の通り、修正します。修正ポイントは以下です。

* ベースイメージを前述の有志によるARM64版イメージに変更
* ccenvにインストールするNPMのバージョンをnode v8に合ったものに指定
* toolsにyqをインストール
    * hl-fabric-operator内で宣言的な処理に対応するためfabric-toolsイメージをカスタマイズしており、yqの追加はその一環

```diff
diff --git a/images/buildenv/Dockerfile.in b/images/buildenv/Dockerfile.in
index 0780b8497..7611a3d39 100644
--- a/images/buildenv/Dockerfile.in
+++ b/images/buildenv/Dockerfile.in
@@ -2,7 +2,7 @@
 #
 # SPDX-License-Identifier: Apache-2.0

-FROM _BASE_NS_/fabric-baseimage:_BASE_TAG_
+FROM busan15/fabric-baseimage@sha256:5c69f19febf6359436f37e1cf5d5b7dea414ac378c4d16758c81e81a575d3ddb
 COPY payload/protoc-gen-go /usr/local/bin/
 ADD payload/gotools.tar.bz2 /usr/local/bin/

diff --git a/images/ccenv/Dockerfile.in b/images/ccenv/Dockerfile.in
index 57ad3aefc..42c2802ba 100644
--- a/images/ccenv/Dockerfile.in
+++ b/images/ccenv/Dockerfile.in
@@ -2,8 +2,8 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 #
-FROM _BASE_NS_/fabric-baseimage:_BASE_TAG_
-RUN npm install -g npm@latest
+FROM busan15/fabric-baseimage@sha256:5c69f19febf6359436f37e1cf5d5b7dea414ac378c4d16758c81e81a575d3ddb
+RUN npm install -g npm@6.13.4
 COPY payload/chaintool payload/protoc-gen-go /usr/local/bin/
 ADD payload/goshim.tar.bz2 $GOPATH/src/
 RUN mkdir -p /chaincode/input /chaincode/output
diff --git a/images/orderer/Dockerfile.in b/images/orderer/Dockerfile.in
index 3b8a2f7ac..f608c55a4 100644
--- a/images/orderer/Dockerfile.in
+++ b/images/orderer/Dockerfile.in
@@ -2,7 +2,7 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 #
-FROM _BASE_NS_/fabric-baseos:_BASE_TAG_
+FROM busan15/fabric-baseos@sha256:3509039646399c9b7b86420df118686afc16174cad3561b5731936e2fac0ebdc
 ENV FABRIC_CFG_PATH /etc/hyperledger/fabric
 RUN mkdir -p /var/hyperledger/production $FABRIC_CFG_PATH
 COPY payload/orderer /usr/local/bin
diff --git a/images/peer/Dockerfile.in b/images/peer/Dockerfile.in
index f61c2e58b..45314f2a1 100644
--- a/images/peer/Dockerfile.in
+++ b/images/peer/Dockerfile.in
@@ -2,7 +2,7 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 #
-FROM _BASE_NS_/fabric-baseos:_BASE_TAG_
+FROM busan15/fabric-baseos@sha256:3509039646399c9b7b86420df118686afc16174cad3561b5731936e2fac0ebdc
 ENV FABRIC_CFG_PATH /etc/hyperledger/fabric
 RUN mkdir -p /var/hyperledger/production $FABRIC_CFG_PATH
 COPY payload/peer /usr/local/bin
diff --git a/images/tools/Dockerfile.in b/images/tools/Dockerfile.in
index 52b155ed2..86dcf4e68 100644
--- a/images/tools/Dockerfile.in
+++ b/images/tools/Dockerfile.in
@@ -2,7 +2,7 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 #
-FROM _BASE_NS_/fabric-baseimage:_BASE_TAG_ as builder
+FROM busan15/fabric-baseimage@sha256:5c69f19febf6359436f37e1cf5d5b7dea414ac378c4d16758c81e81a575d3ddb as builder
 WORKDIR /opt/gopath
 RUN mkdir src && mkdir pkg && mkdir bin
 ADD . src/github.com/hyperledger/fabric
@@ -10,9 +10,13 @@ WORKDIR /opt/gopath/src/github.com/hyperledger/fabric
 ENV EXECUTABLES go git curl
 RUN make configtxgen configtxlator cryptogen peer discover idemixgen

-FROM _BASE_NS_/fabric-baseimage:_BASE_TAG_
+FROM busan15/fabric-baseimage@sha256:5c69f19febf6359436f37e1cf5d5b7dea414ac378c4d16758c81e81a575d3ddb
 ENV FABRIC_CFG_PATH /etc/hyperledger/fabric
 RUN apt-get update && apt-get install -y jq
+RUN curl "https://bootstrap.pypa.io/pip/2.7/get-pip.py" -o "get-pip.py" && \
+    python get-pip.py && \
+    pip install yq
 VOLUME /etc/hyperledger/fabric
 COPY --from=builder /opt/gopath/src/github.com/hyperledger/fabric/.build/bin /usr/local/bin
 COPY --from=builder /opt/gopath/src/github.com/hyperledger/fabric/sampleconfig $FABRIC_CFG_PATH
+RUN npm install -g npm@6.13.4
```

修正は以下にコミット済です。

* [Changes for RPI env · nekia/fabric@73c0701](https://github.com/nekia/fabric/commit/73c0701e4b22ea8b4b3ca45dd5b32de24ad736dc)

## カスタムfabric-tools向けの修正（パッチ適用）

`hl-fabric-operator`の作者がHyperledger FabricにPull Requestした以下の修正を取り込んだ`peer`コマンドを含む、fabric-toolsイメージ`hl-fabric-tools`を作成します。本修正は残念ながらmainブランチに取り込まれていません。

* [[FAB-15824] Scripting friendly CLI query methods by raftAtGit · Pull Request #345 · hyperledger/fabric](https://github.com/hyperledger/fabric/pull/345)

このパッチをあてることで、hl-fabric-operator内で宣言的な処理(chaincodeやchannelの状態に応じた処理分岐向けにpeerコマンドを介してchaincodeの状態問い合せがスクリプトで処理しやすくなっている)がしやすくなります。

ただし、本パッチはFabric v2.x向けなので、v1.4向けに少し修正したものを以下にコミット済みです。

* [Apply extention for CLI query method · nekia/fabric@0f2d389](https://github.com/nekia/fabric/commit/0f2d38904a3f5576f5ee16fcb0032dc205367aa8)

本パッチを Fabric v1.4.9タグベース＋Dockerfile/Makefileへの修正を適用したコードベースに適用します。

## イメージのビルドおよびDocker Hubへのプッシュ

以下のコマンドを実行して以下4つのイメージを作成します。ネームスペースは任意です。

* `nekia/fabric-ccenv:1.4.9`
* `nekia/fabric-tools:1.4.9`
* `nekia/fabric-orderer:1.4.9`
* `nekia/fabric-peer:1.4.9`
* `nekia/hl-fabric-tools:1.4.3`

```
make peer-docker
make orderer-docker
make tools-docker
make ccenv

docker tag nekia/fabric-tools:1.4.9 nekia/hl-fabric-tools:1.4.3

docker login
docker push nekia/fabric-ccenv:1.4.9
docker push nekia/fabric-tools:1.4.9
docker push nekia/fabric-orderer:1.4.9
docker push nekia/fabric-peer:1.4.9
docker push nekia/hl-fabric-tools:1.4.3
```

# Argo Workflowのセットアップ

hl-fabric-operatorは、コントローラからArgo Workflowを呼び出して、チャネルの生成やジョイン処理、チェーンコードのインストール等を行っています。ARM64上のKubernetesクラスタ上にArgo Workflowをインストールする場合、[Quick Start - Argo Workflows - The workflow engine for Kubernetes](https://argoproj.github.io/argo-workflows/quick-start/)の手順だと一部のデプロイメントが動作しません。以下の2つの修正が必要です。

* minioのイメージタグをARM64用に変更する
    * `minio/minio:RELEASE.2020-11-25T22-36-25Z-arm64`
* `containerRuntimeExecutor`を`docker`から`pns`に変更する
    * これは私のK8s環境が`containerd`をcontainer runtimeに使用しているため
    * [Workflow Executors - Argo Workflows - The workflow engine for Kubernetes](https://argoproj.github.io/argo-workflows/workflow-executors/)

修正後のマニフェスト`quick-start-postgres.yaml`をK8sクラスタに適用しますが、注意点が1つ。Argo Workflowは、`default`の名前空間に適用する必要があります。Workflow内でGenesis blockやcredentialを生成し、それをHyperledger Fabricネットワークの各ノードと共有する必要があるため、`hl-fabric-operator`がネットワークをデプロイする`default`の名前空間でWorkflowも動いている必要があります。

```shell
kubectl apply -f quick-start-postgres.yaml
```

# PIVT Helm Chartの修正

`hl-fabric-operator`は、別のHyperledger Fabric用のHelm Chartをコントローラから呼び出して、各種処理を実行しています。そのHelm Chartが以下です。本Chartは、`hl-fabric-operator`の作者によって公開されています。

* [hyfen-nl/PIVT: Helm charts for running and operating Hyperledger Fabric in Kubernetes. Previously hosted at https://github.com/APGGroeiFabriek/PIVT.](https://github.com/hyfen-nl/PIVT)

主な修正ポイントは以下の通りです。

* 使用するコンテナイメージの変更
    * Docker Hub上の自分のコンテナレジストリ上のイメージを使うように変更
        * `hyperledger/fabric-*`を`nekia/fabric-*`に変更
* PodにDNSの設定を追加
    * Chaincodeの作成時にDocker in Docker内で名前解決できない問題があったので追加
* ChaincodeのShimが分離された対応
    * Goで書かれたチェーンコードをビルドするためにccenvイメージ内に予めGo向けChaincode Shimパッケージをインストールしておく
* Chaincodeのビルダイメージも自作のccenvイメージを使うように環境変数追加
    * 環境変数`CORE_CHAINCODE_BUILDER`で利用イメージ設定を上書き
* DockerソケットパスをContainerdのソケットパスに変更
    * Chaincodeのイメージの作成についてはDocker in Dockerで対応したので本修正はいらなかったはず
    * Docker in Dockerの話については以下を参照ください
        * [fabric@lists.hyperledger.org | Deprecation of Docker Runtime in Kubernetes - No access to local docker socket](https://lists.hyperledger.org/g/fabric/topic/79950272?p=,,,20,0,0,0::,,,0,0,0,79950272)

具体的な修正は以下を参照ください。

* [Comparing b94a6a53e018fdb7cc5455fb3aa9d8b40a51d54d..977759fc2ec42b8e028e4a83788997a91b4fba1d · nekia/PIVT](https://github.com/nekia/PIVT/compare/b94a6a53e018fdb7cc5455fb3aa9d8b40a51d54d..977759fc2ec42b8e028e4a83788997a91b4fba1d)

この修正をPIVTリポジトリの`master`ブランチに取り込んだら、任意のGithub上へコミットをPushします。次節のオペレータのビルドで参照します。

# `hl-fabric-operator`のリビルド

hl-fabric-operatorが内部で参照するHelm Chartを修正したので、修正版を参照するようにオペレータのコンテナイメージを変更する必要があります。

具体的な修正は以下を参照ください。

* Dockerfile内の各ステージのベースイメージをARM64向けイメージに変更
* fabricのARM64向けバイナリを前述の手順で作成した`fabric-tools`イメージから抽出する手順を追加
* Operatorが参照するChartのレポジトリおよびコミットを変更
    * 自身のGithub上にクローンしたレポジトリに変更

具体的な修正は以下を参照ください。

* [Comparing 4e83e1a11d01786d3617e19051723d519f5c23a3..b43996ed7e5c4a217adba2938ebdfb545b35ca2c · nekia/hl-fabric-operator](https://github.com/nekia/hl-fabric-operator/compare/4e83e1a11d01786d3617e19051723d519f5c23a3..b43996ed7e5c4a217adba2938ebdfb545b35ca2c)

この修正をhl-fabric-operatorリポジトリの`master`ブランチに適用したら以下のコマンドでコンテナイメージをビルドし、Docker HubへPushします。

```
docker build -t nekia/rfabric:v0.2.0 -f ./Dockerfile .
docker push nekia/rfabric:v0.2.0
```

以上で各種コンテナイメージの準備は完了しました。続いて、Fabricネットワークの立ち上げに移ります。

# `hl-fabric-operator`のインストール

オペレータのインストール手順は以下のリリースノートに従います。

* [Release v0.2.0 · raftAtGit/hl-fabric-operator](https://github.com/raftAtGit/hl-fabric-operator/releases/tag/v0.2.0)

ただし、ここでhttp経由で直接参照しているマニフェストをARM64向けに編集が必要なので一旦ローカルにダウンロードしてからK8sクラスタに適用します。

```
wget https://github.com/raftAtGit/hl-fabric-operator/releases/download/v0.2.0/install.yaml
```

修正は以下の2カ所のイメージの変更です。

```diff
diff --git a/install.yaml b/install.yaml
index a63e046..0e67048 100644
--- a/install.yaml
+++ b/install.yaml
@@ -643,32 +643,33 @@ spec:
     metadata:
       labels:
         control-plane: controller-manager
     spec:
       containers:
       - args:
         - --secure-listen-address=0.0.0.0:8443
         - --upstream=http://127.0.0.1:8080/
         - --logtostderr=true
         - --v=10
-        image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
+        image: carlosedp/kube-rbac-proxy:v0.5.0
         name: kube-rbac-proxy
         ports:
         - containerPort: 8443
           name: https
       - args:
         - --health-probe-bind-address=:8081
         - --metrics-bind-address=127.0.0.1:8080
         - --leader-elect
         command:
         - /manager
-        image: raft/rfabric:v0.2.0
+        image: nekia/rfabric:v0.2.0
+        imagePullPolicy: Always
         livenessProbe:
           httpGet:
             path: /healthz
             port: 8081
           initialDelaySeconds: 15
           periodSeconds: 20
         name: manager
         readinessProbe:
           httpGet:
             path: /readyz
```

上記修正を適用した`install.yaml`を適用することで`hl-fabric-operator`のインストールが完了です。

```
kubectl apply -f install.yaml
```

最後にローカルからオペレータにアクセスするCLIを公式の手順通りインストールしたら、オペレータのセットアップは完了です。

```
# Download the binary
curl -sLO https://github.com/raftAtGit/hl-fabric-operator/releases/download/v0.2.0/linux-amd64.tar.gz

# Uncompress
tar xf linux-amd64.tar.gz

# Make binary executable
chmod +x rfabric

# Move binary to path
mv rfabric /usr/local/bin/

# Test installation
rfabric version
```

# Hyperledger Fabricネットワークの立ち上げ

もしここまでお付き合いしてくれてる方がいらしたら、おつかれさまでした。いよいよ大詰めです。
`hl-fabric-operator`リポジトリ内に含まれるサンプルシナリオを使ってHyperledger Fabricネットワークを立ち上げてみます。

ここでも少し修正が必要です。

* GoなチェーンコードソースのShimパッケージパスを修正
    * 前述の通りChaincode Shimパッケージが分離された影響でリポジトリ内のチェーンコードソースのままではエラーが発生します。
* DinDのイメージとしてARM64向けイメージを指定
    * このオペレータでは、Peer PodからChaincodeのコンテナをスタートさせるためにDocker in Dockerの仕組みを使用しています。

```diff
diff --git a/samples/chaincode/even-simpler/even-simpler.go b/samples/chaincode/even-simpler/even-simpler.go
index ba9c012..cb2dd5a 100644
--- a/samples/chaincode/even-simpler/even-simpler.go
+++ b/samples/chaincode/even-simpler/even-simpler.go
@@ -1,17 +1,17 @@
 package main

 import (
        "fmt"

-       "github.com/hyperledger/fabric/core/chaincode/shim"
-       sc "github.com/hyperledger/fabric/protos/peer"
+       "github.com/hyperledger/fabric-chaincode-go/shim"
+       sc "github.com/hyperledger/fabric-protos-go/peer"
 )

 // Define the Smart Contract structure
 type SmartContract struct {
 }

 /*
 * The Init method is called when the Smart Contract "fabcar" is instantiated by the blockchain network
 * Best practice is to have any Ledger initialization in separate function -- see initLedger()
  */
diff --git a/samples/simple/fabric-network.yaml b/samples/simple/fabric-network.yaml
index e4a837e..919f105 100644
--- a/samples/simple/fabric-network.yaml
+++ b/samples/simple/fabric-network.yaml
@@ -102,15 +102,16 @@ spec:


   # additional settings passed to relevant Helm charts
   # see each chart's values.yaml file for details
   hlf-kube:
     peer:
       docker:
         dind:
           # use a side car docker in docker container? required for Kubernetes versions 1.19+
           enabled: true
+          image: arm64v8/docker:18.06.0-dind
   channel-flow: {}
   chaincode-flow: {}
   peer-org-flow: {}
   # backup-flow:
   # restore-flow:
```

この修正が完了したら以下のコマンドでFabricネットワーク構築のWorkflowを開始します。

```
rfabric create samples/simple/fabric-network.yaml
```

# ネットワークの立ち上げ確認

以下のいずれかのコマンドでネットワーク立ち上げ処理の状況を確認できます。

* `rfabric`コマンドで確認

```
$ watch rfabric list
NAME    STATUS  MESSAGE                         WORKFLOW
simple  Ready   HL Fabric Network is ready
```
この`STATUS`が以下の順序で遷移していきます。

```
New
HelmChartInstalled
HelmChartReady
ChannelFlowSubmitted
ChannelFlowCompleted
ChaincodeFlowSubmitted
ChaincodeFlowCompleted
Ready
```

* `argo`コマンドで確認

```
$ argo get hlf-channels-6qsd5
Name:                hlf-channels-6qsd5
Namespace:           default
ServiceAccount:      default
Status:              Succeeded
Conditions:
 PodRunning          False
 Completed           True
Created:             Fri Sep 03 19:02:56 +0900 (19 hours ago)
Started:             Fri Sep 03 19:02:56 +0900 (19 hours ago)
Finished:            Fri Sep 03 19:10:28 +0900 (19 hours ago)
Duration:            7 minutes 32 seconds
Progress:            12/12
ResourcesDuration:   5m54s*(1 cpu),5m54s*(100Mi memory)

STEP                                                                           TEMPLATE                                                     PODNAME                        DURATION  MESSAGE
 ✔ hlf-channels-6qsd5                                                          channels
 ├───✔ channel--common                                                         channel--common
 │   ├───✔ create-channel--common                                              create-channel--common
 │   │   └───✔ maybe-create-channel--common--Karga(0)                          maybe-create-channel--common--Karga                          hlf-channels-6qsd5-1586097216  1m
 │   ├───✔ join-channel--common                                                join-channel--common
 │   │   └─┬─✔ maybe-join-channel--common--Atlantis--peer0(0)                  maybe-join-channel--common--Atlantis--peer0                  hlf-channels-6qsd5-4027337367  14s
 │   │     ├─✔ maybe-join-channel--common--Karga--peer0(0)                     maybe-join-channel--common--Karga--peer0                     hlf-channels-6qsd5-10066797    15s
 │   │     └─✔ maybe-join-channel--common--Nevergreen--peer0(0)                maybe-join-channel--common--Nevergreen--peer0                hlf-channels-6qsd5-1999692950  4m
 │   └───✔ update-channel--common                                              update-channel--common
 │       └─┬─✔ maybe-update-channel--common--Karga(0)                          maybe-update-channel--common--Karga                          hlf-channels-6qsd5-1621770838  10s
 │         ├─✔ maybe-update-channel--common--Atlantis(0)                       maybe-update-channel--common--Atlantis                       hlf-channels-6qsd5-2737413770  10s
 │         └─✔ maybe-update-channel--common--Nevergreen(0)                     maybe-update-channel--common--Nevergreen                     hlf-channels-6qsd5-2877294049  10s
 └───✔ channel--private-karga-atlantis                                         channel--private-karga-atlantis
     ├───✔ create-channel--private-karga-atlantis                              create-channel--private-karga-atlantis
     │   └───✔ maybe-create-channel--private-karga-atlantis--Karga(0)          maybe-create-channel--private-karga-atlantis--Karga          hlf-channels-6qsd5-1851545531  9s
     ├───✔ join-channel--private-karga-atlantis                                join-channel--private-karga-atlantis
     │   └─┬─✔ maybe-join-channel--private-karga-atlantis--Atlantis--peer0(0)  maybe-join-channel--private-karga-atlantis--Atlantis--peer0  hlf-channels-6qsd5-3109638900  8s
     │     └─✔ maybe-join-channel--private-karga-atlantis--Karga--peer0(0)     maybe-join-channel--private-karga-atlantis--Karga--peer0     hlf-channels-6qsd5-1468716520  9s
     └───✔ update-channel--private-karga-atlantis                              update-channel--private-karga-atlantis
         └─┬─✔ maybe-update-channel--private-karga-atlantis--Atlantis(0)       maybe-update-channel--private-karga-atlantis--Atlantis       hlf-channels-6qsd5-1479374483  11s
           └─✔ maybe-update-channel--private-karga-atlantis--Karga(0)          maybe-update-channel--private-karga-atlantis--Karga          hlf-channels-6qsd5-191283417   8s
```

# さいごに

内容は、Hyperledger FabricのARM64環境を如何にしてX64上で用意するか、を中心としたものになりましたが、オペレータの実装例やHelm Chartの構成、Argo Workflowを利用した処理シーケンスの定義方法など、Kubernetes関連の学びもそれなりにあり、楽しむことができました。ようやく環境が整ったので、今後のHelm ChartやOperatorの作成に活かしたいところです。