【Hyperledger Fabric】環境構築でPROXYの壁に盛大に阻まれた話

お久しぶりです
どーも、のぶこふです。

環境構築時に、プロキシさんに盛大に阻まれ、ようやくどうにかなったので、備忘録として残しておきます。（2週間近くかかったのは内緒）
行ったことは、みんなおなじみの「fabric-samplesのfabcarを動かす」です。

なお、各種にはある程度PROXYが設定してあるものと想定します。
（どの程度やねん）

## 環境
* ホスト：Windows 10
* 実行環境：CentOS7 on VirtualBox
* Hyperledger Fabric 1.4.0
* 巨大な壁：社内PROXY

## エラー

特にハマったのが「`./startFabric.sh javascript`」を実行した時の下記エラー①と、クエリ発行時（`node query.js`）の下記エラー②です。

```terminal:エラー①
Submitting initLedger transaction to smart contract on mychannel
+ docker exec -e CORE_PEER_LOCALMSPID=Org1MSP -e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt cli peer --tls=true --cafile=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --orderer=orderer.example.com:7050 chaincode invoke -C mychannel -n fabcar -c '{"function":"initLedger","Args":[]}' --waitForEvent --waitForEventTimeout 300s --peerAddresses peer0.org1.example.com:7051 --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
Error: endorsement failure during invoke. response: status:500 message:"failed to execute transaction e669b01d7dfbf6c5ef0c3f573e8d23e79a1a4f375bd944578bc768e4efdb70a0: [channel mychannel] could not launch chaincode fabcarv1:c79fbaddd7150c13e1f14ed606339d8660bcc5af770ac6e127bf8174869faf0a: error starting container: error starting container: Failed to generate platform-specific docker build: Error returned from build: 1 \"npm ERR! code EAI_AGAIN\nnpm ERR! errno EAI_AGAIN\nnpm ERR! request to https://registry.npmjs.org/fabric-contract-api failed, reason: getaddrinfo EAI_AGAIN registry.npmjs.org registry.npmjs.org:443\n\nnpm ERR! A complete log of this run can be found in:\nnpm ERR!     /root/.npm/_logs/2019-10-11T05_22_28_582Z-debug.log\n\""
```

```terminal:エラー②
2019-10-11T05:48:11.930Z - error: [Remote.js]: Error: Failed to connect before the deadline URL:grpcs://localhost:7051 timeout:3000
2019-10-11T05:48:11.931Z - error: [Channel.js]: Error: Failed to connect before the deadline URL:grpcs://localhost:7051 timeout:3000
2019-10-11T05:48:14.948Z - error: [Remote.js]: Error: Failed to connect before the deadline URL:grpcs://localhost:8051 timeout:3000
2019-10-11T05:48:14.948Z - error: [Channel.js]: Error: Failed to connect before the deadline URL:grpcs://localhost:8051 timeout:3000
2019-10-11T05:48:14.949Z - error: [Network]: _initializeInternalChannel: Unable to initialize channel. Attempted to contact 2 Peers. Last error was Error: Failed to connect before the deadline URL:grpcs://localhost:8051 timeout:3000
Failed to evaluate transaction: Error: Unable to initialize channel. Attempted to contact 2 Peers. Last error was Error: Failed to connect before the deadline URL:grpcs://localhost:8051 timeout:3000
```

## 解決策（対応策）

解決策というか、私の対応としては下記になります。

* エラー①
    * 言語を指定せずに「`./startFabric.sh`」として実行する
    * 言語を指定しないと、デフォルトでGolangとなりますが、さしあたって特に問題ありませんでした
        * 上記実行後、`cd javascript/`　～　`node invoke.js`まで実行確認済み
    * Javascriptをどうしても・・・というのであれば、`fabric-samples/scripts/ci_scripts/fabcar.sh`の`npm install`の記述前にプロキシ設定を入れれば、どうにかなったはずです。

```sh:fabric-samples/scripts/ci_scripts/fabcar.sh
30 for LANGUAGE in ${LANGUAGES}; do
31     echo -e "\033[1m ${LANGUAGE} Test\033[0m"
32     echo -e "\033[32m starting fabcar test (${LANGUAGE})" "\033[0m"
33     # Start Fabric, and deploy the smart contract
34     ./startFabric.sh ${LANGUAGE}
35     copy_logs $? fabcar-${LANGUAGE}
36     # If an application exists for this language, test it
37     if [ -d ${LANGUAGE} ]; then
38         pushd ${LANGUAGE}
39         if [ ${LANGUAGE} = "javascript" -o ${LANGUAGE} = "typescript" ]; then
40             if [ ${LANGUAGE} = "javascript" ]; then
41                 COMMAND=node
42                 PREFIX=
43                 SUFFIX=.js
                   # <<<<< 下記を追加
                   npm -g config set proxy http://host:port
                   npm -g config set https-proxy http://host:port
                   npm -g config set registry http://host:port
44                 npm install
45             elif [ ${LANGUAGE} = "typescript" ]; then
46                 COMMAND=node
47                 PREFIX=dist/
48                 SUFFIX=.js
                   # <<<<< 下記を追加
                   npm -g config set proxy http://host:port
                   npm -g config set https-proxy http://host:port
                   npm -g config set registry http://host:port
49                 npm install
50                 npm run build
51             fi
```

* エラー②
    * `no_proxy`に`localhost,127.0.0.1`を設定する
    * これはどうやらgrpcの既知のバグ？らしくて、プロキシ設定を行うとローカルでもプロキシが反映されてしまうようなので「`no_proxy`を設定して、反映させないようにしましょうね」ということらしいです
    * `no_proxy`が設定できれば、どのような方法でも良いと思いますが、私は「`/etc/environment`」を修正して反映（`source /etc/environment`）させました
        * 念の為に、大文字と小文字で設定

```config:/etc/environment
http_proxy="http://host:port"
https_proxy="http://host:port"
HTTP_PROXY="http://host:port"
HTTPS_PROXY="http://host:port"
ftp_proxy="ftp://host:port"
FTP_PROXY="ftp://host:port"
no_proxy="localhost,127.0.0.1,.hoge.jp"
NO_PROXY="localhost,127.0.0.1,.hoge.jp"
```

## おわりに
意外と設定の漏れがあるものですね・・・・
ここにたどり着くまで、iptables（ファイアウォール）の設定を見直したりとか、OSをUbuntuにしてみるとか、HLFのバージョンを変えてみるとか、あの手この手を尽くし果たした感じでした。
なんならK8sを導入しようかとも考えました（きっと意味なかったのだろうけど）

これでようやく開発のスタートラインに立てました。
久々にHLF Lifeを過ごそうと思います。


ということで、2.0-alphaの冒険にでも出ますかね。
（fabcarを動かすだけでも`fabric-samples/first-network/byfn.sh`、`fabric-samples/first-network/configtx.yaml`、`fabric-samples/fabcar/javascript/enrollAdmin.js,enrollAdmin.js,query.js,invoke.js`、あたりを修正しないと動かないことは確認済み）

今回は以上です。
ありがとうございました。