15

Here is a set up I have been working on and am having issues with ability to create a private network with peers. Basic set up: Used the dockerfile from https://github.com/ethereum/ethereum-dockers/tree/master/go-ethereum-base, and added a line for installation of Ethereum to the image.

  1. Upon creation of the image, I ran 2 instances of the image, (note that both contain basic custom genesis JSON file)

    docker run -it -p 127.0.0.1:30303:30303 -p 3001:3001 --name e1 
    

    and

    docker run -it -p 127.0.0.1:30304:30304 -p 3002:3002 --name e2 \
      --link e1:e1 
    
  2. Next, I attached to the container, e1 and ran the following command:

    geth --identity "ethnode1" --datadir "/tempdatadir1" --rpc         \
      --port "30303" --rpccorsdomain "*" --rpcport "3001"              \
      --genesis genesis.json --networkid 6161                          \
      --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \
      --rpcapi "db,eth,net,web3" --nat "any" --maxpeers 2 console
    

This launched a geth console, wherein I am able to check the node info using commands such as admin.nodeInfo, etc. Extracted the enode value for connecting the second node: enode://@[::]:30303

Exit console using Crtl-C

  1. Attached to the container e2, and ran the following command:

    geth --identity "ethnode2" --datadir "/tempdatadir2" --rpc         \
      --port "30304" --rpccorsdomain "*" --rpcport "3002"              \
      --genesis genesis.json --networkid 6161                          \
      --ipcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" \
      --rpcapi "db,eth,net,web3" --nat "any" --maxpeers 2 console
    

This launched a geth console, wherein I am able to check the node info using commands such as admin.nodeInfo, etc. At this point, I tried adding the first node using the following command: admin.addPeer("enode://@127.0.0.1:30303"), which returns true. However, when I try to list the peers using either admin.Peers, I see an empty array and using net.peerCount gives 0.

Suggestions, as to how the connectivity between the two can be enabled?

  • Is it that the wrong IP address is being used? In general, is it possible to utilize a specific IP address from the host by forwarding the IP Address appropriately.
  • Should the console not be exited in Step 2 above?
  • In either of the above cases, how do we connect to an existing geth instance? I tried using geth attach "http://127.0.0.1:3001", but it gave me an error saying, connection refused. Any suggestions as to how we can attach to an existing geth instance?

2 Answers 2

15

Summary

  1. Check that there is network connectivity between the two Docker containers and reconfigure if necessary. Check there is sufficient memory allocated to each container.
  2. In each Docker container

    • Install the go-ethereum geth program
    • Create two accounts (Ethereum addresses)
    • Run geth with the exact same custom genesis.json file, same --networkid, --datadir set to your preferred directory and with the parameter for geth to start mining.
    • Test that geth is working
  3. Connect the geth instances.


Short Answer To Your Questions

  • Q: How the connectivity between the two can be enabled?

    • A: First set up connectivity between the Docker containers. Some references provided, but don't use 127.0.0.1 as this is normally confined to be used within your operating system / Docker container.
  • Q: Is it that the wrong IP address is being used? In general, is it possible to utilize a specific IP address from the host by forwarding the IP Address appropriately.

    • A: There should be a non-127.0.0.1 IP address available from within the Docker container. Instructions below to find this address.
  • Q: Should the console not be exited in Step 2 above?

    • A: Test your setup first using geth ... console. Don't exit the geth command prompt while you are testing.
  • Q: In either of the above cases, how do we connect to an existing geth instance? I tried using geth attach "http://127.0.0.1:3001", but it gave me an error saying, connection refused. Any suggestions as to how we can attach to an existing geth instance?

    • A: I've listed some tests below to check your Docker container networking connectivity. Once connectivity is resolved, use your --rpc* parameters and your should be able to connect using geth attach ... with the non-127.0.0.1 address and port.

EDIT 23/04/2016 - OP solved the connectivity issue using 192.*.*.* instead of 127.0.0.1 for the IP addresses as shown in the following Docker commands:

docker run -it -p 192.XXX.XXX.XXX:30303:30303 --name e1 <eth image>

and

docker run -it -p 192.XXX.XXX.XXX:30304:30304 --name e2 --link e1:e1 <eth image>

EDIT 24/04/2016 - OP has the data directories to be created in the root (/) directory. This will require superuser (root) permission. It is better to store the data directory within your home directory. Use $HOME/tempdatadir1 instead of /tempdatadir1. By default, geth will create your data directory in $HOME/.ethereum.


Details Below


Docker Container Connectivity And Requirements

Memory

geth will require more than 512 Mb so you may want to test with 1 Gb and increase it if necessary.


Docker Networking

Aim

You will need to set up your Docker containers so that geth in Container #1 can connect to geth in Container #2 and vice versa.

