Hyperledger1.4 Fabric to kubernetes
Hyperledger Fabric
环境说明
系统说明
IP | Hostname | 标识 |
---|---|---|
192.168.0.247 | kubernetes-1 | K8S-Master and Kubectl-Cli |
192.168.0.248 | kubernetes-2 | K8S-Master and Node |
192.168.0.249 | kubernetes-3 | K8S-Node and NFS Server |
服务说明
名称 | 版本 |
---|---|
CentOS | 7 x64 |
Hyperledger Fabric | 1.4 |
kubernetes | 1.13.2 |
docker | 18.06.1-ce |
Fabric 环境配置
docker 配置
由于 实例化 chaincode 需要由 docker 创建容器
而 这个容器需要跟 k8s 里的 peer svc 通信, 所以需要额外配置
# 配置 docker 配置 修改 docker 选项 DOCKER_OPTS 在 DOCKER_OPTS 中 增加 --dns 添加 k8s 中 dns 的 ip [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get svc -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE coredns ClusterIP 10.233.0.3 <none> 53/UDP,53/TCP,9153/TCP 4d23h # 我这个环境中 coredns IP 为 10.233.0.3 # 所以 添加 --dns 10.233.0.3
cryptogen 下载
cryptogen 用于简化生成 fabric 所需要的所有证书
# 官方离线下载地址为 https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric/hyperledger-fabric/ # 选择相应版本 CentOS 选择 linux-amd64-1.4.0 # Mac 选择 darwin-amd64-1.4.0 # 创建工作目录 ( 后续所有文件都存于此目录中 ) mkdir -p /opt/jicki cd /opt/jicki wget https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric/hyperledger-fabric/linux-amd64-1.4.0/hyperledger-fabric-linux-amd64-1.4.0.tar.gz # 解压文件 [root@kubernetes-1 /opt/jicki]# tar zxvf hyperledger-fabric-linux-amd64-1.4.0.tar.gz # 删除 config 这个文件夹, 这里用不到 [root@kubernetes-1 /opt/jicki]# rm -rf config # 查看文件 [root@kubernetes-1 /opt/jicki]# tree . └── bin ├── configtxgen ├── configtxlator ├── cryptogen ├── discover ├── get-docker-images.sh ├── idemixgen ├── orderer └── peer 1 directory, 8 files # 为方便使用 我们配置一个 环境变量 vi /etc/profile # fabric env export PATH=$PATH:/opt/jicki/bin # 使文件生效 source /etc/profile
Fabric 源码下载
[root@kubernetes-1 /opt/jicki]# git clone https://github.com/hyperledger/fabric
生成 证书
# 创建 cryptogen.yaml 文件, 1.4版本 crypto-config.yaml 文件更改为 cryptogen.yaml vi cryptogen.yaml OrdererOrgs: - Name: Orderer Domain: orgorderer1 CA: Country: CN Province: GuangDong Locality: ShenZhen Specs: - Hostname: orderer0 PeerOrgs: - Name: Org1 Domain: org1 EnableNodeOUs: true CA: Country: CN Province: GuangDong Locality: ShenZhen Template: Count: 2 Users: Count: 1 - Name: Org2 Domain: org2 EnableNodeOUs: true CA: Country: CN Province: GuangDong Locality: ShenZhen Template: Count: 2 Users: Count: 1
# 生成证书 [root@kubernetes-1 /opt/jicki]# cryptogen generate --config=./cryptogen.yaml org1 org2 # 查看生成目录结构 [root@kubernetes-1 /opt/jicki]# tree -d crypto-config/ crypto-config/ ├── ordererOrganizations │ └── orgorderer1 │ ├── ca │ ├── msp │ │ ├── admincerts │ │ ├── cacerts │ │ └── tlscacerts │ ├── orderers │ │ └── orderer0.orgorderer1 │ │ ├── msp │ │ │ ├── admincerts │ │ │ ├── cacerts │ │ │ ├── keystore │ │ │ ├── signcerts │ │ │ └── tlscacerts │ │ └── tls │ ├── tlsca │ └── users │ └── Admin@orgorderer1 │ ├── msp │ │ ├── admincerts │ │ ├── cacerts │ │ ├── keystore │ │ ├── signcerts │ │ └── tlscacerts │ └── tls └── peerOrganizations ├── org1 │ ├── ca │ ├── msp │ │ ├── admincerts │ │ ├── cacerts │ │ └── tlscacerts │ ├── peers │ │ ├── peer0.org1 │ │ │ ├── msp │ │ │ │ ├── admincerts │ │ │ │ ├── cacerts │ │ │ │ ├── keystore │ │ │ │ ├── signcerts │ │ │ │ └── tlscacerts │ │ │ └── tls │ │ └── peer1.org1 │ │ ├── msp │ │ │ ├── admincerts │ │ │ ├── cacerts │ │ │ ├── keystore │ │ │ ├── signcerts │ │ │ └── tlscacerts │ │ └── tls │ ├── tlsca │ └── users │ ├── Admin@org1 │ │ ├── msp │ │ │ ├── admincerts │ │ │ ├── cacerts │ │ │ ├── keystore │ │ │ ├── signcerts │ │ │ └── tlscacerts │ │ └── tls │ └── User1@org1 │ ├── msp │ │ ├── admincerts │ │ ├── cacerts │ │ ├── keystore │ │ ├── signcerts │ │ └── tlscacerts │ └── tls └── org2 ├── ca ├── msp │ ├── admincerts │ ├── cacerts │ └── tlscacerts ├── peers │ ├── peer0.org2 │ │ ├── msp │ │ │ ├── admincerts │ │ │ ├── cacerts │ │ │ ├── keystore │ │ │ ├── signcerts │ │ │ └── tlscacerts │ │ └── tls │ └── peer1.org2 │ ├── msp │ │ ├── admincerts │ │ ├── cacerts │ │ ├── keystore │ │ ├── signcerts │ │ └── tlscacerts │ └── tls ├── tlsca └── users ├── Admin@org2 │ ├── msp │ │ ├── admincerts │ │ ├── cacerts │ │ ├── keystore │ │ ├── signcerts │ │ └── tlscacerts │ └── tls └── User1@org2 ├── msp │ ├── admincerts │ ├── cacerts │ ├── keystore │ ├── signcerts │ └── tlscacerts └── tls
生成初始化Fabric文件
# 创建 configtx.yaml 文件 vi configtx.yaml Organizations: - &OrdererOrg Name: Orgorderer1MSP ID: Orgorderer1MSP MSPDir: crypto-config/ordererOrganizations/orgorderer1/msp Policies: Readers: Type: Signature Rule: "OR('Orgorderer1MSP.member')" Writers: Type: Signature Rule: "OR('Orgorderer1MSP.member')" Admins: Type: Signature Rule: "OR('Orgorderer1MSP.admin')" - &Org1 Name: Org1MSP ID: Org1MSP MSPDir: crypto-config/peerOrganizations/org1/msp Policies: Readers: Type: Signature Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')" Writers: Type: Signature Rule: "OR('Org1MSP.admin', 'Org1MSP.client')" Admins: Type: Signature Rule: "OR('Org1MSP.admin')" AnchorPeers: - Host: peer0.org1 Port: 7051 - &Org2 Name: Org2MSP ID: Org2MSP MSPDir: crypto-config/peerOrganizations/org2/msp Policies: Readers: Type: Signature Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')" Writers: Type: Signature Rule: "OR('Org2MSP.admin', 'Org2MSP.client')" Admins: Type: Signature Rule: "OR('Org2MSP.admin')" AnchorPeers: - Host: peer0.org2 Port: 7051 Capabilities: Channel: &ChannelCapabilities V1_3: true Orderer: &OrdererCapabilities V1_1: true Application: &ApplicationCapabilities V1_3: true V1_2: false V1_1: false Application: &ApplicationDefaults Organizations: Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" Capabilities: <<: *ApplicationCapabilities Orderer: &OrdererDefaults OrdererType: kafka Addresses: - orderer0.orgorderer1:7050 BatchTimeout: 2s BatchSize: MaxMessageCount: 10 AbsoluteMaxBytes: 99 MB PreferredMaxBytes: 512 KB Kafka: Brokers: - kafka-0.broker.kafka:9092 - kafka-1.broker.kafka:9092 - kafka-2.broker.kafka:9092 - kafka-3.broker.kafka:9092 Organizations: Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" BlockValidation: Type: ImplicitMeta Rule: "ANY Writers" Channel: &ChannelDefaults Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" Capabilities: <<: *ChannelCapabilities Profiles: TwoOrgsOrdererGenesis: <<: *ChannelDefaults Orderer: <<: *OrdererDefaults Organizations: - *OrdererOrg Capabilities: <<: *OrdererCapabilities Consortiums: SampleConsortium: Organizations: - *Org1 - *Org2 TwoOrgsChannel: Consortium: SampleConsortium Application: <<: *ApplicationDefaults Organizations: - *Org1 - *Org2 Capabilities: <<: *ApplicationCapabilities SampleDevModeKafka: <<: *ChannelDefaults Capabilities: <<: *ChannelCapabilities Orderer: <<: *OrdererDefaults OrdererType: kafka Kafka: Brokers: - kafka-0.broker.kafka:9092 - kafka-1.broker.kafka:9092 - kafka-2.broker.kafka:9092 - kafka-3.broker.kafka:9092 Organizations: - *OrdererOrg Capabilities: <<: *OrdererCapabilities Application: <<: *ApplicationDefaults Organizations: - <<: *OrdererOrg Consortiums: SampleConsortium: Organizations: - *Org1 - *Org2
# 首先需要创建一个文件夹 mkdir -p /opt/jicki/channel-artifacts # 创建 创世区块 TwoOrgsOrdererGenesis 是 # configtx.yaml 中 Profiles 字段下的名称 [root@kubernetes-1 /opt/jicki]# configtxgen -profile TwoOrgsOrdererGenesis \ -outputBlock ./channel-artifacts/genesis.block
# 下面来生成一个 peer 服务 中使用的 tx 文件 TwoOrgsChannel 名称为 configtx.yaml 中 Profiles 字段下的,这里必须指定上面的 channelID
[root@kubernetes-1 /opt/jicki]# configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
# 定义组织 生成锚节点更新文件 # Org1MSP [root@kubernetes-1 /opt/jicki]# configtxgen -profile TwoOrgsChannel \ -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP # Org2MSP [root@kubernetes-1 /opt/jicki]# configtxgen -profile TwoOrgsChannel \ -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
# 查看生成文件 [root@kubernetes-1 /opt/jicki]# tree channel-artifacts/ channel-artifacts/ ├── channel.tx ├── genesis.block ├── Org1MSPanchors.tx └── Org2MSPanchors.tx 0 directories, 4 files
配置 NFS StorageClass
NFS 用于 k8s 中 文件挂载,共享
安装NFS
# 服务端 安装 NFS 软件 [root@kubernetes-3 ~]# yum -y install nfs-utils rpcbind # k8s 所有节点 安装 NFS 客户端 [root@kubernetes-1 ~]# yum -y install nfs-utils [root@kubernetes-2 ~]# yum -y install nfs-utils
配置 NFS
这里需要创建几个目录 /opt/nfs/data, /opt/nfs/fabric/
/opt/nfs/data 用于存放 zk, kafka 数据
/opt/nfs/fabric 用于存放 fabric 所有的文件
# 创建目录 [root@kubernetes-3 ~]# mkdir -p /opt/nfs/{data,fabric} # 修改配置文件 [root@kubernetes-3 ~]# vi /etc/exports 增加 /opt/nfs/data 192.168.0.0/24(rw,sync,no_root_squash) /opt/nfs/fabric 192.168.0.0/24(rw,sync,no_root_squash)
# 启动 NFS 服务 [root@kubernetes-3 ~]# systemctl enable rpcbind.service [root@kubernetes-3 ~]# systemctl enable nfs-server.service [root@kubernetes-3 ~]# systemctl start rpcbind.service [root@kubernetes-3 ~]# systemctl start nfs-server.service [root@kubernetes-3 ~]# systemctl status rpcbind.service [root@kubernetes-3 ~]# systemctl status nfs-server.service # 查看服务 [root@kubernetes-3 ~]# showmount -e 192.168.0.249 Export list for 192.168.0.249: /opt/nfs/fabric 192.168.0.0/24 /opt/nfs/data 192.168.0.0/24
配置 NFS Client Provisioner
官方 说明 https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client
# 下载官方 yaml 文件 wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/nfs-client/deploy/rbac.yaml wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/nfs-client/deploy/deployment.yaml wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/nfs-client/deploy/class.yaml
# 修改 deployment.yaml 文件 vi deployment.yaml apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner --- kind: Deployment apiVersion: extensions/v1beta1 metadata: name: nfs-client-provisioner spec: replicas: 1 strategy: type: Recreate template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: quay.io/external_storage/nfs-client-provisioner:latest volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: fuseim.pri/ifs - name: NFS_SERVER value: 192.168.0.249 - name: NFS_PATH value: /opt/nfs/data volumes: - name: nfs-client-root nfs: server: 192.168.0.249 path: /opt/nfs/data
# 修改 class.yaml , 这里修改 name 名称 vi class.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: zk-kafka-nfs-storage provisioner: fuseim.pri/ifs parameters: archiveOnDelete: "false"
# 导入 yaml 文件 [root@kubernetes-1 /opt/yaml/nfs-client]# kubectl apply -f . storageclass.storage.k8s.io/fabric-nfs-storage created serviceaccount/nfs-client-provisioner created clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created deployment.extensions/nfs-client-provisioner created clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
# 查看服务 [root@kubernetes-1 /opt/yaml/nfs-client]# kubectl get storageclass NAME PROVISIONER AGE zk-kafka-nfs-storage fuseim.pri/ifs 27s [root@kubernetes-1 /opt/yaml/nfs-client]# kubectl get pods NAME READY STATUS RESTARTS AGE nfs-client-provisioner-578785c589-qlgnx 1/1 Running 0 2m24s
部署 fabric
创建 zookeeper
[root@kubernetes-1 /opt/jicki/k8s-yaml]# vi kafka-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: kafka
# 创建 zk [root@kubernetes-1 /opt/jicki/k8s-yaml]# vi zookeeper.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: zoo namespace: kafka spec: serviceName: "zoo" replicas: 4 template: metadata: labels: app: zookeeper spec: terminationGracePeriodSeconds: 10 containers: - name: zookeeper image: hyperledger/fabric-zookeeper:0.4.14 ports: - containerPort: 2181 name: client - containerPort: 2888 name: peer - containerPort: 3888 name: leader-election volumeMounts: - name: zkdata mountPath: /var/lib/zookeeper volumeClaimTemplates: - metadata: name: zkdata annotations: volume.beta.kubernetes.io/storage-class: "zk-kafka-nfs-storage" spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 10Gi --- apiVersion: v1 kind: Service metadata: name: zoo namespace: kafka spec: ports: - port: 2888 name: peer - port: 3888 name: leader-election clusterIP: None selector: app: zookeeper --- apiVersion: v1 kind: Service metadata: name: zookeeper namespace: kafka spec: ports: - port: 2181 name: client selector: app: zookeeper
# 导入 yaml 文件 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f namespace.yaml [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f zookeeper.yaml
# 查看服务 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get all -n kafka NAME READY STATUS RESTARTS AGE pod/zoo-0 1/1 Running 0 20m pod/zoo-1 1/1 Running 0 9m11s pod/zoo-2 1/1 Running 0 111s pod/zoo-3 1/1 Running 0 108s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/zoo ClusterIP None <none> 2888/TCP,3888/TCP 21m service/zookeeper ClusterIP 10.233.22.96 <none> 2181/TCP 21m NAME READY AGE statefulset.apps/zoo 4/4 20m
创建 kafka
vi kafka.yaml apiVersion: apps/v1beta1 kind: StatefulSet metadata: name: kafka namespace: kafka spec: serviceName: "broker" replicas: 4 template: metadata: labels: app: kafka spec: terminationGracePeriodSeconds: 10 containers: - name: broker image: hyperledger/fabric-kafka:0.4.14 ports: - containerPort: 9092 env: - name: KAFKA_MESSAGE_MAX_BYTES value: "102760448" - name: KAFKA_REPLICA_FETCH_MAX_BYTES value: "102760448" - name: KAFKA_UNCLEAN_LEADER_ELECTION_ENABLE value: "false" - name: KAFKA_ZOOKEEPER_CONNECT value: zoo-0.zoo:2181,zoo-1.zoo:2181,zoo-2.zoo:2181,zoo-3.zoo:2181 - name: KAFKA_PORT value: "9092" - name: GODEBUG value: netdns=go - name: KAFKA_ZOOKEEPER_CONNECTION_TIMEOUT_MS value: "30000" - name: KAFKA_LOG_DIRS value: /opt/kafka/data - name: KAFKA_LOG_RETENTION_MS value: "-1" volumeMounts: - name: kafkadata mountPath: /opt/kafka/data volumeClaimTemplates: - metadata: name: kafkadata annotations: volume.beta.kubernetes.io/storage-class: "zk-kafka-nfs-storage" spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 20Gi --- apiVersion: v1 kind: Service metadata: name: kafka namespace: kafka spec: ports: - port: 9092 selector: app: kafka --- apiVersion: v1 kind: Service metadata: name: broker namespace: kafka spec: ports: - port: 9092 clusterIP: None selector: app: kafka
# 导入 yaml 文件 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f kafka.yaml statefulset.apps/kafka created service/kafka created service/broker created
# 查看服务 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get pods -n kafka NAME READY STATUS RESTARTS AGE kafka-0 1/1 Running 0 2m26s kafka-1 1/1 Running 0 100s kafka-2 1/1 Running 0 53s kafka-3 1/1 Running 0 43s [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get svc -n kafka NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE broker ClusterIP None <none> 9092/TCP 2m45s kafka ClusterIP 10.233.48.233 <none> 9092/TCP 2m45s [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get statefulset -n kafka NAME READY AGE kafka 4/4 3m13s
创建 fabric 服务
初始化
# 在 操作的机器上 挂载 nfs 目录 /opt/nfs/fabric # 为了预先拷贝一些证书进去 mkdir -p /opt/nfs/fabric mount -t nfs 192.168.0.249:/opt/nfs/fabric /opt/nfs/fabric
# 拷贝文件到挂载目录 # 创建两个目录 data 数据目录, 以及 证书,创世区块 等文件目录 mkdir -p /opt/nfs/fabric/{data,fabric}
# 拷贝 证书文件 创世区块 文件 mkdir ./channel-artifacts/chaincode cp -r ./fabric/examples/chaincode/go/example* channel-artifacts/chaincode/ cp ./channel-artifacts/genesis.block ./crypto-config/ordererOrganizations/* cp -r ./crypto-config /opt/nfs/fabric/fabric/ cp -r ./channel-artifacts /opt/nfs/fabric/fabric/
# 创建 fabric 运行时生成的共享数据文件夹 mkdir -p /opt/nfs/fabric/data/{orderer,peer} mkdir -p /opt/nfs/fabric/data/orderer/orgorderer1/orderer0 mkdir -p /opt/nfs/fabric/data/peer/org{1,2}/ca mkdir -p /opt/nfs/fabric/data/peer/org{1,2}/peer{0,1}/{couchdb,peerdata}
配置 orderer
# 创建 orderer1 的 namespaces vi orgorderer1-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: orgorderer1
# 创建 orderer1 的 pv 与 pvc vi orgorderer1-pv-pvc.yaml apiVersion: v1 kind: PersistentVolume metadata: name: orgorderer1-pv labels: app: orgorderer1-pv spec: capacity: storage: 500Mi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/fabric/crypto-config/ordererOrganizations/orgorderer1 server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: orgorderer1 name: orgorderer1-pv spec: accessModes: - ReadWriteMany resources: requests: storage: 10Mi selector: matchLabels: app: orgorderer1-pv --- apiVersion: v1 kind: PersistentVolume metadata: name: orgorderer1-pvdata labels: app: orgorderer1-pvdata spec: capacity: storage: 10Gi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/data/orderer/orgorderer1 server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: orgorderer1 name: orgorderer1-pvdata spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi selector: matchLabels: app: orgorderer1-pvdata
# 创建 orderer1 Deployment 服务 vi orderer0.orgorderer1.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: orgorderer1 name: orderer0-orgorderer1 spec: replicas: 1 strategy: {} template: metadata: labels: app: hyperledger role: orderer org: orgorderer1 orderer-id: orderer0 spec: containers: - name: orderer0-orgorderer1 image: hyperledger/fabric-orderer:1.4.0 env: - name: ORDERER_GENERAL_LOGLEVEL value: debug - name: ORDERER_GENERAL_LISTENADDRESS value: 0.0.0.0 - name: ORDERER_GENERAL_GENESISMETHOD value: file - name: ORDERER_GENERAL_GENESISFILE value: /var/hyperledger/orderer/orderer.genesis.block - name: ORDERER_GENERAL_LOCALMSPID value: Orgorderer1MSP - name: ORDERER_GENERAL_LOCALMSPDIR value: /var/hyperledger/orderer/msp - name: ORDERER_GENERAL_TLS_ENABLED value: "false" - name: ORDERER_GENERAL_TLS_PRIVATEKEY value: /var/hyperledger/orderer/tls/server.key - name: ORDERER_GENERAL_TLS_CERTIFICATE value: /var/hyperledger/orderer/tls/server.crt - name: ORDERER_GENERAL_TLS_ROOTCAS value: '[/var/hyperledger/orderer/tls/ca.crt]' - name: ORDERER_KAFKA_VERSION value: 0.10.0.1 - name: ORDERER_KAFKA_VERBOSE value: "true" - name: ORDERER_KAFKA_BROKERS value: "kafka-0.broker.kafka:9092,kafka-1.broker.kafka:9092,kafka-2.broker.kafka:9092,kafka-3.broker.kafka:9092" - name: GODEBUG value: netdns=go workingDir: /opt/gopath/src/github.com/hyperledger/fabric ports: - containerPort: 7050 command: ["orderer"] volumeMounts: - mountPath: /var/hyperledger/orderer/msp name: certificate subPath: orderers/orderer0.orgorderer1/msp - mountPath: /var/hyperledger/orderer/tls name: certificate subPath: orderers/orderer0.orgorderer1/tls - mountPath: /var/hyperledger/orderer/orderer.genesis.block name: certificate subPath: genesis.block - mountPath: /var/hyperledger/production name: ordererdata subPath: orderer0 volumes: - name: certificate persistentVolumeClaim: claimName: orgorderer1-pv - name: ordererdata persistentVolumeClaim: claimName: orgorderer1-pvdata --- apiVersion: v1 kind: Service metadata: name: orderer0 namespace: orgorderer1 spec: selector: app: hyperledger role: orderer orderer-id: orderer0 org: orgorderer1 type: NodePort ports: - name: listen-endpoint protocol: TCP port: 7050 targetPort: 7050 nodePort: 32000
# 导入 yaml 文件 创建服务 # 创建 namespaces [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f orgorderer1-namespace.yaml namespace/orgorderer1 created # 创建 pv pvc [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f orgorderer1-pv-pvc.yaml persistentvolume/orgorderer1-pv created persistentvolumeclaim/orgorderer1-pv created persistentvolume/orgorderer1-pvdata created persistentvolumeclaim/orgorderer1-pvdata created # 创建 deployment [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f orderer0.orgorderer1.yaml deployment.extensions/orderer0-orgorderer1 created service/orderer0 created
# 查看创建的服务 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get pods -n orgorderer1 NAME READY STATUS RESTARTS AGE orderer0-orgorderer1-6b896b94c4-5gs2c 1/1 Running 0 36s [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE orgorderer1-pv 500Mi RWX Retain Bound orgorderer1/orgorderer1-pv 115s orgorderer1-pvdata 10Gi RWX Retain Bound orgorderer1/orgorderer1-pvdata 115s [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get pvc -n orgorderer1 NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE orgorderer1-pv Bound orgorderer1-pv 500Mi RWX 2m9s orgorderer1-pvdata Bound orgorderer1-pvdata 10Gi RWX 2m9s
配置 org1 服务
每个 org 包含 ca cli peer 三个服务
# 配置 org1 namespaces vi org1-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: org1
# 配置 org1 pv 与 pvc vi org1-pv-pvc.yaml apiVersion: v1 kind: PersistentVolume metadata: name: org1-pv labels: app: org1-pv spec: capacity: storage: 500Mi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/fabric/crypto-config/peerOrganizations/org1 server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: org1 name: org1-pv spec: accessModes: - ReadWriteMany resources: requests: storage: 10Mi selector: matchLabels: app: org1-pv --- apiVersion: v1 kind: PersistentVolume metadata: name: org1-pvdata labels: app: org1-pvdata spec: capacity: storage: 10Gi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/data/peer/org1 server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: org1 name: org1-pvdata spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi selector: matchLabels: app: org1-pvdata
# 配置 org1 ca # FABRIC_CA_SERVER_TLS_KEYFILE 配置为自己生成的 sk # sk 存在目录 crypto-config/peerOrganizations/org1/ca/ vi org1-ca.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: org1 name: ca spec: replicas: 1 strategy: {} template: metadata: labels: app: hyperledger role: ca org: org1 name: ca spec: containers: - name: ca image: hyperledger/fabric-ca:1.4.0 env: - name: FABRIC_CA_HOME value: /etc/hyperledger/fabric-ca-server - name: FABRIC_CA_SERVER_CA_NAME value: ca - name: FABRIC_CA_SERVER_TLS_ENABLED value: "false" - name: FABRIC_CA_SERVER_TLS_CERTFILE value: /etc/hyperledger/fabric-ca-server-config/ca.org1-cert.pem - name: FABRIC_CA_SERVER_TLS_KEYFILE value: /etc/hyperledger/fabric-ca-server-config/904aa978bf690c8198526a6410045cc308468ca7171d02af70ffc7d969eb4c7e_sk - name: GODEBUG value: netdns=go ports: - containerPort: 7054 command: ["sh"] args: ["-c", " fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org1-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/904aa978bf690c8198526a6410045cc308468ca7171d02af70ffc7d969eb4c7e_sk -b admin:adminpw -d "] volumeMounts: - mountPath: /etc/hyperledger/fabric-ca-server-config name: certificate subPath: ca/ - mountPath: /etc/hyperledger/fabric-ca-server name: cadata subPath: ca/ volumes: - name: certificate persistentVolumeClaim: claimName: org1-pv - name: cadata persistentVolumeClaim: claimName: org1-pvdata --- apiVersion: v1 kind: Service metadata: namespace: org1 name: ca spec: selector: app: hyperledger role: ca org: org1 name: ca type: NodePort ports: - name: endpoint protocol: TCP port: 7054 targetPort: 7054 nodePort: 30000
# 配置 org1 peer 服务 # 这里有两个 peer 分别为 peer0, peer1 vi peer0.org1.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: org1 name: peer0-org1 spec: replicas: 1 strategy: {} template: metadata: creationTimestamp: null labels: app: hyperledger role: peer peer-id: peer0 org: org1 spec: containers: - name: couchdb image: hyperledger/fabric-couchdb:0.4.10 env: - name: COUCHDB_USER value: "" - name: COUCHDB_PASSWORD value: "" ports: - containerPort: 5984 volumeMounts: - mountPath: /opt/couchdb/data name: peerdata subPath: peer0/couchdb - name: peer0-org1 image: hyperledger/fabric-peer:1.4.0 env: - name: CORE_LEDGER_STATE_STATEDATABASE value: "CouchDB" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS value: "localhost:5984" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME value: "" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD value: "" - name: CORE_VM_ENDPOINT value: "unix:///host/var/run/docker.sock" - name: CORE_LOGGING_LEVEL value: "DEBUG" - name: CORE_PEER_TLS_ENABLED value: "false" - name: CORE_PEER_GOSSIP_USELEADERELECTION value: "true" - name: CORE_PEER_GOSSIP_ORGLEADER value: "false" - name: CORE_PEER_PROFILE_ENABLED value: "true" - name: CORE_PEER_TLS_CERT_FILE value: "/etc/hyperledger/fabric/tls/server.crt" - name: CORE_PEER_TLS_KEY_FILE value: "/etc/hyperledger/fabric/tls/server.key" - name: CORE_PEER_TLS_ROOTCERT_FILE value: "/etc/hyperledger/fabric/tls/ca.crt" - name: CORE_PEER_ADDRESSAUTODETECT value: "true" - name: CORE_PEER_CHAINCODELISTENADDRESS value: "0.0.0.0:7052" - name: CORE_PEER_ID value: peer0.org1 - name: CORE_PEER_ADDRESS value: peer0.org1:7051 - name: CORE_PEER_GOSSIP_BOOTSTRAP value: peer0.org1:7051 - name: CORE_PEER_GOSSIP_EXTERNALENDPOINT value: peer0.org1:7051 - name: CORE_PEER_LOCALMSPID value: Org1MSP workingDir: /opt/gopath/src/github.com/hyperledger/fabric/peer ports: - containerPort: 7051 - containerPort: 7052 - containerPort: 7053 command: ["peer"] args: ["node","start"] volumeMounts: - mountPath: /etc/hyperledger/fabric/msp name: certificate subPath: peers/peer0.org1/msp - mountPath: /etc/hyperledger/fabric/tls name: certificate subPath: peers/peer0.org1/tls - mountPath: /var/hyperledger/production name: peerdata subPath: peer0/peerdata - mountPath: /host/var/run/ name: run volumes: - name: certificate persistentVolumeClaim: claimName: org1-pv - name: peerdata persistentVolumeClaim: claimName: org1-pvdata - name: run hostPath: path: /var/run --- apiVersion: v1 kind: Service metadata: namespace: org1 name: peer0 spec: selector: app: hyperledger role: peer peer-id: peer0 org: org1 type: NodePort ports: - name: externale-listen-endpoint protocol: TCP port: 7051 targetPort: 7051 nodePort: 30001 - name: chaincode-listen protocol: TCP port: 7052 targetPort: 7052 nodePort: 30002 - name: event-listen protocol: TCP port: 7053 targetPort: 7053 nodePort: 30003
vi peer1.org1.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: org1 name: peer1-org1 spec: replicas: 1 strategy: {} template: metadata: creationTimestamp: null labels: app: hyperledger role: peer peer-id: peer1 org: org1 spec: containers: - name: couchdb image: hyperledger/fabric-couchdb:0.4.10 env: - name: COUCHDB_USER value: "" - name: COUCHDB_PASSWORD value: "" ports: - containerPort: 5984 volumeMounts: - mountPath: /opt/couchdb/data name: peerdata subPath: peer1/couchdb - name: peer1-org1 image: hyperledger/fabric-peer:1.4.0 env: - name: CORE_LEDGER_STATE_STATEDATABASE value: "CouchDB" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS value: "localhost:5984" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME value: "" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD value: "" - name: CORE_VM_ENDPOINT value: "unix:///host/var/run/docker.sock" - name: CORE_LOGGING_LEVEL value: "DEBUG" - name: CORE_PEER_TLS_ENABLED value: "false" - name: CORE_PEER_GOSSIP_USELEADERELECTION value: "true" - name: CORE_PEER_GOSSIP_ORGLEADER value: "false" - name: CORE_PEER_PROFILE_ENABLED value: "true" - name: CORE_PEER_TLS_CERT_FILE value: "/etc/hyperledger/fabric/tls/server.crt" - name: CORE_PEER_TLS_KEY_FILE value: "/etc/hyperledger/fabric/tls/server.key" - name: CORE_PEER_TLS_ROOTCERT_FILE value: "/etc/hyperledger/fabric/tls/ca.crt" - name: CORE_PEER_ADDRESSAUTODETECT value: "true" - name: CORE_PEER_CHAINCODELISTENADDRESS value: "0.0.0.0:7052" - name: CORE_PEER_ID value: peer1.org1 - name: CORE_PEER_ADDRESS value: peer1.org1:7051 - name: CORE_PEER_GOSSIP_BOOTSTRAP value: peer1.org1:7051 - name: CORE_PEER_GOSSIP_EXTERNALENDPOINT value: peer1.org1:7051 - name: CORE_PEER_LOCALMSPID value: Org1MSP workingDir: /opt/gopath/src/github.com/hyperledger/fabric/peer ports: - containerPort: 7051 - containerPort: 7052 - containerPort: 7053 command: ["peer"] args: ["node","start"] volumeMounts: - mountPath: /etc/hyperledger/fabric/msp name: certificate subPath: peers/peer1.org1/msp - mountPath: /etc/hyperledger/fabric/tls name: certificate subPath: peers/peer1.org1/tls - mountPath: /var/hyperledger/production name: peerdata subPath: peer1/peerdata - mountPath: /host/var/run/ name: run volumes: - name: certificate persistentVolumeClaim: claimName: org1-pv - name: peerdata persistentVolumeClaim: claimName: org1-pvdata - name: run hostPath: path: /var/run --- apiVersion: v1 kind: Service metadata: namespace: org1 name: peer1 spec: selector: app: hyperledger role: peer peer-id: peer1 org: org1 type: NodePort ports: - name: externale-listen-endpoint protocol: TCP port: 7051 targetPort: 7051 nodePort: 30004 - name: chaincode-listen protocol: TCP port: 7052 targetPort: 7052 nodePort: 30005 - name: event-listen protocol: TCP port: 7053 targetPort: 7053 nodePort: 30006
# 导入 yaml 文件 创建服务 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org1-namespace.yaml namespace/org1 created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org1-pv-pvc.yaml persistentvolume/org1-pv created persistentvolumeclaim/org1-pv created persistentvolume/org1-pvdata created persistentvolumeclaim/org1-pvdata created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org1-ca.yaml deployment.extensions/ca created service/ca created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f peer0.org1.yaml deployment.extensions/peer0-org1 created service/peer0 created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f peer1.org1.yaml deployment.extensions/peer1-org1 created service/peer1 created
# 查看 创建的服务 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get all -n org1 NAME READY STATUS RESTARTS AGE pod/ca-75b9859c54-d5x9b 1/1 Running 0 120m pod/peer0-org1-5767789cd7-7g2z7 2/2 Running 0 22m pod/peer1-org1-866b6bcd45-c5mbp 2/2 Running 0 22m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ca NodePort 10.233.5.5 <none> 7054:30000/TCP 120m service/peer0 NodePort 10.233.57.55 <none> 7051:30001/TCP,7052:30002/TCP,7053:30003/TCP 36m service/peer1 NodePort 10.233.31.189 <none> 7051:30004/TCP,7052:30005/TCP,7053:30006/TCP 34m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/ca 1/1 1 1 120m deployment.apps/peer0-org1 1/1 1 1 36m deployment.apps/peer1-org1 1/1 1 1 34m NAME DESIRED CURRENT READY AGE replicaset.apps/ca-75b9859c54 1 1 1 120m replicaset.apps/peer0-org1-5767789cd7 1 1 1 22m replicaset.apps/peer0-org1-8c98c4c9 0 0 0 36m replicaset.apps/peer1-org1-768c8d8f69 0 0 0 34m replicaset.apps/peer1-org1-866b6bcd45 1 1 1 22m
配置 org2 服务
# 配置 org2 namespaces vi org2-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: org2
# 配置 org2 pv pvc vi org2-pv-pvc.yaml apiVersion: v1 kind: PersistentVolume metadata: name: org2-pv labels: app: org2-pv spec: capacity: storage: 500Mi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/fabric/crypto-config/peerOrganizations/org2 server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: org2 name: org2-pv spec: accessModes: - ReadWriteMany resources: requests: storage: 10Mi selector: matchLabels: app: org2-pv --- apiVersion: v1 kind: PersistentVolume metadata: name: org2-pvdata labels: app: org2-pvdata spec: capacity: storage: 10Gi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/data/peer/org2 server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: org2 name: org2-pvdata spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi selector: matchLabels: app: org2-pvdata
# 配置 org2 ca # FABRIC_CA_SERVER_TLS_KEYFILE 配置为自己生成的 sk # sk 存在目录 crypto-config/peerOrganizations/org2/ca/ vi org2-ca.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: org2 name: ca spec: replicas: 1 strategy: {} template: metadata: labels: app: hyperledger role: ca org: org2 name: ca spec: containers: - name: ca image: hyperledger/fabric-ca:1.4.0 env: - name: FABRIC_CA_HOME value: /etc/hyperledger/fabric-ca-server - name: FABRIC_CA_SERVER_CA_NAME value: ca - name: FABRIC_CA_SERVER_TLS_ENABLED value: "false" - name: FABRIC_CA_SERVER_TLS_CERTFILE value: /etc/hyperledger/fabric-ca-server-config/ca.org2-cert.pem - name: FABRIC_CA_SERVER_TLS_KEYFILE value: /etc/hyperledger/fabric-ca-server-config/44299d5dfb204e07b5274a7048269171876157d1efdab11a5ac631bd78d2fe0d_sk - name: GODEBUG value: netdns=go ports: - containerPort: 7054 command: ["sh"] args: ["-c", " fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org2-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/44299d5dfb204e07b5274a7048269171876157d1efdab11a5ac631bd78d2fe0d_sk -b admin:adminpw -d "] volumeMounts: - mountPath: /etc/hyperledger/fabric-ca-server-config name: certificate subPath: ca/ - mountPath: /etc/hyperledger/fabric-ca-server name: cadata subPath: ca/ volumes: - name: certificate persistentVolumeClaim: claimName: org2-pv - name: cadata persistentVolumeClaim: claimName: org2-pvdata --- apiVersion: v1 kind: Service metadata: namespace: org2 name: ca spec: selector: app: hyperledger role: ca org: org2 name: ca type: NodePort ports: - name: endpoint protocol: TCP port: 7054 targetPort: 7054 nodePort: 30100
# 配置 org2 peer 服务 # 这里有两个 peer 分别为 peer0, peer1 vi peer0.org2.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: org2 name: peer0-org2 spec: replicas: 1 strategy: {} template: metadata: creationTimestamp: null labels: app: hyperledger role: peer peer-id: peer0 org: org2 spec: containers: - name: couchdb image: hyperledger/fabric-couchdb:0.4.10 env: - name: COUCHDB_USER value: "" - name: COUCHDB_PASSWORD value: "" ports: - containerPort: 5984 volumeMounts: - mountPath: /opt/couchdb/data name: peerdata subPath: peer0/couchdb - name: peer0-org2 image: hyperledger/fabric-peer:1.4.0 env: - name: CORE_LEDGER_STATE_STATEDATABASE value: "CouchDB" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS value: "localhost:5984" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME value: "" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD value: "" - name: CORE_VM_ENDPOINT value: "unix:///host/var/run/docker.sock" - name: CORE_LOGGING_LEVEL value: "DEBUG" - name: CORE_PEER_TLS_ENABLED value: "false" - name: CORE_PEER_GOSSIP_USELEADERELECTION value: "true" - name: CORE_PEER_GOSSIP_ORGLEADER value: "false" - name: CORE_PEER_PROFILE_ENABLED value: "true" - name: CORE_PEER_TLS_CERT_FILE value: "/etc/hyperledger/fabric/tls/server.crt" - name: CORE_PEER_TLS_KEY_FILE value: "/etc/hyperledger/fabric/tls/server.key" - name: CORE_PEER_TLS_ROOTCERT_FILE value: "/etc/hyperledger/fabric/tls/ca.crt" - name: CORE_PEER_ADDRESSAUTODETECT value: "true" - name: CORE_PEER_CHAINCODELISTENADDRESS value: "0.0.0.0:7052" - name: CORE_PEER_ID value: peer0.org2 - name: CORE_PEER_ADDRESS value: peer0.org2:7051 - name: CORE_PEER_GOSSIP_BOOTSTRAP value: peer0.org2:7051 - name: CORE_PEER_GOSSIP_EXTERNALENDPOINT value: peer0.org2:7051 - name: CORE_PEER_LOCALMSPID value: Org2MSP workingDir: /opt/gopath/src/github.com/hyperledger/fabric/peer ports: - containerPort: 7051 - containerPort: 7052 - containerPort: 7053 command: ["peer"] args: ["node","start"] volumeMounts: - mountPath: /etc/hyperledger/fabric/msp name: certificate subPath: peers/peer0.org2/msp - mountPath: /etc/hyperledger/fabric/tls name: certificate subPath: peers/peer0.org2/tls - mountPath: /var/hyperledger/production name: peerdata subPath: peer0/peerdata - mountPath: /host/var/run/ name: run volumes: - name: certificate persistentVolumeClaim: claimName: org2-pv - name: peerdata persistentVolumeClaim: claimName: org2-pvdata - name: run hostPath: path: /var/run --- apiVersion: v1 kind: Service metadata: namespace: org2 name: peer0 spec: selector: app: hyperledger role: peer peer-id: peer0 org: org2 type: NodePort ports: - name: externale-listen-endpoint protocol: TCP port: 7051 targetPort: 7051 nodePort: 30101 - name: chaincode-listen protocol: TCP port: 7052 targetPort: 7052 nodePort: 30102 - name: event-listen protocol: TCP port: 7053 targetPort: 7053 nodePort: 30103
# 配置 org2 的 peer1 vi peer1.org2.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: org2 name: peer1-org2 spec: replicas: 1 strategy: {} template: metadata: creationTimestamp: null labels: app: hyperledger role: peer peer-id: peer1 org: org2 spec: containers: - name: couchdb image: hyperledger/fabric-couchdb:0.4.10 env: - name: COUCHDB_USER value: "" - name: COUCHDB_PASSWORD value: "" ports: - containerPort: 5984 volumeMounts: - mountPath: /opt/couchdb/data name: peerdata subPath: peer1/couchdb - name: peer1-org2 image: hyperledger/fabric-peer:1.4.0 env: - name: CORE_LEDGER_STATE_STATEDATABASE value: "CouchDB" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS value: "localhost:5984" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME value: "" - name: CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD value: "" - name: CORE_VM_ENDPOINT value: "unix:///host/var/run/docker.sock" - name: CORE_LOGGING_LEVEL value: "DEBUG" - name: CORE_PEER_TLS_ENABLED value: "false" - name: CORE_PEER_GOSSIP_USELEADERELECTION value: "true" - name: CORE_PEER_GOSSIP_ORGLEADER value: "false" - name: CORE_PEER_PROFILE_ENABLED value: "true" - name: CORE_PEER_TLS_CERT_FILE value: "/etc/hyperledger/fabric/tls/server.crt" - name: CORE_PEER_TLS_KEY_FILE value: "/etc/hyperledger/fabric/tls/server.key" - name: CORE_PEER_TLS_ROOTCERT_FILE value: "/etc/hyperledger/fabric/tls/ca.crt" - name: CORE_PEER_ADDRESSAUTODETECT value: "true" - name: CORE_PEER_CHAINCODELISTENADDRESS value: "0.0.0.0:7052" - name: CORE_PEER_ID value: peer1.org2 - name: CORE_PEER_ADDRESS value: peer1.org2:7051 - name: CORE_PEER_GOSSIP_BOOTSTRAP value: peer1.org2:7051 - name: CORE_PEER_GOSSIP_EXTERNALENDPOINT value: peer1.org2:7051 - name: CORE_PEER_LOCALMSPID value: Org2MSP workingDir: /opt/gopath/src/github.com/hyperledger/fabric/peer ports: - containerPort: 7051 - containerPort: 7052 - containerPort: 7053 command: ["peer"] args: ["node","start"] volumeMounts: - mountPath: /etc/hyperledger/fabric/msp name: certificate subPath: peers/peer1.org2/msp - mountPath: /etc/hyperledger/fabric/tls name: certificate subPath: peers/peer1.org2/tls - mountPath: /var/hyperledger/production name: peerdata subPath: peer1/peerdata - mountPath: /host/var/run/ name: run volumes: - name: certificate persistentVolumeClaim: claimName: org2-pv - name: peerdata persistentVolumeClaim: claimName: org2-pvdata - name: run hostPath: path: /var/run --- apiVersion: v1 kind: Service metadata: namespace: org2 name: peer1 spec: selector: app: hyperledger role: peer peer-id: peer1 org: org2 type: NodePort ports: - name: externale-listen-endpoint protocol: TCP port: 7051 targetPort: 7051 nodePort: 30104 - name: chaincode-listen protocol: TCP port: 7052 targetPort: 7052 nodePort: 30105 - name: event-listen protocol: TCP port: 7053 targetPort: 7053 nodePort: 30106
# 导入 yaml 文件 创建服务 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org2-namespace.yaml namespace/org2 created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org2-pv-pvc.yaml persistentvolume/org2-pv created persistentvolumeclaim/org2-pv created persistentvolume/org2-pvdata created persistentvolumeclaim/org2-pvdata created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org2-ca.yaml deployment.extensions/ca created service/ca created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f peer0.org2.yaml deployment.extensions/peer0-org2 created service/peer0 created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f peer1.org2.yaml deployment.extensions/peer1-org2 created service/peer1 created
# 查看 org2 的服务 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get all -n org2 NAME READY STATUS RESTARTS AGE pod/ca-594d86d8fc-fwg7r 1/1 Running 0 55s pod/peer0-org2-68579cc9fd-gjmdw 2/2 Running 0 40s pod/peer1-org2-7645b97c44-5f64k 2/2 Running 0 30s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ca NodePort 10.233.4.94 <none> 7054:30100/TCP 55s service/peer0 NodePort 10.233.49.35 <none> 7051:30101/TCP,7052:30102/TCP,7053:30103/TCP 40s service/peer1 NodePort 10.233.56.135 <none> 7051:30104/TCP,7052:30105/TCP,7053:30106/TCP 30s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/ca 1/1 1 1 55s deployment.apps/peer0-org2 1/1 1 1 40s deployment.apps/peer1-org2 1/1 1 1 30s NAME DESIRED CURRENT READY AGE replicaset.apps/ca-594d86d8fc 1 1 1 55s replicaset.apps/peer0-org2-68579cc9fd 1 1 1 40s replicaset.apps/peer1-org2-7645b97c44 1 1 1 30s
配置 cli 服务
cli 服务,用于 命令行操作组织节点的环境。
这里每一个 org 配置一个 cli 服务,方便操作不同的 org 节点
# 创建 org1 cli 的 pv pvc vi org1-cli-pv-pvc.yaml apiVersion: v1 kind: PersistentVolume metadata: name: org1-cli-pv labels: app: org1-cli-pv spec: capacity: storage: 500Mi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/fabric/channel-artifacts server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: org1 name: org1-cli-pv spec: accessModes: - ReadWriteMany resources: requests: storage: 10Mi selector: matchLabels: app: org1-cli-pv
# 创建 org1 cli 服务 vi org1-cli.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: org1 name: cli spec: replicas: 1 strategy: {} template: metadata: labels: app: cli spec: containers: - name: cli image: hyperledger/fabric-tools:1.4.0 env: - name: CORE_PEER_TLS_ENABLED value: "false" - name: CORE_VM_ENDPOINT value: unix:///host/var/run/docker.sock - name: GOPATH value: /opt/gopath - name: CORE_LOGGING_LEVEL value: DEBUG - name: CORE_PEER_ID value: cli - name: CORE_PEER_ADDRESS value: peer0.org1:7051 - name: CORE_PEER_LOCALMSPID value: Org1MSP - name: CORE_PEER_MSPCONFIGPATH value: /etc/hyperledger/fabric/msp - name: GODEBUG value: netdns=go workingDir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: ["/bin/bash", "-c", "--"] args: ["while true; do sleep 30; done;"] volumeMounts: - mountPath: /host/var/run/ name: run - mountPath: /etc/hyperledger/fabric/msp name: certificate subPath: users/Admin@org1/msp - mountPath: /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts name: artifacts volumes: - name: certificate persistentVolumeClaim: claimName: org1-pv - name: artifacts persistentVolumeClaim: claimName: org1-cli-pv - name: run hostPath: path: /var/run
# 导入 yaml 文件 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org1-cli-pv-pvc.yaml persistentvolume/org1-cli-pv created persistentvolumeclaim/org1-cli-pv created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org1-cli.yaml deployment.extensions/cli created
# 创建 org2 cli 的 pv pvc vi org2-cli-pv-pvc.yaml apiVersion: v1 kind: PersistentVolume metadata: name: org2-cli-pv labels: app: org2-cli-pv spec: capacity: storage: 500Mi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/fabric/channel-artifacts server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: org2 name: org2-cli-pv spec: accessModes: - ReadWriteMany resources: requests: storage: 10Mi selector: matchLabels: app: org2-cli-pv
# 创建 org2 cli 服务 vi org2-cli.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: org2 name: cli spec: replicas: 1 strategy: {} template: metadata: labels: app: cli spec: containers: - name: cli image: hyperledger/fabric-tools:1.4.0 env: - name: CORE_PEER_TLS_ENABLED value: "false" - name: CORE_VM_ENDPOINT value: unix:///host/var/run/docker.sock - name: GOPATH value: /opt/gopath - name: CORE_LOGGING_LEVEL value: DEBUG - name: CORE_PEER_ID value: cli - name: CORE_PEER_ADDRESS value: peer0.org2:7051 - name: CORE_PEER_LOCALMSPID value: Org2MSP - name: CORE_PEER_MSPCONFIGPATH value: /etc/hyperledger/fabric/msp - name: GODEBUG value: netdns=go workingDir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: ["/bin/bash", "-c", "--"] args: ["while true; do sleep 30; done;"] volumeMounts: - mountPath: /host/var/run/ name: run - mountPath: /etc/hyperledger/fabric/msp name: certificate subPath: users/Admin@org2/msp - mountPath: /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts name: artifacts volumes: - name: certificate persistentVolumeClaim: claimName: org2-pv - name: artifacts persistentVolumeClaim: claimName: org2-cli-pv - name: run hostPath: path: /var/run
# 导入 yaml 文件 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org2-cli-pv-pvc.yaml persistentvolume/org2-cli-pv created persistentvolumeclaim/org2-cli-pv created [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl apply -f org2-cli.yaml deployment.extensions/cli created
# 查看服务 [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE org1 cli-68647b4c-6db4f 1/1 Running 0 5m12s org2 cli-5bd96dc66d-bhm65 1/1 Running 0 18s
测试 集群
测试集群
- 初始化 channel 2. 加入 channel 3. 更新为 锚节点 4. 安装 chaincode 5. 实例化 chaincode 6. 操作 chaincode
org1 节点
# 登录 org1 cli [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl exec -it cli-68647b4c-6db4f -n org1 bash 1. 初始化 创建channel peer channel create -o orderer0.orgorderer1:7050 -c mychannel -f ./channel-artifacts/channel.tx
拷贝 mychannel.block 文件到 channel-artifacts 共享目录
# 拷贝 cp mychannel.block channel-artifacts # 加入 channel peer channel join -b channel-artifacts/mychannel.block 2019-01-21 02:40:58.478 UTC [main] InitCmd -> WARN 001 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 02:40:58.497 UTC [main] SetOrdererEnv -> WARN 002 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 02:40:58.500 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized 2019-01-21 02:40:58.589 UTC [channelCmd] executeJoin -> INFO 004 Successfully submitted proposal to join channel
# 更新 锚节点 peer,每个 org 只需执行一次 # 更新对应的 org1 的 peer channel update -o orderer0.orgorderer1:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx
org2 节点
# 登录 org2 节点 cli [root@kubernetes-1 /opt/jicki/k8s-yaml]# kubectl exec -it cli-5bd96dc66d-j2m6d -n org2 bash
# 加入 mychannel peer channel join -b channel-artifacts/mychannel.block 2019-01-21 02:47:14.529 UTC [main] InitCmd -> WARN 001 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 02:47:14.549 UTC [main] SetOrdererEnv -> WARN 002 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 02:47:14.551 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized 2019-01-21 02:47:14.629 UTC [channelCmd] executeJoin -> INFO 004 Successfully submitted proposal to join channel
# 更新 锚节点 peer,每个 org 只需执行一次 # 更新对应的 org2 的 peer channel update -o orderer0.orgorderer1:7050 -c mychannel -f ./channel-artifacts/Org2MSPanchors.tx
安装 chaincode
安装 chaincode 需要在 org1 org2 的 cli 分别安装
# org1 kubectl exec -it cli-68647b4c-lhdhf -n org1 bash # org2 kubectl exec -it cli-5bd96dc66d-j2m6d -n org2 bash
# 分别执行安装 peer chaincode install -n example2 -v 1.0 -p github.com/hyperledger/fabric/peer/channel-artifacts/chaincode/example02
实例化 chaincode
实例化 chaincode 只需要在 其中一个 org 执行就可以
peer chaincode instantiate -o orderer0.orgorderer1:7050 \ -C mychannel -n example2 -v 1.0 \ -c '{"Args":["init","A", "100", "B","200"]}' \ -P "OR ('Org1MSP.peer','Org2MSP.peer')"
# 实例化以后~会在 docker 中生成 一个容器, 脱离于k8s 是由 docker 生成 [root@kubernetes-3 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 26666283f935 dev-peer0.org1-example2-1.0-e8792315af3bc6f98b5be21c4c98ece1ab5c65537e361691af638304c0670cd5 "chaincode -peer.add…" 6 minutes ago Up 6 minutes dev-peer0.org1-example2-1.0
操作 chaincode
执行 转账,查询 操作
# 查询 A, B 账户的值 peer chaincode query -C mychannel -n example2 -c '{"Args":["query","A"]}' # 输出如下: 2019-01-21 03:45:18.469 UTC [main] InitCmd -> WARN 001 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 03:45:18.485 UTC [main] SetOrdererEnv -> WARN 002 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 100 peer chaincode query -C mychannel -n example2 -c '{"Args":["query","B"]}' # 输出如下: 2019-01-21 03:47:21.683 UTC [main] InitCmd -> WARN 001 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 03:47:21.701 UTC [main] SetOrdererEnv -> WARN 002 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 200
# invoke 转账 # 从A账户 转账 50 个币 到 B 账户 peer chaincode invoke -C mychannel -n example2 -c '{"Args":["invoke", "A", "B", "50"]}' # 输出如下: 2019-01-21 03:48:43.787 UTC [main] InitCmd -> WARN 001 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 03:48:43.806 UTC [main] SetOrdererEnv -> WARN 002 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 03:48:43.816 UTC [chaincodeCmd] InitCmdFactory -> INFO 003 Retrieved channel (mychannel) orderer endpoint: orderer0.orgorderer1:7050 2019-01-21 03:48:43.830 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 004 Chaincode invoke successful. result: status:200 # 转账后在查询 A, B 的值 peer chaincode query -C mychannel -n example2 -c '{"Args":["query","A"]}' # 输出: 2019-01-21 03:49:10.686 UTC [main] InitCmd -> WARN 001 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 03:49:10.702 UTC [main] SetOrdererEnv -> WARN 002 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 50 peer chaincode query -C mychannel -n example2 -c '{"Args":["query","B"]}' # 输出: 2019-01-21 03:49:41.883 UTC [main] InitCmd -> WARN 001 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 2019-01-21 03:49:41.898 UTC [main] SetOrdererEnv -> WARN 002 CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable 250
blockchain-explorer 部署
blockchain-explorer 是 fabric 的区块浏览器
配置 postgres
# 创建 数据目录 , 创建于 nfs 中 mkdir -p /opt/nfs/fabric/data/postgres
# 创建 namesapce vi explorer-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: explorer
# 创建 pv pvc vi explorer-pv-pvc.yaml apiVersion: v1 kind: PersistentVolume metadata: name: postgres-pv labels: app: postgres-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/data/postgres server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: explorer name: postgres-pv spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi selector: matchLabels: app: postgres-pv --- apiVersion: v1 kind: PersistentVolume metadata: name: explorer-pv labels: app: explorer-pv spec: capacity: storage: 500Mi accessModes: - ReadWriteMany nfs: path: /opt/nfs/fabric/fabric/crypto-config server: 192.168.0.249 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: namespace: explorer name: explorer-pv spec: accessModes: - ReadWriteMany resources: requests: storage: 100Mi selector: matchLabels: app: explorer-pv
# 创建 postgres deployment vi postgres-deployment.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: explorer name: postgres-db spec: replicas: 1 template: metadata: labels: name: explorer-db spec: containers: - name: postgres image: postgres:10-alpine env: - name: TZ value: "Asia/Shanghai" - name: DATABASE_DATABASE value: "fabricexplorer" - name: DATABASE_USERNAME value: "jicki" - name: DATABASE_PASSWORD value: "password" volumeMounts: - mountPath: /var/lib/postgresql/data name: postgresdata volumes: - name: postgresdata persistentVolumeClaim: claimName: postgres-pv --- apiVersion: v1 kind: Service metadata: name: postgres-db namespace: explorer labels: run: explorer-db spec: selector: name: explorer-db ports: - protocol: TCP port: 5432
# 查看 服务 [root@kubernetes-1 /opt/jicki/k8s-yaml/explorer]# kubectl get pods -n explorer NAME READY STATUS RESTARTS AGE postgres-db-7884d8c859-s8hqq 1/1 Running 0 32s
# 初始化数据库 # 初始化数据库这边只能手动登录 pods 里操作一下, 导入表结构以及初始化数据。 kubectl get pods -n explorer NAME READY STATUS RESTARTS AGE postgres-db-7884d8c859-s8hqq 1/1 Running 0 2m33s kubectl exec -it postgres-db-7884d8c859-s8hqq -n explorer bash cd /tmp/ wget https://raw.githubusercontent.com/hyperledger/blockchain-explorer/master/app/persistence/fabric/postgreSQL/db/createdb.sh wget https://raw.githubusercontent.com/hyperledger/blockchain-explorer/master/app/persistence/fabric/postgreSQL/db/explorerpg.sql wget https://raw.githubusercontent.com/hyperledger/blockchain-explorer/master/app/persistence/fabric/postgreSQL/db/processenv.js wget https://raw.githubusercontent.com/hyperledger/blockchain-explorer/master/app/persistence/fabric/postgreSQL/db/updatepg.sql # 安装依赖软件 apk update apk add jq apk add nodejs apk add sudo rm -rf /var/cache/apk/* # 执行创建脚本 chmod +x ./createdb.sh ./createdb.sh # 看出输出 表示完成 You are now connected to database "fabricexplorer" as user "postgres". 退出pods
# 创建 explorer 配置文件 config.json vi config.json { "network-configs": { "network-1": { "version": "1.0", "clients": { "client-1": { "tlsEnable": false, "organization": "Org1MSP", "channel": "mychannel", "credentialStore": { "path": "./tmp/credentialStore_Org1/credential", "cryptoStore": { "path": "./tmp/credentialStore_Org1/crypto" } } } }, "channels": { "mychannel": { "peers": { "peer0.org1": {}, "peer1.org1": {}, "peer0.org2": {}, "peer1.org2": {} }, "connection": { "timeout": { "peer": { "endorser": "6000", "eventHub": "6000", "eventReg": "6000" } } } } }, "organizations": { "Org1MSP": { "mspid": "Org1MSP", "fullpath": false, "adminPrivateKey": { "path": "/fabric/peerOrganizations/org1/users/Admin@org1/msp/keystore" }, "signedCert": { "path": "/fabric/peerOrganizations/org1/users/Admin@org1/msp/signcerts" } }, "Org2MSP": { "mspid": "Org2MSP", "fullpath": false, "adminPrivateKey": { "path": "/fabric/peerOrganizations/org2/users/Admin@org2/msp/keystore" }, "signedCert": { "path": "/fabric/peerOrganizations/org2/users/Admin@org2/msp/signcerts" } }, "Orgorderer1MSP": { "mspid": "Orgorderer1MSP", "adminPrivateKey": { "path": "/fabric/ordererOrganizations/orgorderer1/users/Admin@orgorderer1/msp/keystore" } } }, "peers": { "peer0.org1": { "tlsCACerts": { "path": "/fabric/peerOrganizations/org1/peers/peer0.org1/tls/ca.crt" }, "url": "grpc://peer0.org1:7051", "eventUrl": "grpc://peer0.org1:7053", "grpcOptions": { "ssl-target-name-override": "peer0.org1" } }, "peer1.org1": { "tlsCACerts": { "path": "/fabric/peerOrganizations/org1/peers/peer1.org1/tls/ca.crt" }, "url": "grpc://peer1.org1:7051", "eventUrl": "grpc://peer1.org1:7053", "grpcOptions": { "ssl-target-name-override": "peer1.org1" } }, "peer0.org2": { "tlsCACerts": { "path": "/fabric/peerOrganizations/org2/peers/peer0.org2/tls/ca.crt" }, "url": "grpc://peer0.org2:7051", "eventUrl": "grpc://peer0.org2:7053", "grpcOptions": { "ssl-target-name-override": "peer0.org2" } }, "peer1.org2": { "tlsCACerts": { "path": "/fabric/peerOrganizations/org2/peers/peer1.org2/tls/ca.crt" }, "url": "grpc://peer1.org2:7051", "eventUrl": "grpc://peer1.org2:7053", "grpcOptions": { "ssl-target-name-override": "peer1.org2" } } }, "orderers": { "orderer0.orgorderer1": { "url": "grpc://orderer0.orgorderer1:7050" } } }, "network-2": {} }, "configtxgenToolPath": "/fabric-path/workspace/fabric-samples/bin", "license": "Apache-2.0" }
# 创建运行脚本 run.sh vi run.sh #!/bin/sh mkdir -p /opt/explorer/app/platform/fabric/ mv /opt/explorer/app/platform/fabric/config.json /opt/explorer/app/platform/fabric/config.json.vanilla cp /fabric/config.json /opt/explorer/app/platform/fabric/config.json cd /opt/explorer node $EXPLORER_APP_PATH/main.js && tail -f /dev/null
# 拷贝文件到 NFS 目录中 并 授权 cp config.json run.sh /opt/nfs/fabric/fabric/crypto-config/ chmod +x /opt/nfs/fabric/fabric/crypto-config/run.sh
# 创建 deployment 服务 vi explorer-deployment.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: explorer name: explorer spec: replicas: 1 template: metadata: labels: name: explorer spec: containers: - name: explorer image: hyperledger/explorer:latest command: ["sh" , "-c" , "/fabric/run.sh"] env: - name: TZ value: "Asia/Shanghai" - name: DATABASE_HOST value: "postgres-db" - name: DATABASE_USERNAME value: "jicki" - name: DATABASE_PASSWORD value: "password" volumeMounts: - mountPath: /fabric name: certfile volumes: - name: certfile persistentVolumeClaim: claimName: explorer-pv --- apiVersion: v1 kind: Service metadata: name: explorer namespace: explorer spec: selector: name: explorer ports: - name: webui protocol: TCP port: 8080 --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: explorer-ingress namespace: explorer spec: rules: - host: explorer.jicki.me http: paths: - backend: serviceName: explorer servicePort: 8080