@ -0,0 +1,288 @@ | |||
Using Ansible | |||
============= | |||
.. figure:: assets/a_plus_t.png | |||
:alt: Ansible plus Tendermint | |||
Ansible plus Tendermint | |||
The playbooks in `our ansible directory <https://github.com/tendermint/tools/tree/master/ansible>`__ | |||
run ansible `roles <http://www.ansible.com/>`__ which: | |||
- install and configure basecoin or ethermint | |||
- start/stop basecoin or ethermint and reset their configuration | |||
Prerequisites | |||
------------- | |||
- Ansible 2.0 or higher | |||
- SSH key to the servers | |||
Optional for DigitalOcean droplets: \* DigitalOcean API Token \* python | |||
dopy package | |||
For a description on how to get a DigitalOcean API Token, see the explanation | |||
in the `using terraform tutorial <terraform-digitalocean.rst>`__. | |||
Optional for Amazon AWS instances: \* Amazon AWS API access key ID and | |||
secret access key. | |||
The cloud inventory scripts come from the ansible team at their | |||
`GitHub <https://github.com/ansible/ansible>`__ page. You can get the | |||
latest version from the ``contrib/inventory`` folder. | |||
Setup | |||
----- | |||
Ansible requires a "command machine" or "local machine" or "orchestrator | |||
machine" to run on. This can be your laptop or any machine that can run | |||
ansible. (It does not have to be part of the cloud network that hosts | |||
your servers.) | |||
Use the official `Ansible installation | |||
guide <http://docs.ansible.com/ansible/intro_installation.html>`__ to | |||
install Ansible. Here are a few examples on basic installation commands: | |||
Ubuntu/Debian: | |||
:: | |||
sudo apt-get install ansible | |||
CentOS/RedHat: | |||
:: | |||
sudo yum install epel-release | |||
sudo yum install ansible | |||
Mac OSX: If you have `Homebrew <https://brew.sh>`__ installed, then it's: | |||
:: | |||
brew install ansible | |||
If not, you can install it using ``pip``: | |||
:: | |||
sudo easy_install pip | |||
sudo pip install ansible | |||
To make life easier, you can start an SSH Agent and load your SSH | |||
key(s). This way ansible will have an uninterrupted way of connecting to | |||
your servers. | |||
:: | |||
ssh-agent > ~/.ssh/ssh.env | |||
source ~/.ssh/ssh.env | |||
ssh-add private.key | |||
Subsequently, as long as the agent is running, you can use | |||
``source ~/.ssh/ssh.env`` to load the keys to the current session. Note: | |||
On Mac OSX, you can add the ``-K`` option to ssh-add to store the | |||
passphrase in your keychain. The security of this feature is debated but | |||
it is convenient. | |||
Optional cloud dependencies | |||
~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
If you are using a cloud provider to host your servers, you need the | |||
below dependencies installed on your local machine. | |||
DigitalOcean inventory dependencies: | |||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |||
Ubuntu/Debian: | |||
:: | |||
sudo apt-get install python-pip | |||
sudo pip install dopy | |||
CentOS/RedHat: | |||
:: | |||
sudo yum install python-pip | |||
sudo pip install dopy | |||
Mac OSX: | |||
:: | |||
sudo pip install dopy | |||
Amazon AWS inventory dependencies: | |||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |||
Ubuntu/Debian: | |||
:: | |||
sudo apt-get install python-boto | |||
CentOS/RedHat: | |||
:: | |||
sudo yum install python-boto | |||
Mac OSX: | |||
:: | |||
sudo pip install boto | |||
Refreshing the DigitalOcean inventory | |||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |||
If you just finished creating droplets, the local DigitalOcean inventory | |||
cache is not up-to-date. To refresh it, run: | |||
:: | |||
DO_API_TOKEN="<The API token received from DigitalOcean>" | |||
python -u inventory/digital_ocean.py --refresh-cache 1> /dev/null | |||
Refreshing the Amazon AWS inventory | |||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |||
If you just finished creating Amazon AWS EC2 instances, the local AWS | |||
inventory cache is not up-to-date. To refresh it, run: | |||
:: | |||
AWS_ACCESS_KEY_ID='<The API access key ID received from Amazon>' | |||
AWS_SECRET_ACCESS_KEY='<The API secret access key received from Amazon>' | |||
python -u inventory/ec2.py --refresh-cache 1> /dev/null | |||
Note: you don't need the access key and secret key set, if you are | |||
running ansible on an Amazon AMI instance with the proper IAM | |||
permissions set. | |||
Running the playbooks | |||
--------------------- | |||
The playbooks are locked down to only run if the environment variable | |||
``TF_VAR_TESTNET_NAME`` is populated. This is a precaution so you don't | |||
accidentally run the playbook on all your servers. | |||
The variable ``TF_VAR_TESTNET_NAME`` contains the testnet name which | |||
ansible translates into an ansible group. If you used Terraform to | |||
create the servers, it was the testnet name used there. | |||
If the playbook cannot connect to the servers because of public key | |||
denial, your SSH Agent is not set up properly. Alternatively you can add | |||
the SSH key to ansible using the ``--private-key`` option. | |||
If you need to connect to the nodes as root but your local username is | |||
different, use the ansible option ``-u root`` to tell ansible to connect | |||
to the servers and authenticate as the root user. | |||
If you secured your server and you need to ``sudo`` for root access, use | |||
the the ``-b`` or ``--become`` option to tell ansible to sudo to root | |||
after connecting to the server. In the Terraform-DigitalOcean example, | |||
if you created the ec2-user by adding the ``noroot=true`` option (or if | |||
you are simply on Amazon AWS), you need to add the options | |||
``-u ec2-user -b`` to ansible to tell it to connect as the ec2-user and | |||
then sudo to root to run the playbook. | |||
DigitalOcean | |||
~~~~~~~~~~~~ | |||
:: | |||
DO_API_TOKEN="<The API token received from DigitalOcean>" | |||
TF_VAR_TESTNET_NAME="testnet-servers" | |||
ansible-playbook -i inventory/digital_ocean.py install.yml -e service=basecoin | |||
Amazon AWS | |||
~~~~~~~~~~ | |||
:: | |||
AWS_ACCESS_KEY_ID='<The API access key ID received from Amazon>' | |||
AWS_SECRET_ACCESS_KEY='<The API secret access key received from Amazon>' | |||
TF_VAR_TESTNET_NAME="testnet-servers" | |||
ansible-playbook -i inventory/ec2.py install.yml -e service=basecoin | |||
Installing custom versions | |||
~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
By default ansible installs the tendermint, basecoin or ethermint binary | |||
versions from the latest release in the repository. If you build your | |||
own version of the binaries, you can tell ansible to install that | |||
instead. | |||
:: | |||
GOPATH="<your go path>" | |||
go get -u github.com/tendermint/basecoin/cmd/basecoin | |||
DO_API_TOKEN="<The API token received from DigitalOcean>" | |||
TF_VAR_TESTNET_NAME="testnet-servers" | |||
ansible-playbook -i inventory/digital_ocean.py install.yml -e service=basecoin -e release_install=false | |||
Alternatively you can change the variable settings in | |||
``group_vars/all``. | |||
Other commands and roles | |||
------------------------ | |||
There are few extra playbooks to make life easier managing your servers. | |||
- install.yml - Install basecoin or ethermint applications. (Tendermint | |||
gets installed automatically.) Use the ``service`` parameter to | |||
define which application to install. Defaults to ``basecoin``. | |||
- reset.yml - Stop the application, reset the configuration and data, | |||
then start the application again. You need to pass | |||
``-e service=<servicename>``, like ``-e service=basecoin``. It will | |||
restart the underlying tendermint application too. | |||
- restart.yml - Restart a service on all nodes. You need to pass | |||
``-e service=<servicename>``, like ``-e service=basecoin``. It will | |||
restart the underlying tendermint application too. | |||
- stop.yml - Stop the application. You need to pass | |||
``-e service=<servicename>``. | |||
- status.yml - Check the service status and print it. You need to pass | |||
``-e service=<servicename>``. | |||
- start.yml - Start the application. You need to pass | |||
``-e service=<servicename>``. | |||
- ubuntu16-patch.yml - Ubuntu 16.04 does not have the minimum required | |||
python package installed to be able to run ansible. If you are using | |||
ubuntu, run this playbook first on the target machines. This will | |||
install the python pacakge that is required for ansible to work | |||
correctly on the remote nodes. | |||
- upgrade.yml - Upgrade the ``service`` on your testnet. It will stop | |||
the service and restart it at the end. It will only work if the | |||
upgraded version is backward compatible with the installed version. | |||
- upgrade-reset.yml - Upgrade the ``service`` on your testnet and reset | |||
the database. It will stop the service and restart it at the end. It | |||
will work for upgrades where the new version is not | |||
backward-compatible with the installed version - however it will | |||
reset the testnet to its default. | |||
The roles are self-sufficient under the ``roles/`` folder. | |||
- install - install the application defined in the ``service`` | |||
parameter. It can install release packages and update them with | |||
custom-compiled binaries. | |||
- unsafe\_reset - delete the database for a service, including the | |||
tendermint database. | |||
- config - configure the application defined in ``service``. It also | |||
configures the underlying tendermint service. Check | |||
``group_vars/all`` for options. | |||
- stop - stop an application. Requires the ``service`` parameter set. | |||
- status - check the status of an application. Requires the ``service`` | |||
parameter set. | |||
- start - start an application. Requires the ``service`` parameter set. | |||
Default variables | |||
----------------- | |||
Default variables are documented under ``group_vars/all``. You can the | |||
parameters there to deploy a previously created genesis.json file | |||
(instead of dynamically creating it) or if you want to deploy custom | |||
built binaries instead of deploying a released version. |
@ -0,0 +1,120 @@ | |||
Using Docker | |||
============ | |||
`This folder <https://github.com/tendermint/tools/tree/master/docker>`__ contains Docker container descriptions. Using this folder | |||
you can build your own Docker images with the tendermint application. | |||
It is assumed that you have already setup docker. | |||
If you don't want to build the images yourself, you should be able to | |||
download them from Docker Hub. | |||
Tendermint | |||
---------- | |||
Build the container: Copy the ``tendermint`` binary to the | |||
``tendermint`` folder. | |||
:: | |||
docker build -t tendermint tendermint | |||
The application configuration will be stored at ``/tendermint`` in the | |||
container. The ports 46656 and 46657 will be open for ABCI applications | |||
to connect. | |||
Initialize tendermint configuration and keep it after the container is | |||
finished in a docker volume called ``data``: | |||
:: | |||
docker run --rm -v data:/tendermint tendermint init | |||
If you want the docker volume to be a physical directory on your | |||
filesystem, you have to give an absolute path to docker and make sure | |||
the permissions allow the application to write it. | |||
Get the public key of tendermint: | |||
:: | |||
docker run --rm -v data:/tendermint tendermint show_validator | |||
Run the docker tendermint application with: | |||
:: | |||
docker run --rm -d -v data:/tendermint tendermint node | |||
Basecoin | |||
-------- | |||
Build the container: Copy the ``basecoin`` binary to the ``basecoin`` | |||
folder. | |||
:: | |||
docker build -t basecoin basecoin | |||
The application configuration will be stored at ``/basecoin``. | |||
Initialize basecoin configuration and keep it after the container is | |||
finished: | |||
:: | |||
docker run --rm -v basecoindata:/basecoin basecoin init deadbeef | |||
Use your own basecoin account instead of ``deadbeef`` in the ``init`` | |||
command. | |||
Get the public key of basecoin: We use a trick here: since the basecoin | |||
and the tendermint configuration folders are similar, the ``tendermint`` | |||
command can extract the public key for us if we feed the basecoin | |||
configuration folder to tendermint. | |||
:: | |||
docker run --rm -v basecoindata:/tendermint tendermint show_validator | |||
Run the docker tendermint application with: This is a two-step process: | |||
\* Run the basecoin container. \* Run the tendermint container and | |||
expose the ports that allow clients to connect. The --proxy\_app should | |||
contain the basecoin application's IP address and port. | |||
:: | |||
docker run --rm -d -v basecoindata:/basecoin basecoin start --without-tendermint | |||
docker run --rm -d -v data:/tendermint -p 46656-46657:46656-46657 tendermint node --proxy_app tcp://172.17.0.2:46658 | |||
Ethermint | |||
--------- | |||
Build the container: Copy the ``ethermint`` binary and the setup folder | |||
to the ``ethermint`` folder. | |||
:: | |||
docker build -t ethermint ethermint | |||
The application configuration will be stored at ``/ethermint``. The | |||
files required for initializing ethermint (the files in the source | |||
``setup`` folder) are under ``/setup``. | |||
Initialize ethermint configuration: | |||
:: | |||
docker run --rm -v ethermintdata:/ethermint ethermint init /setup/genesis.json | |||
Start ethermint as a validator node: This is a two-step process: \* Run | |||
the ethermint container. You will have to define where tendermint runs | |||
as the ethermint binary connects to it explicitly. \* Run the tendermint | |||
container and expose the ports that allow clients to connect. The | |||
--proxy\_app should contain the ethermint application's IP address and | |||
port. | |||
:: | |||
docker run --rm -d -v ethermintdata:/ethermint ethermint --tendermint_addr tcp://172.17.0.3:46657 | |||
docker run --rm -d -v data:/tendermint -p 46656-46657:46656-46657 tendermint node --proxy_app tcp://172.17.0.2:46658 |
@ -0,0 +1,289 @@ | |||
Using Kubernetes | |||
================ | |||
.. figure:: assets/t_plus_k.png | |||
:alt: Tendermint plus Kubernetes | |||
Tendermint plus Kubernetes | |||
This should primarily be used for testing purposes or for | |||
tightly-defined chains operated by a single stakeholder (see `the | |||
security precautions <#security>`__). If your desire is to launch an | |||
application with many stakeholders, consider using our set of Ansible | |||
scripts. | |||
Quick Start | |||
----------- | |||
For either platform, see the `requirements <https://github.com/kubernetes/minikube#requirements>`__ | |||
MacOS | |||
^^^^^ | |||
:: | |||
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/kubectl | |||
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.18.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/ | |||
minikube start | |||
git clone https://github.com/tendermint/tools.git && cd tools/mintnet-kubernetes/examples/basecoin && make create | |||
Linux | |||
^^^^^ | |||
:: | |||
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/kubectl | |||
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.18.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/ | |||
minikube start | |||
git clone https://github.com/tendermint/tools.git && cd tools/mintnet-kubernetes/examples/basecoin && make create | |||
Verify it worked | |||
~~~~~~~~~~~~~~~~ | |||
**Using a shell:** | |||
First wait until all the pods are ``Running``: | |||
``kubectl get pods -w -o wide -L tm`` | |||
then query the Tendermint app logs from the first pod: | |||
``kubectl logs -c tm -f tm-0`` | |||
finally, use `Rest API <rpc.html>`__ to fetch the status of the second pod's Tendermint app. | |||
Note we are using ``kubectl exec`` because pods are not exposed (and should not be) to the | |||
outer network: | |||
``kubectl exec -c tm tm-0 -- curl -s http://tm-1.basecoin:46657/status | json_pp`` | |||
**Using the dashboard:** | |||
:: | |||
minikube dashboard | |||
Clean up | |||
~~~~~~~~ | |||
:: | |||
make destroy | |||
Usage | |||
----- | |||
Setup a Kubernetes cluster | |||
^^^^^^^^^^^^^^^^^^^^^^^^^^ | |||
- locally using `Minikube <https://github.com/kubernetes/minikube>`__ | |||
- on GCE with a single click in the web UI | |||
- on AWS using `Kubernetes | |||
Operations <https://github.com/kubernetes/kops/blob/master/docs/aws.md>`__ | |||
- on Linux machines (Digital Ocean) using | |||
`kubeadm <https://kubernetes.io/docs/getting-started-guides/kubeadm/>`__ | |||
- on AWS, Azure, GCE or bare metal using `Kargo | |||
(Ansible) <https://kubernetes.io/docs/getting-started-guides/kargo/>`__ | |||
Please refer to `the official | |||
documentation <https://kubernetes.io/docs/getting-started-guides/>`__ | |||
for overview and comparison of different options. | |||
Kubernetes on Digital Ocean | |||
~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
Available options: | |||
- `kubeadm (alpha) <https://kubernetes.io/docs/getting-started-guides/kubeadm/>`__ | |||
- `kargo <https://kubernetes.io/docs/getting-started-guides/kargo/>`__ | |||
- `rancher <http://rancher.com/>`__ | |||
- `terraform <https://github.com/hermanjunge/kubernetes-digitalocean-terraform>`__ | |||
As you can see, there is no single tool for creating a cluster on DO. | |||
Therefore, choose the one you know and comfortable working with. If you know | |||
and used `terraform <https://www.terraform.io/>`__ before, then choose it. If you | |||
know Ansible, then pick kargo. If none of these seem familiar to you, go with | |||
``kubeadm``. Rancher is a beautiful UI for deploying and managing containers in | |||
production. | |||
Kubernetes on Google Cloud Engine | |||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
Review the `Official Documentation <https://kubernetes.io/docs/getting-started-guides/gce/>`__ for Kubernetes on Google Compute | |||
Engine. | |||
**Create a cluster** | |||
The recommended way is to use `Google Container | |||
Engine <https://cloud.google.com/container-engine/>`__. You should be able | |||
to create a fully fledged cluster with just a few clicks. | |||
**Connect to it** | |||
Install ``gcloud`` as a part of `Google Cloud SDK <https://cloud.google.com/sdk/>`__. | |||
Make sure you have credentials for GCloud by running ``gcloud auth login``. | |||
In order to make API calls against GCE, you must also run ``gcloud auth | |||
application-default login``. | |||
Press ``Connect``: | |||
.. figure:: assets/gce1.png | |||
and execute the first command in your shell. Then start a proxy by | |||
executing ``kubectl` proxy``. | |||
.. figure:: assets/gce2.png | |||
Now you should be able to run ``kubectl`` command to create resources, get | |||
resource info, logs, etc. | |||
**Make sure you have Kubernetes >= 1.5, because you will be using | |||
StatefulSets, which is a beta feature in 1.5.** | |||
Create a configuration file | |||
^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |||
Download a template: | |||
:: | |||
curl -Lo app.yaml https://github.com/tendermint/tools/raw/master/mintnet-kubernetes/app.template.yaml | |||
Open ``app.yaml`` in your favorite editor and configure your app | |||
container (navigate to ``- name: app``). Kubernetes DSL (Domain Specific | |||
Language) is very simple, so it should be easy. You will need to set | |||
Docker image, command and/or run arguments. Replace variables prefixed | |||
with ``YOUR_APP`` with corresponding values. Set genesis time to now and | |||
preferable chain ID in ConfigMap. | |||
Please note if you are changing ``replicas`` number, do not forget to | |||
update ``validators`` set in ConfigMap. You will be able to scale the | |||
cluster up or down later, but new pods (nodes) won't become validators | |||
automatically. | |||
Deploy your application | |||
^^^^^^^^^^^^^^^^^^^^^^^ | |||
:: | |||
kubectl create -f ./app.yaml | |||
Observe your cluster | |||
^^^^^^^^^^^^^^^^^^^^ | |||
`web UI <https://github.com/kubernetes/dashboard>`__ | |||
The easiest way to access Dashboard is to use ``kubectl``. Run the following | |||
command in your desktop environment: | |||
:: | |||
kubectl proxy | |||
``kubectl`` will handle authentication with apiserver and make Dashboard | |||
available at http://localhost:8001/ui | |||
**shell** | |||
List all the pods: | |||
:: | |||
kubectl get pods -o wide -L tm | |||
StatefulSet details: | |||
:: | |||
kubectl describe statefulsets tm | |||
First pod details: | |||
:: | |||
kubectl describe pod tm-0 | |||
Tendermint app logs from the first pod: | |||
:: | |||
kubectl logs tm-0 -c tm -f | |||
App logs from the first pod: | |||
:: | |||
kubectl logs tm-0 -c app -f | |||
Status of the second pod's Tendermint app: | |||
:: | |||
kubectl exec -c tm tm-0 -- curl -s http://tm-1.<YOUR_APP_NAME>:46657/status | json_pp | |||
Security | |||
-------- | |||
Due to the nature of Kubernetes, where you typically have a single | |||
master, the master could be a SPOF (Single Point Of Failure). Therefore, | |||
you need to make sure only authorized people can access it. And these | |||
people themselves had taken basic measures in order not to get hacked. | |||
These are the best practices: | |||
- all access to the master is over TLS | |||
- access to the API Server is X.509 certificate or token based | |||
- etcd is not exposed directly to the cluster | |||
- ensure that images are free of vulnerabilities | |||
(`1 <https://github.com/coreos/clair>`__) | |||
- ensure that only authorized images are used in your environment | |||
- disable direct access to Kubernetes nodes (no SSH) | |||
- define resource quota | |||
Resources: | |||
- https://kubernetes.io/docs/admin/accessing-the-api/ | |||
- http://blog.kubernetes.io/2016/08/security-best-practices-kubernetes-deployment.html | |||
- https://blog.openshift.com/securing-kubernetes/ | |||
Fault tolerance | |||
--------------- | |||
Having a single master (API server) is a bad thing also because if | |||
something happens to it, you risk being left without an access to the | |||
application. | |||
To avoid that you can `run Kubernetes in multiple | |||
zones <https://kubernetes.io/docs/admin/multiple-zones/>`__, each zone | |||
running an `API | |||
server <https://kubernetes.io/docs/admin/high-availability/>`__ and load | |||
balance requests between them. Do not forget to make sure only one | |||
instance of scheduler and controller-manager are running at once. | |||
Running in multiple zones is a lightweight version of a broader `Cluster | |||
Federation feature <https://kubernetes.io/docs/admin/federation/>`__. | |||
Federated deployments could span across multiple regions (not zones). We | |||
haven't tried this feature yet, so any feedback is highly appreciated! | |||
Especially, related to additional latency and cost of exchanging data | |||
between the regions. | |||
Resources: | |||
- https://kubernetes.io/docs/admin/high-availability/ | |||
Starting process | |||
---------------- | |||
.. figure:: assets/statefulset.png | |||
:alt: StatefulSet | |||
StatefulSet | |||
Init containers (``tm-gen-validator``) are run before all other | |||
containers, creating public-private key pair for each pod. Every ``tm`` | |||
container then asks other pods for their public keys, which are served | |||
with nginx (``pub-key`` container). When ``tm`` container have all the | |||
keys, it forms a genesis file and starts the Tendermint process. |
@ -0,0 +1,111 @@ | |||
Using Terraform | |||
=============== | |||
This is a generic `Terraform <https://www.terraform.io/>`__ | |||
configuration that sets up DigitalOcean droplets. See the | |||
`terraform-digitalocean <https://github.com/tendermint/tools/tree/master/terraform-digitalocean>`__ | |||
for the required files. | |||
Prerequisites | |||
------------- | |||
- Install `HashiCorp Terraform <https://www.terraform.io>`__ on a linux | |||
machine. | |||
- Create a `DigitalOcean API | |||
token <https://cloud.digitalocean.com/settings/api/tokens>`__ with | |||
read and write capability. | |||
- Create a private/public key pair for SSH. This is needed to log onto | |||
your droplets as well as by Ansible to connect for configuration | |||
changes. | |||
- Set up the public SSH key at the `DigitalOcean security | |||
page <https://cloud.digitalocean.com/settings/security>`__. | |||
`Here <https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets>`__'s | |||
a tutorial. | |||
- Find out your SSH key ID at DigitalOcean by querying the below | |||
command on your linux box: | |||
:: | |||
DO_API_TOKEN="<The API token received from DigitalOcean>" | |||
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $DO_API_TOKEN" "https://api.digitalocean.com/v2/account/keys" | |||
Initialization | |||
-------------- | |||
If this is your first time using terraform, you have to initialize it by | |||
running the below command. (Note: initialization can be run multiple | |||
times) | |||
:: | |||
terraform init | |||
After initialization it's good measure to create a new Terraform | |||
environment for the droplets so they are always managed together. | |||
:: | |||
TESTNET_NAME="testnet-servers" | |||
terraform env new "$TESTNET_NAME" | |||
Note this ``terraform env`` command is only available in terraform | |||
``v0.9`` and up. | |||
Execution | |||
--------- | |||
The below command will create 4 nodes in DigitalOcean. They will be | |||
named ``testnet-servers-node0`` to ``testnet-servers-node3`` and they | |||
will be tagged as ``testnet-servers``. | |||
:: | |||
DO_API_TOKEN="<The API token received from DigitalOcean>" | |||
SSH_IDS="[ \"<The SSH ID received from the curl call above.>\" ]" | |||
terraform apply -var TESTNET_NAME="testnet-servers" -var servers=4 -var DO_API_TOKEN="$DO_API_TOKEN" -var ssh_keys="$SSH_IDS" | |||
Note: ``ssh_keys`` is a list of strings. You can add multiple keys. For | |||
example: ``["1234567","9876543"]``. | |||
Alternatively you can use the default settings. The number of default | |||
servers is 4 and the testnet name is ``tf-testnet1``. Variables can also | |||
be defined as environment variables instead of the command-line. | |||
Environment variables that start with ``TF_VAR_`` will be translated | |||
into the Terraform configuration. For example the number of servers can | |||
be overriden by setting the ``TF_VAR_servers`` variable. | |||
:: | |||
TF_VAR_DO_API_TOKEN="<The API token received from DigitalOcean>" | |||
TF_VAR_TESTNET_NAME="testnet-servers" | |||
terraform-apply | |||
Security | |||
-------- | |||
DigitalOcean uses the root user by default on its droplets. This is fine | |||
as long as SSH keys are used. However some people still would like to | |||
disable root and use an alternative user to connect to the droplets - | |||
then ``sudo`` from there. Terraform can do this but it requires SSH | |||
agent running on the machine where terraform is run, with one of the SSH | |||
keys of the droplets added to the agent. (This will be neede for ansible | |||
too, so it's worth setting it up here. Check out the | |||
`ansible <https://github.com/tendermint/tools/tree/master/ansible>`__ | |||
page for more information.) After setting up the SSH key, run | |||
``terraform apply`` with ``-var noroot=true`` to create your droplets. | |||
Terraform will create a user called ``ec2-user`` and move the SSH keys | |||
over, this way disabling SSH login for root. It also adds the | |||
``ec2-user`` to the sudoers file, so after logging in as ec2-user you | |||
can ``sudo`` to ``root``. | |||
DigitalOcean announced firewalls but the current version of Terraform | |||
(0.9.8 as of this writing) does not support it yet. Fortunately it is | |||
quite easy to set it up through the web interface (and not that bad | |||
through the `RESTful | |||
API <https://developers.digitalocean.com/documentation/v2/#firewalls>`__ | |||
either). When adding droplets to a firewall rule, you can add tags. All | |||
droplets in a testnet are tagged with the testnet name so it's enough to | |||
define the testnet name in the firewall rule. It is not necessary to add | |||
the nodes one-by-one. Also, the firewall rule "remembers" the testnet | |||
name tag so if you change the servers but keep the name, the firewall | |||
rules will still apply. |
@ -0,0 +1,144 @@ | |||
Benchmarking and Monitoring | |||
=========================== | |||
tm-bench | |||
-------- | |||
Tendermint blockchain benchmarking tool: https://github.com/tendermint/tools/tree/master/tm-bench | |||
For example, the following: | |||
:: | |||
tm-bench -T 10 -r 1000 localhost:46657 | |||
will output: | |||
:: | |||
Stats Avg Stdev Max | |||
Block latency 6.18ms 3.19ms 14ms | |||
Blocks/sec 0.828 0.378 1 | |||
Txs/sec 963 493 1811 | |||
Quick Start | |||
^^^^^^^^^^^ | |||
Docker | |||
~~~~~~ | |||
:: | |||
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint init | |||
docker run -it --rm -v "/tmp:/tendermint" -p "46657:46657" --name=tm tendermint/tendermint | |||
docker run -it --rm --link=tm tendermint/bench tm:46657 | |||
Binaries | |||
~~~~~~~~ | |||
If **Linux**, start with: | |||
:: | |||
curl -L https://s3-us-west-2.amazonaws.com/tendermint/0.10.4/tendermint_linux_amd64.zip && sudo unzip -d /usr/local/bin tendermint_linux_amd64.zip && sudo chmod +x tendermint | |||
if **Mac OS**, start with: | |||
:: | |||
curl -L https://s3-us-west-2.amazonaws.com/tendermint/0.10.4/tendermint_darwin_amd64.zip && sudo unzip -d /usr/local/bin tendermint_darwin_amd64.zip && sudo chmod +x tendermint | |||
then run: | |||
:: | |||
tendermint init | |||
tendermint node --app_proxy=dummy | |||
tm-bench localhost:46657 | |||
with the last command being in a seperate window. | |||
Usage | |||
^^^^^ | |||
:: | |||
tm-bench [-c 1] [-T 10] [-r 1000] [endpoints] | |||
Examples: | |||
tm-bench localhost:46657 | |||
Flags: | |||
-T int | |||
Exit after the specified amount of time in seconds (default 10) | |||
-c int | |||
Connections to keep open per endpoint (default 1) | |||
-r int | |||
Txs per second to send in a connection (default 1000) | |||
-v Verbose output | |||
tm-monitor | |||
---------- | |||
Tendermint blockchain monitoring tool; watches over one or more nodes, collecting and providing various statistics to the user: https://github.com/tendermint/tools/tree/master/tm-monitor | |||
Quick Start | |||
^^^^^^^^^^^ | |||
Docker | |||
~~~~~~ | |||
:: | |||
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint init | |||
docker run -it --rm -v "/tmp:/tendermint" -p "46657:46657" --name=tm tendermint/tendermint | |||
docker run -it --rm --link=tm tendermint/monitor tm:46657 | |||
Binaries | |||
~~~~~~~~ | |||
This will be the same as you did for ``tm-bench`` above, except for the last line which should be: | |||
:: | |||
tm-monitor localhost:46657 | |||
Usage | |||
^^^^^ | |||
:: | |||
tm-monitor [-v] [-no-ton] [-listen-addr="tcp://0.0.0.0:46670"] [endpoints] | |||
Examples: | |||
# monitor single instance | |||
tm-monitor localhost:46657 | |||
# monitor a few instances by providing comma-separated list of RPC endpoints | |||
tm-monitor host1:46657,host2:46657 | |||
Flags: | |||
-listen-addr string | |||
HTTP and Websocket server listen address (default "tcp://0.0.0.0:46670") | |||
-no-ton | |||
Do not show ton (table of nodes) | |||
-v verbose logging | |||
RPC UI | |||
^^^^^^ | |||
Run ``tm-monitor`` and visit http://localhost:46670 | |||
You should see the list of the available RPC endpoints: | |||
:: | |||
http://localhost:46670/status | |||
http://localhost:46670/status/network | |||
http://localhost:46670/monitor?endpoint=_ | |||
http://localhost:46670/status/node?name=_ | |||
http://localhost:46670/unmonitor?endpoint=_ | |||
The API is available as GET requests with URI encoded parameters, or as JSONRPC | |||
POST requests. The JSONRPC methods are also exposed over websocket. | |||