fabric源碼解析4——配置系統

fabric源碼解析4——配置系統

fabric的配置系統是程序原始數據的來源之一,雖然簡單卻很重要。在閱讀源碼過程中對於具象化程序也很有幫助。在分析peer的具體交易工作之前,我們可以先分析一下fabric的配置系統。我們還將我們的目光聚焦在/fabric/peer/main.go的main函數中,除了一系列mainCmd的命令操作,還有viper進行的一系列配置操作,並通過err := common.InitConfig(cmdRoot)進行了配置的初始化。

fabric索取配置的途徑有:環境變量,命令行參數,各種格式的配置文件。其中以配置文件爲主,環境變量和命令行參數輔助,三者可以相互作用。主要的配置文件有core.yaml,orderer.yaml等,在/fabric/sampleconfig中有示例。主要使用的配置代碼集中在/fabric/core/config下。

viper簡介

fabric的配置系統主要運用第三方包viper,可在github.com/spf13/viper下載。viper可以對系統環境變量,yaml/json等格式的配置文件甚至是遠程配置進行讀取和設置,並可以在不重啓服務的情況下動態設置新的配置項的值並使之實時生效,是一個專門處理配置的解決方案。 而且,viper,眼鏡蛇,稱自己與cobra(見peer命令結構一文)是companion,足見使用viper的理由。

viper的基礎用法如下:

//設置一個要讀取的配置文件名(不包含後綴),一個viper只支持一個文件名
viper.SetConfigName("config")
//設置一個搜索配置文件的路徑,viper的搜索路徑可以有多個
viper.AddConfigPath("/etc/appname/")
viper.AddConfigPath(".")
//讀取配置文件
viper.ReadInConfig()
//獲取其中一個name項的值
viper.Get("name")
//將name的值設置爲Bill
viper.Set("name", "Bill")

viper搜索路徑和文件

peer命令對core.yaml的引入也是通過viper,具體過程如下:

  • /fabric/peer/main.go中定義const cmdRoot = "core"
  • main函數中調用err := common.InitConfig(cmdRoot),該參數一路向下傳遞。
  • InitConfig函數在/fabric/peer/common/common.go中定義,其中調用了config.InitViper(nil, cmdRoot)viper.ReadInConfig()
  • InitViper在/fabric/core/config/config.go中定義,接收cmdRoot作爲參數,最終調用了viper.SetConfigName(),也即將core設置爲了配置文件名。
  • common.InitConfig(cmdRoot)中的viper.ReadInConfig()則讀取了該配置文件

orderer命令則使用orderer.yaml配置文件,由viper引入,具體過程如下:

  • 在/fabric/orderer/main.go中main函數調用了config.Load()
  • Load在/fabric/orderer/localconfig/config.go中定義。該文件中定義了Prefix = "ORDERER"configName string,並在init初始化函數中將configName賦值爲strings.ToLower(Prefix),即orderer,也即所用的配置文件名爲orderer。Load函數新建了一個用於orderer自己的viper,並調用了cf.InitViper(config, configName),其中config參數爲新建的用於orderer自身的viper,configName爲配置文件名orderer
  • InitViper在/fabric/core/config/config.go中定義,最終調用了viper.SetConfigName(),也即將orderer設置爲了配置文件名
  • Load隨後調用了config.ReadInConfig(),讀取了配置文件

InitViper

上述步驟中peer和orderer在初始化配置文件時,最終都將調用的終點指向了/fabric/core/config/config.go中定義InitViper()。下面集中分析InitViper。

  • 首先判斷環境變量FABRIC_CFG_PATH是否有值,如果有值,則是手工定義了FABRIC的配置文件所在路徑。參考Getting Started中關於手工設置export FABRIC_CFG_PATH=$PWD(當前目錄)。

  • 若沒有定義該環境變量的值,則用代碼添加三個路徑作爲搜索配置文件的路徑:當前工作目錄,$GOPATH/src/github.com/hyperledger/fabric/sampleconfig,/etc/hyperledger/fabric

    • 當前工作目錄,調用addConfigPath(v, “./”)添加,其內部調用的是viper.AddConfigPath()。

    • $GOPATH/src/github.com/hyperledger/fabric/sampleconfig,通過調用AddDevConfigPath(v)添加。

      • AddDevConfigPath首先調用GetDevConfigDir(),讀取GOPATHsrc/github.com/hyperledger/fabric/sampleconfigfilepath.Join GOPATH和src/github.com/hyperledger/fabric/sampleconfig,形成完整的路徑並返回。
      • AddDevConfigPath接着調用addConfigPath函數,其內部調用的是viper.AddConfigPath()。
    • /etc/hyperledger/fabric。定義了OfficialPath = “/etc/hyperledger/fabric”常量,如果該路徑存在,則調用addConfigPath加入該路徑。
  • 調用SetConfigName()設置配置文件名,所指的的配置文件名configName是由參數傳遞進來的。

