How to Manage Your Full Nodes — Part 1: Containerizing Bitcoin and Ethereum with Docker

Oliver Wee
MW Partners
Published in
7 min readJul 31, 2018

This article is the part 1 of 3 series on How to manage your full nodes.

Today, we will be talking about — Part 1: Containerization Bitcoin and Ethereum using Docker.

Why run a full a node?

Learning Objectives

  1. Write a simple Dockerfile for Bitcoin and Ethereum
  2. Deploy Bitcoin and Ethereum with Docker

Benefits of Containerization

Isolation

Every container has it’s own dedicated CPU, memory and network resources, meaning we can run multiple blockchain clients on the same machine without worrying if the one client’s excess resource consumption would cause the other clients to crash.

Security

Isolation means that each container is unable to view other containers and the host’s running processes and resources, which reduces the surface area for attackers. Damage done to a blockchain client running inside the container is mostly limited to that container.

Continuous Deployment

Write once , deploy everywhere. Whether we are upgrading the client version or adding a new blockchain client to the machine altogether, we will produce a new container image which can be pushed to external Docker repositories like Amazon (ECR) , Dockerhub for easy access. It also means that we are agnostic to the host operating system / cloud provider so long as the platform supports Docker, it can run our application. This combined with CI / CD tools like CircleCI will make deployment to production environments much faster.

Standardizing Environments

In the past, one of the largest peeves among developers is for an application to run well on their local machine only to fail in testing or production environments. Containers ship with their dependencies explicitly stated and packaged with the application, with environment specific configuration either laid out in a configuration file or coded into the environment variables. Each container image is given a hash, which can be used to manage application releases allowing for easy rollback / implementation of multiple versions of a blockchain client.

What is Docker?

Docker is a tool that allows you to create, deploy and manage applications in containers. Containers contain everything required to run the application ranging from packaged libraries to environment variables and much more. Each container is isolated from the host machine and is deployed with it’s own CPU, memory, and network.

For a great introduction to Docker concepts check out Preethi Kasireddy’s article at https://medium.freecodecamp.org/a-beginner-friendly-introduction-to-containers-vms-and-docker-79a9e3e119b.

Prerequisites

Download blockchain clients

Official Bitcoin Core client:

Choose the Linux (tgz) option.

Instructions on how to verify the clients with Bitcoin Core’s release signature can also be found on that page.

Official Ethereum Client:

Choose the Geth 1.8.12 for Linux.

Setting Up Docker

You may find relevant instructions for installing Docker and Kubernetes for your operating system below:

Writing the Configs and Dockerfiles

Bitcoin

client.conf

##
## bitcoin.conf configuration file. Lines beginning with # are comments.
##
# Uncomment below to run on the test network instead of the real bitcoin network.# testnet=0# server=1 tells Bitcoin-Qt and bitcoind to accept JSON-RPC commands
server=1
# Data Directory
datadir=/app/data
# Index Transactions
txindex=1
# RPC
rpcbind=0.0.0.0:8332
rpcallowip=::/0

In the above client.conf file, we specify a custom data directory /app/data, start a JSON-RPC server and index the transactions, so that old spent transactions can be found by the getRawTransaction RPC call.

Dockerfile

# 1. Base OS Image
FROM ubuntu:16.04
# 2. Copy blockchain client
ADD bitcoin-0.16.2 /app
# 3. Setup directory
WORKDIR /app/bin
# 4. Make permissions
RUN chmod +x /app/bin/bitcoind
# 5. Add client.conf file
COPY client.conf /app/client.conf
# 6. Entrypoint
ENTRYPOINT ["/app/bin/bitcoind", "-conf=/app/client.conf"]

We use Ubuntu Server 16.04 LTS as our base image, copy the bitcoin client folder to /app/ and set the permissions on the bitcoin client executable.

Finally, we copy the configuration file into the /app/ directory and set the ENTRYPOINT to run the Bitcoin client.

Your File Directory should look like this:

> Your Folder
> bitcoin-0.16.2 (Bitcoin Client Folder from Bitcoin Website)
> client.conf
> Dockerfile

*UPDATE (14 Aug 2018): The command #2 Copy blockchain client
‘ADD bitcoin-0.16.2 /app’ in the Dockerfile is dependant on the latest version that is available at https://bitcoincore.org/en/download/.*

Ethereum

Extract the downloaded .tar.gz file into a folder and rename it geth.

You can get the default geth client.toml file by running

geth dumpconfig > client.toml

You can also customize the config by adding CLI options specified here:

https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options

Below is a sample of the default config file with the database cache increased to 1536 for faster syncing.

client.toml

