https://medium.com/taipei-ethereum-meetup/%E4%BD%BF%E7%94%A8-go-ethereum-1-6-clique-poa-consensus-%E5%BB%BA%E7%AB%8B-private-chain-1-4d359f28feff

node 1
node 2
signer 1
signer 2

all private key & address create by https://vanity-eth.tk/
check again private key & address by https://www.myetherwallet.com/#view-wallet-info

 node1
private key:138cbbfb21686ddc3b5ffeb2cfc83491175af68319977acb81d0ae93392c626c
account address:e79d33e93bd888b35e055f1a12d876354729037b

 node2
private key:df0c39faccd3c9d6d10091932f2214b9d42e92bd07b64a1552d13d39a6a84122
account address:Bf95EAacf10BEA53f0a73955a7eFCE2fb4A4Ef1d

signer1
nodekeyhex:fcc406a7344690f66c757cc2c9987e3e78bb01e33229f9877d48a7fecc2d6657
node address:256330933851d6d3c5f7326b01021553415a33cd5485e23bfbe35f6321e6e2f8373bb1c94933fdb3283a1a8b2b737587dd99c555029e65e173a3094daa39277c

private key:d05bd152f3d71ff5f91830f3ccc1090fb670c7026ebf8c2136d4e5090d59398d
account address:5921a4C1B13afbD4b61d63e9c7BD47741C47B176

signer2
private key:df504d175ae63abf209bad9dda965310d99559620550e74521a6798a41215f46
account address:8Cc5A1a0802DB41DB826C2FcB72423744338DcB0

docker-compose

  
version: '3.3'  
  
services:  
  go-ethereum-node1:  
    build:  
      context: go-ethereum-node1/  
    volumes:  
      #- ./go-ethereum/keystore:/root/.ethereum/devchain/keystore:rw  
      - ./go-ethereum-node1/genesis/poa_for_dev.json:/root/genesis/poa_for_dev.json:ro  
      - /etc/localtime:/etc/localtime:ro  
      #- ./go-ethereum/log:/root/log:rw  
    entrypoint: /root/start.sh  
    ports:  
      - "18545:8545"  
      - "30313:30303"  
      - "30313:30303/udp"  
    networks:  
      - fastdev  
  
  go-ethereum-node2:  
    build:  
      context: go-ethereum-node2/  
    volumes:  
      - ./go-ethereum-node2/genesis/poa_for_dev.json:/root/genesis/poa_for_dev.json:ro  
      - /etc/localtime:/etc/localtime:ro  
    entrypoint: /root/start.sh  
    ports:  
      - "28545:8545"  
      - "30323:30303"  
      - "30323:30303/udp"  
    networks:  
      - fastdev  
  
  go-ethereum-signer1:  
    build:  
      context: go-ethereum-signer1/  
    volumes:  
      - ./go-ethereum-signer1/genesis/poa_for_dev.json:/root/genesis/poa_for_dev.json:ro  
      - /etc/localtime:/etc/localtime:ro  
    entrypoint: /root/start.sh  
    ports:  
      - "38545:8545"  
      - "30333:30303"  
      - "30333:30303/udp"  
    networks:  
      - fastdev  
  
  go-ethereum-signer2:  
    build:  
      context: go-ethereum-signer2/  
    volumes:  
      - ./go-ethereum-signer2/genesis/poa_for_dev.json:/root/genesis/poa_for_dev.json:ro  
      - /etc/localtime:/etc/localtime:ro  
    entrypoint: /root/start.sh  
    ports:  
      - "48545:8545"  
      - "30343:30303"  
      - "30343:30303/udp"  
    networks:  
      - fastdev  
  
  mongo:  
    image: mongo  
    #restart: always  
    environment:  
      MONGO_INITDB_ROOT_USERNAME: root  
      MONGO_INITDB_ROOT_PASSWORD: example  
    volumes:  
      - alldata:/data/db  
    networks:  
      - fastdev  
  
  mongo-express:  
    image: mongo-express  
    #restart: always  
    links:  
      - mongo:mongo  
    ports:  
      - 8081:8081  
    environment:  
      ME_CONFIG_MONGODB_ADMINUSERNAME: root  
      ME_CONFIG_MONGODB_ADMINPASSWORD: example  
    networks:  
      - fastdev  
  
  postgres:  
    image: postgres  
    #restart: always  
    environment:  
      PGDATA: /var/lib/postgresql/data/pgdata  
      POSTGRES_USER: root  
      POSTGRES_PASSWORD: example  
    volumes:  
      - alldata:/var/lib/postgresql/data  
    networks:  
      - fastdev  
  
  mariadb:  
    image: mariadb  
    #restart: always  
    environment:  
      MYSQL_ROOT_PASSWORD: example  
    volumes:  
      - alldata:/var/lib/mysql  
    networks:  
      - fastdev  
  
  adminer:  
    image: adminer  
    #restart: always  
    ports:  
      - 8082:8080  
    networks:  
      - fastdev  
        
  openldap:  
    build:  
      context: openldap/  
    command: [--copy-service,  --loglevel, debug]  
    environment:  
      LDAP_ORGANISATION: "das-labor"  
      LDAP_DOMAIN: "das-labor.org"  
      LDAP_BASE_DN: "dc=das-labor,dc=org"  
      LDAP_ADMIN_PASSWORD: "abc123"  
      LDAP_CONFIG_PASSWORD: "abc123"  
    volumes:  
      - ./openldap/data/ldap/environment:/container/environment/01-custom  
      - ./openldap/data/slapd/database:/var/lib/ldap  
      - ./openldap/data/slapd/config:/etc/ldap/slapd.d  
      #- ./openldap/certs:/container/service/slapd/assets/certs  
    ports:  
      - "389:389"  
      - "689:689"  
    networks:  
      - fastdev  
  
  phpldapadmin:  
    image: osixia/phpldapadmin  
    command: [--loglevel, debug]  
    environment:  
      PHPLDAPADMIN_LDAP_HOSTS: "openldap"  
    ports:  
      - "6443:443"  
    networks:  
      - fastdev  
  