In your question, you have mapped 127.0.0.1:30303 to be accessed externally through port 30303. The 127.0.0.1 IP address is a localhost addresses that normally does not allow communication from outside the operating system. Please check for the non-127.0.0.1 IP address by using ifconfig -a within your Docker containers to determine what your non-localhost IP addresses are. Try using these IP addresses to communicate across the Docker containers.

References


Check Connectivity

Get the IP address from within Container #1 using ifconfig -a:

ifconfig -a
lo      ...
        inet addr:127.0.0.1 ...
        ...
docker0 ...
        inet addr:192.168.0.1

Run geth on port 30303 in Container #1 as shown in the next section (or as you documented in your Question).

From Container #2 or the host, you should be able to run the following command - you will have to hit Control-C to teminate the connection:

user@Kumquat:~$ telnet 192.168.0.1 30303
Trying 192.168.0.1...
Connected to 192.168.0.1.
Escape character is '^]'.

If your IP address is not set up to receive your connection attempt, your results should look like:

user@Kumquat:~$ telnet 192.168.0.1 30303
Trying 192.168.0.1...
telnet: Unable to connect to remote host: No route to host

If your IP address is correct, but your port is not mapped correctly, you should see:

user@Kumquat:~$ telnet 192.168.0.1 30303
Trying 192.168.0.1...
telnet: Unable to connect to remote host: Connection refused



Configure geth

Configure geth with the basic parameters so we can verify that it is working as expected, without the P2P connection between the Docker containers. You will firstly need to configure two accounts to test your mining.


New Accounts

In Container #1, run the following command twice to create two new accounts:

user@Kumquat:~$ geth --datadir "$HOME/tempdatadir1" account new
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase: 
Repeat Passphrase: 
Address: {a6847de2447db964ef89644752921c204bf563ab}

Data related to your account (in encrypted format) is stored in your --datadir directory under the subdirectory keystore. Make sure that you back these files up (and remember your password) if you are using this account in the main Ethereum network.

user@Kumquat:~$ ls -al $HOME/tempdatadir1/keystore
total 12
drwx------ 2 user user 4096 Apr 24 16:11 .
drwx------ 3 user user 4096 Apr 24 16:11 ..
-rw------- 1 user user  491 Apr 24 16:11 UTC--2016-04-24T06-11-04.534736154Z--a6847de2447db964ef89644752921c204bf563ab

And the same in Container #2, using the --datadir for Container #2.


Run geth Miner

Run the following command in Container #1, and you should see messages like the ones listed below:

geth --datadir "/tempdatadir1" --port "30303" \
  --genesis genesis.json --networkid 6161     \
  --mine --minerthreads 1 console

Same for Container #2:

geth --datadir "/tempdatadir2" --port "30304" \
  --genesis genesis.json --networkid 6161     \
  --mine --minerthreads 1 console

The messages you should be seeing follow:

I0422 23:24:07.347255    8218 worker.go:348] 🔨  Mined block (#6248 / 11175b1e). Wait 5 blocks for confirmation
I0422 23:24:07.347868    8218 worker.go:569] commit new work on block 6249 with 0 txs & 0 uncles. Took 521.208µs
I0422 23:24:07.348356    8218 worker.go:569] commit new work on block 6249 with 0 txs & 0 uncles. Took 378.62µs
I0422 23:24:18.248751    8218 worker.go:348] 🔨  Mined block (#6249 / 50cdfdeb). Wait 5 blocks for confirmation
I0422 23:24:18.249306    8218 worker.go:569] commit new work on block 6250 with 0 txs & 0 uncles. Took 470.831µs


Sending An Ether From Account #1 to Account #2

In each container, run the sendTransaction command in the geth console. You mining operation should be adding ethers to eth.accounts[0] (first account, also called coinbase). This command will send an ether from eth.accounts[0] to eth.accounts[1]:

> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether")})
"0xde465790a8ae4ce1aad3179d071ac49ed447c09199de26ce02327e8790e63e4b"

Wait for the transaction to be mined. Then run the getTransaction command to check the transaction has been mined into a block:

> eth.getTransaction("0xde465790a8ae4ce1aad3179d071ac49ed447c09199de26ce02327e8790e63e4b")
{
  ...
  blockNumber: 6266,
  ...
}

Check the account balance of eth.accounts[1]:

> web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
1



Connect The geth Instances

You will need to find the enode information for each geth instance. I've shortened the long node public key from "d9d93b749257a1d4eaec18ab1c1ad39dc9220e449cfe248aceafc586193ead0ac14a088be5afb8455bd8f14bab7428162b8fbeda399ec748f5df0369789730d9" to "d9d9...30d9" for ease of reading - use the full version in your configuration.

In Container #1, run the following command in the geth ... console:

> admin.nodeInfo
{
  enode: "enode://d9d9...30d9@[::]:30303?discport=0",
  ...
}

Get the same information from geth in Container #2.

In the Peer Discovery section below, replace [::] in your enode with the externally accessible IP address of your Docker container, and remove the ?discport=0 text.


Peer Discovery

You have 3 methods to get geth in your Docker containers to connect to each other:

  1. Bootnodes

    In Container #1, add the --bootnodes parameter to your geth command line like, where "d9d9...30d9" needs to be replaced by the appropriate public key for geth in Container #2:

    geth --bootnodes "enode://[email protected]:30304" ...
    

    In Container #2, you can add the similar parameters:

    geth --bootnodes "enode://[email protected]:30303" ...
    

    This will connect your geth nodes for the initial peer discovery where they should discover each other an maintain a P2P connection.

  2. static-nodes.json

    Add the following text, replaced with your node information, in your --datadir directory in a file named static-nodes.json:

    [
      "enode://[email protected]:30304",
      "enode://[email protected]:30303"
    ]
    
  3. trusted-nodes.json

    Same as static-nodes.json above, but the node connections here do not count towards the --maxpeers parameter if specified.

Try the different configuration styles until I find one that is stable for at least a few days.


Peer Discovery References



How To Run geth In The Background

To run geth as a background process, remove the console parameter from your geth command and append the & symbol that will start the process in the background. As you may want to inspect the messages from geth, you should pipe (send) the output from geth into a log file.

This is how I do it:

  1. Make a subdirectory logs in your $HOME directory:

    mkdir $HOME/logs
    
  2. Set up a script file with your geth command line option. I call mine runGeth and save it in $HOME/bin . Ths full filename is $HOME/bin/runGeth, and this file contains:

    #!/bin/sh
    
    # Kill any running geth instances gracefully
    killall -q --signal SIGINT geth
    
    # Wait for 10 seconds
    sleep 10
    
    # Make sure that geth is really killed. Try hard killing again
    killall -q geth
    
    # Run geth in the background,
    #  piping the output messages to a log file
    geth --rpc [other parameters] --verbosity 3 2>> $HOME/logs/geth.log &
    

    You will have to run the following command to make this script executable:

    user@Kumquat:~$ chmod 700 $HOME/bin/runGeth
    

    You can now start geth running the script from your command line:

    user@Kumquat:~$ runGeth
    

    If this does not work, use the full pathname:

    user@Kumquat:~$ $HOME/bin/runGeth
    
  3. To attach to your geth instance running in the background, use the command:

    geth attach
    

    This will use the IPC protocol to connect to the geth instance running in the background.

    If you want to connect to the geth instance from your other Docker container, or from outside your Docker container, use the following command with the correct IP and port numbers:

    geth attach rpc:http://192.XXX.XXX.XXX:8545
    

    Note that the port 8545 is the default RPC port that can be set using the --rpcport {port} command line parameter.

    You can exit from these geth attach processes without affecting the geth instance running in the background.

    And as I don't like typing out long command line parameters, I create the file $HOME/bin/attachGeth with the following contents:

    #!/bin/sh
    
    geth attach rpc:http://192.XXX.XXX.XXX:8545
    

    And chmod 700 $HOME/bin/attachGeth so I can attach to the background running geth using the command attachGeth or $HOME/bin/attachGeth.

  4. To view the log files from the geth instance running in the background:

    tail -F $HOME/logs/geth.log
    

    Hit Control-C to terminate this process.

9
  • I've completed re-writing the answer. Hopefully it is clearer. Main issue is getting the connectivity across the Docker containers. Non-127.0.0.1 addresses would work best. Apr 22, 2016 at 14:38
  • Extension to the above case: Creating accounts in separate containers and sending funds from one to another container. Few issues with creating accounts at the two separate instances, say g1 and g2 running in their own containers, say e1 and e2. Within e1, I am able to create two accounts using: geth --datadir "d1" account new 1. When a similar command was typed in e2, to create account, after typing in the pass phrase, the error response is "Killed". Note: datadir not created 2. At this point a similar error occurs upon new account creation in e1. Any suggestions as to how to get around this?
    – skarred14
    Apr 24, 2016 at 5:53
  • You normally cannot create a data directory under the root directory, eg: "/tempdatadir1" without the superuser (root) permission. Create your data directory in your home subdirectory using --datadir $HOME/tempdatadir1 . Apr 24, 2016 at 6:07
  • I've just added some instructions to run geth in the background to the bottom of my answer. Apr 24, 2016 at 8:56
  • This answer could be a blog.. Well written ..
    – niksmac
    Apr 24, 2016 at 14:29
2

Eris has a geth Dockerfile with some custom scripts here:

https://github.com/eris-ltd/common/tree/master/docker/geth

It's somewhat out of date though updates are in the pipeline over the next month. The image for that Dockerfile is quay.io/eris/geth and can be run with eris services start geth if eris-cli is installed.

Subscribe to this issue to track progress.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.