Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Build image

on:
push:
branches: [main]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v7

- uses: docker/setup-buildx-action@v4

- uses: docker/login-action@v4
if: github.event_name == 'push'
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=sha,format=long
type=raw,value=latest,enable={{is_default_branch}}

- uses: docker/build-push-action@v7
with:
context: .
push: ${{ github.event_name == 'push' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64
65 changes: 65 additions & 0 deletions k8s/base/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: token-supply-api
labels:
app.kubernetes.io/name: token-supply-api
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: token-supply-api
template:
metadata:
labels:
app.kubernetes.io/name: token-supply-api
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
imagePullSecrets:
- name: ghcr-credentials
containers:
- name: token-supply-api
# Pinned per environment by the overlay `images:` transformer.
image: ghcr.io/0xsend/token-supply-api:latest
ports:
- containerPort: 8080
name: http
env:
- name: NODE_ENV
value: production
envFrom:
- secretRef:
name: token-supply-api
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
resources:
requests:
cpu: 20m
memory: 96Mi
limits:
memory: 256Mi
# The server binds only after the first total and circulating supply
# lookups succeed, so an answering /total means the cached values exist.
startupProbe:
httpGet:
path: /total
port: http
periodSeconds: 5
failureThreshold: 24
readinessProbe:
httpGet:
path: /total
port: http
periodSeconds: 15
livenessProbe:
httpGet:
path: /total
port: http
periodSeconds: 30
24 changes: 24 additions & 0 deletions k8s/base/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Cloudflare (proxied, TLS at the edge) -> ingress-nginx -> Service, like the
# rest of the swiss fleet. supply.send.it reaches the cluster through the
# proxied *.send.it wildcard once its DigitalOcean CNAME is removed.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: token-supply-api
labels:
app.kubernetes.io/name: token-supply-api
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: supply.send.it
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: token-supply-api
port:
number: 80
7 changes: 7 additions & 0 deletions k8s/base/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- deployment.yaml
- service.yaml
- ingress.yaml
14 changes: 14 additions & 0 deletions k8s/base/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: token-supply-api
labels:
app.kubernetes.io/name: token-supply-api
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: token-supply-api
ports:
- name: http
port: 80
targetPort: http
25 changes: 25 additions & 0 deletions k8s/overlays/prod/externalsecret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# RPC endpoints carry provider API keys, so they come from 1Password item
# `token-supply-api` in the sendapp-prod vault.
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: token-supply-api
labels:
app.kubernetes.io/name: token-supply-api
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: op-sendapp-prod
target:
name: token-supply-api
creationPolicy: Owner
data:
- secretKey: MAINNET_RPC_URL
remoteRef:
key: token-supply-api
property: mainnet-rpc-url
- secretKey: BASE_RPC_URL
remoteRef:
key: token-supply-api
property: base-rpc-url
13 changes: 13 additions & 0 deletions k8s/overlays/prod/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: token-supply-prod

resources:
- namespace.yaml
- externalsecret.yaml
- ../../base

images:
- name: ghcr.io/0xsend/token-supply-api
newTag: sha-REPLACE_WITH_MAIN_SHA
10 changes: 10 additions & 0 deletions k8s/overlays/prod/namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Namespace
metadata:
name: token-supply-prod
labels:
# Injects the ghcr-credentials image pull secret (fleet convention).
ghcr-enabled: "true"
app.kubernetes.io/name: token-supply-api
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
Loading