mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-13 21:31:23 +00:00
copy mintnet-kubernetes from https://github.com/tendermint/mintnet-kubernetes
This commit is contained in:
192
mintnet-kubernetes/LICENSE
Normal file
192
mintnet-kubernetes/LICENSE
Normal file
@ -0,0 +1,192 @@
|
||||
Copyright (C) 2017 Tendermint
|
||||
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
233
mintnet-kubernetes/README.md
Normal file
233
mintnet-kubernetes/README.md
Normal file
@ -0,0 +1,233 @@
|
||||
# Tendermint network powered by Kubernetes
|
||||
|
||||

|
||||
|
||||
* [QuickStart (MacOS)](#quickstart-macos)
|
||||
* [QuickStart (Linux)](#quickstart-linux)
|
||||
* [Usage](#usage)
|
||||
* [Security](#security)
|
||||
* [Fault tolerance](#fault-tolerance)
|
||||
* [Starting process](#starting-process)
|
||||
|
||||
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.
|
||||
|
||||
## QuickStart (MacOS)
|
||||
|
||||
[Requirements](https://github.com/kubernetes/minikube#requirements)
|
||||
|
||||
```
|
||||
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.17.1/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
|
||||
```
|
||||
|
||||
## QuickStart (Linux)
|
||||
|
||||
[Requirements](https://github.com/kubernetes/minikube#requirements)
|
||||
|
||||
```
|
||||
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.17.1/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 everything works
|
||||
|
||||
**Using a shell:**
|
||||
|
||||
1. wait until all the pods are `Running`.
|
||||
|
||||
```
|
||||
kubectl get pods -w -o wide -L tm
|
||||
```
|
||||
|
||||
2. query the Tendermint app logs from the first pod.
|
||||
|
||||
```
|
||||
kubectl logs -c tm -f tm-0
|
||||
```
|
||||
|
||||
3. use [Rest API](https://tendermint.com/docs/internals/rpc) 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
|
||||
|
||||
### (1/4) 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. See our guides for [Google Cloud
|
||||
Engine](docs/SETUP_K8S_ON_GCE.md) or [Digital Ocean](docs/SETUP_K8S_ON_DO.md).
|
||||
|
||||
**Make sure you have Kubernetes >= 1.5, because you will be using StatefulSets,
|
||||
which is a beta feature in 1.5.**
|
||||
|
||||
### (2/4) 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.
|
||||
|
||||
### (3/4) Deploy your application
|
||||
|
||||
```
|
||||
kubectl create -f ./app.yaml
|
||||
```
|
||||
|
||||
### (4/4) 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](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
|
||||
|
||||

|
||||
|
||||
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 Tendermint process.
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] run tendermint from tmuser
|
||||
```
|
||||
securityContext:
|
||||
fsGroup: 999
|
||||
```
|
265
mintnet-kubernetes/app.template.yaml
Normal file
265
mintnet-kubernetes/app.template.yaml
Normal file
@ -0,0 +1,265 @@
|
||||
---
|
||||
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: 46656
|
||||
name: p2p
|
||||
- port: 46657
|
||||
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.9.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.9.0
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
ports:
|
||||
- containerPort: 46656
|
||||
name: p2p
|
||||
- containerPort: 46657
|
||||
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: TMROOT
|
||||
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=$(echo $(hostname -f) | sed 's#[^.]*\.\(\)#\1#')
|
||||
for v in "${VALS_ARR[@]}"; do
|
||||
# wait until validator generates priv/pub key pair
|
||||
set +e
|
||||
|
||||
curl -s "http://$v.$fqdn_suffix/pub_key.json" > /dev/null
|
||||
ERR=$?
|
||||
while [ "$ERR" != 0 ]; do
|
||||
sleep 5
|
||||
curl -s "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)]" > /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:46656")
|
||||
done
|
||||
seeds=$(IFS=','; echo "${seeds[*]}")
|
||||
|
||||
tendermint node --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
|
13
mintnet-kubernetes/docs/SETUP_K8S_ON_DO.md
Normal file
13
mintnet-kubernetes/docs/SETUP_K8S_ON_DO.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Setup a Kubernetes cluster on Digital Ocean (DO)
|
||||
|
||||
Available options:
|
||||
|
||||
1. [kubeadm (alpha)](https://kubernetes.io/docs/getting-started-guides/kubeadm/)
|
||||
2. [kargo](https://kubernetes.io/docs/getting-started-guides/kargo/)
|
||||
3. [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.
|
31
mintnet-kubernetes/docs/SETUP_K8S_ON_GCE.md
Normal file
31
mintnet-kubernetes/docs/SETUP_K8S_ON_GCE.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Setup a Kubernetes cluster on Google Cloud Engine (GCE)
|
||||
|
||||
Main article: [Running Kubernetes on Google Compute
|
||||
Engine](https://kubernetes.io/docs/getting-started-guides/gce/)
|
||||
|
||||
## 1. Create a cluster
|
||||
|
||||
The recommended way is to use [Google Container
|
||||
Engine](https://cloud.google.com/container-engine/) (GKE). You should be able
|
||||
to create a fully fledged cluster with just a few clicks.
|
||||
|
||||
## 2. 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` button:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
and execute the first command in your shell. Then start a proxy by
|
||||
executing `kubectl proxy`.
|
||||
|
||||
Now you should be able to run `kubectl` command to create resources, get
|
||||
resource info, logs, etc.
|
10
mintnet-kubernetes/examples/basecoin/Makefile
Normal file
10
mintnet-kubernetes/examples/basecoin/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
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
|
42
mintnet-kubernetes/examples/basecoin/README.md
Normal file
42
mintnet-kubernetes/examples/basecoin/README.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Basecoin example
|
||||
|
||||
This is an example of using [basecoin](https://github.com/tendermint/basecoin).
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
make create
|
||||
```
|
||||
|
||||
### Check account balance and send a transaction
|
||||
|
||||
1. wait until all the pods are `Running`.
|
||||
|
||||
```
|
||||
kubectl get pods -w -o wide -L tm
|
||||
```
|
||||
|
||||
2. wait until app starts.
|
||||
|
||||
```
|
||||
kubectl logs -c app -f tm-0
|
||||
```
|
||||
|
||||
3. get account's address of the second pod
|
||||
|
||||
```
|
||||
kubectl exec -c app tm-1 -- cat /app/key.json | grep "address"
|
||||
```
|
||||
|
||||
4. send 5 coins to it from the first pod
|
||||
|
||||
```
|
||||
kubectl exec -c app tm-0 -- basecoin tx send --to 0x<address> --amount 5
|
||||
```
|
||||
|
||||
|
||||
## Clean up
|
||||
|
||||
```
|
||||
make destroy
|
||||
```
|
320
mintnet-kubernetes/examples/basecoin/app.yaml
Normal file
320
mintnet-kubernetes/examples/basecoin/app.yaml
Normal file
@ -0,0 +1,320 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
name: basecoin
|
||||
labels:
|
||||
app: basecoin
|
||||
spec:
|
||||
ports:
|
||||
- port: 46656
|
||||
name: p2p
|
||||
- port: 46657
|
||||
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-05T06:02:31.526Z",
|
||||
"chain_id": "chain-tTH4mi",
|
||||
"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/; }
|
||||
location /app_pub_key.json { root /usr/share/nginx/; }
|
||||
}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: app-config
|
||||
data:
|
||||
genesis.json: |-
|
||||
[
|
||||
"base/chainID",
|
||||
"test_chain_id",
|
||||
"base/account",
|
||||
{
|
||||
"coins" : [
|
||||
{"denom": "blank", "amount": 1000}
|
||||
],
|
||||
"pub_key" : ["tm-0"]
|
||||
},
|
||||
"base/account",
|
||||
{
|
||||
"coins" : [
|
||||
{"denom": "blank", "amount": 1000}
|
||||
],
|
||||
"pub_key" : ["tm-1"]
|
||||
},
|
||||
"base/account",
|
||||
{
|
||||
"coins" : [
|
||||
{"denom": "blank", "amount": 1000}
|
||||
],
|
||||
"pub_key" : ["tm-2"]
|
||||
},
|
||||
"base/account",
|
||||
{
|
||||
"coins" : [
|
||||
{"denom": "blank", "amount": 1000}
|
||||
],
|
||||
"pub_key" : ["tm-3"]
|
||||
}
|
||||
]
|
||||
---
|
||||
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: basecoin
|
||||
replicas: 4
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: tm
|
||||
annotations:
|
||||
pod.beta.kubernetes.io/init-containers: '[{
|
||||
"name": "tm-gen-validator",
|
||||
"image": "tendermint/tendermint:0.9.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"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "app-gen-key",
|
||||
"image": "tendermint/basecoin:latest",
|
||||
"imagePullPolicy": "IfNotPresent",
|
||||
"command": ["bash", "-c", "
|
||||
set -ex\n
|
||||
if [ ! -f /app/key.json ]; then\n
|
||||
basecoin key new > /app/key.json\n
|
||||
# pub_key.json will be served by app-pub-key container\n
|
||||
cat /app/key.json | jq \".pub_key\" > /app/pub_key.json\n
|
||||
fi\n
|
||||
"],
|
||||
"volumeMounts": [
|
||||
{"name": "appdir", "mountPath": "/app"}
|
||||
]
|
||||
}]'
|
||||
spec:
|
||||
containers:
|
||||
- name: tm
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: tendermint/tendermint:0.9.0
|
||||
ports:
|
||||
- containerPort: 46656
|
||||
name: p2p
|
||||
- containerPort: 46657
|
||||
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: TMROOT
|
||||
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=$(echo $(hostname -f) | sed 's#[^.]*\.\(\)#\1#')
|
||||
for v in "${VALS_ARR[@]}"; do
|
||||
# wait until validator generates priv/pub key pair
|
||||
set +e
|
||||
|
||||
curl -s "http://$v.$fqdn_suffix/pub_key.json" > /dev/null
|
||||
ERR=$?
|
||||
while [ "$ERR" != 0 ]; do
|
||||
sleep 5
|
||||
curl -s "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)]" > /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:46656")
|
||||
done
|
||||
seeds=$(IFS=','; echo "${seeds[*]}")
|
||||
|
||||
tendermint node --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: tendermint/basecoin:latest
|
||||
workingDir: /app
|
||||
command:
|
||||
- bash
|
||||
- "-c"
|
||||
- |
|
||||
set -ex
|
||||
|
||||
# replace "tm-N" with public keys in genesis file
|
||||
cp /etc/app/genesis.json genesis.json
|
||||
fqdn_suffix=$(echo $(hostname -f) | sed 's#[^.]*\.\(\)#\1#')
|
||||
# for every "base/account"
|
||||
i=3
|
||||
length=$(cat genesis.json | jq ". | length")
|
||||
while [ $i -lt $length ]; do
|
||||
# extract pod name ("tm-0")
|
||||
pod=$(cat genesis.json | jq -r ".[$i].pub_key[0]")
|
||||
|
||||
# wait until pod starts to serve its pub_key
|
||||
set +e
|
||||
|
||||
curl -s "http://$pod.$fqdn_suffix/app_pub_key.json" > /dev/null
|
||||
ERR=$?
|
||||
while [ "$ERR" != 0 ]; do
|
||||
sleep 5
|
||||
curl -s "http://$pod.$fqdn_suffix/app_pub_key.json" > /dev/null
|
||||
ERR=$?
|
||||
done
|
||||
set -e
|
||||
|
||||
# get its pub_key
|
||||
curl -s "http://$pod.$fqdn_suffix/app_pub_key.json" | jq "." > k.json
|
||||
|
||||
# replace pod name with it (["tm-0"] => "[1, XXXXXXXXXXXXXXXXXXXX]")
|
||||
cat genesis.json | jq ".[$i].pub_key = $(cat k.json | jq '.')" > genesis.json
|
||||
rm -f k.json
|
||||
|
||||
i=$((i+2)) # skip "base/account" field itself
|
||||
done
|
||||
|
||||
rm -f /socks/app.sock # remove old socket
|
||||
|
||||
basecoin start --address="unix:///socks/app.sock"
|
||||
volumeMounts:
|
||||
- name: appdir
|
||||
mountPath: /app
|
||||
- mountPath: /etc/app/genesis.json
|
||||
name: appconfigdir
|
||||
subPath: genesis.json
|
||||
- name: socksdir
|
||||
mountPath: /socks
|
||||
|
||||
- name: pub-key
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
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
|
||||
cp /app/pub_key.json /usr/share/nginx/app_pub_key.json
|
||||
nginx -g "daemon off;"
|
||||
volumeMounts:
|
||||
- name: tmdir
|
||||
mountPath: /tendermint
|
||||
- name: appdir
|
||||
mountPath: /app
|
||||
- mountPath: /etc/nginx/conf.d/pub_key.conf
|
||||
name: tmconfigdir
|
||||
subPath: pub_key_nginx.conf
|
||||
|
||||
volumes:
|
||||
- name: tmconfigdir
|
||||
configMap:
|
||||
name: tm-config
|
||||
- name: appconfigdir
|
||||
configMap:
|
||||
name: app-config
|
||||
- name: socksdir
|
||||
emptyDir: {}
|
||||
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: tmdir
|
||||
annotations:
|
||||
volume.alpha.kubernetes.io/storage-class: anything
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
- metadata:
|
||||
name: appdir
|
||||
annotations:
|
||||
volume.alpha.kubernetes.io/storage-class: anything
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 12Mi
|
98
mintnet-kubernetes/examples/basecoin/lightclient.md
Normal file
98
mintnet-kubernetes/examples/basecoin/lightclient.md
Normal file
@ -0,0 +1,98 @@
|
||||
# Using with lightclient
|
||||
|
||||
We have an awesome cluster running, let's try to test this out without
|
||||
relying on executing commands on the cluster. Rather, we can connect to the
|
||||
rpc interface with the `light-client` package and execute commands locally,
|
||||
or even proxy our webapp to the kubernetes backend.
|
||||
|
||||
## Setup
|
||||
|
||||
In order to get this working, we need to know a few pieces of info,
|
||||
the chain id of tendermint, the chain id of basecoin, and an account
|
||||
with a bit of cash....
|
||||
|
||||
### Tendermint Chain ID
|
||||
|
||||
`kubectl exec -c tm tm-0 -- curl -s http://tm-1.basecoin:46657/status | json_pp | grep network`
|
||||
|
||||
set TM_CHAIN with the value there
|
||||
|
||||
### Basecoin Chain ID
|
||||
|
||||
`kubectl exec -c app tm-1 -- grep -A1 chainID /app/genesis.json`
|
||||
|
||||
set BC_CHAIN with the value there
|
||||
|
||||
### Expose tendermint rpc
|
||||
|
||||
We need to be able to reach the tendermint rpc interface from our shell.
|
||||
|
||||
`kubectl port-forward tm-0 46657:46657`
|
||||
|
||||
### Start basecoin-proxy
|
||||
|
||||
Using this info, let's connect our proxy and get going
|
||||
|
||||
`proxy-basecoin -tmchain=$TM_CHAIN -chain=$BC_CHAIN -rpc=localhost:46657`
|
||||
|
||||
## Basecoin accounts
|
||||
|
||||
Well, we can connect, but we don't have a registered account yet...
|
||||
Let's look around, then use the cli to send some money from one of
|
||||
the validators to our client's address so we can play.
|
||||
|
||||
**TODO** we can add some of our known accounts (from `/keys`) into
|
||||
the genesis file, so we can skip all the kubectl money fiddling here.
|
||||
We will want to start with money on some known non-validators.
|
||||
|
||||
### Getting validator info (kubectl)
|
||||
|
||||
The basecoin app deployment starts with 1000 "blank" coin in an account of
|
||||
each validator. Let's get the address of the first validator
|
||||
|
||||
`kubectl exec -c app tm-1 -- grep address /app/key.json`
|
||||
|
||||
Store this info as VAL1_ADDR
|
||||
|
||||
### Querying state (proxy)
|
||||
|
||||
The proxy can read any public info via the tendermint rpc, so let's check
|
||||
out this account.
|
||||
|
||||
`curl localhost:8108/query/account/$VAL1_ADDR`
|
||||
|
||||
Now, let's make out own account....
|
||||
|
||||
`curl -XPOST http://localhost:8108/keys/ -d '{"name": "k8demo", "passphrase": "1234567890"}'`
|
||||
|
||||
(or pick your own user and password). Remember the address you get here. You can
|
||||
always find it out later by calling:
|
||||
|
||||
`curl http://localhost:8108/keys/k8demo`
|
||||
|
||||
and store it in DEMO_ADDR, which is empty at first
|
||||
|
||||
`curl localhost:8108/query/account/$DEMO_ADDR`
|
||||
|
||||
|
||||
### "Stealing" validator cash (kubectl)
|
||||
|
||||
Run one command, that will be signed, now we have money
|
||||
|
||||
`kubectl exec -c app tm-0 -- basecoin tx send --to <k8demo-address> --amount 500`
|
||||
|
||||
### Using our money
|
||||
|
||||
Returning to our remote shell, we have a remote account with some money.
|
||||
Let's see that.
|
||||
|
||||
`curl localhost:8108/query/account/$DEMO_ADDR`
|
||||
|
||||
Cool. Now we need to send it to a second account.
|
||||
|
||||
`curl -XPOST http://localhost:8108/keys/ -d '{"name": "buddy", "passphrase": "1234567890"}'`
|
||||
|
||||
and store the resulting address in BUDDY_ADDR
|
||||
|
||||
**TODO** finish this
|
||||
|
10
mintnet-kubernetes/examples/counter/Makefile
Normal file
10
mintnet-kubernetes/examples/counter/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
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
|
217
mintnet-kubernetes/examples/counter/app.yaml
Normal file
217
mintnet-kubernetes/examples/counter/app.yaml
Normal file
@ -0,0 +1,217 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
name: counter
|
||||
labels:
|
||||
app: counter
|
||||
spec:
|
||||
ports:
|
||||
- port: 46656
|
||||
name: p2p
|
||||
- port: 46657
|
||||
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.9.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.9.0
|
||||
ports:
|
||||
- containerPort: 46656
|
||||
name: p2p
|
||||
- containerPort: 46657
|
||||
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: TMROOT
|
||||
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=$(echo $(hostname -f) | sed 's#[^.]*\.\(\)#\1#')
|
||||
for v in "${VALS_ARR[@]}"; do
|
||||
# wait until validator generates priv/pub key pair
|
||||
set +e
|
||||
|
||||
curl -s "http://$v.$fqdn_suffix/pub_key.json" > /dev/null
|
||||
ERR=$?
|
||||
while [ "$ERR" != 0 ]; do
|
||||
sleep 5
|
||||
curl -s "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)]" > /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:46656")
|
||||
done
|
||||
seeds=$(IFS=','; echo "${seeds[*]}")
|
||||
|
||||
tendermint node --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 -d github.com/tendermint/abci/cmd/counter
|
||||
cd $GOPATH/src/github.com/tendermint/abci/
|
||||
make get_deps
|
||||
make install
|
||||
|
||||
rm -f /socks/app.sock # remove old socket
|
||||
|
||||
counter --serial --addr="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
|
17
mintnet-kubernetes/examples/dummy/Makefile
Normal file
17
mintnet-kubernetes/examples/dummy/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
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
|
196
mintnet-kubernetes/examples/dummy/app.yaml
Normal file
196
mintnet-kubernetes/examples/dummy/app.yaml
Normal file
@ -0,0 +1,196 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
name: dummy
|
||||
labels:
|
||||
app: dummy
|
||||
spec:
|
||||
ports:
|
||||
- port: 46656
|
||||
name: p2p
|
||||
- port: 46657
|
||||
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.9.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.9.0
|
||||
ports:
|
||||
- containerPort: 46656
|
||||
name: p2p
|
||||
- containerPort: 46657
|
||||
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: TMROOT
|
||||
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=$(echo $(hostname -f) | sed 's#[^.]*\.\(\)#\1#')
|
||||
for v in "${VALS_ARR[@]}"; do
|
||||
# wait until validator generates priv/pub key pair
|
||||
set +e
|
||||
|
||||
curl -s "http://$v.$fqdn_suffix/pub_key.json" > /dev/null
|
||||
ERR=$?
|
||||
while [ "$ERR" != 0 ]; do
|
||||
sleep 5
|
||||
curl -s "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)]" > /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:46656")
|
||||
done
|
||||
seeds=$(IFS=','; echo "${seeds[*]}")
|
||||
|
||||
tendermint node --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
|
13
mintnet-kubernetes/examples/dummy/tm-monitor-pod.yaml
Normal file
13
mintnet-kubernetes/examples/dummy/tm-monitor-pod.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: monitor
|
||||
spec:
|
||||
containers:
|
||||
- name: monitor
|
||||
image: tendermint/monitor
|
||||
args: ["-listen-addr=tcp://0.0.0.0:46670", "tm-0.dummy:46657,tm-1.dummy:46657,tm-2.dummy:46657,tm-3.dummy:46657"]
|
||||
ports:
|
||||
- containerPort: 46670
|
||||
name: rpc
|
19
mintnet-kubernetes/examples/dummy/transacter-pod.yaml
Normal file
19
mintnet-kubernetes/examples/dummy/transacter-pod.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
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:46657"
|
||||
sleep 1
|
||||
done
|
10
mintnet-kubernetes/examples/localchain/Makefile
Normal file
10
mintnet-kubernetes/examples/localchain/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
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
|
288
mintnet-kubernetes/examples/localchain/app.yaml
Normal file
288
mintnet-kubernetes/examples/localchain/app.yaml
Normal file
@ -0,0 +1,288 @@
|
||||
---
|
||||
# Single pod installation (see basecoin for distributed setup)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
name: localchain
|
||||
labels:
|
||||
app: localchain
|
||||
spec:
|
||||
ports:
|
||||
- port: 46656
|
||||
name: p2p
|
||||
- port: 46657
|
||||
name: rpc
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: tm
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: tm-config
|
||||
data:
|
||||
validators: "tm-0"
|
||||
validator.power: "10"
|
||||
genesis.json: |-
|
||||
{
|
||||
"genesis_time": "2016-03-24T23:29:20.457Z",
|
||||
"chain_id": "chain-iqwZgb",
|
||||
"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/; }
|
||||
location /app_pub_key.json { root /usr/share/nginx/; }
|
||||
}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: app-config
|
||||
data:
|
||||
genesis.json: |-
|
||||
[
|
||||
"base/chainID",
|
||||
"test_chain_id",
|
||||
"base/account",
|
||||
{
|
||||
"pub_key": ["tm-0"],
|
||||
"coins": [
|
||||
{"denom":"CITI/USD","amount":1000},
|
||||
{"denom":"UBS/EURO","amount":1000}
|
||||
]
|
||||
}
|
||||
]
|
||||
---
|
||||
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: localchain
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: tm
|
||||
annotations:
|
||||
pod.beta.kubernetes.io/init-containers: '[{
|
||||
"name": "tm-gen-validator",
|
||||
"image": "tendermint/tendermint:0.9.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"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "app-gen-key",
|
||||
"image": "tendermint/basecoin:latest",
|
||||
"imagePullPolicy": "IfNotPresent",
|
||||
"command": ["bash", "-c", "
|
||||
set -ex\n
|
||||
if [ ! -f /app/key.json ]; then\n
|
||||
basecoin key new > /app/key.json\n
|
||||
# pub_key.json will be served by app-pub-key container\n
|
||||
cat /app/key.json | jq \".pub_key\" > /app/pub_key.json\n
|
||||
fi\n
|
||||
"],
|
||||
"volumeMounts": [
|
||||
{"name": "appdir", "mountPath": "/app"}
|
||||
]
|
||||
}]'
|
||||
spec:
|
||||
containers:
|
||||
- name: tm
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: tendermint/tendermint:0.9.0
|
||||
ports:
|
||||
- containerPort: 46656
|
||||
name: p2p
|
||||
- containerPort: 46657
|
||||
name: rpc
|
||||
env:
|
||||
- name: VALIDATOR_POWER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: tm-config
|
||||
key: validator.power
|
||||
- name: VALIDATORS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: tm-config
|
||||
key: validators
|
||||
- name: TMROOT
|
||||
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=$(echo $(hostname -f) | sed 's#[^.]*\.\(\)#\1#')
|
||||
for v in "${VALS_ARR[@]}"; do
|
||||
# wait until validator generates priv/pub key pair
|
||||
set +e
|
||||
|
||||
curl -s "http://$v.$fqdn_suffix/pub_key.json" > /dev/null
|
||||
ERR=$?
|
||||
while [ "$ERR" != 0 ]; do
|
||||
sleep 5
|
||||
curl -s "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)]" > /tendermint/genesis.json
|
||||
rm pub_validator.json
|
||||
done
|
||||
|
||||
tendermint node --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: tendermint/basecoin:latest
|
||||
workingDir: /app
|
||||
command:
|
||||
- bash
|
||||
- "-c"
|
||||
- |
|
||||
set -ex
|
||||
|
||||
# replace "tm-N" with public keys in genesis file
|
||||
cp /etc/app/genesis.json genesis.json
|
||||
fqdn_suffix=$(echo $(hostname -f) | sed 's#[^.]*\.\(\)#\1#')
|
||||
# for every "base/account"
|
||||
i=3
|
||||
length=$(cat genesis.json | jq ". | length")
|
||||
while [ $i -lt $length ]; do
|
||||
# extract pod name ("tm-0")
|
||||
pod=$(cat genesis.json | jq -r ".[$i].pub_key[0]")
|
||||
|
||||
# wait until pod starts to serve its pub_key
|
||||
set +e
|
||||
|
||||
curl -s "http://$pod.$fqdn_suffix/app_pub_key.json" > /dev/null
|
||||
ERR=$?
|
||||
while [ "$ERR" != 0 ]; do
|
||||
sleep 5
|
||||
curl -s "http://$pod.$fqdn_suffix/app_pub_key.json" > /dev/null
|
||||
ERR=$?
|
||||
done
|
||||
set -e
|
||||
|
||||
# get its pub_key
|
||||
curl -s "http://$pod.$fqdn_suffix/app_pub_key.json" | jq "." > k.json
|
||||
|
||||
# replace pod name with it (["tm-0"] => "[1, XXXXXXXXXXXXXXXXXXXX]")
|
||||
cat genesis.json | jq ".[$i].pub_key = $(cat k.json | jq '.')" > genesis.json
|
||||
rm -f k.json
|
||||
|
||||
i=$((i+2)) # skip "base/account" field itself
|
||||
done
|
||||
|
||||
rm -f /socks/app.sock # remove old socket
|
||||
|
||||
basecoin start --address="unix:///socks/app.sock"
|
||||
volumeMounts:
|
||||
- name: appdir
|
||||
mountPath: /app
|
||||
- mountPath: /etc/app/genesis.json
|
||||
name: appconfigdir
|
||||
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
|
||||
cp /app/pub_key.json /usr/share/nginx/app_pub_key.json
|
||||
nginx -g "daemon off;"
|
||||
volumeMounts:
|
||||
- name: tmdir
|
||||
mountPath: /tendermint
|
||||
- name: appdir
|
||||
mountPath: /app
|
||||
- mountPath: /etc/nginx/conf.d/pub_key.conf
|
||||
name: tmconfigdir
|
||||
subPath: pub_key_nginx.conf
|
||||
|
||||
volumes:
|
||||
- name: tmconfigdir
|
||||
configMap:
|
||||
name: tm-config
|
||||
- name: appconfigdir
|
||||
configMap:
|
||||
name: app-config
|
||||
- name: socksdir
|
||||
emptyDir: {}
|
||||
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: tmdir
|
||||
annotations:
|
||||
volume.alpha.kubernetes.io/storage-class: anything
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
- metadata:
|
||||
name: appdir
|
||||
annotations:
|
||||
volume.alpha.kubernetes.io/storage-class: anything
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 12Mi
|
BIN
mintnet-kubernetes/img/gce1.png
Normal file
BIN
mintnet-kubernetes/img/gce1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
mintnet-kubernetes/img/gce2.png
Normal file
BIN
mintnet-kubernetes/img/gce2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
mintnet-kubernetes/img/statefulset.png
Normal file
BIN
mintnet-kubernetes/img/statefulset.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
mintnet-kubernetes/img/t_plus_k.png
Normal file
BIN
mintnet-kubernetes/img/t_plus_k.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Reference in New Issue
Block a user