volumes:    
  alldata:   
  
networks:  
  fastdev:  
    driver: bridge  

geth Dockerfile all same

  
FROM ethereum/client-go:alltools-latest  
  
RUN \  
    echo '@edge http://dl-cdn.alpinelinux.org/alpine/edge/main' >> /etc/apk/repositories && \  
    echo '@edge http://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories && \  
    echo '@edge http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories && \  
    apk --no-cache upgrade  
  
RUN apk update &&\  
    apk add git nodejs bash perl  
  
ADD ./genesis/poa_for_dev.json /root/genesis/poa_for_dev.json  
#RUN geth init /root/genesis/genesis.json --datadir "~/.ethereum/devchain"  
  
  
#RUN geth --dev --rpcapi "db,personal,eth,net,web3" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --mine   
#geth --syncmode "light" --cache=2048  
#./geth --datadir /root/.ethereum --password /root/geth.password --unlock "0" --port 30310 --rpc --rpcaddr "0.0.0.0" -rpcapi "eth,web3" --rpcport 8110 --networkid 4567890 --dev --lightkdf --nodiscover --maxpeers 0 --verbosity 6 --pprof --pprofport 6110 $@ 2> /tmp/geth.log  
  
COPY start.sh /root/start.sh  
RUN chmod +x /root/start.sh  
  
ENTRYPOINT /root/start.sh  

genesis use puppeth see

https://medium.com/taipei-ethereum-meetup/%E4%BD%BF%E7%94%A8-go-ethereum-1-6-clique-poa-consensus-%E5%BB%BA%E7%AB%8B-private-chain-1-4d359f28feff

start.sh all different

node1

  
#!/bin/bash  
set -e  
datadir="~/.ethereum/devchain"  
#ip=$(echo `awk 'END{print $1}' /etc/hosts`)  
ip=$(ping -c1 go-ethereum-signer1 | sed -nE 's/^PING[^(]+\(([^)]+)\).*/\1/p')  
  
echo "======== geth ========"  
echo "======== init ========"  
geth --datadir=$datadir init "/root/genesis/poa_for_dev.json"  
  
sleep 2  
echo "======== bootnode ========"  
#bootkey="fcc406a7344690f66c757cc2c9987e3e78bb01e33229f9877d48a7fecc2d6657"  
#bootnode -nodekeyhex $bootkey -verbosity 4 &  
#bootnodeid=$(bootnode --nodekeyhex=$bootkey -writeaddress) #node address: 256330933851d6d3c5f7326b01021553415a33cd5485e23bfbe35f6321e6e2f8373bb1c94933fdb3283a1a8b2b737587dd99c555029e65e173a3094daa39277c  
  
#bootnode --genkey=boot.key  
#bootnode --nodekey=boot.key -verbosity 4 &  
#bootnode --nodekey=boot.key  -writeaddress > bootnodeid.txt  
#bootnodeid=$(bootnode --nodekey=boot.key  -writeaddress)  
  
sleep 2  
echo "======== account ========"  
privatekey="138cbbfb21686ddc3b5ffeb2cfc83491175af68319977acb81d0ae93392c626c"  
address="e79d33e93bd888b35e055f1a12d876354729037b"  
  
echo "======== check account exist ========"  
isInFile=$(echo `geth account list --datadir=$datadir | grep -c $address`)  
if [ $isInFile -eq 0 ]; then  
    echo "======== acoount no exist! Starting import! ========"  
    echo "" > ~/.accountpassword  
    echo $privatekey > ~/.privatekey  
    geth account import --datadir=$datadir --password ~/.accountpassword  ~/.privatekey  
else  
   echo "======== account exist ========"  
fi  
  
sleep 2  
echo "======== mine ========"  
nodeaddress="256330933851d6d3c5f7326b01021553415a33cd5485e23bfbe35f6321e6e2f8373bb1c94933fdb3283a1a8b2b737587dd99c555029e65e173a3094daa39277c"  
  
#no use bootnode, fix nodekeyhex  
#geth --datadir=$datadir --nodekeyhex "fcc406a7344690f66c757cc2c9987e3e78bb01e33229f9877d48a7fecc2d6657" --networkid 53809 --port 30303 --rpcapi "db,admin,debug,miner,personal,txpool,eth,net,web3" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcvhosts=* --password ~/.accountpassword --unlock $address --mine --minerthreads=1  2> /root/geth.log  
  
#use bootnode  
bootnodeId="enode://"$nodeaddress"@"$ip":30303"  
#bootnodeId="enode://"$bootnodeid"@"$ip":30303"  
until echo | nc -z -v go-ethereum-signer1 30303; do  
    echo "Waiting go-ethereum-signer1 to start..."  
    sleep 2  
done  
geth --datadir=$datadir --bootnodes $bootnodeId --networkid 11559 --port 30303 --rpcapi "db,admin,debug,miner,personal,txpool,eth,net,web3" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcvhosts=* --password ~/.accountpassword --etherbase $address  2> /root/geth.log  

node2

  
#!/bin/bash  
set -e  
datadir="~/.ethereum/devchain"  
#ip=$(echo `awk 'END{print $1}' /etc/hosts`)  
ip=$(ping -c1 go-ethereum-signer1 | sed -nE 's/^PING[^(]+\(([^)]+)\).*/\1/p')  
  
echo "======== geth ========"  
echo "======== init ========"  
geth --datadir=$datadir init "/root/genesis/poa_for_dev.json"  
  
sleep 2  
echo "======== bootnode ========"  
#bootkey="fcc406a7344690f66c757cc2c9987e3e78bb01e33229f9877d48a7fecc2d6657"  
#bootnode -nodekeyhex $bootkey -verbosity 4 &  
#bootnodeid=$(bootnode --nodekeyhex=$bootkey -writeaddress) #node address: 256330933851d6d3c5f7326b01021553415a33cd5485e23bfbe35f6321e6e2f8373bb1c94933fdb3283a1a8b2b737587dd99c555029e65e173a3094daa39277c  
  
#bootnode --genkey=boot.key  
#bootnode --nodekey=boot.key -verbosity 4 &  
#bootnode --nodekey=boot.key  -writeaddress > bootnodeid.txt  
#bootnodeid=$(bootnode --nodekey=boot.key  -writeaddress)  
  
sleep 2  
echo "======== account ========"  
privatekey="df0c39faccd3c9d6d10091932f2214b9d42e92bd07b64a1552d13d39a6a84122"  
address="bf95eaacf10bea53f0a73955a7efce2fb4a4ef1d"  
  
echo "======== check account exist ========"  
isInFile=$(echo `geth account list --datadir=$datadir | grep -c $address`)  
if [ $isInFile -eq 0 ]; then  
    echo "======== acoount no exist! Starting import! ========"  
    echo "" > ~/.accountpassword  
    echo $privatekey > ~/.privatekey  
    geth account import --datadir=$datadir --password ~/.accountpassword  ~/.privatekey  
else  
   echo "======== account exist ========"  
fi  
  
sleep 2  
echo "======== mine ========"  
nodeaddress="256330933851d6d3c5f7326b01021553415a33cd5485e23bfbe35f6321e6e2f8373bb1c94933fdb3283a1a8b2b737587dd99c555029e65e173a3094daa39277c"  
  
