Many quarters ago, I started mining Monero using Docker containers. The reason for using Docker was simple. If you are running Monero on servers you may not want to have the dependencies installed on the base OS and you likely want some isolation. Virtual Machines are not suitable for efficient mining which is why so many Dockerized Windows mining attempts end in poor results. For some background, you can read our Monero Mining on Linux made easy with Docker piece. Today we have the updated version of that guide.
The Quick Monero Background
Bitcoin is still the largest cryptocurrency by far. Monero is a cryptocurrency that put an emphasis on privacy and is considered significantly more anonymous than Bitcoin. As a result, Monero has fairly consistently been a top 10 cryptocurrency in 2017.
The advantage of this has been that Monero is now very easy to exchange and has tools that are more mature than several other cryptocurrencies. For STH readers there is a larger implication. Unlike Bitcoin mining which is dominated by ASICs, Monero is currently best mined on GPUs. CPU mining can be profitable as well. That means STH readers have the infrastructure able to mine Monero. Here is what our public Docker Hub repository looks like by way of gauging popularity:
Just to give some perspective, for a decent part of the year, we have been able to offset 20-30% of our data center costs mining Monero. Some of the new, more efficient architectures are even better. Dual AMD EPYC 7601 CPUs Can Offset Operational Costs Using Monero Mining.
If you read STH, and have a Linux OS installed on machines with low utilization periods, you have all you need to start mining Monero. Using Docker to learn Monero mining is actually a great way to start learning Docker.
Monero mining difficulty has been increasing much faster than the appreciation of the currency. We are approaching a time when mining Monero is not going to be profitable if you have to purchase hardware, however, if you have inexpensive power and cooling, it can still make sense to spin up on existing hardware.
Switching to xmrig with Docker
Although our Monero CPU mining Docker images have had 100’s of thousands of pulls on Docker Hub, we are making a major change: moving to the xmrig miner. We did some “informal” benchmarks on these machines to validate Monero mining using three popular miners Wolf’s (the “granddaddy” miner), Stak and xmrig. These servers are all deployed in a data center and run normal workloads the vast majority of the time. We used the auto-generated Stak configuration file as that is easy to deploy on hundreds of heterogeneous nodes. Here are a few data points:
A few notes here. First, we are using this in a method that is easy to deploy on 10,000 servers. If you are hand editing configuration files and OS settings to do core affinity tuning beyond the auto-generated stak-xmr config file, stak is a good option. Second, we are using the standard Wolfs configuration we used to benchmark almost 100 server Monero Mining CPU configurations this year. While we knew there were better miners, we also wanted to keep a consistent data set.
We originally found xmrig was giving us significantly lower results on 2, 4, and 8 NUMA node systems. To get to the numbers in black, we are still using only the docker run command, but we were able to use the –cpuset-cpus command. Here is a look just at a few Intel Xeon E5 V3 generation dual socket configurations where we saw 9.7% – 15% greater performance:
On AMD EPYC, the difference was so large, especially on dual socket configurations, that you essentially must do this tuning.
In terms of impact, we are now at just below 4KH/s from a dual AMD EPYC 7601 system and just below 6KH/s on a quad Intel Xeon Platinum 8180 system. The other major impact with launching one container per NUMA node is that one can run mining on one CPU while the other is left untouched for standard workloads.
Universal xmrig Docker Monero Mining Image
We created a new Dockerized xmrig Monero CPU mining image that is a clear evolution over our previous attempts. For this generation, we have made a number of improvements:
- Designed to be a universal mining image (not tied to one pool)
- Designed to have defaults to make starting mining easy
- Designed to be constrained to NUMA nodes and have scripted launches for those managing Docker clusters with Ansible, Jenkins, Kubernetes, Docker Compose or other tools.
Previous generations we tied to an architecture and a pool. That meant there was one pool image and then different tags for Ryzen, EPYC, Atom CPUs, NVIDIA GPUs, and etc. With this generation, we are starting with a generic CPU miner. Our default is using Dwarfpool USA since we have had good experience mining several hundred XMR there.
Here is the actual launch command we are using:
./xmrig -o stratum+tcp://$xmrpool:$startport -u $username -p $password -t $numthreads --donate-level=$donate
All four variables other than $username have default values. Username does not since that is your wallet address that you need to earn proceeds from mining.
These four variables are passed to a Docker container as environment variables (“-e”). As a quick rundown in your docker run command you would have:
- -e xmrpool=<pool address>
- -e startport=<pool port>
- -e username=<username field usually wallet address or wallet.workerID>
- -e password=<password, x or e-mail usually>
- -e numthreads=<number of threads to use>
- -e donate=<percentage of mining time to donate to the xmrig developers in whole integer>
On the defaults, the xmrpool address will default to xmr-usa.dwarfpool.com. The startport will default to 8100 as most servers will have fewer rejected shares starting at a higher difficulty. The username has no default since you need to put your Monero wallet address there. The password will default to x. Numthreads will use nproc as a default just to get the miner running, but you should change this. Donate does not have a default value so it starts at 0%, but it is a good idea to support the development of miners.
The idea here is that you can skip having to build xmrig, and instead just pass environment variables in. That means you can easily look up syntax of various pools and map directly to the Docker image.
Getting Started with the xmrig Docker Miner and Mining in 2 Minutes
If you want to start mining on Dwarfpool USA, here is what you would need to use:
docker run -itd -e username=<wallet> -e password=<e-mail address> -e numthreads=<threds> servethehome/monero_xmrig
Let us say you wanted to run only on the fourth NUMA node on a single socket AMD EPYC 7501 we can use the –cpuset-cpus to specifically target the last NUMA node. Here is what our lscpu output looks like:
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
On-line CPU(s) list: 0-63
Thread(s) per core: 2
Core(s) per socket: 32
NUMA node(s): 4
Vendor ID: AuthenticAMD
CPU family: 23
Model name: AMD EPYC 7501 32-Core Processor
CPU MHz: 1200.000
CPU max MHz: 2000.0000
CPU min MHz: 1200.0000
L1d cache: 32K
L1i cache: 64K
L2 cache: 512K
L3 cache: 8192K
NUMA node0 CPU(s): 0-7,32-39
NUMA node1 CPU(s): 8-15,40-47
NUMA node2 CPU(s): 16-23,48-55
NUMA node3 CPU(s): 24-31,56-63
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tscnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_l2 mwa clzero irperf arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic overflow_recov succor smca
Here we are targeting NUMA node3 and we know we have 16MB L3 cache on that NUMA node. As a result, we want to place 8 mining threads and there are eight physical cores. Here we would use:
docker run -itd -e username=<wallet> -e password=<e-mail address> -e numthreads=8 --cpuset-cpus"24-31" servethehome/monero_xmrig
That does two things for us. First, it constrains us to physical CPU cores (56-63 are the SMT / hyper-threading cores.) Second, it constrains our miner to a NUMA node. On AMD EPYC, constraining miners to a single NUMA node has an enormous impact, especially on dual socket systems to where we can see 20%+ performance improvement.
Let us say we wanted to donate 3% to the xmrig developers. We also want to change pools to a small pool like xmrpool.net that offers solo mining and an EU server. You can look up their address, ports and syntax on their getting started page.
docker run -itd -e xmrpool=frankfurt-1.xmrpool.net -e startport=7779 -e username=<wallet> -e password=$(hostname)-epyc7501-3 -e numthreads=8 -e donate=3 --cpuset-cpus"24-31" servethehome/monero_xmrig
All pools are a bit different so instead of an e-mail address in the password field, we use a worker name. A quick tip here: $(hostname)-<numa node> is very effective if you ever need to troubleshoot an offline miner later.
Final Words and Where to Get More Information
We have a full getting started guide from creating your wallet to using this image in the forums here: How to start mining Monero in Docker. That also has sample scripts to show how to startup across multiple NUMA nodes easily which is important if you are managing larget clusters.
If you did want to donate XMR: 45X3YiUzvG1hVo5FrhvGx8gh3d6rjpmHobLKEfVagrKz1uuGuByoHe9WwT5GbtMqc83BXsomR4zLJTBhk88qBxgeRnAeoEs
We did receive 0.14 XMR of donations from our last efforts which got hundreds of thousands of nodes online so are not expecting much.