由經由InitViper,形成了以下viper配置:

搜索路徑(二選一)

  • FABRIC_CFG_PATH指定的路徑
  • ./,$GOPATH/src/github.com/hyperledger/fabric/sampleconfig,/etc/hyperledger/fabric

搜索的配置文件名

  • core —— 核心配置,供各個模塊使用
  • orderer —— orderer配置,orderer使用

另外注意InitViper的第一個參數,v *viper.Viper。在InitViper函數中,無論是添加搜索路徑(使用的是addConfigPath函數),還是設置要搜索的配置文件名(viper自身的SetConfigName函數),都分爲全局的viper和特定的viper(也就是參數v)。最終由viper.AddConfigPath或viper.SetConfigName完成的,則是全局的,由v.AddConfigPath或v.SetConfigName完成的,則是特定的。這樣就可以很方便的初始化需要單獨使用viper的模塊,如orderer就是單獨使用一條毒蛇,其在/fabric/orderer/localconfig/config.go中的Load函數中,config := viper.New()新養了一條自己的蛇,然後將此蛇通過參數傳給InitViper,cf.InitViper(config, configName)。

安全文件配置

安全配置相關的代碼在/fabric/peer/main.go中沒有體現,而是在/fabric/peer/node/start.go中的serve函數中才初次出現。若grpc服務中使用了TLS網絡,則需要.key,.crt,.ca文件配套文件。在此簡略介紹,關於TLS,將會在將來專門的文章中詳細介紹。

在/fabric/peer/node/start.go中的serve函數中secureConfig, err := peer.GetSecureConfig()獲取安全配置。

使用的安全配置結構爲/fabric/core/comm/server.go中定義的SecureServerConfig,用於一個grpc服務端實例。
.key,.crt,.ca文件所在的目錄都是在core.yaml中定義都的tls文件夾中,當使用TLS網絡時,會讀取這些文件的數據到SecureServerConfig對象中。在GetSecureConfig()函數中,使用ioutil.ReadFile讀取由/fabric/core/config/config.go中定義的config.GetPath(“…”)函數獲取的tls路徑下的相應文件。如/etc/hyperledger/fabric/tls/server.crt。

命令選項配置

以peer start命令爲例,在/fabric/peer/node/start.go中startCmd()函數中,flags.BoolVarP(&chaincodeDevMode, "peer-chaincodedev", "", false,"Whether peer in chaincode development mode")設置了peer start命令的選項之一爲peer-chaincodedev,用於賦值文件中的全局變量chaincodeDevMode,該變量指定了chaincode的模式。chaincode的模式在core.yaml中也有定義,chaincode.mode的值爲net,爲默認選項。而當執行peer start 命令時指定了選項peer-chaincodedev=true,也即將chaincodeDevMode賦值爲true,在serve()函數中,就會使用viper.Set("chaincode.mode", chaincode.DevModeUserRunsChaincode)將chaincode的模式值設置成了dev

環境變量配置

在fabric目前的階段,各個peer都是在容器中運行的,因此環境變量指的是各個容器中的環境變量。在各個容器的啓動腳本中對容器的一些環境變量也進行了設置。在peer-base-no-tls.yaml(見源碼解析1——線頭)中,如peer容器中,設置瞭如下環境變量:

    - CORE_PEER_ADDRESSAUTODETECT=true
    - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
    - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=e2ecli_default
    - CORE_LOGGING_LEVEL=ERROR
    ...

在fabric/peer/main.go中的開始,即對容器的環境變量進行了獲取並設置:

    //設置了環境變量前置,在此也就是peer
    viper.SetEnvPrefix(cmdRoot)
    //將環境變量加載進來了
    viper.AutomaticEnv()
    replacer := strings.NewReplacer(".", "_")
    //將環境變量中的_換成.,這樣就和yaml文件的配置相匹配了。
    //因爲viper讀取yaml文件所形成的配置項就是按層級並以.分隔的格式,如peer.address
    viper.SetEnvKeyReplacer(replacer)
發佈了30 篇原創文章 · 獲贊 142 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章