#no use bootnode, fix nodekeyhex  
#geth --datadir=$datadir --nodekeyhex "fcc406a7344690f66c757cc2c9987e3e78bb01e33229f9877d48a7fecc2d6657" --networkid 53809 --port 30303 --rpcapi "db,admin,debug,miner,personal,txpool,eth,net,web3" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcvhosts=* --password ~/.accountpassword --unlock $address --mine --minerthreads=1  2> /root/geth.log  
  
#use bootnode  
bootnodeId="enode://"$nodeaddress"@"$ip":30303"  
#bootnodeId="enode://"$bootnodeid"@"$ip":30303"  
until echo | nc -z -v go-ethereum-signer1 30303; do  
    echo "Waiting go-ethereum-signer1 to start..."  
    sleep 2  
done  
geth --datadir=$datadir --bootnodes $bootnodeId --networkid 11559 --port 30303 --rpcapi "db,admin,debug,miner,personal,txpool,eth,net,web3" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcvhosts=* --password ~/.accountpassword --etherbase $address  2> /root/geth.log  

signer1

  
#!/bin/bash  
set -e  
datadir="~/.ethereum/devchain"  
ip=$(echo `awk 'END{print $1}' /etc/hosts`)  
#ip=$(ping -c1 go-ethereum-signer1 | sed -nE 's/^PING[^(]+\(([^)]+)\).*/\1/p')  
  
echo "======== geth ========"  
echo "======== init ========"  
geth --datadir=$datadir init "/root/genesis/poa_for_dev.json"  
  
sleep 2  
echo "======== bootnode ========"  
#bootkey="fcc406a7344690f66c757cc2c9987e3e78bb01e33229f9877d48a7fecc2d6657"  
#bootnode -nodekeyhex $bootkey -verbosity 4 &  
#bootnodeid=$(bootnode --nodekeyhex=$bootkey -writeaddress) #node address: 256330933851d6d3c5f7326b01021553415a33cd5485e23bfbe35f6321e6e2f8373bb1c94933fdb3283a1a8b2b737587dd99c555029e65e173a3094daa39277c  
  
#bootnode --genkey=boot.key  
#bootnode --nodekey=boot.key -verbosity 4 &  
#bootnode --nodekey=boot.key  -writeaddress > bootnodeid.txt  
#bootnodeid=$(bootnode --nodekey=boot.key  -writeaddress)  
  
sleep 2  
echo "======== account ========"  
privatekey="d05bd152f3d71ff5f91830f3ccc1090fb670c7026ebf8c2136d4e5090d59398d"  
address="5921a4c1b13afbd4b61d63e9c7bd47741c47b176"  
  
echo "======== check account exist ========"  
isInFile=$(echo `geth account list --datadir=$datadir | grep -c $address`)  
if [ $isInFile -eq 0 ]; then  
    echo "======== acoount no exist! Starting import! ========"  
    echo "" > ~/.accountpassword  
    echo $privatekey > ~/.privatekey  
    geth account import --datadir=$datadir --password ~/.accountpassword  ~/.privatekey  
else  
   echo "======== account exist ========"  
fi  
  
sleep 2  
echo "======== mine ========"  
#nodeaddress="256330933851d6d3c5f7326b01021553415a33cd5485e23bfbe35f6321e6e2f8373bb1c94933fdb3283a1a8b2b737587dd99c555029e65e173a3094daa39277c"  
  
#no use bootnode, fix nodekeyhex  
geth --datadir=$datadir --nodekeyhex "fcc406a7344690f66c757cc2c9987e3e78bb01e33229f9877d48a7fecc2d6657" --networkid 11559 --port 30303 --rpcapi "db,admin,debug,miner,personal,txpool,eth,net,web3" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcvhosts=* --password ~/.accountpassword --unlock $address --mine --minerthreads=1  2> /root/geth.log  
  
#use bootnode  
#bootnodeId="enode://"$nodeaddress"@"$ip":30303"  
#bootnodeId="enode://"$bootnodeid"@"$ip":30303"  
#until echo | nc -z -v go-ethereum-signer1 30303; do  
#    echo "Waiting go-ethereum-signer1 to start..."  
#    sleep 2  
#done  
#geth --datadir=$datadir --bootnodes $bootnodeId --networkid 11559 --port 30303 --rpcapi "db,admin,debug,miner,personal,txpool,eth,net,web3" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcvhosts=* --password ~/.accountpassword --etherbase $address  2> /root/geth.log  