[Eth]
NetworkId = 1 # 1 - Main Network, 3 - Ropsten , 4 - Rinkeby
SyncMode = "fast"
LightPeers = 100
DatabaseCache = 1536 # 0.75 of 2048, Amount of memory to use.
GasPrice = 18000000000
EnablePreimageRecording = false
[Eth.Ethash]
CacheDir = "ethash"
CachesInMem = 2
CachesOnDisk = 3
DatasetDir = "/app/data/.ethash"
DatasetsInMem = 1
DatasetsOnDisk = 2
PowMode = 0
[Eth.TxPool]
NoLocals = false
Journal = "transactions.rlp"
Rejournal = 3600000000000
PriceLimit = 1
PriceBump = 10
AccountSlots = 16
GlobalSlots = 4096
AccountQueue = 64
GlobalQueue = 1024
Lifetime = 10800000000000
[Eth.GPO]
Blocks = 20
Percentile = 60
[Shh]
MaxMessageSize = 1048576
MinimumAcceptedPOW = 2e-01
[Node]
DataDir = "/app/data/ethlive"
IPCPath = "geth.ipc"
HTTPHost = "0.0.0.0"
HTTPPort = 8545 # JSON RPC Port
HTTPVirtualHosts = ["localhost"]
HTTPModules = ["net", "web3", "eth", "shh"]
WSHost = "0.0.0.0"
WSPort = 8546
WSModules = ["net", "web3", "eth", "shh"]
[Node.P2P]
MaxPeers = 25
NoDiscovery = false
BootstrapNodes = ["enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", "enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303", "enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303", "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"]
BootstrapNodesV5 = ["enode://06051a5573c81934c9554ef2898eb13b33a34b94cf36b202b69fde139ca17a85051979867720d4bdae4323d4943ddf9aeeb6643633aa656e0be843659795007a@35.177.226.168:30303", "enode://0cc5f5ffb5d9098c8b8c62325f3797f56509bff942704687b6530992ac706e2cb946b90a34f1f19548cd3c7baccbcaea354531e5983c7d1bc0dee16ce4b6440b@40.118.3.223:30304", "enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30306", "enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30307"]
StaticNodes = []
TrustedNodes = []
ListenAddr = ":30303"
EnableMsgEvents = false
[Dashboard]
Host = "localhost"
Port = 8080
Refresh = 500000000

Dockerfile

# 1. Base OS Image
FROM ubuntu:16.04
# 2. Create the Ethereum directory
ADD geth /app
COPY client.toml /app/client.toml
# 3. Setup entrypoint
WORKDIR /app
RUN chmod +x /app/geth
# 4. Setup NTP
CMD timedatectl set-ntp no
CMD apt-get install ntp
ENTRYPOINT ["/app/geth", "--config /app/client.toml >> /app/data/stdout.log 2>> /app/data/stderr.log"]

In the above Dockerfile, we use Ubuntu 16.04 LTS as the base image, add the geth directory to /app/ and copy the configuration file to the app. We have to set up NTP for the Ethereum client to work correctly.

Lastly, we set the ENTRYPOINT to run the Ethereum client to use the client.toml and pipe the STDOUT and STDERR to two files so we can look up the logs on the filesystem later.

Your file directory should look like this:

> Your Folder
> geth Folder (Downloaded from Ethereum website)
> client.toml
> Dockerfile

Deploying with Docker

In the above two configuration files, we specified the data directory to be /app/data. We will continue now to create two folders /data/btc-live and /data/eth-live in order to mount them as volumes into the Docker container later.

Bitcoin

docker build -t test-btc-img .docker run --name testing-btc-live -v /data/btc-live:/app/data -p 18332:8332 -p 8333:8333 -td test-btc-img

In the above command, we build a new Docker Image from the Dockerfile and tag it as test-btc-img . Next, we create a new Docker container named testing-btc-live and mount the /data/btc-live folder we have on our host as the /app/data volume in the container. Then, we expose the container ports 8332,8333 on the host as ports 18332,8333 for the JSON-RPC server and Bitcoin client respectively.

Ethereum

docker build -t test-eth-img .docker run --name testing-eth-live -v /data/eth-live:/app/data -p 30303:30303 -p 8545:8545 -td test-eth-img

We build a new Docker image from the Dockerfile and tag it as test-eth-img . Then, we create a new Docker container named testing-eth-live and mount the /data/eth-live/ folder on the host as the /app/data volume in the container. Finally, we expose the container ports 30303,8545 on the host as ports 30303,8545 for the Ethereum client and JSON-RPC server respectively.

Geth’s output logs are piped to stderr , which are now available in your /data/eth-live directory as stderr.log

Summary

We have successfully created and deployed two Docker containers for Bitcoin and Ethereum for the main net. We can also create testnet clients for Bitcoin and Ethereum by changing the configuration files specified above and exposing the port 18333 in place of 8333 for Bitcoin. We have barely scratched the surface of what Docker is able to do but I hope this short tutorial is helpful for those who are starting out running their full nodes.

Want to learn more?

Follow us on our Twitter and Medium for more updates. If you are a developer who is keen to contribute towards building a developer community alongside MW Partners, kindly reach out to hello@mwpartners.io.

P.S, a little teaser to all our readers — our next article will touch on Kubernetes, an open-source container-orchestration system for automating deployment, scaling and management of containerized application. Kindly stay tuned!

--

--