## Description Remove mintnet as discussed on team call. closes #1941pull/6629/head
@ -1,290 +0,0 @@ | |||
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 our `Rest API <https://tendermint.com/docs/tendermint-core/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:26657/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>:26657/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. |
@ -1,265 +0,0 @@ | |||
--- | |||
apiVersion: v1 | |||
kind: Service | |||
metadata: | |||
annotations: | |||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" | |||
name: YOUR_APP_NAME | |||
labels: | |||
app: YOUR_APP_NAME | |||
spec: | |||
ports: | |||
- port: 26656 | |||
name: p2p | |||
- port: 26657 | |||
name: rpc | |||
clusterIP: None | |||
selector: | |||
app: tm | |||
--- | |||
apiVersion: v1 | |||
kind: ConfigMap | |||
metadata: | |||
name: tm-config | |||
data: | |||
seeds: "tm-0,tm-1,tm-2,tm-3" | |||
validators: "tm-0,tm-1,tm-2,tm-3" | |||
validator.power: "10" | |||
genesis.json: |- | |||
{ | |||
"genesis_time": "2017-01-02T10:10:10.164Z", | |||
"chain_id": "chain-B5XXm5", | |||
"validators": [], | |||
"app_hash": "" | |||
} | |||
pub_key_nginx.conf: |- | |||
server { | |||
listen 80 default_server; | |||
listen [::]:80 default_server ipv6only=on; | |||
location /pub_key.json { root /usr/share/nginx/; } | |||
} | |||
--- | |||
apiVersion: policy/v1beta1 | |||
kind: PodDisruptionBudget | |||
metadata: | |||
name: tm-budget | |||
spec: | |||
selector: | |||
matchLabels: | |||
app: tm | |||
minAvailable: 2 | |||
--- | |||
apiVersion: apps/v1beta1 | |||
kind: StatefulSet | |||
metadata: | |||
name: tm | |||
spec: | |||
serviceName: YOUR_APP_NAME | |||
replicas: 4 | |||
template: | |||
metadata: | |||
labels: | |||
app: tm | |||
version: v1 | |||
annotations: | |||
pod.beta.kubernetes.io/init-containers: '[{ | |||
"name": "tm-gen-validator", | |||
"image": "tendermint/tendermint:0.10.0", | |||
"imagePullPolicy": "IfNotPresent", | |||
"command": ["bash", "-c", " | |||
set -ex\n | |||
if [ ! -f /tendermint/priv_validator.json ]; then\n | |||
tendermint gen_validator > /tendermint/priv_validator.json\n | |||
# pub_key.json will be served by pub-key container\n | |||
cat /tendermint/priv_validator.json | jq \".pub_key\" > /tendermint/pub_key.json\n | |||
fi\n | |||
"], | |||
"volumeMounts": [ | |||
{"name": "tmdir", "mountPath": "/tendermint"} | |||
] | |||
}]' | |||
spec: | |||
containers: | |||
- name: tm | |||
imagePullPolicy: IfNotPresent | |||
image: tendermint/tendermint:0.10.0 | |||
resources: | |||
requests: | |||
cpu: 50m | |||
memory: 128Mi | |||
limits: | |||
cpu: 100m | |||
memory: 256Mi | |||
ports: | |||
- containerPort: 26656 | |||
name: p2p | |||
- containerPort: 26657 | |||
name: rpc | |||
env: | |||
- name: SEEDS | |||
valueFrom: | |||
configMapKeyRef: | |||
name: tm-config | |||
key: seeds | |||
- name: VALIDATOR_POWER | |||
valueFrom: | |||
configMapKeyRef: | |||
name: tm-config | |||
key: validator.power | |||
- name: VALIDATORS | |||
valueFrom: | |||
configMapKeyRef: | |||
name: tm-config | |||
key: validators | |||
- name: TMHOME | |||
value: /tendermint | |||
command: | |||
- bash | |||
- "-c" | |||
- | | |||
set -ex | |||
# copy template | |||
cp /etc/tendermint/genesis.json /tendermint/genesis.json | |||
# fill genesis file with validators | |||
IFS=',' read -ra VALS_ARR <<< "$VALIDATORS" | |||
fqdn_suffix=$(hostname -f | sed 's#[^.]*\.\(\)#\1#') | |||
for v in "${VALS_ARR[@]}"; do | |||
# wait until validator generates priv/pub key pair | |||
set +e | |||
curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null | |||
ERR=$? | |||
while [ "$ERR" != 0 ]; do | |||
sleep 5 | |||
curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null | |||
ERR=$? | |||
done | |||
set -e | |||
# add validator to genesis file along with its pub_key | |||
curl -s "http://$v.$fqdn_suffix/pub_key.json" | jq ". as \$k | {pub_key: \$k, amount: $VALIDATOR_POWER, name: \"$v\"}" > pub_validator.json | |||
cat /tendermint/genesis.json | jq ".validators |= .+ [$(cat pub_validator.json)]" > tmpgenesis && mv tmpgenesis /tendermint/genesis.json | |||
rm pub_validator.json | |||
done | |||
# construct seeds | |||
IFS=',' read -ra SEEDS_ARR <<< "$SEEDS" | |||
seeds=() | |||
for s in "${SEEDS_ARR[@]}"; do | |||
seeds+=("$s.$fqdn_suffix:26656") | |||
done | |||
seeds=$(IFS=','; echo "${seeds[*]}") | |||
tendermint node --p2p.seeds="$seeds" --moniker="`hostname`" --proxy-app="unix:///socks/app.sock" | |||
volumeMounts: | |||
- name: tmdir | |||
mountPath: /tendermint | |||
- mountPath: /etc/tendermint/genesis.json | |||
name: configdir | |||
subPath: genesis.json | |||
- name: socksdir | |||
mountPath: /socks | |||
- name: app | |||
imagePullPolicy: IfNotPresent | |||
image: YOUR_APP_IMAGE | |||
args: ["--addr=\"unix:///socks/app.sock\""] | |||
volumeMounts: | |||
- name: socksdir | |||
mountPath: /socks | |||
######## OR ######## | |||
# | |||
# - name: app | |||
# imagePullPolicy: IfNotPresent | |||
# image: golang:1.7.5 | |||
# resources: | |||
# requests: | |||
# cpu: YOUR_APP_CPU_REQ | |||
# memory: YOUR_APP_MEM_REQ | |||
# limits: | |||
# cpu: YOUR_APP_CPU_LIMIT | |||
# memory: YOUR_APP_MEM_LIMIT | |||
# command: | |||
# - bash | |||
# - "-c" | |||
# - | | |||
# set -ex | |||
# go get -d YOUR_APP_PACKAGE | |||
# cd $GOPATH/YOUR_APP_PACKAGE | |||
# make install | |||
# | |||
# rm -f /socks/app.sock # remove old socket | |||
# YOUR_APP_EXEC --addr="unix:///socks/app.sock" | |||
# volumeMounts: | |||
# - name: socksdir | |||
# mountPath: /socks | |||
######## OPTIONALLY ######## | |||
# | |||
# - name: data | |||
# imagePullPolicy: IfNotPresent | |||
# image: golang:1.7.5 | |||
# command: | |||
# - bash | |||
# - "-c" | |||
# - | | |||
# set -ex | |||
# go get github.com/tendermint/merkleeyes/cmd/merkleeyes | |||
# rm -f /socks/data.sock # remove old socket | |||
# merkleeyes server --address="unix:///socks/data.sock" | |||
# volumeMounts: | |||
# - name: socksdir | |||
# mountPath: /socks | |||
- name: pub-key | |||
imagePullPolicy: IfNotPresent | |||
image: nginx:1.11.9 | |||
resources: | |||
requests: | |||
cpu: 10m | |||
memory: 12Mi | |||
limits: | |||
cpu: 20m | |||
memory: 24Mi | |||
ports: | |||
- containerPort: 80 | |||
name: pub-key | |||
command: | |||
- bash | |||
- "-c" | |||
- | | |||
set -ex | |||
# fixes 403 Permission Denied (open() "/tendermint/pub_key.json" failed (13: Permission denied)) | |||
# => we cannot serve from /tendermint, so we copy the file | |||
mkdir -p /usr/share/nginx | |||
cp /tendermint/pub_key.json /usr/share/nginx/pub_key.json | |||
nginx -g "daemon off;" | |||
volumeMounts: | |||
- name: tmdir | |||
mountPath: /tendermint | |||
- mountPath: /etc/nginx/conf.d/pub_key.conf | |||
name: configdir | |||
subPath: pub_key_nginx.conf | |||
volumes: | |||
- name: configdir | |||
configMap: | |||
name: tm-config | |||
- name: socksdir | |||
emptyDir: {} | |||
volumeClaimTemplates: | |||
- metadata: | |||
name: tmdir | |||
annotations: | |||
volume.alpha.kubernetes.io/storage-class: anything | |||
spec: | |||
accessModes: ["ReadWriteOnce"] | |||
resources: | |||
requests: | |||
storage: 2Gi |
@ -1,10 +0,0 @@ | |||
create: | |||
@echo "==> Creating deployment" | |||
@kubectl create -f app.yaml | |||
destroy: | |||
@echo "==> Destroying deployment" | |||
@kubectl delete -f app.yaml | |||
@kubectl delete pvc -l app=tm | |||
.PHONY: create destroy |
@ -1,214 +0,0 @@ | |||
--- | |||
apiVersion: v1 | |||
kind: Service | |||
metadata: | |||
annotations: | |||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" | |||
name: counter | |||
labels: | |||
app: counter | |||
spec: | |||
ports: | |||
- port: 26656 | |||
name: p2p | |||
- port: 26657 | |||
name: rpc | |||
clusterIP: None | |||
selector: | |||
app: tm | |||
--- | |||
apiVersion: v1 | |||
kind: ConfigMap | |||
metadata: | |||
name: tm-config | |||
data: | |||
seeds: "tm-0,tm-1,tm-2,tm-3" | |||
validators: "tm-0,tm-1,tm-2,tm-3" | |||
validator.power: "10" | |||
genesis.json: |- | |||
{ | |||
"genesis_time": "2016-02-05T23:17:31.164Z", | |||
"chain_id": "chain-B5XXm5", | |||
"validators": [], | |||
"app_hash": "" | |||
} | |||
pub_key_nginx.conf: |- | |||
server { | |||
listen 80 default_server; | |||
listen [::]:80 default_server ipv6only=on; | |||
location /pub_key.json { root /usr/share/nginx/; } | |||
} | |||
--- | |||
apiVersion: policy/v1beta1 | |||
kind: PodDisruptionBudget | |||
metadata: | |||
name: tm-budget | |||
spec: | |||
selector: | |||
matchLabels: | |||
app: tm | |||
minAvailable: 2 | |||
--- | |||
apiVersion: apps/v1beta1 | |||
kind: StatefulSet | |||
metadata: | |||
name: tm | |||
spec: | |||
serviceName: counter | |||
replicas: 4 | |||
template: | |||
metadata: | |||
labels: | |||
app: tm | |||
annotations: | |||
pod.beta.kubernetes.io/init-containers: '[{ | |||
"name": "tm-gen-validator", | |||
"image": "tendermint/tendermint:0.10.0", | |||
"imagePullPolicy": "IfNotPresent", | |||
"command": ["bash", "-c", " | |||
set -ex\n | |||
if [ ! -f /tendermint/priv_validator.json ]; then\n | |||
tendermint gen_validator > /tendermint/priv_validator.json\n | |||
# pub_key.json will be served by pub-key container\n | |||
cat /tendermint/priv_validator.json | jq \".pub_key\" > /tendermint/pub_key.json\n | |||
fi\n | |||
"], | |||
"volumeMounts": [ | |||
{"name": "tmdir", "mountPath": "/tendermint"} | |||
] | |||
}]' | |||
spec: | |||
containers: | |||
- name: tm | |||
imagePullPolicy: IfNotPresent | |||
image: tendermint/tendermint:0.10.0 | |||
ports: | |||
- containerPort: 26656 | |||
name: p2p | |||
- containerPort: 26657 | |||
name: rpc | |||
env: | |||
- name: SEEDS | |||
valueFrom: | |||
configMapKeyRef: | |||
name: tm-config | |||
key: seeds | |||
- name: VALIDATOR_POWER | |||
valueFrom: | |||
configMapKeyRef: | |||
name: tm-config | |||
key: validator.power | |||
- name: VALIDATORS | |||
valueFrom: | |||
configMapKeyRef: | |||
name: tm-config | |||
key: validators | |||
- name: TMHOME | |||
value: /tendermint | |||
command: | |||
- bash | |||
- "-c" | |||
- | | |||
set -ex | |||
# copy template | |||
cp /etc/tendermint/genesis.json /tendermint/genesis.json | |||
# fill genesis file with validators | |||
IFS=',' read -ra VALS_ARR <<< "$VALIDATORS" | |||
fqdn_suffix=$(hostname -f | sed 's#[^.]*\.\(\)#\1#') | |||
for v in "${VALS_ARR[@]}"; do | |||
# wait until validator generates priv/pub key pair | |||
set +e | |||
curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null | |||
ERR=$? | |||
while [ "$ERR" != 0 ]; do | |||
sleep 5 | |||
curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null | |||
ERR=$? | |||
done | |||
set -e | |||
# add validator to genesis file along with its pub_key | |||
curl -s "http://$v.$fqdn_suffix/pub_key.json" | jq ". as \$k | {pub_key: \$k, amount: $VALIDATOR_POWER, name: \"$v\"}" > pub_validator.json | |||
cat /tendermint/genesis.json | jq ".validators |= .+ [$(cat pub_validator.json)]" > tmpgenesis && mv tmpgenesis /tendermint/genesis.json | |||
rm pub_validator.json | |||
done | |||
# construct seeds | |||
IFS=',' read -ra SEEDS_ARR <<< "$SEEDS" | |||
seeds=() | |||
for s in "${SEEDS_ARR[@]}"; do | |||
seeds+=("$s.$fqdn_suffix:26656") | |||
done | |||
seeds=$(IFS=','; echo "${seeds[*]}") | |||
tendermint node --p2p.seeds="$seeds" --moniker="`hostname`" --proxy-app="unix:///socks/app.sock" | |||
volumeMounts: | |||
- name: tmdir | |||
mountPath: /tendermint | |||
- mountPath: /etc/tendermint/genesis.json | |||
name: tmconfigdir | |||
subPath: genesis.json | |||
- name: socksdir | |||
mountPath: /socks | |||
- name: app | |||
imagePullPolicy: IfNotPresent | |||
image: golang:latest | |||
command: | |||
- bash | |||
- "-c" | |||
- | | |||
set -ex | |||
go get github.com/tendermint/tendermint/abci/cmd/abci-cli | |||
rm -f /socks/app.sock # remove old socket | |||
abci-cli counter --serial=true --address="unix:///socks/app.sock" | |||
volumeMounts: | |||
- name: socksdir | |||
mountPath: /socks | |||
- name: pub-key | |||
imagePullPolicy: IfNotPresent | |||
image: nginx:latest | |||
ports: | |||
- containerPort: 80 | |||
name: pub-key | |||
command: | |||
- bash | |||
- "-c" | |||
- | | |||
set -ex | |||
# fixes 403 Permission Denied (open() "/tendermint/pub_key.json" failed (13: Permission denied)) | |||
# => we cannot serve from /tendermint, so we copy the file | |||
mkdir -p /usr/share/nginx | |||
cp /tendermint/pub_key.json /usr/share/nginx/pub_key.json | |||
nginx -g "daemon off;" | |||
volumeMounts: | |||
- name: tmdir | |||
mountPath: /tendermint | |||
- mountPath: /etc/nginx/conf.d/pub_key.conf | |||
name: tmconfigdir | |||
subPath: pub_key_nginx.conf | |||
volumes: | |||
- name: tmconfigdir | |||
configMap: | |||
name: tm-config | |||
- name: socksdir | |||
emptyDir: {} | |||
volumeClaimTemplates: | |||
- metadata: | |||
name: tmdir | |||
annotations: | |||
volume.alpha.kubernetes.io/storage-class: anything | |||
spec: | |||
accessModes: ["ReadWriteOnce"] | |||
resources: | |||
requests: | |||
storage: 2Gi |
@ -1,17 +0,0 @@ | |||
create: | |||
@echo "==> Creating deployment" | |||
@kubectl create -f app.yaml | |||
@echo "==> Waiting 10s until it is probably ready" | |||
@sleep 10 | |||
@echo "==> Creating monitor and transacter pods" | |||
@kubectl create -f tm-monitor-pod.yaml | |||
@kubectl create -f transacter-pod.yaml | |||
destroy: | |||
@echo "==> Destroying deployment" | |||
@kubectl delete -f transacter-pod.yaml | |||
@kubectl delete -f tm-monitor-pod.yaml | |||
@kubectl delete -f app.yaml | |||
@kubectl delete pvc -l app=tm | |||
.PHONY: create destroy |
@ -1,196 +0,0 @@ | |||
--- | |||
apiVersion: v1 | |||
kind: Service | |||
metadata: | |||
annotations: | |||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" | |||
name: dummy | |||
labels: | |||
app: dummy | |||
spec: | |||
ports: | |||
- port: 26656 | |||
name: p2p | |||
- port: 26657 | |||
name: rpc | |||
clusterIP: None | |||
selector: | |||
app: tm | |||
--- | |||
apiVersion: v1 | |||
kind: ConfigMap | |||
metadata: | |||
name: tm-config | |||
data: | |||
seeds: "tm-0,tm-1,tm-2,tm-3" | |||
validators: "tm-0,tm-1,tm-2,tm-3" | |||
validator.power: "10" | |||
genesis.json: |- | |||
{ | |||
"genesis_time": "2016-02-05T23:17:31.164Z", | |||
"chain_id": "chain-B5XXm5", | |||
"validators": [], | |||
"app_hash": "" | |||
} | |||
pub_key_nginx.conf: |- | |||
server { | |||
listen 80 default_server; | |||
listen [::]:80 default_server ipv6only=on; | |||
location /pub_key.json { root /usr/share/nginx/; } | |||
} | |||
--- | |||
apiVersion: policy/v1beta1 | |||
kind: PodDisruptionBudget | |||
metadata: | |||
name: tm-budget | |||
spec: | |||
selector: | |||
matchLabels: | |||
app: tm | |||
minAvailable: 2 | |||
--- | |||
apiVersion: apps/v1beta1 | |||
kind: StatefulSet | |||
metadata: | |||
name: tm | |||
spec: | |||
serviceName: dummy | |||
replicas: 4 | |||
template: | |||
metadata: | |||
labels: | |||
app: tm | |||
annotations: | |||
pod.beta.kubernetes.io/init-containers: '[{ | |||
"name": "tm-gen-validator", | |||
"image": "tendermint/tendermint:0.10.0", | |||
"imagePullPolicy": "IfNotPresent", | |||
"command": ["bash", "-c", " | |||
set -ex\n | |||
if [ ! -f /tendermint/priv_validator.json ]; then\n | |||
tendermint gen_validator > /tendermint/priv_validator.json\n | |||
# pub_key.json will be served by pub-key container\n | |||
cat /tendermint/priv_validator.json | jq \".pub_key\" > /tendermint/pub_key.json\n | |||
fi\n | |||
"], | |||
"volumeMounts": [ | |||
{"name": "tmdir", "mountPath": "/tendermint"} | |||
] | |||
}]' | |||
spec: | |||
containers: | |||
- name: tm | |||
imagePullPolicy: IfNotPresent | |||
image: tendermint/tendermint:0.10.0 | |||
ports: | |||
- containerPort: 26656 | |||
name: p2p | |||
- containerPort: 26657 | |||
name: rpc | |||
env: | |||
- name: SEEDS | |||
valueFrom: | |||
configMapKeyRef: | |||
name: tm-config | |||
key: seeds | |||
- name: VALIDATOR_POWER | |||
valueFrom: | |||
configMapKeyRef: | |||
name: tm-config | |||
key: validator.power | |||
- name: VALIDATORS | |||
valueFrom: | |||
configMapKeyRef: | |||
name: tm-config | |||
key: validators | |||
- name: TMHOME | |||
value: /tendermint | |||
command: | |||
- bash | |||
- "-c" | |||
- | | |||
set -ex | |||
# copy template | |||
cp /etc/tendermint/genesis.json /tendermint/genesis.json | |||
# fill genesis file with validators | |||
IFS=',' read -ra VALS_ARR <<< "$VALIDATORS" | |||
fqdn_suffix=$(hostname -f | sed 's#[^.]*\.\(\)#\1#') | |||
for v in "${VALS_ARR[@]}"; do | |||
# wait until validator generates priv/pub key pair | |||
set +e | |||
curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null | |||
ERR=$? | |||
while [ "$ERR" != 0 ]; do | |||
sleep 5 | |||
curl -s --fail "http://$v.$fqdn_suffix/pub_key.json" > /dev/null | |||
ERR=$? | |||
done | |||
set -e | |||
# add validator to genesis file along with its pub_key | |||
curl -s "http://$v.$fqdn_suffix/pub_key.json" | jq ". as \$k | {pub_key: \$k, amount: $VALIDATOR_POWER, name: \"$v\"}" > pub_validator.json | |||
cat /tendermint/genesis.json | jq ".validators |= .+ [$(cat pub_validator.json)]" > tmpgenesis && mv tmpgenesis /tendermint/genesis.json | |||
rm pub_validator.json | |||
done | |||
# construct seeds | |||
IFS=',' read -ra SEEDS_ARR <<< "$SEEDS" | |||
seeds=() | |||
for s in "${SEEDS_ARR[@]}"; do | |||
seeds+=("$s.$fqdn_suffix:26656") | |||
done | |||
seeds=$(IFS=','; echo "${seeds[*]}") | |||
tendermint node --p2p.seeds="$seeds" --moniker="`hostname`" --proxy-app="dummy" | |||
volumeMounts: | |||
- name: tmdir | |||
mountPath: /tendermint | |||
- mountPath: /etc/tendermint/genesis.json | |||
name: tmconfigdir | |||
subPath: genesis.json | |||
- name: socksdir | |||
mountPath: /socks | |||
- name: pub-key | |||
imagePullPolicy: IfNotPresent | |||
image: nginx:latest | |||
ports: | |||
- containerPort: 80 | |||
name: pub-key | |||
command: | |||
- bash | |||
- "-c" | |||
- | | |||
set -ex | |||
# fixes 403 Permission Denied (open() "/tendermint/pub_key.json" failed (13: Permission denied)) | |||
# => we cannot serve from /tendermint, so we copy the file | |||
mkdir -p /usr/share/nginx | |||
cp /tendermint/pub_key.json /usr/share/nginx/pub_key.json | |||
nginx -g "daemon off;" | |||
volumeMounts: | |||
- name: tmdir | |||
mountPath: /tendermint | |||
- mountPath: /etc/nginx/conf.d/pub_key.conf | |||
name: tmconfigdir | |||
subPath: pub_key_nginx.conf | |||
volumes: | |||
- name: tmconfigdir | |||
configMap: | |||
name: tm-config | |||
- name: socksdir | |||
emptyDir: {} | |||
volumeClaimTemplates: | |||
- metadata: | |||
name: tmdir | |||
annotations: | |||
volume.alpha.kubernetes.io/storage-class: anything | |||
spec: | |||
accessModes: ["ReadWriteOnce"] | |||
resources: | |||
requests: | |||
storage: 2Gi |
@ -1,13 +0,0 @@ | |||
--- | |||
apiVersion: v1 | |||
kind: Pod | |||
metadata: | |||
name: monitor | |||
spec: | |||
containers: | |||
- name: monitor | |||
image: tendermint/monitor | |||
args: ["-listen-addr=tcp://0.0.0.0:26670", "tm-0.dummy:26657,tm-1.dummy:26657,tm-2.dummy:26657,tm-3.dummy:26657"] | |||
ports: | |||
- containerPort: 26670 | |||
name: rpc |
@ -1,19 +0,0 @@ | |||
--- | |||
apiVersion: v1 | |||
kind: Pod | |||
metadata: | |||
name: transacter | |||
spec: | |||
containers: | |||
- name: transacter | |||
image: tendermint/transacter | |||
command: | |||
- bash | |||
- "-c" | |||
- | | |||
set -ex | |||
while true | |||
do | |||
./transact 100 "tm-0.dummy:26657" | |||
sleep 1 | |||
done |