signer2

  
#!/bin/bash  
set -e  
datadir="~/.ethereum/devchain"  
#ip=$(echo `awk 'END{print $1}' /etc/hosts`)  
ip=$(ping -c1 go-ethereum-signer1 | sed -nE 's/^PING[^(]+\(([^)]+)\).*/\1/p')  
  
echo "======== geth ========"  
echo "======== init ========"  
geth --datadir=$datadir init "/root/genesis/poa_for_dev.json"  
  
sleep 2  
echo "======== bootnode ========"  
#bootkey="fcc406a7344690f66c757cc2c9987e3e78bb01e33229f9877d48a7fecc2d6657"  
#bootnode -nodekeyhex $bootkey -verbosity 4 &  
#bootnodeid=$(bootnode --nodekeyhex=$bootkey -writeaddress) #node address: 256330933851d6d3c5f7326b01021553415a33cd5485e23bfbe35f6321e6e2f8373bb1c94933fdb3283a1a8b2b737587dd99c555029e65e173a3094daa39277c  
  
#bootnode --genkey=boot.key  
#bootnode --nodekey=boot.key -verbosity 4 &  
#bootnode --nodekey=boot.key  -writeaddress > bootnodeid.txt  
#bootnodeid=$(bootnode --nodekey=boot.key  -writeaddress)  
  
sleep 2  
echo "======== account ========"  
privatekey="df504d175ae63abf209bad9dda965310d99559620550e74521a6798a41215f46"  
address="8cc5a1a0802db41db826c2fcb72423744338dcb0"  
  
echo "======== check account exist ========"  
isInFile=$(echo `geth account list --datadir=$datadir | grep -c $address`)  
if [ $isInFile -eq 0 ]; then  
    echo "======== acoount no exist! Starting import! ========"  
    echo "" > ~/.accountpassword  
    echo $privatekey > ~/.privatekey  
    geth account import --datadir=$datadir --password ~/.accountpassword  ~/.privatekey  
else  
   echo "======== account exist ========"  
fi  
  
  
sleep 2  
echo "======== mine ========"  
nodeaddress="256330933851d6d3c5f7326b01021553415a33cd5485e23bfbe35f6321e6e2f8373bb1c94933fdb3283a1a8b2b737587dd99c555029e65e173a3094daa39277c"  
  
#no use bootnode, fix nodekeyhex  
bootnodeId="enode://"$nodeaddress"@"$ip":30303"  
until echo | nc -z -v go-ethereum-signer1 30303; do  
    echo "Waiting go-ethereum-signer1 to start..."  
    sleep 2  
done  
geth --datadir=$datadir --bootnodes $bootnodeId --networkid 11559 --port 30303 --rpcapi "db,admin,debug,miner,personal,txpool,eth,net,web3" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcvhosts=* --password ~/.accountpassword --unlock $address --mine --minerthreads=1  2> /root/geth.log  
  
#use bootnode  
#bootnodeId="enode://"$nodeaddress"@"$ip":30303"  
#bootnodeId="enode://"$bootnodeid"@"$ip":30303"  
#until echo | nc -z -v go-ethereum-signer1 30303; do  
#    echo "Waiting go-ethereum-signer1 to start..."  
#    sleep 2  
#done  
#geth --datadir=$datadir --bootnodes $bootnodeId --networkid 11559 --port 30303 --rpcapi "db,admin,debug,miner,personal,txpool,eth,net,web3" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcvhosts=* --password ~/.accountpassword --etherbase $address  2> /root/geth.log  

Best Important is

1. private key & address must right.
2. signer1 must start, so node1 node2 signer2 wait signer1
3. start.sh file must utf-8 & LE
4. docker inside port different outside port(expose port)

Final check:

login docker signer1

  
docker ps -a |grep signer1    Get docker signer1 id  
docker exec -it xxxid /bin/bash  

into docker

  
>find / -name geth.ipc     Get geth.ipc path  
>get attach ipc:/xxxx/xxxxx/xxxxx/xxxxx/geth.ipc  

into geth console

  
>admin.peers    Can see three node (node1 node2 signer2)  
>personal.listWallets   Check unlock   
>eth.mining   Check true (mining start mining)  

PS:keep bootnode code for if you want wake up bootnode and not use signer1 be connect. This can make code more easy and smae, only some key word ( private key, address..etc) different.

PS:If create finish, change volumn path that maybe get “can’t find .accountpassword “. fix way:just add again at account exist

 echo "" > ~/.accountpassword

full demo like this

  
else  
   echo "======== account exist ========"  
   echo "" > ~/.accountpassword  
fi