diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa1ec1e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.tgz diff --git a/stellar-core/Chart.yaml b/stellar-core/Chart.yaml new file mode 100644 index 0000000..b2b12f3 --- /dev/null +++ b/stellar-core/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +appVersion: "10.0.0" +description: Backbone node of the Stellar cryptocurrency network. +name: stellar-core +version: 1.0.0 +icon: https://www.stellar.org/developers/images/favicon/rocket-180x180.png +home: https://www.stellar.org +maintainers: + - name: andrenarchy + email: andre.extern@satoshipay.io + url: https://github.com/andrenarchy + - name: rendhalver + email: pete.brown@powerhrg.com +sources: + - https://github.com/satoshipay/docker-stellar-core/ +keywords: + - stellar + - stellar-core + - cryptocurrency + - blockchain +engine: gotpl diff --git a/stellar-core/OWNERS b/stellar-core/OWNERS new file mode 100644 index 0000000..6af8701 --- /dev/null +++ b/stellar-core/OWNERS @@ -0,0 +1,6 @@ +approvers: +- andrenarchy +- rendhalver +reviewers: +- andrenarchy +- rendhalver diff --git a/stellar-core/README.md b/stellar-core/README.md new file mode 100644 index 0000000..2ce97f6 --- /dev/null +++ b/stellar-core/README.md @@ -0,0 +1,101 @@ +# Stellar Core + +[Stellar](https://www.stellar.org) is an open-source and distributed payments infrastructure. Stellar Core is the software that powers the backbone of the Stellar network and validates and agrees on transactions. For more information see the [Stellar network overview](https://www.stellar.org/developers/guides/get-started/). + +## Introduction + +This chart bootstraps a [Stellar Core](https://github.com/stellar/stellar-core/) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. By default the deployment includes a PostgreSQL database. The chart is based on the Kubernetes-ready [Stellar Core images provided by SatoshiPay](https://github.com/satoshipay/docker-stellar-core/). + +## Prerequisites + +- You need a node seed to run Stellar Core. If you don't have one you can generate one with the following command: + ```bash + $ docker run --rm -it --entrypoint '' satoshipay/stellar-core stellar-core --genseed + ``` + The output will look like + ``` + Secret seed: SDUFQA7YL3KTWZNKOXX7XXIYU4R5R6JKELMREKHDQOYY2WPUGXFVJN52 + Public: GDJFYQK2VFVMQAOFSBM7RVE4I5HCUT7VNWOKSJKGI5JEODIH6F3EM6YX + ``` + The node seed must be kept secret but the public key can (and should) be shared with other Stellar node operators. +- Kubernetes 1.8+ with Beta APIs enabled +- PV provisioner support in the underlying infrastructure (Only when persisting data) + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```bash +$ helm install --name my-release stable/stellar-core +``` + +🚨 **Warning:** Make sure to use your own node seed, either via setting `nodeSeed` or `existingNodeSeedSecret`. See [prerequisites](#prerequisites) for how to generate a new node seed. + +## Configuration + +The following table lists the configurable parameters of the Stellar Core chart and their default values. + +| Parameter | Description | Default | +| ----------------------- | --------------------------------------------- | --------------------------------------------- | +| `nodeSeed` | Stellar Core node seed (if `existingNodeSeedSecret` is not set) | Not set | +| `existingNodeSeedSecret` | Existing secret with the node seed (if `nodeSeed` is not set) | Not set | +| `existingNodeSeedSecret.name` | Secret containing the node seed | Not set | +| `existingNodeSeedSecret.key` | Key of the node seed in the secret | Not set | +| `nodeIsValidator` | Should the node participate in SCP? Otherwise it is only observing | `true` | +| `networkPassphrase` | The network this instance should talk to | `Public Global Stellar Network ; September 2015` | +| `catchupRecent` | Number of ledgers to catch up (`0` means minimal catchup) | `0` | +| `maxPeerConnections` | Maximum number of connections to other peers | `50` | +| `knownPeers` | List of hostnames/IPs and ports of peers to connect to initially | Default peers, see `values.yaml` | +| `preferredPeers` | List of hostnames/IPs and ports of peers to stay connected to | Default peers, see `values.yaml` | +| `nodeNames` | List of node public keys and node names | Default node names, see `values.yaml` | +| `nodeNames[].publicKey` | Public key of a node | See above | +| `nodeNames[].name` | Name of a node | See above | +| `quorumSet` | List of quorum set definitions | Default quorum set, see `values.yaml` | +| `quorumSet.thresholdPercent` | Threshold in percent for the quorum set | See above | +| `quorumSet.validators` | List of node names (prefixed with `$$`) or public keys in this set | See above | +| `quorumSet.path` | Path for sub-quorum-sets | See above | +| `history` | Definition for fetching and storing the history of the network | Default history, see `values.yaml` | +| `history.$name.get` | Command for fetching from the history archive | See above | +| `history.$name.put` | Command for storing the history in an archive | See above | +| `initializeHistoryArchives` | Set to `true` if you want history archives to be initialized | `false` | +| `gcloudServiceAccountKey` | Gcloud service account key for `gcloud` flavor | Not set | +| `environment` | Additional environment variables for Stellar Core | `{}` | +| `postgresql.enabled` | Enable PostgreSQL database | `true` | +| `postgresql.postgresDatabase` | PostgreSQL database name | `stellar-core` | +| `postgresql.postgresUser` | PostgreSQL username | `postgres` | +| `postgresql.postgresPassword` | PostgreSQL password | Random password (see PostgreSQL chart) | +| `postgresql.persistence` | PostgreSQL persistence options | See PostgreSQL chart | +| `postgresql.*` | Any PostgreSQL option | See PostgreSQL chart | +| `existingDatabase` | Provide existing database (used if `postgresql.enabled` is `false`)| | +| `existingDatabase.passwordSecret` | Existing secret with the database password | `{name: 'postgresql-core', value: 'password'}` | +| `existingDatabase.url` | Existing database URL (use `$(DATABASE_PASSWORD` as the password) | Not set | +| `image.repository` | `stellar-core` image repository | `satoshipay/stellar-core` | +| `image.tag` | `stellar-core` image tag | `10.0.0-2` | +| `image.flavor` | `stellar-core` flavor (e.g., `aws` or `gcloud`) | Not set | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `peerService.type` | p2p service type | `LoadBalancer` | +| `peerService.port` | p2p service TCP port | `11625` | +| `peerService.loadBalancerIP` | p2p service load balancer IP | Not set | +| `peerService.externalTrafficPolicy` | p2p service traffic policy | Not set | +| `httpService.type` | Non-public HTTP admin endpoint service type | `ClusterIP` | +| `httpService.port` | Non-public HTTP admin endpoint TCP port | `11626` | +| `persistence.enabled` | Use a PVC to persist data | `true` | +| `persistence.existingClaim` | Provide an existing PersistentVolumeClaim | Not set | +| `persistence.storageClass` | Storage class of backing PVC | Not set (uses alpha storage class annotation) | +| `persistence.accessMode` | Use volume as ReadOnly or ReadWrite | `ReadWriteOnce` | +| `persistence.annotations` | Persistent Volume annotations | `{}` | +| `persistence.size` | Size of data volume | `8Gi` | +| `persistence.subPath` | Subdirectory of the volume to mount at | `stellar-core` | +| `persistence.mountPath` | Mount path of data volume | `/data` | +| `resources` | CPU/Memory resource requests/limits | Requests: `512Mi` memory, `100m` CPU | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Toleration labels for pod assignment | [] | +| `affinity` | Affinity settings for pod assignment | {} | +| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `serviceAccount.name` | The name of the ServiceAccount to create | Generated using the fullname template | + +## Persistence + +Both Stellar Core and PostgreSQL (if `postgresql.enabled` is `true`) need to store data and thus this chart creates [Persistent Volumes](http://kubernetes.io/docs/user-guide/persistent-volumes/) by default. Make sure to size them properly for your needs and use an appropriate storage class, e.g. SSDs. + +You can also use existing claims with the `persistence.existingClaim` and `postgresql.persistence.existingClaim` options. diff --git a/stellar-core/requirements.lock b/stellar-core/requirements.lock new file mode 100644 index 0000000..a3b04bd --- /dev/null +++ b/stellar-core/requirements.lock @@ -0,0 +1,6 @@ +dependencies: +- name: postgresql + repository: https://kubernetes-charts.storage.googleapis.com/ + version: 0.19.0 +digest: sha256:31a2190b81ff68c4c1793c17fd4cbf6157683cc6d2f9fef66a1423938593e93d +generated: 2018-10-09T16:15:19.465844319+02:00 diff --git a/stellar-core/requirements.yaml b/stellar-core/requirements.yaml new file mode 100644 index 0000000..f6f4cc1 --- /dev/null +++ b/stellar-core/requirements.yaml @@ -0,0 +1,5 @@ +dependencies: +- name: postgresql + version: ^0.19.0 + repository: "https://kubernetes-charts.storage.googleapis.com/" + condition: postgresql.enabled diff --git a/stellar-core/templates/NOTES.txt b/stellar-core/templates/NOTES.txt new file mode 100644 index 0000000..82a2533 --- /dev/null +++ b/stellar-core/templates/NOTES.txt @@ -0,0 +1,15 @@ +1. The node will take a while to sync with the network (~1h or more + is not unusual for the default config). + +2. Allow other nodes to connect to you + + You can publish your external IP address and port as well as your + node's public key so other validators can include your node in + their quorum sets. + +{{- if contains "LoadBalancer" .Values.peerService.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc -w {{ template "stellar-core.fullname" . }}-peer' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "stellar-core.fullname" . }}-peer -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP:{{ .Values.peerService.port }} +{{- end }} diff --git a/stellar-core/templates/_helpers.tpl b/stellar-core/templates/_helpers.tpl new file mode 100644 index 0000000..dbafb19 --- /dev/null +++ b/stellar-core/templates/_helpers.tpl @@ -0,0 +1,174 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "stellar-core.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "stellar-core.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "stellar-core.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "stellar-core.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "stellar-core.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "stellar-core.postgresql.fullname" -}} +{{- if .Values.postgresql.fullnameOverride -}} +{{- .Values.postgresql.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default "postgresql" .Values.postgresql.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{- define "stellar-core.env" -}} +{{- with .Values.existingNodeSeedSecret }} +- name: NODE_SEED + valueFrom: + secretKeyRef: + name: {{ required "name of existingNodeSeedSecret is required" .name | quote }} + key: {{ required "key of existingNodeSeedSecret is required" .key | quote }} +{{- else }} +- name: NODE_SEED + valueFrom: + secretKeyRef: + name: {{ template "stellar-core.fullname" . }} + key: nodeSeed +{{- end }} +{{- if .Values.postgresql.enabled }} +- name: DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "stellar-core.postgresql.fullname" . }} + key: postgres-password +- name: DATABASE + value: postgresql://dbname={{ .Values.postgresql.postgresDatabase }} user={{ .Values.postgresql.postgresUser }} password=$(DATABASE_PASSWORD) host={{ template "stellar-core.postgresql.fullname" . }} connect_timeout={{ .Values.postgresqlConnectTimeout }} +{{- else }} +{{- with .Values.existingDatabase.passwordSecret }} +- name: DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .name | quote }} + key: {{ .key | quote }} +{{- end }} +- name: DATABASE + value: {{ .Values.existingDatabase.url }} +{{- end }} +- name: INITIALIZE_DB + value: {{ .Values.initializeDatabase | quote }} +{{- with .Values.knownPeers }} +- name: KNOWN_PEERS + value: "{{ join "," .}}" +{{- end }} +{{- with .Values.preferredPeerKeys }} +- name: PREFERRED_PEER_KEYS + value: "{{ join "," .}}" +{{- end }} +{{- with .Values.preferredPeers }} +- name: PREFERRED_PEERS + value: "{{ join "," .}}" +{{- end }} +{{- with .Values.nodeNames }} +- name: NODE_NAMES + value: "{{range $index, $element := . }}{{ if gt $index 0 }},{{ end }}{{ $element.publicKey }} {{ $element.name }}{{ end }}" +{{- end }} +{{- with .Values.knownCursors }} +- name: KNOWN_CURSORS + value: "{{ join "," .}}" +{{- end }} +{{- if .Values.unsafeQuorum }} +- name: UNSAFE_QUORUM + value: "true" +{{- end }} +{{- with .Values.quorumSet }} +- name: QUORUM_SET + value: {{ . | toJson | quote }} +{{- end }} +{{- with .Values.history }} +- name: HISTORY + value: {{ . | toJson | quote }} +{{- end }} +- name: INITIALIZE_HISTORY_ARCHIVES + value: {{ .Values.initializeHistoryArchives | quote }} +{{- if .Values.gcloudServiceAccountKey }} +- name: GCLOUD_SERVICE_ACCOUNT_KEY + valueFrom: + secretKeyRef: + name: {{ template "stellar-core.fullname" . }} + key: gcloudServiceAccountKey +{{- end }} +{{- with .Values.nodeIsValidator }} +- name: NODE_IS_VALIDATOR + value: {{ . | quote }} +{{- end }} +{{- with .Values.networkPassphrase }} +- name: NETWORK_PASSPHRASE + value: {{ . | quote }} +{{- end }} +{{- with .Values.catchupComplete }} +- name: CATCHUP_COMPLETE + value: {{ . | quote }} +{{- end }} +{{- with .Values.catchupRecent }} +- name: CATCHUP_RECENT + value: {{ . | quote }} +{{- end }} +{{- with .Values.targetPeerConnections }} +- name: TARGET_PEER_CONNECTIONS + value: {{ . | quote }} +{{- end }} +{{- with .Values.maxAdditionalPeerConnections }} +- name: MAX_ADDITIONAL_PEER_CONNECTIONS + value: {{ . | quote }} +{{- end }} +{{- with .Values.maxPendingConnections }} +- name: MAX_PENDING_CONNECTIONS + value: {{ . | quote }} +{{- end }} +{{- with .Values.maxConcurrentSubprocesses }} +- name: MAX_CONCURRENT_SUBPROCESSES + value: {{ . | quote }} +{{- end }} +{{- range $key, $val := .Values.environment }} +- name: {{ $key }} + value: {{ $val | quote }} +{{- end }} +{{- end -}} diff --git a/stellar-core/templates/deployment.yaml b/stellar-core/templates/deployment.yaml new file mode 100644 index 0000000..4d15d4e --- /dev/null +++ b/stellar-core/templates/deployment.yaml @@ -0,0 +1,95 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "stellar-core.fullname" . }} + labels: + app: {{ template "stellar-core.name" . }} + chart: {{ template "stellar-core.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: {{ template "stellar-core.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "stellar-core.name" . }} + release: {{ .Release.Name }} + spec: + serviceAccountName: "{{ template "stellar-core.serviceAccountName" . }}" + + initContainers: + {{- if .Values.forceScp }} + - name: {{ .Chart.Name }}-forcescp + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}{{ with .Values.image.flavor }}-{{.}}{{ end }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: ["stellar-core", "--conf", "/stellar-core.cfg", "force-scp"] + env: + {{ include "stellar-core.env" . | indent 12 }} + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.initCatchup.enabled }} + - name: {{ .Chart.Name }}-catchup + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}{{ with .Values.image.flavor }}-{{.}}{{ end }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: ["stellar-core", "--conf", "/stellar-core.cfg", "--catchup-to", '{{ printf "%.0f" .Values.initCatchup.ledger }}'] + env: + {{ include "stellar-core.env" . | indent 12 }} + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}{{ with .Values.image.flavor }}-{{.}}{{ end }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: peer + containerPort: 11625 + protocol: TCP + - name: http + containerPort: 11626 + protocol: TCP + env: + {{ include "stellar-core.env" . | indent 12 }} + livenessProbe: + tcpSocket: + port: peer + readinessProbe: + tcpSocket: + port: peer + resources: +{{ toYaml .Values.resources | indent 12 }} + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + volumes: + - name: data + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (include "stellar-core.fullname" .) }} + {{- else }} + emptyDir: {} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/stellar-core/templates/pvc.yaml b/stellar-core/templates/pvc.yaml new file mode 100644 index 0000000..718adad --- /dev/null +++ b/stellar-core/templates/pvc.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) -}} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "stellar-core.fullname" . }} + labels: + app: {{ template "stellar-core.name" . }} + chart: {{ template "stellar-core.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.persistence.annotations }} + annotations: +{{ toYaml .Values.persistence.annotations | indent 4 }} +{{- end }} +spec: + accessModes: + - {{ .Values.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +{{- if .Values.persistence.storageClass }} +{{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" +{{- end }} +{{- end }} +{{- end -}} diff --git a/stellar-core/templates/secret.yaml b/stellar-core/templates/secret.yaml new file mode 100644 index 0000000..57768a6 --- /dev/null +++ b/stellar-core/templates/secret.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "stellar-core.fullname" . }} + labels: + app: {{ template "stellar-core.name" . }} + chart: {{ template "stellar-core.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +type: Opaque +data: +{{- if not .Values.existingNodeSeedSecret }} + nodeSeed: {{ required "nodeSeed is required if existingNodeSeedSecret is not provided" .Values.nodeSeed | b64enc }} +{{- end }} +{{- with .Values.gcloudServiceAccountKey }} + gcloudServiceAccountKey: {{ . | b64enc }} +{{- end }} diff --git a/stellar-core/templates/service-http.yaml b/stellar-core/templates/service-http.yaml new file mode 100644 index 0000000..fffcc15 --- /dev/null +++ b/stellar-core/templates/service-http.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "stellar-core.fullname" . }}-http + labels: + app: {{ template "stellar-core.name" . }} + chart: {{ template "stellar-core.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.httpService.type }} + ports: + - port: {{ .Values.httpService.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "stellar-core.name" . }} + release: {{ .Release.Name }} diff --git a/stellar-core/templates/service-peer.yaml b/stellar-core/templates/service-peer.yaml new file mode 100644 index 0000000..0d51648 --- /dev/null +++ b/stellar-core/templates/service-peer.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "stellar-core.fullname" . }}-peer + labels: + app: {{ template "stellar-core.name" . }} + chart: {{ template "stellar-core.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.peerService.type }} + ports: + - port: {{ .Values.peerService.port }} + targetPort: peer + protocol: TCP + name: peer + {{- with .Values.peerService.loadBalancerIP }} + loadBalancerIP: {{ . }} + {{- end }} + {{- with .Values.peerService.externalTrafficPolicy }} + externalTrafficPolicy: {{ . }} + {{- end }} + selector: + app: {{ template "stellar-core.name" . }} + release: {{ .Release.Name }} diff --git a/stellar-core/templates/serviceaccount.yaml b/stellar-core/templates/serviceaccount.yaml new file mode 100644 index 0000000..4b84ff7 --- /dev/null +++ b/stellar-core/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "stellar-core.serviceAccountName" . }} + labels: + app: {{ template "stellar-core.name" . }} + chart: {{ template "stellar-core.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- end -}} diff --git a/stellar-core/values.yaml b/stellar-core/values.yaml new file mode 100644 index 0000000..3650aca --- /dev/null +++ b/stellar-core/values.yaml @@ -0,0 +1,139 @@ +## NOTE: +## You have to provide a node seed +## * either by specifying nodeSeed directly +## * or by specifying existingNodeSeedSecret that points to an existing secret +## You can generate a node seed by running the following command: +## docker run --rm -it --entrypoint '' satoshipay/stellar-core stellar-core --genseed + +## WARNING: make sure to replace this in your configuration or use existingNodeSeedSecret +nodeSeed: SDUFQA7YL3KTWZNKOXX7XXIYU4R5R6JKELMREKHDQOYY2WPUGXFVJN52 +# existingNodeSeedSecret: +# name: stellar-core +# key: nodeSeed + +nodeIsValidator: true + +networkPassphrase: Public Global Stellar Network ; September 2015 + +catchupComplete: false +catchupRecent: 0 + +# targetPeerConnections: 8 +# maxAdditionalPeerConnections: 50 +# maxPendingConnections: 500 +maxConcurrentSubprocesses: 2 + +knownPeers: [] + +preferredPeers: [] + +nodeNames: [] + +unsafeQuorum: false + +quorumSet: {} + # - threshold_percent: 66 + # validators: + # - $$eno + # - $$keybase0 + # - $$tempo + # - $$umbrel + # - path: satoshipay + # threshold_percent: 51 + # validators: + # - $$satoshipay1 + # - $$satoshipay2 + # - $$satoshipay3 + +history: {} + # sdf1: + # get: "curl -sf http://history.stellar.org/prd/core-live/core_live_001/{0} -o {1}" + # sdf2: + # get: "curl -sf http://history.stellar.org/prd/core-live/core_live_002/{0} -o {1}" + # sdf3: + # get: "curl -sf http://history.stellar.org/prd/core-live/core_live_003/{0} -o {1}" + +initializeDatabase: true +initializeHistoryArchives: false + +initCatchup: + enabled: false + ledger: 21000000 + +environment: {} + +postgresql: + enabled: true + postgresDatabase: stellar-core + postgresUser: postgres + # options from https://github.com/helm/charts/tree/master/stable/postgresql + # postgresPassword: + +postgresqlConnectTimeout: 5 + +## NOTE: +## existingDatabase is only used if postgresql.enabled is false +existingDatabase: + passwordSecret: + name: postgresql-core + key: password + ## NOTE: + ## $(DATABASE_PASSWORD) is automatically replaced with the value of the passwordSecret + # url: postgresql://dbname=stellar-core host=postgresql-core password=$(DATABASE_PASSWORD) + +image: + repository: satoshipay/stellar-core + tag: '11.0.0' + # flavor: aws + # flavor: gcloud + pullPolicy: IfNotPresent + +peerService: + type: LoadBalancer + port: 11625 + # loadBalancerIP: 35.13.37.42 + # externalTrafficPolicy: Local + +httpService: + type: ClusterIP + port: 11626 + +persistence: + enabled: true + + ## A manually managed Persistent Volume and Claim + ## Requires persistence.enabled: true + ## If defined, PVC must be created manually before volume will be bound + # existingClaim: + + ## database data Persistent Volume Storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + # storageClass: "-" + accessMode: ReadWriteOnce + size: 8Gi + + subPath: "stellar-core" + mountPath: /data + + ## Annotations for the persistent volume claim + # annotations: + +resources: + requests: + cpu: 100m + memory: 512Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +serviceAccount: + create: true + name: diff --git a/stellar-friendbot/Chart.yaml b/stellar-friendbot/Chart.yaml new file mode 100644 index 0000000..9661619 --- /dev/null +++ b/stellar-friendbot/Chart.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +appVersion: "0.13.0" +description: Friendbot that sends money in the Stellar cryptocurrency (testnet) network. +name: stellar-friendbot +version: 1.0.0 +icon: https://www.stellar.org/developers/images/favicon/rocket-180x180.png +home: https://www.stellar.org +maintainers: + - name: andrenarchy + email: andre.extern@satoshipay.io + url: https://github.com/andrenarchy +sources: + - https://github.com/satoshipay/docker-stellar-friendbot/ +keywords: + - stellar + - stellar-friendbot + - testnet + - cryptocurrency + - blockchain +engine: gotpl diff --git a/stellar-friendbot/OWNERS b/stellar-friendbot/OWNERS new file mode 100644 index 0000000..3ed8897 --- /dev/null +++ b/stellar-friendbot/OWNERS @@ -0,0 +1,4 @@ +approvers: +- andrenarchy +reviewers: +- andrenarchy diff --git a/stellar-friendbot/README.md b/stellar-friendbot/README.md new file mode 100644 index 0000000..968554f --- /dev/null +++ b/stellar-friendbot/README.md @@ -0,0 +1,53 @@ +# Stellar Friendbot + +[Stellar](https://www.stellar.org) is an open-source and distributed payments infrastructure. Stellar Friendbot is a simple server that sends funds from the friendbot's account to another account. Friendbot is usually deployed in a test network. + +## Introduction + +This chart bootstraps a [Stellar Friendbot](https://github.com/stellar/go/) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. The chart is based on the Kubernetes-ready [Stellar Friendbot images provided by SatoshiPay](https://github.com/satoshipay/docker-stellar-friendbot/). + +## Prerequisites + +- Kubernetes 1.8+ with Beta APIs enabled + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```bash +$ helm install --name my-release stable/stellar-friendbot +``` + +## Configuration + +The following table lists the configurable parameters of the Stellar Friendbot chart and their default values. + +| Parameter | Description | Default | +| ----------------------- | --------------------------------------------- | --------------------------------------------- | +| `accountSecret` | Friendbot's account secret (if `existingAccountSecretSecret` is not set) | Not set | +| `existingAccountSecretSecret` | Existing secret with the account secret (if `accountSecret` is not set) | Not set | +| `existingAccountSecretSecret.name` | Secret containing the account secret | Not set | +| `existingAccountSecretSecret.key` | Key of the account secret in the secret | Not set | +| `networkPassphrase` | The network the friendbot should use | `Public Global Stellar Network ; September 2015` | +| `horizonUrl` | URL of Stellar Horizon where the transaction should be submitted | `https://horizon.stellar.org` | +| `startingBalance` | Starting balance of newly funded accounts | `10000` | +| `environment` | Additional environment variables for Stellar Friendbot | `{}` | +| `image.repository` | `stellar-friendbot` image repository | `satoshipay/stellar-friendbot` | +| `image.tag` | `stellar-friendbot` image tag | `0.13.0` | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `service.type` | HTTP endpoint service type | `ClusterIP` | +| `service.port` | HTTP endpoint TCP port | `80` | +| `ingress.enabled` | Enable ingress controller resource | `false` | +| `ingress.hosts[0].name` | Hostname to your Friendbot installation | `stellar-friendbot.local` | +| `ingress.hosts[0].path` | Path within the url structure | `/` | +| `ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `stellar-friendbot.local-tls-secret` | +| `ingress.hosts[0].annotations` | Annotations for this host's ingress record | `[]` | +| `ingress.secrets[0].name` | TLS Secret Name | `nil` | +| `ingress.secrets[0].certificate` | TLS Secret Certificate | `nil` | +| `ingress.secrets[0].key` | TLS Secret Key | `nil` | +| `resources` | CPU/Memory resource requests/limits | Requests: `128Mi` memory, `10m` CPU | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Toleration labels for pod assignment | [] | +| `affinity` | Affinity settings for pod assignment | {} | +| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `serviceAccount.name` | The name of the ServiceAccount to create | Generated using the fullname template | diff --git a/stellar-friendbot/templates/NOTES.txt b/stellar-friendbot/templates/NOTES.txt new file mode 100644 index 0000000..4ae52c7 --- /dev/null +++ b/stellar-friendbot/templates/NOTES.txt @@ -0,0 +1,19 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "stellar-friendbot.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc -w {{ include "stellar-friendbot.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "stellar-friendbot.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "stellar-friendbot.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/stellar-friendbot/templates/_helpers.tpl b/stellar-friendbot/templates/_helpers.tpl new file mode 100644 index 0000000..a0c2429 --- /dev/null +++ b/stellar-friendbot/templates/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "stellar-friendbot.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "stellar-friendbot.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "stellar-friendbot.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "stellar-friendbot.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "stellar-friendbot.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/stellar-friendbot/templates/deployment.yaml b/stellar-friendbot/templates/deployment.yaml new file mode 100644 index 0000000..03d9a2a --- /dev/null +++ b/stellar-friendbot/templates/deployment.yaml @@ -0,0 +1,75 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ include "stellar-friendbot.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "stellar-friendbot.name" . }} + helm.sh/chart: {{ include "stellar-friendbot.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: {{ include "stellar-friendbot.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "stellar-friendbot.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + serviceAccountName: "{{ template "stellar-friendbot.serviceAccountName" . }}" + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + {{- with .Values.existingAccountSecretSecret }} + - name: FRIENDBOT_SECRET + valueFrom: + secretKeyRef: + name: {{ required "name of existingAccountSecretSecret is required" .name | quote }} + key: {{ required "key of existingAccountSecretSecret is required" .key | quote }} + {{- else }} + - name: FRIENDBOT_SECRET + valueFrom: + secretKeyRef: + name: {{ template "stellar-friendbot.fullname" . }} + key: accountSecret + {{- end }} + - name: NETWORK_PASSPHRASE + value: {{ .Values.networkPassphrase | quote }} + - name: HORIZON_URL + value: {{ .Values.horizonUrl | quote }} + - name: STARTING_BALANCE + value: {{ .Values.startingBalance | quote }} + {{- range $key, $val := .Values.environment }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end }} + ports: + - name: http + containerPort: 8000 + protocol: TCP + # Note: we can't use httpGet here because friendbot throws 4xx without a valid dest addr + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/stellar-friendbot/templates/ingress.yaml b/stellar-friendbot/templates/ingress.yaml new file mode 100644 index 0000000..f2ddf8b --- /dev/null +++ b/stellar-friendbot/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.hosts }} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: "{{- printf "%s-%s" .name $.Release.Name | trunc 63 | trimSuffix "-" -}}" + labels: + app.kubernetes.io/name: {{ include "stellar-friendbot.name" $ }} + helm.sh/chart: {{ include "stellar-friendbot.chart" $ }} + app.kubernetes.io/instance: {{ $.Release.Name }} + app.kubernetes.io/managed-by: {{ $.Release.Service }} + annotations: + {{- range $key, $value := .annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: + - host: {{ .name }} + http: + paths: + - path: {{ default "/" .path }} + backend: + serviceName: {{ template "stellar-friendbot.fullname" $ }} + servicePort: http +{{- if .tls }} + tls: + - hosts: + - {{ .name }} + secretName: {{ .tlsSecret }} +{{- end }} +--- +{{- end }} +{{- end }} diff --git a/stellar-friendbot/templates/secret.yaml b/stellar-friendbot/templates/secret.yaml new file mode 100644 index 0000000..9b7ff2c --- /dev/null +++ b/stellar-friendbot/templates/secret.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "stellar-friendbot.fullname" . }} + labels: + app: {{ template "stellar-friendbot.name" . }} + chart: {{ template "stellar-friendbot.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +type: Opaque +data: +{{- if not .Values.existingAccountSecretSecret }} + accountSecret: {{ required "accountSecret is required if existingAccountSecretSecret is not provided" .Values.accountSecret | b64enc }} +{{- end }} + diff --git a/stellar-friendbot/templates/service.yaml b/stellar-friendbot/templates/service.yaml new file mode 100644 index 0000000..f8add03 --- /dev/null +++ b/stellar-friendbot/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "stellar-friendbot.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "stellar-friendbot.name" . }} + helm.sh/chart: {{ include "stellar-friendbot.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: {{ include "stellar-friendbot.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/stellar-friendbot/templates/serviceaccount.yaml b/stellar-friendbot/templates/serviceaccount.yaml new file mode 100644 index 0000000..a123459 --- /dev/null +++ b/stellar-friendbot/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "stellar-friendbot.serviceAccountName" . }} + labels: + app.kubernetes.io/name: {{ include "stellar-friendbot.name" . }} + helm.sh/chart: {{ include "stellar-friendbot.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} diff --git a/stellar-friendbot/values.yaml b/stellar-friendbot/values.yaml new file mode 100644 index 0000000..da404f5 --- /dev/null +++ b/stellar-friendbot/values.yaml @@ -0,0 +1,75 @@ +## WARNING: make sure to replace this in your configuration or use existingAccountSecretSecret +accountSecret: SBZYPEOQK7TWABPRW2LSSYWDI7O7TWZQZUH4RUUNEAUGNVHKKUH4Y6QF +# existingAccountSecretSecret: +# name: stellar-friendbot +# key: accountSecret + +networkPassphrase: Test SDF Network ; September 2015 + +horizonUrl: https://horizon-testnet.stellar.org + +startingBalance: 10000 + +environment: {} + +image: + repository: satoshipay/stellar-friendbot + tag: '0.13.0' + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + + ## The list of hostnames to be covered with this ingress record. + ## Most likely this will be just one host, but in the event more hosts are needed, this is an array + hosts: + - name: stellar-friendbot.local + + ## Set this to true in order to enable TLS on the ingress record + tls: false + + ## If TLS is set to true, you must declare what secret will store the key/certificate for TLS + tlsSecret: stellar-friendbot.local-tls + + ## Ingress annotations done as key:value pairs + ## If you're using kube-lego, you will want to add: + ## kubernetes.io/tls-acme: true + ## + ## For a full list of possible ingress annotations, please see + ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/annotations.md + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: true + + secrets: + ## If you're providing your own certificates, please use this to add the certificates as secrets + ## key and certificate should start with -----BEGIN CERTIFICATE----- or + ## -----BEGIN RSA PRIVATE KEY----- + ## + ## name should line up with a tlsSecret set further up + ## If you're using kube-lego, this is unneeded, as it will create the secret for you if it is not set + ## + ## It is also possible to create and manage the certificates outside of this helm chart + ## Please see README.md for more information + # - name: stellar-friendbot.local-tls + # key: + # certificate: + +resources: + requests: + cpu: 10m + memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +serviceAccount: + create: true + name: diff --git a/stellar-horizon/Chart.yaml b/stellar-horizon/Chart.yaml new file mode 100644 index 0000000..ed559aa --- /dev/null +++ b/stellar-horizon/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +appVersion: "0.15.1" +description: Client-facing API server for the Stellar cryptocurrency network. +name: stellar-horizon +version: 1.0.0 +icon: https://www.stellar.org/developers/images/favicon/rocket-180x180.png +home: https://www.stellar.org +maintainers: + - name: andrenarchy + email: andre.extern@satoshipay.io + url: https://github.com/andrenarchy +sources: + - https://github.com/satoshipay/docker-stellar-horizon/ +keywords: + - stellar + - stellar-horizon + - cryptocurrency + - blockchain +engine: gotpl diff --git a/stellar-horizon/OWNERS b/stellar-horizon/OWNERS new file mode 100644 index 0000000..3ed8897 --- /dev/null +++ b/stellar-horizon/OWNERS @@ -0,0 +1,4 @@ +approvers: +- andrenarchy +reviewers: +- andrenarchy diff --git a/stellar-horizon/README.md b/stellar-horizon/README.md new file mode 100644 index 0000000..9327fa6 --- /dev/null +++ b/stellar-horizon/README.md @@ -0,0 +1,70 @@ +# Stellar Horizon + +[Stellar](https://www.stellar.org) is an open-source and distributed payments infrastructure. Stellar Horizon is a HTTP REST API server that allows applications to interact with the Stellar network. Stellar Horizon needs access to a Stellar Core node. For more information see the [Stellar network overview](https://www.stellar.org/developers/guides/get-started/). + +## Introduction + +This chart bootstraps a [Stellar Horizon](https://github.com/stellar/go/) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. By default the deployment includes a PostgreSQL database and a Stellar Core node (which in turn includes another PostgreSQL database). The chart is based on the Kubernetes-ready [Stellar Horizon images provided by SatoshiPay](https://github.com/satoshipay/docker-stellar-horizon/). + +## Prerequisites + +- Kubernetes 1.8+ with Beta APIs enabled +- PV provisioner support in the underlying infrastructure (Only when persisting data) + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```bash +$ helm install --name my-release stable/stellar-horizon +``` + +## Configuration + +The following table lists the configurable parameters of the Stellar Horizon chart and their default values. + +| Parameter | Description | Default | +| ----------------------- | --------------------------------------------- | --------------------------------------------- | +| `postgresql.enabled` | Enable PostgreSQL database | `true` | +| `postgresql.postgresDatabase` | PostgreSQL database name | `stellar-core` | +| `postgresql.postgresUser` | PostgreSQL username | `postgres` | +| `postgresql.postgresPassword` | PostgreSQL password | Random password (see PostgreSQL chart) | +| `postgresql.persistence` | PostgreSQL persistence options | See PostgreSQL chart | +| `postgresql.*` | Any PostgreSQL option | See PostgreSQL chart | +| `existingDatabase` | Provide existing database (used if `postgresql.enabled` is `false`) | | +| `existingDatabase.passwordSecret` | Existing secret with the database password | `{name: 'postgresql-horizon', value: 'password'}`| +| `existingDatabase.url` | Existing database URL (use `$(DATABASE_PASSWORD` as the password) | Not set | +| `stellar-core.enabled` | Enable Stellar Core | `true` | +| `stellar-core.nodeSeed` | Node seed for Stellar Core | Not set | +| `stellar-core.*` | Any Stellar Core option, see `stellar-core` chart | | +| `stellar-core.postgresql.*` | Any PostgreSQL option (for Stellar Core) | | +| `existingStellarCore` | Provide existing Stellar Core (used if `stellar-core.enabled` is false)| | +| `existingStellarCore.url` | URL for HTTP admin endpoint of Stellar Core | Not set | +| `existingStellarCore.databaseUrl` | URL for Stellar Core PostgreSQL | Not set | +| `existingStellarCore.databasePasswordSecret` | Existing secret with the Stellar Core PostgreSQL password | `{name: 'postgresql-core', value: 'password'}` | +| `environment` | Additional environment variables for Stellar Horizon | `{}` | +| `image.repository` | `stellar-horizon` image repository | `satoshipay/stellar-horizon` | +| `image.tag` | `stellar-horizon` image tag | `0.14.2` | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `service.type` | HTTP endpoint service type | `ClusterIP` | +| `service.port` | HTTP endpoint TCP port | `80` | +| `ingress.enabled` | Enable ingress controller resource | `false` | +| `ingress.hosts[0].name` | Hostname to your Horizon installation | `stellar-horizon.local` | +| `ingress.hosts[0].path` | Path within the url structure | `/` | +| `ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `stellar-horizon.local-tls-secret` | +| `ingress.hosts[0].annotations` | Annotations for this host's ingress record | `[]` | +| `ingress.secrets[0].name` | TLS Secret Name | `nil` | +| `ingress.secrets[0].certificate` | TLS Secret Certificate | `nil` | +| `ingress.secrets[0].key` | TLS Secret Key | `nil` | +| `resources` | CPU/Memory resource requests/limits | Requests: `512Mi` memory, `100m` CPU | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Toleration labels for pod assignment | [] | +| `affinity` | Affinity settings for pod assignment | {} | +| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `serviceAccount.name` | The name of the ServiceAccount to create | Generated using the fullname template | + +## Persistence + +If PostgreSQL is enabled (`postgresql.enabled` is `true`) or if Stellar Core is enabled (`stellar-core.enabled` is `true`), they need to store data and thus this chart creates [Persistent Volumes](http://kubernetes.io/docs/user-guide/persistent-volumes/) by default. Make sure to size them properly for your needs and use an appropriate storage class, e.g. SSDs. + +You can also use existing claims with the `postgresql.persistence.existingClaim` and `stellar-core.persistence.existingClaim` options. diff --git a/stellar-horizon/requirements.lock b/stellar-horizon/requirements.lock new file mode 100644 index 0000000..42a81e2 --- /dev/null +++ b/stellar-horizon/requirements.lock @@ -0,0 +1,9 @@ +dependencies: +- name: postgresql + repository: https://kubernetes-charts.storage.googleapis.com/ + version: 0.19.0 +- name: stellar-core + repository: file://../stellar-core/ + version: 1.0.0 +digest: sha256:840d49072d3da7a02a1e80fe0d6dd204741b087da0c8a2ffce64d50cd6c89b50 +generated: 2018-11-13T09:00:49.946224246+01:00 diff --git a/stellar-horizon/requirements.yaml b/stellar-horizon/requirements.yaml new file mode 100644 index 0000000..f3e42d4 --- /dev/null +++ b/stellar-horizon/requirements.yaml @@ -0,0 +1,9 @@ +dependencies: +- name: postgresql + version: ^0.19.0 + repository: "https://kubernetes-charts.storage.googleapis.com/" + condition: postgresql.enabled +- name: stellar-core + version: ^1.0.0 + repository: "file://../stellar-core/" + condition: stellar-core.enabled diff --git a/stellar-horizon/templates/NOTES.txt b/stellar-horizon/templates/NOTES.txt new file mode 100644 index 0000000..01e4686 --- /dev/null +++ b/stellar-horizon/templates/NOTES.txt @@ -0,0 +1,33 @@ +1. Wait until Stellar Horizon is ready (i.e., ingested all requested data + from Stellar Core + +2. Get the Stellar Horizon URL: + +{{- if .Values.ingress.enabled }} + + You should be able to access your new Stellar Horizon installation through + + {{- range .Values.ingress.hosts }} + {{ if .tls }}https{{ else }}http{{ end }}://{{ .name }}/ + {{- end }} + +{{- else if contains "LoadBalancer" .Values.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "stellar-horizon.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "stellar-horizon.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo "Stellar Core URL: http://$SERVICE_IP:{{ .Values.service.port }}/" + +{{- else if contains "ClusterIP" .Values.service.type }} + + echo "Stellar Core URL: http://127.0.0.1/" + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "stellar-horizon.fullname" . }} 8080:{{ .Values.service.port }} + +{{- else if contains "NodePort" .Values.service.type }} + + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "stellar-horizon.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "Stellar Core URL: http://$NODE_IP:$NODE_PORT/" + +{{- end }} diff --git a/stellar-horizon/templates/_helpers.tpl b/stellar-horizon/templates/_helpers.tpl new file mode 100644 index 0000000..ef3db09 --- /dev/null +++ b/stellar-horizon/templates/_helpers.tpl @@ -0,0 +1,145 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "stellar-horizon.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "stellar-horizon.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "stellar-horizon.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "stellar-horizon.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "stellar-horizon.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "stellar-horizon.postgresql.fullname" -}} +{{- if .Values.postgresql.fullnameOverride -}} +{{- .Values.postgresql.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default "postgresql" .Values.postgresql.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "stellar-horizon.stellar-core.fullname" -}} +{{- $stellarCore := index .Values "stellar-core" -}} +{{- if $stellarCore.fullnameOverride -}} +{{- $stellarCore.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default "stellar-core" $stellarCore.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "stellar-horizon.stellar-core.postgresql.fullname" -}} +{{- $postgresql := index .Values "stellar-core" "postgresql" -}} +{{- if $postgresql.fullnameOverride -}} +{{- $postgresql.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default "postgresql" $postgresql.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{- define "stellar-horizon.env" -}} +{{- if .Values.postgresql.enabled }} +- name: DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "stellar-horizon.postgresql.fullname" . }} + key: postgres-password +- name: DATABASE_URL + value: postgres://{{ .Values.postgresql.postgresUser }}:$(DATABASE_PASSWORD)@{{ template "stellar-horizon.postgresql.fullname" . }}/{{ .Values.postgresql.postgresDatabase }}?sslmode=disable +{{- else }} +{{- with .Values.existingDatabase.passwordSecret }} +- name: DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .name | quote }} + key: {{ .key | quote }} +{{- end }} +- name: DATABASE_URL + value: {{ .Values.existingDatabase.url }} +{{- end }} +{{- if index .Values "stellar-core" "enabled" }} +- name: STELLAR_CORE_URL + value: http://{{ template "stellar-horizon.stellar-core.fullname" . }}-http:11626 +- name: STELLAR_CORE_DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "stellar-horizon.stellar-core.postgresql.fullname" . }} + key: postgres-password +- name: STELLAR_CORE_DATABASE_URL + value: postgres://postgres:$(STELLAR_CORE_DATABASE_PASSWORD)@{{ template "stellar-horizon.stellar-core.postgresql.fullname" . }}/stellar-core?sslmode=disable +{{- else }} +- name: STELLAR_CORE_URL + value: {{ .Values.existingStellarCore.url }} +{{- with .Values.existingStellarCore.databasePasswordSecret }} +- name: STELLAR_CORE_DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .name | quote }} + key: {{ .key | quote }} +{{- end }} +- name: STELLAR_CORE_DATABASE_URL + value: {{ .Values.existingStellarCore.databaseUrl }} +{{- end }} +{{- with .Values.networkPassphrase }} +- name: NETWORK_PASSPHRASE + value: {{ . | quote }} +{{- end }} +{{- end -}} diff --git a/stellar-horizon/templates/deployment.yaml b/stellar-horizon/templates/deployment.yaml new file mode 100644 index 0000000..fe8035c --- /dev/null +++ b/stellar-horizon/templates/deployment.yaml @@ -0,0 +1,72 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "stellar-horizon.fullname" . }} + labels: + app: {{ template "stellar-horizon.name" . }} + chart: {{ template "stellar-horizon.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: {{ template "stellar-horizon.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "stellar-horizon.name" . }} + release: {{ .Release.Name }} + spec: + serviceAccountName: "{{ template "stellar-horizon.serviceAccountName" . }}" + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 8000 + protocol: TCP + env: + {{ include "stellar-horizon.env" . | indent 12 }} + {{- if .Values.ingest }} + - name: INGEST + value: "true" + {{- end }} + {{- if .Values.ingestFailedTransactions }} + - name: INGEST_FAILED_TRANSACTIONS + value: "true" + {{- end }} + {{- if .Values.enableAssetStats }} + - name: ENABLE_ASSET_STATS + value: "true" + {{- end }} + {{- range $key, $val := .Values.environment }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end }} + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + timeoutSeconds: 5 + exec: + command: [ /ready.sh ] + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/stellar-horizon/templates/ingress.yaml b/stellar-horizon/templates/ingress.yaml new file mode 100644 index 0000000..2858ad8 --- /dev/null +++ b/stellar-horizon/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.hosts }} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: "{{- printf "%s-%s" .name $.Release.Name | trunc 63 | trimSuffix "-" -}}" + labels: + app: {{ template "stellar-horizon.name" $ }} + chart: {{ template "stellar-horizon.chart" $ }} + release: {{ $.Release.Name }} + heritage: {{ $.Release.Service }} + annotations: + {{- range $key, $value := .annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: + - host: {{ .name }} + http: + paths: + - path: {{ default "/" .path }} + backend: + serviceName: {{ template "stellar-horizon.fullname" $ }} + servicePort: http +{{- if .tls }} + tls: + - hosts: + - {{ .name }} + secretName: {{ .tlsSecret }} +{{- end }} +--- +{{- end }} +{{- end }} diff --git a/stellar-horizon/templates/job-backfill.yaml b/stellar-horizon/templates/job-backfill.yaml new file mode 100644 index 0000000..da70e5e --- /dev/null +++ b/stellar-horizon/templates/job-backfill.yaml @@ -0,0 +1,30 @@ +{{- if not (eq .Values.backfill "0") }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "stellar-horizon.fullname" . }}-backfill + labels: + app: {{ template "stellar-horizon.name" . }} + chart: {{ template "stellar-horizon.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + template: + metadata: + name: horizon-backfill + labels: + app: {{ template "stellar-horizon.name" . }} + chart: {{ template "stellar-horizon.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + spec: + containers: + - name: horizon-backfill + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: ["horizon", "db", "backfill", "{{ .Values.backfill }}"] + env: + {{ include "stellar-horizon.env" . | indent 10 }} + # Do not restart containers after they exit + restartPolicy: Never +{{- end }} diff --git a/stellar-horizon/templates/job-migrate.yaml b/stellar-horizon/templates/job-migrate.yaml new file mode 100644 index 0000000..c549503 --- /dev/null +++ b/stellar-horizon/templates/job-migrate.yaml @@ -0,0 +1,30 @@ +{{- if .Values.migrate }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "stellar-horizon.fullname" . }}-migrate + labels: + app: {{ template "stellar-horizon.name" . }} + chart: {{ template "stellar-horizon.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + template: + metadata: + name: horizon-migrate + labels: + app: {{ template "stellar-horizon.name" . }} + chart: {{ template "stellar-horizon.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + spec: + containers: + - name: horizon-migrate + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: ["horizon", "db", "migrate", "up"] + env: + {{ include "stellar-horizon.env" . | indent 10 }} + # Do not restart containers after they exit + restartPolicy: Never +{{- end }} diff --git a/stellar-horizon/templates/service.yaml b/stellar-horizon/templates/service.yaml new file mode 100644 index 0000000..4439940 --- /dev/null +++ b/stellar-horizon/templates/service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "stellar-horizon.fullname" . }} + labels: + app: {{ template "stellar-horizon.name" . }} + chart: {{ template "stellar-horizon.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + {{- range $key, $value := .Values.service.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "stellar-horizon.name" . }} + release: {{ .Release.Name }} diff --git a/stellar-horizon/templates/serviceaccount.yaml b/stellar-horizon/templates/serviceaccount.yaml new file mode 100644 index 0000000..039f2a9 --- /dev/null +++ b/stellar-horizon/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "stellar-horizon.serviceAccountName" . }} + labels: + app: {{ template "stellar-horizon.name" . }} + chart: {{ template "stellar-horizon.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- end -}} diff --git a/stellar-horizon/templates/tls-secrets.yaml b/stellar-horizon/templates/tls-secrets.yaml new file mode 100644 index 0000000..3267f6f --- /dev/null +++ b/stellar-horizon/templates/tls-secrets.yaml @@ -0,0 +1,18 @@ +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.secrets }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .name }} + labels: + app: {{ template "stellar-horizon.name" $ }} + chart: {{ template "stellar-horizon.chart" $ }} + release: {{ $.Release.Name }} + heritage: {{ $.Release.Service }} +type: kubernetes.io/tls +data: + tls.crt: {{ .certificate | b64enc }} + tls.key: {{ .key | b64enc }} +--- +{{- end }} +{{- end }} diff --git a/stellar-horizon/values.yaml b/stellar-horizon/values.yaml new file mode 100644 index 0000000..46f5a5b --- /dev/null +++ b/stellar-horizon/values.yaml @@ -0,0 +1,106 @@ +postgresql: + enabled: true + nameOverride: postgresql-horizon + postgresDatabase: stellar-horizon + postgresUser: postgres + # options from https://github.com/helm/charts/tree/master/stable/postgresql + # postgresPassword: + +## NOTE: +## existingDatabase is only used if postgresql.enabled is false +existingDatabase: + passwordSecret: + name: postgresql-horizon + key: password + ## NOTE: + ## $(DATABASE_PASSWORD) is automatically replaced with the value of the passwordSecret + # url: postgres://postgres:$(DATABASE_PASSWORD)@postgresql-horizon/stellar-horizon?sslmode=disable + +stellar-core: + enabled: true + # nodeSeed: SDUFQA7YL3KTWZNKOXX7XXIYU4R5R6JKELMREKHDQOYY2WPUGXFVJN52 + + postgresql: + nameOverride: postgresql-core + +## NOTE: +## existingStellarCore is only used if stellar-core.enabled is false +existingStellarCore: + url: http://stellar-core:11626 + databaseUrl: postgres://postgres:$(DATABASE_PASSWORD)@postgresql-core/stellar-core?sslmode=disable + databasePasswordSecret: + name: postgresql-core + key: password + +ingest: true +ingestFailedTransactions: true +enableAssetStats: false + +backfill: 0 +migrate: false +networkPassphrase: Public Global Stellar Network ; September 2015 + +environment: {} + +image: + repository: satoshipay/stellar-horizon + tag: '0.17.6' + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + annotations: + +ingress: + enabled: false + + ## The list of hostnames to be covered with this ingress record. + ## Most likely this will be just one host, but in the event more hosts are needed, this is an array + hosts: + - name: stellar-horizon.local + + ## Set this to true in order to enable TLS on the ingress record + tls: false + + ## If TLS is set to true, you must declare what secret will store the key/certificate for TLS + tlsSecret: stellar-horizon.local-tls + + ## Ingress annotations done as key:value pairs + ## If you're using kube-lego, you will want to add: + ## kubernetes.io/tls-acme: true + ## + ## For a full list of possible ingress annotations, please see + ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/annotations.md + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: true + + secrets: + ## If you're providing your own certificates, please use this to add the certificates as secrets + ## key and certificate should start with -----BEGIN CERTIFICATE----- or + ## -----BEGIN RSA PRIVATE KEY----- + ## + ## name should line up with a tlsSecret set further up + ## If you're using kube-lego, this is unneeded, as it will create the secret for you if it is not set + ## + ## It is also possible to create and manage the certificates outside of this helm chart + ## Please see README.md for more information + # - name: stellar-horizon.local-tls + # key: + # certificate: + +resources: + requests: + cpu: 100m + memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +serviceAccount: + create: true + name: