Running Ethereum’s Execution & Consensus Nodes on Azure Kubernetes Service

Itay Podhajcer
Microsoft Azure
Published in
4 min readSep 29, 2022

Now that Ethereum’s merge is behind us, where Eth1 and Eth2 are now one single network with a consensus layer and an execution layer, the task of running your own node got a little bit harder. Instead of just running one piece of software that previously was responsible for everything (such as Go Ethereum or Parity), now only handles execution and transactions, and another piece that is responsible for the proof-of-stake consensus is required.

In this article we will be using Terraform to deploy a simple Azure Kubernetes Service, and in it we will be using Helm charts to start and run a Go Ethereum service as the execution node and Lighthouse service as the consensus node.

Prerequisites

Will be using Terraform and its azurerm provider, so we will be needing the following installed on our workstation:

  • Terraform: installation guide is here.
  • Azure CLI: installation guide is here.

As we will be interacting with a Kubernetes cluster and using Helm charts to deploy our service, it would be a good idea to also have on our workstation:

  • kubectl: installation guide is here.
  • helm: installation guide is here.

Example Repository

A complete example Terraform script, which creates a private network, an Azure Kubernetes Service cluster, and deploys the two services using Helm charts, is available in the following GitHub repository:

The script

For brevity, I will only cover the area of the Terraform script that specifically creates the cluster and the shared secret on the cluster, and only the Helm templates that are specific to Go Ethereum and Lighthouse.

We will start by creating an Azure Kubernetes Service cluster with a minimum version of 1.24, which is the first version to have the MixedProtocolLBService feature graduated from alpha status (it reached beta in 1.24, which makes it available in AKS). We need that feature because both our services need to expose TCP and UDP ports to the internet for discovery purposes.

Also, because we want to be able to use well known public IP addresses (again for discovery purposes), we will be using a custom virtual network (either an existing one or a new one), and we will need to grant the cluster’s identity the ability to access the security group that contains those IP addresses. Also, because the virtual network is not managed by Kubernetes, a Network Security Group with rules to allow communication to the private network from the internet will also be required.

Next, we will create a secret which will be alter mounted to the service as the jwt-secret the consensus node uses to authenticate to the execution node.

Now we can start working on the services. We will be creating two Helm charts, one for each service. Both services will be defined as a StatefulSet , due to the long synchronization both require, which we don’t want it re-running each time a pod is recreated and the need for each of the nodes to have a fixed identity in the Ethereum network.

Go Ethereum’s StatefulSet definition:

Lighthouse’s StatefulSet definition:

Note that both definitions have the jwt-secret mounted to them and a persistent volume that will be used to store the synchronized state between pod terminations.

To allow Lighthouse to communicate with Go Ethereum internally, without leaving the boundaries of the cluster, we will create a headless service for Go Ethereum, which will allow Lighthouse to resolve the generated internal hostname.

The last part is to expose both services to the internet using a LoadBalancer service with a few Azure specific tricks (annotations) that will set the name of the resource groups that contains the public IP that should be used (the actual IP is in the .spec.loadBalancerIP field), enable mixed protocol support for the service and give it an external DNS label under the <region>.cloudapp.azure.com domain. Each service will have a selector that will use the statefulset.kubernetes.io/pod-name with the name of the single pod of the service (which is instance name with a -0 suffix, as that is the only pod instance).

Go Ethereum’s LoadBalancer definition:

Lighthouse’s LoadBalancer definition:

And the definition of the pod selector:

The last part is just to run terraform apply to deploy everything to Azure (you might need to do az login if haven’t done so lately).

Testing The Deployment

The synchronization of both the consensus and later the execution nodes will take time, probably a few days (execution node synchronization only starts when the consensus node synchronization is complete).

You will be able to check the logs of both the pods (using either kubectl or the azure portal) and see whether the synchronization is complete or not, and once they are, you will be able to test your node using the JSON-RPC calls you used with your old, pre-merge node.

Conclusion

The example discussed in this document will get you up and running in a relatively simple manner, but for high load/high reliability scenarios this deployment won’t be enough, as those scenarios will require a Kubernetes cluster with more than node and maybe more than one instance of each of the services deployed for redundancy. As for managing a production grade Kubernetes cluster in a production environment, this example is far from it (monitoring, logging, internal network policies, etc.), so you should probably use this deployment for development and testing purposes only.

--

--

Itay Podhajcer
Microsoft Azure

Tech expert with 20+ years’ experience as CTO, Chief Architect, and Consultant. 3x Microsoft MVP award winner. Passionate blogger and open-source contributor