Beta environment deployment #7

Closed
adam wants to merge 17 commits from feat/mvp-deploy-beta into feat/mvp
44 changed files with 559 additions and 92 deletions

4
.gitignore vendored
View File

@ -26,3 +26,7 @@ vite.config.ts.timestamp-*
.DS_Store
# keys
.age.txt

6
.sops.yaml Normal file
View File

@ -0,0 +1,6 @@
creation_rules:
- path_regex: env/.*/master\.json$
pgp: 4FA79E5B6598505C8DFA30A7A466CEE1415C0B9C
- path_regex: env/base/.*\.yaml$
encrypted_regex: ^(data|stringData)$
age: age1d5vst0g82v6xml29ydsrxefmf3vclgm6dj3npw6mefa7yu9xueaqztjqlg

View File

@ -7,3 +7,5 @@ buf 1.17.0
k9s 0.26.3
golang 1.19
nodejs lts
sops 3.7.3
jq 1.6

View File

@ -15,11 +15,49 @@ clobber:
@rm -f $(KUBECONFIG)
.PHONY: build
build:
docker build --build-arg "service=runner" -t bh/service-runner -f ./src/Dockerfile.service ./src
docker build --build-arg "service=catalog" -t bh/service-catalog -f ./src/Dockerfile.service ./src
docker build --build-arg "service=proxy-admin" -t bh/service-proxy-admin -f ./src/Dockerfile.service ./src
SERVICE = "catalog"
ENV = ""
ORIGIN = "https://barretthousen.com"
BUILD_INITIATOR = "Development Machine"
VERSION = $(shell git rev-parse --verify --short HEAD)
GIT_REF = $(shell git rev-parse --verify HEAD)
BUILD_DATE := $(shell date +%Y-%m-%d-%T)
.PHONY: build-client-image
build-client-image:
docker build --target=production \
--label 'com.barretthousen.service=$(SERVICE)' \
--label 'com.barretthousen.version=$(VERSION)' \
--label 'com.barretthousen.git-ref=$(GIT_REF)' \
--label 'com.barretthousen.build-date=$(BUILD_DATE)' \
--label 'com.barrethousen.builder=$(BUILD_INITIATOR)' \
--build-arg 'origin=$(ORIGIN)' \
-t barretthousen/client-$(SERVICE):$(VERSION) \
-t git.vdhsn.com/barretthousen/client-$(SERVICE):$(VERSION) \
-f ./src/$(SERVICE)/Dockerfile.frontend ./src/$(SERVICE)
@[ ! -z $(ENV) ] && docker tag git.vdhsn.com/barretthousen/client-$(SERVICE):$(VERSION) git.vdhsn.com/barretthousen/client-$(SERVICE):$(ENV) || true
@[ ! -z $(ENV) ] && docker push git.vdhsn.com/barretthousen/client-$(SERVICE):$(VERSION) || true
@[ ! -z $(ENV) ] && docker push git.vdhsn.com/barretthousen/client-$(SERVICE):$(ENV) || true
.PHONY: build-backend-image
build-backend-image:
docker build --target=production \
--label 'com.barretthousen.service=$(SERVICE)' \
--label 'com.barretthousen.version="$(VERSION)"' \
--label 'com.barretthousen.git-ref="$(GIT_REF)"' \
--label 'com.barretthousen.build-date=$(BUILD_DATE)' \
--label 'com.barrethousen.builder=$(BUILD_INITIATOR)' \
--build-arg 'service=$(SERVICE)' \
-t barretthousen/service-$(SERVICE):$(VERSION) \
-t git.vdhsn.com/barretthousen/service-$(SERVICE):$(VERSION) \
-t git.vdhsn.com/barretthousen/service-$(SERVICE):$(ENV) \
-f ./src/Dockerfile.prod-backend ./src
@[ ! -z $(ENV) ] && docker tag git.vdhsn.com/barretthousen/service-$(SERVICE):$(VERSION) git.vdhsn.com/barretthousen/service-$(SERVICE):$(ENV) || true
@[ ! -z $(ENV) ] && docker push git.vdhsn.com/barretthousen/service-$(SERVICE):$(VERSION) || true
@[ ! -z $(ENV) ] && docker push git.vdhsn.com/barretthousen/service-$(SERVICE):$(ENV) || true
.PHONY: acceptance-test
acceptance-test:
@ -36,8 +74,9 @@ gen: $(GOBIN)/sqlc buf.lock
.PHONY: setup
setup: $(GOBIN)/sqlc $(GOBIN)/buf
setup: $(GOBIN)/sqlc $(GOBIN)/buf ./env/.age.txt
@asdf install || true
@docker login git.vdhsn.com
buf.lock: $(GOBIN)/buf
@$(GOBIN)/buf mod update ./src
@ -52,3 +91,11 @@ $(GOBIN)/sqlc:
@KUBECONFIG=$(KUBECONFIG) ctlptl create registry kind-bh-registry --port=5005
@KUBECONFIG=$(KUBECONFIG) ctlptl create cluster kind --name=kind-bh-local --registry=kind-bh-registry --kubernetes-version $(K8S_VERSION)
@kind get kubeconfig --name=bh-local > .kubeconfig
# used to encrypt/decrypt sensitive values with sops
age_identity=$(shell sops -d ./env/master.json)
./env/.age.txt:
@echo "# created: $(shell echo '$(age_identity)' | jq -r '.created')" >> $@
@echo "# public key: $(shell echo '$(age_identity)' | jq -r '.public_key')" >> $@
@echo "$(shell echo '$(age_identity)' | jq -r '.private_key')" >> $@
@echo "$@ created!"

View File

@ -2,6 +2,8 @@
Search and get alerts for items across the most popular auction sites.
Built with microservice architecture, for learning purposes
### Links
- [Keybase Team Chat](keybase://team/barretthousen)
@ -16,7 +18,6 @@ Search and get alerts for items across the most popular auction sites.
1. Ability to search upcoming and live auctions across major auction sites
2. Get an email digest of upcoming auctions for the week
Future goals
1. Get email alerts when these auctions are about to go live
@ -65,9 +66,18 @@ Monolithic postgres datbabase tying it all together
Install `asdf` and run `hack/asdf_plugin_setup`
```sh
make setup # install asdf stuff and build tooling
# install asdf tools, build tooling, encryption key for sops
make setup
make gen # generate protobufs and sql boilerplate
# generate protobufs and sql boilerplate
make gen
make dev # spin up a k8s cluster, build and deploy servicces w/ hot reloading
# spin up a k8s cluster, build and deploy services locally w/ hot reloading
make dev
# build production docker images for the backend microservices, optionally push to the respective env
make build-backend-image SERVICE=[catalog, runner, proxy-client, proxy-admin] [ENV=[beta, prod]]
# build client docker image for web frontends, optionally push to the respective env
make build-client-image SERVICE=[web-client] [ENV=[beta, prod]]
```

View File

@ -16,14 +16,15 @@ helm_repo('grafana', 'https://grafana.github.io/helm-charts', labels=["9-repos"]
helm_resource(
'ingress',
'traefik/traefik',
namespace='barretthousen-local',
flags=[
'--set', 'logs.access.enabled=true'
],
resource_deps=['traefik'],
port_forwards=[
port_forward(8000, 8000, name='Barretthousen'),
port_forward(9000, 9000, name='Traefik', link_path='/dashboard/#/')
],
resource_deps=['traefik'],
labels=["1-ingress"]
)
@ -38,7 +39,7 @@ k8s_resource(
helm_resource(
'postgres',
'bitnami/postgresql',
resource_deps=['bitnami'],
namespace='barretthousen-local',
flags=[
'--set', 'fullnameOverride=bh-db',
'--set', 'auth.enablePostgresUser=true',
@ -47,6 +48,7 @@ helm_resource(
],
port_forwards=[
port_forward(5432, 5432, name='BH DB')],
resource_deps=['bitnami'],
labels=["9-data"])
k8s_yaml(
@ -58,7 +60,8 @@ def bh_backend_service(service="", port_forwards=[], migrateDB=False, devMode=Tr
'{}-go-compile'.format(service),
'CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -gcflags "all=-N -l" -o .bin/{}-debug ./src/{}'.format(service, service),
deps=['./src/{}'.format(service), './src/lib'],
resource_deps=deps
resource_deps=deps,
labels=['3-compilation']
)
entry_cmd = [
@ -103,7 +106,7 @@ def bh_backend_service(service="", port_forwards=[], migrateDB=False, devMode=Tr
)
k8s_resource(
workload='local-{}'.format(service),
workload='{}-local'.format(service),
port_forwards=port_forwards,
labels=labels,
resource_deps=deps,
@ -130,16 +133,22 @@ bh_backend_service(service="proxy-client", port_forwards=[
docker_build(
ref='barretthousen/service-web-client',
context='./src/web-client',
dockerfile='./src/web-client/Dockerfile.frontend',
dockerfile='./src/web-client/Dockerfile.dev-frontend',
target='development'
)
k8s_resource(
workload='local-web-client',
workload='web-client-local',
port_forwards=['8080:80'],
labels=['2-services'],
resource_deps=['ingress']
)
k8s_resource(
workload='runner-sync-local',
labels='2-services'
)
# local_resource(
# 'web-client',
# dir='./src/web-client',
@ -159,6 +168,7 @@ k8s_resource(
# labels=['2-services']
# )
# helm_resource(
# 'loki-stack',
# 'grafana/loki-stack',

88
doc/deployment.md Normal file
View File

@ -0,0 +1,88 @@
# Deployment
Services deployed (using kustomize):
- [catalog](./src/catalog)
- [runner](./src/runner)
- [proxy-admin](./src/proxy-admin)
- [proxy-client](./src/proxy-client)
- [web-client](./src/web-client)
Platform components deployed (using helm):
- [Traefik]()
- [Postgresql]()
## [Beta](https://beta.barretthousen.com)
The [Beta](https://beta.barretthousen.com) environment lives in my [homelab repo](https://git.vdhsn.com/adam/SunnyHomeLab),
and is auto deployed using Flux w/ kustomize.
See [./env/beta](./env/beta/kustomization.yaml) for how it's set up.
- There are only 3 environments: `local`, `beta`, `prod`
- `local`: optimize for iteration speed, observability, mutability. Ephemeral data. Should be quick to create and destroy.
- `beta`: optimize for likeness with prod, observability, and durable data.
- `prod`: optimize for up time, automated change control, observability, data durability.
- Each environment should pull from the image tag that matches it's name (ie catalog service running in `beta` env will use `git.vdhsn.com/barretthousen/service-catalog:beta` docker image)
- All environments should have resources suffixed with their name (ie `deployment/catalog-beta` in `beta` env)
- All environments must use kustomize, and have the same resources - configuration of those resources can vary as needed
### Initial environment setup
Deploy the following with Helm (assuming we're setting up a new `beta` env with the following commands):
1. Traefik:
```sh
helm repo add traefik https://traefik.github.io/charts;
helm install --upgrade ingress traefik/traefik -n 'barretthousen-beta'\
--set=logs.access.enabled=true
```
2. Postgresql:
```sh
helm repo add bitnami https://charts.bitnami.com/bitnami;
helm install --upgrade bh-db bitnami/postgresql -n 'barretthousen-beta' \
--set='fullnameOverride=bh-db' \
--set='auth.enablePostgresuser=true' \
--set='auth.postgresPassword=bh-admin' \
--set='auth.database=bh'
```
### Deployment steps
1. Build and publish prod images
```sh
make build-backend-image SERVICE=catalog env=beta
make build-backend-image SERVICE=runner env=beta
make build-backend-image SERVICE=proxy-admin env=beta
make build-backend-image SERVICE=proxy-client env=beta
make build-client-image SERVICE=web-client env=beta
```
2. Rolling restart deployments in the beta env
```sh
kubectl rollout restart -n barretthousen-beta deployment runner-beta
kubectl rollout status -n barretthousen-beta deployment runner-beta -w
kubectl rollout restart -n barretthousen-beta deployment catalog-beta
kubectl rollout status -n barretthousen-beta deployment catalog-beta -w
kubectl rollout restart -n barretthousen-beta deployment proxy-admin-beta
kubectl rollout status -n barretthousen-beta deployment proxy-admin-beta -w
kubectl rollout restart -n barretthousen-beta deployment proxy-client-beta
kubectl rollout status -n barretthousen-beta deployment proxy-client-beta -w
kubectl rollout restart -n barretthousen-beta deployment web-client-beta
kubectl rollout status -n barretthousen-beta deployment web-client-beta -w
```
## Prod
TBD

View File

@ -12,9 +12,11 @@ spec:
labels:
service: catalog
spec:
serviceAccountName: barretthousen-service
containers:
- name: catalog
image: barretthousen/service-catalog
image: barretthousen/service-catalog:prod
imagePullPolicy: Always
ports:
- containerPort: 5001
name: grpc

27
env/base/image-pull-secret.yaml vendored Normal file
View File

@ -0,0 +1,27 @@
apiVersion: v1
kind: Secret
metadata:
name: bh-registry
type: kubernetes.io/dockerconfigjson
stringData:
.dockerconfigjson: ENC[AES256_GCM,data:bfqlh7Vy3HDYFtgv56xO+8lXOLO9bQWRC16N8hAzv6xJaIN6CmXDwFzoLoGWPrP9s/o446tuOEJEylf5z/ITnLtdGJgMsN13Xk7OiF9B2unV8yOOrzt6U6R2s5cFpbSL3tAHQmDKHxRrzbvyV2J3magen7oHQWbkwkOQq7FqV/k7wFly+bei1u+YLJ9hq798Xa5HG9j4LsVWi5izKt1BBss2xFlo3yzEFqNmQ+AzcUN1uK1xwStplK4IKC36rewONDS+yyqj830LLShb,iv:qDwYxBqK+ZamBcWEuF+UEfW8gLFROagaBqVAc1tCjUI=,tag:OYhChcvisxP0r3kQ4hq4SA==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1d5vst0g82v6xml29ydsrxefmf3vclgm6dj3npw6mefa7yu9xueaqztjqlg
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaRG1ERkdkTXMvUllCSHdS
TXVBVWNMd0hYeXMvTXh6OFVTYXV0MkVoOEJ3Ck9XakJTbHMyTWpvazFzYUtNcmtx
NTVoVnUwWkpKYjg4MWs1dmxpT3JGRFUKLS0tIHdHRk8yL1lCRk9DM0haYjN4Z1Ry
d25rRklvOUdLQlU0S2l0WXBpUXhyR2MKQgJXQgxp0T2rr0V2NjwSjWFlzNyig5vW
S8PW6OpCOyfMqzz5NWTdUVymY7UEdAguwZH+MY2DdvEn3NM/TcnRwA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2023-05-27T02:48:45Z"
mac: ENC[AES256_GCM,data:SCjcJPn7hg9sUFYlOUKAVJBXKNIrcz/x3aqyX43xf7UO7Zo/pGDp1JDaKA7lCaKTgPEAe1zRRv6LjejNGX3DlpmxMS6o2xaI3nb0e0CnLj9t9t57L5svrciwh9wOennWj26DirgzAB+uqCJ/NGOJh4S8yTPOF5MgBNkqNw6FN94=,iv:YTtckdYzKnBBqbQYvjw9FpvGHsUxX6MnAeNopYhFe7I=,tag:BPUitJtY65JbnanHJgJatg==,type:str]
pgp: []
encrypted_regex: ^(data|stringData)$
version: 3.7.3

View File

@ -1,4 +1,6 @@
resources:
- ./image-pull-secret.yaml
- ./namespace.yaml
- ./catalog-deployment.yaml
- ./runner-deployment.yaml
- ./proxy-admin-deployment.yaml
@ -6,3 +8,4 @@ resources:
- ./web-client-deployment.yaml
- ./client-ingress.yaml
- ./admin-ingress.yaml
- ./scrape-cronjob.yaml

17
env/base/namespace.yaml vendored Normal file
View File

@ -0,0 +1,17 @@
apiVersion: v1
kind: Namespace
metadata:
name: barretthousen
annotations:
description: |
environment for barretthousen
labels:
name: barretthousen
app: barretthousen
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: barretthousen-service
imagePullSecrets:
- name: bh-registry

View File

@ -11,9 +11,11 @@ spec:
labels:
service: proxy-admin
spec:
serviceAccountName: barretthousen-service
containers:
- name: proxy-admin
image: barretthousen/service-proxy-admin
image: barretthousen/service-proxy-admin:prod
imagePullPolicy: Always
ports:
- containerPort: 80
name: http
@ -51,4 +53,4 @@ data:
log_level: 2
port: 80
endpoints:
runner: local-runner:5001
runner: runner-local:5001

View File

@ -11,9 +11,11 @@ spec:
labels:
service: proxy-client
spec:
serviceAccountName: barretthousen-service
containers:
- name: proxy-client
image: barretthousen/service-proxy-client
image: barretthousen/service-proxy-client:prod
imagePullPolicy: Always
ports:
- containerPort: 80
name: http
@ -50,5 +52,6 @@ data:
config.yaml: |
log_level: 2
port: 80
access_control_allow_origin: "*"
endpoints:
catalog: local-catalog:5001
catalog: catalog-local:5001

View File

@ -12,11 +12,11 @@ spec:
labels:
service: runner
spec:
serviceAccountName: barretthousen-service
containers:
- name: runner
image: barretthousen/service-runner
tty: true
stdin: true
image: barretthousen/service-runner:prod
imagePullPolicy: Always
ports:
- containerPort: 5001
name: grpc

24
env/base/scrape-cronjob.yaml vendored Normal file
View File

@ -0,0 +1,24 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: runner-sync
spec:
schedule: "*/2 * * * *"
jobTemplate:
spec:
template:
metadata:
labels:
name: runner-sync
spec:
restartPolicy: OnFailure
containers:
- name: runner-curl
image: curlimages/curl:latest
command:
[
"curl",
"http://proxy-admin-local/api/v1/sync",
'-d=''{"target":"liveauctioneers"}''',
"-vvvv",
]

View File

@ -11,11 +11,16 @@ spec:
labels:
app: web-client
spec:
serviceAccountName: barretthousen-service
containers:
- name: web-client
image: barretthousen/service-web-client
image: barretthousen/service-web-client:prod
imagePullPolicy: Always
stdin: true
tty: true
env:
- name: ORIGIN
value: https://barretthousen.com
ports:
- containerPort: 80
name: http

22
env/beta/catalog-configmap.yaml vendored Normal file
View File

@ -0,0 +1,22 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: catalog-config
data:
config.yaml: |
log_level: 2
port: 5001
db_service:
scheme: postgres
port: 5432
host: bh-db
name: bh
user: catalog-service
password: catalog-service
db_migrate:
scheme: postgres
port: 5432
host: bh-db
name: bh
user: postgres
password: bh-admin-beta

View File

@ -1,7 +1,67 @@
resources:
- ../base
commonLabels:
environment: beta
nameSuffix: -beta
namespace: barretthousen-beta
namePrefix: beta-
patchesStrategicMerge:
- scrape-cronjob.yaml
- catalog-configmap.yaml
- proxy-admin-configmap.yaml
- proxy-client-configmap.yaml
- runner-configmap.yaml
patches:
- target:
kind: Ingress
name: admin
patch: |-
- op: replace
path: /spec/rules/0/host
value: admin.beta.barretthousen.com
- target:
kind: Ingress
name: web
patch: |-
- op: replace
path: /spec/rules/0/host
value: beta.barretthousen.com
- target:
kind: Deployment
name: catalog
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: git.vdhsn.com/barretthousen/service-catalog:beta
- target:
kind: Deployment
name: runner
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: git.vdhsn.com/barretthousen/service-runner:beta
- target:
kind: Deployment
name: proxy-admin
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: git.vdhsn.com/barretthousen/service-proxy-admin:beta
- target:
kind: Deployment
name: proxy-client
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: git.vdhsn.com/barretthousen/service-proxy-client:beta
- target:
kind: Deployment
name: web-client
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: git.vdhsn.com/barretthousen/client-web-client:beta
- op: replace
path: /spec/template/spec/containers/0/env/0/value
value: https://beta.barretthousen.com

10
env/beta/proxy-admin-configmap.yaml vendored Normal file
View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: proxy-admin-config
data:
config.yaml: |
log_level: 2
port: 80
endpoints:
runner: runner-beta:5001

11
env/beta/proxy-client-configmap.yaml vendored Normal file
View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: proxy-client-config
data:
config.yaml: |
log_level: 2
port: 80
access_control_allow_origin: "beta.barretthousen.com"
endpoints:
catalog: catalog-beta:5001

23
env/beta/runner-configmap.yaml vendored Normal file
View File

@ -0,0 +1,23 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: runner-config
data:
config.yaml: |
log_level: 2
port: 5001
catalog_endpoint: catalog-beta:5001
db_service:
scheme: postgres
port: 5432
host: bh-db
name: bh
user: runner-service
password: runner-service
db_migrate:
scheme: postgres
port: 5432
host: bh-db
name: bh
user: postgres
password: bh-admin-beta

19
env/beta/scrape-cronjob.yaml vendored Normal file
View File

@ -0,0 +1,19 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: runner-sync
spec:
schedule: "0 */2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: runner-curl
command:
[
"curl",
"http://proxy-admin-beta/api/v1/sync",
'-d=''{"target":"liveauctioneers"}''',
"-vvvv",
]

8
env/local/image-pull-secret.yaml vendored Normal file
View File

@ -0,0 +1,8 @@
apiVersion: v1
kind: Secret
metadata:
name: bh-registry
type: kubernetes.io/dockerconfigjson
stringData:
.dockerconfigjson: |
{ "auths": {} }

View File

@ -4,13 +4,22 @@ resources:
commonLabels:
environment: local
namePrefix: local-
nameSuffix: -local
namespace: barretthousen-local
patchesStrategicMerge:
- debug-catalog.yaml
- debug-runner.yaml
- image-pull-secret.yaml
patches:
- target:
kind: CronJob
name: runner-sync
patch: |-
- op: replace
path: /spec/schedule
value: "* * * * *"
- target:
kind: Ingress
name: admin

23
env/master.json vendored Normal file
View File

@ -0,0 +1,23 @@
{
"created": "ENC[AES256_GCM,data:eyA43QPLejsqy/4SSWOkaLPMO2+EbuifxQ==,iv:0wEGpIk4023HaDqmXlCimTC4AviguxqzO8LSCIoBPow=,tag:XmpNZzlxNinyPnWP0U7dXQ==,type:str]",
"public_key": "ENC[AES256_GCM,data:f7DxyKaLbgjHvTmNNa6K/pGqFtxrm/JmTQs+I00YQpr4XP8ja0ff+7vM2qi8hzYWQsZ8wiIr/VsPImi/RPQ=,iv:O23u+cuva4qJZ/OpVEoYr3o5X4GxsPt+U3Q5GgQLymc=,tag:6XJtLb/g+WJLhsFH6M6FlA==,type:str]",
"private_key": "ENC[AES256_GCM,data:TTVQUdE+Xd1M3RHix2bkxggrxo3ILdmonjNcq9Ticb2WSIG+IuR+lytgSb+7UHzjFx8wr/lMfap/v7lAum+nYw08Fd56t0B4aHI=,iv:CmYfrd2MtwoyLxjqWC3TZRdK9CRs96n4BYo51MY6uzs=,tag:GYfVWSYE05/tdRaul4JPxw==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": null,
"lastmodified": "2023-05-27T01:53:31Z",
"mac": "ENC[AES256_GCM,data:nUmf5oSS+I7WPoJZ4hCpamhQRYeAeSWnzNM6OMAkar+ZXJ/LMynUNy2BA9hHbX6sNoMh7jrGrABAwfXqoGVCkl0F3PtHGky59uiQ0jmSU48n504dhL8/5kr16MeGSMCuVnp+oVy9V9tYFxt4LTxVzMK9mBr92B7kcRqKsb7jO6w=,iv:A5kjc0qtrTTTDOKBgKLslPwv+InCGNVOWLu1T3LmIYw=,tag:2vhk0BEk6MSZHW8zHrIuQg==,type:str]",
"pgp": [
{
"created_at": "2023-05-27T01:53:31Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAzSNwvjPuwiyAQ/9F9BIr5Qu9VC2y8gIBjNKiDxbR5sOo0gopJnCtAWoM4RU\nZO4aU3+MlUjr25PfYauqmdyc86vzDshbyfsQ8uQJW20pl4wJFzbtsSEgMio89FE5\nlfyKB9WcTvivrVUYSarXE7DrPvdr5qOh5qUrc6HLGaniwyN3MxGnm/qu5Ip2z3i8\n6g2GarUJmWXF1U8F0oXw069ImgvTd1u2gUC+CXMDSW+38FYN5dmtbo271g9/7Ikl\nEaP+7B9PlPUAav8IE/k/dGwqeQOjiEce6h0rxyl8PqgcTvxpaJ8Kd197iTovXeyt\nAK1Fv9sMVBBGi/pma85cPxkn8vU68v6LQJvMSwAJ8y+2rXrUb7nxFt1+iBvJWwRr\napGBhceLriV1eL9l0CtLpZNrQvvldF8mNMaNK0vVGdsDrHZq2wU9jSeKZq92Cy2y\nQ+0sEPlBKJIRTcrghtOgKbNatNWM7zShwmxAJ4Kw6qFSpEOTj9Y4WOL70ivWynSt\np7aaKbSwtwBcXezZZqp1C5/xlcrWal83bsjUqAnXhd30VYBw66JGhZa2PkD0VyqL\n4yoCUC9H8Ea8XtD/z4iG4y8z2yn/+Qa3KoW6vTp78i8OzdzqnfLB9pa6rinueaeV\n1S9y6B+kvwdqDTtgrIfGMUifaE0qE2ZKiPGbyKnqjUrBmY9VUsAQNTkfgXIhQnDS\nXAGDvTBFmmdZzEWE/OP+l1tdk88HJzfhDxIXxdncIYW79ib7bKoqRW6CcrPawxC+\nDn4ykqRZZNYw4j207YXqvYZWBKRCnInWKPmyfT9Ozfd7/HZnX91cKIawwPz2\n=ufAq\n-----END PGP MESSAGE-----\n",
"fp": "A466CEE1415C0B9C"
}
],
"unencrypted_suffix": "_unencrypted",
"version": "3.7.3"
}
}

View File

@ -0,0 +1,2 @@
web-client
.idea

View File

@ -1,17 +1,19 @@
FROM golang:1.19-alpine as builder
FROM golang:1.19 as builder
ARG service
RUN go install github.com/bufbuild/buf/cmd/buf@v1.17.0
RUN go install github.com/kyleconroy/sqlc/cmd/sqlc@latest
COPY . /go/src
WORKDIR /go/src/${service}
WORKDIR /go/src/
RUN /go/bin/sqlc generate -f /go/src/sqlc.yaml
RUN /go/bin/buf mod update /go/src/src \
&& /go/bin/buf generate
RUN /go/bin/buf mod update /go/src && /go/bin/buf generate
ARG service
WORKDIR /go/src/${service}
RUN go mod tidy \
&& CGO_ENABLED=0 go build -v -gcflags="-trimpath=$(go env GOPATH)" -asmflags="-trimpath=$(go env GOPATH)" -o /opt/${service} /go/src/${service}
@ -24,4 +26,4 @@ COPY --from=builder /opt/${service} /opt/${service}
ENV SERVICE=${SERVICE}
ENTRYPOINT ['/opt/${SERVICE}']
ENTRYPOINT ["/opt/${SERVICE}"]

View File

@ -18,6 +18,7 @@ require (
github.com/joho/godotenv v1.5.1 // indirect
github.com/pressly/goose/v3 v3.11.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.8.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect

View File

@ -180,6 +180,7 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@ -5,6 +5,7 @@ go 1.19
require (
github.com/jackc/pgx/v4 v4.18.1
go.uber.org/automaxprocs v1.5.2
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
google.golang.org/grpc v1.55.0
)

View File

@ -175,6 +175,7 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@ -30,36 +30,8 @@ func Run(parent context.Context, app App) {
ctx, canceller := context.WithCancel(parent)
defer canceller()
sig := make(chan os.Signal, 5)
signal.Notify(sig, syscall.SIGTERM, syscall.SIGHUP)
go func() {
defer canceller()
select {
case signal := <-sig:
TraceLog.Printf("[SHUTDOWN TRIGGERED] got shutdown signal: %v", signal)
case <-ctx.Done():
TraceLog.Println("[SHUTDOWN TRIGGERED] context exited unexpectedly")
}
InfoLog.Println("Shutting down service ⛔⚠️😱")
stopCtx, stopCanceller := context.WithTimeout(parent, time.Second*5)
defer stopCanceller()
app.OnStop(stopCtx)
errs := &errgroup.Group{}
errs.Go(CloseGRPCConns)
errs.Go(StopHTTPServer)
errs.Go(StopGRPCServer)
if err := errs.Wait(); err != nil {
ErrorLog.Printf("There was an error shutting down the application gracefully: %v", err)
}
}()
InfoLog.Println("Starting service 🚀")
if err := loadConfig(app); err != nil {
@ -71,6 +43,35 @@ func Run(parent context.Context, app App) {
ErrorLog.Println(err)
return
}
}()
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGTERM, syscall.SIGHUP)
select {
case signal := <-sig:
TraceLog.Printf("[SHUTDOWN TRIGGERED] got shutdown signal: %v", signal)
case <-ctx.Done():
TraceLog.Println("[SHUTDOWN TRIGGERED] context exited")
}
InfoLog.Println("Shutting down service ⛔⚠️😱")
errs := &errgroup.Group{}
errs.Go(CloseGRPCConns)
errs.Go(StopHTTPServer)
errs.Go(StopGRPCServer)
if err := errs.Wait(); err != nil {
ErrorLog.Printf("There was an error shutting down the application gracefully: %v", err)
}
stopCtx, stopCanceller := context.WithTimeout(parent, time.Second*5)
defer stopCanceller()
app.OnStop(stopCtx)
TraceLog.Println("Shutdown process fully completed")
}
func loadConfig(cfg interface{}) error {

View File

@ -51,6 +51,7 @@ func StartGRPCServer(ctx context.Context, port int, sb ServerBuilder, opts ...gr
}
func StopGRPCServer() error {
TraceLog.Println("stopping GRPC server...")
grpcServerInstance.GracefulStop()
return nil
}
@ -83,7 +84,12 @@ func StartHTTPServer(ctx context.Context, port int, handler http.Handler) (err e
}
func StopHTTPServer() error {
ctx, canceler := context.WithDeadline(context.Background(), time.Now().Add(time.Second*5))
if httpServerInstance == nil {
return nil
}
TraceLog.Println("stopping HTTP Server...")
ctx, canceler := context.WithDeadline(context.Background(), time.Now().Add(time.Second*3))
defer canceler()
return httpServerInstance.Shutdown(ctx)
}
@ -132,6 +138,7 @@ func DialGRPC(endpoint string, opts ...grpc.DialOption) (conn *grpc.ClientConn,
}
func CloseGRPCConns() error {
grpcServerInstance.GracefulStop()
grpcConns.Lock()
defer grpcConns.Unlock()
for k, v := range grpcConns.openConns {

View File

@ -27,6 +27,7 @@ require (
go.uber.org/automaxprocs v1.5.2 // indirect
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect

View File

@ -179,6 +179,8 @@ golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@ -27,6 +27,7 @@ require (
go.uber.org/automaxprocs v1.5.2 // indirect
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect

View File

@ -178,6 +178,7 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@ -17,6 +17,7 @@ import (
type ProxyClientApp struct {
LogLevel kernel.LogLevel `yaml:"log_level" env:"BH_LOG_LEVEL" env-default:"0" yaml-default:"0"`
Port int `yaml:"port" env:"PROXY_CLIENT_PORT"`
AccessControlAllowOrigin string `yaml:"access_control_allow_origin", env:"PROXY_CLIENT_CORS_ORIGIN`
Endpoints struct {
Catalog string `yaml:"catalog" env:"CATALOG_ENDPOINT"`
} `yaml:"endpoints" env:"PROXY_CLIENT_SERVICES"`
@ -45,7 +46,7 @@ func (app *ProxyClientApp) Start(ctx context.Context) error {
Handler: http.StripPrefix("/api", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
kernel.TraceLog.Printf("{ \"Client\": \"%s\", \"Path\":\"%s\", \"User-Agent\":\"%s\" } ", r.RemoteAddr, r.URL, r.UserAgent())
// TODO: pull the allowed origin host names from the config file
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Origin", app.AccessControlAllowOrigin)
grpcMux.ServeHTTP(w, r)
})),
}

View File

@ -42,7 +42,7 @@ func main() {
flag.Parse()
kernel.Run(context.Background(), &runnerApp{
CatalogEndpoint: "local-catalog:5001",
CatalogEndpoint: "catalog-local:5001",
LogLevel: kernel.LevelTrace,
Port: 5001,
})

View File

@ -0,0 +1 @@
build

View File

@ -0,0 +1,9 @@
FROM node:lts AS development
COPY . /opt/web-client
WORKDIR /opt/web-client
RUN npm install && npm install -g vite
CMD vite dev --port=80 --host=0.0.0.0 --strictPort --logLevel info

View File

@ -1,42 +1,42 @@
FROM node:lts AS development
COPY . /opt/web-client
WORKDIR /opt/web-client
RUN npm install && npm install -g vite
CMD vite dev --port=80 --host=0.0.0.0 --strictPort --logLevel info
FROM node:lts AS build
ARG origin=https://barretthousen.com
ENV ENV=production
ENV PROTOCOL_HEADER=x-forwarded-proto
ENV HOST_HEADER=x-forwarded-host
ENV ADDRESS_HEADER=True-Client-IP
ENV ORIGIN=${origin}
WORKDIR /opt/web-client
COPY --from=development /opt/web-client .
COPY . /opt/web-client
RUN npm build \
&& cp -rv /opt/web-client/package.json /opt/web-client/build \
&& cp -rv /opt/web-client/package-lock.json /opt/web-client/build
RUN npm run build \
&& cp -v /opt/web-client/package.json /opt/web-client/build \
&& cp -v /opt/web-client/package-lock.json /opt/web-client/build \
&& cd /opt/web-client/build && npm ci --omit dev
FROM node:lts AS production
LABEL com.barretthousen.service="web-client"
LABEL com.barretthousen.tags="frontend,public"
LABEL com.barretthousen.release-date="2023-05-01"
LABEL com.barretthousen.version="alpha-0.0.1"
LABEL com.barretthousen.git-ref="000000000000000000000000000000000000000000000000"
ARG origin=https://barretthousen.com
ENV ENV=production
ENV PROTOCOL_HEADER=x-forwarded-proto
ENV HOST_HEADER=x-forwarded-host
ENV ORIGIN=${origin}
WORKDIR /opt
COPY --from=build /var/web-client/build/* /opt/web-client
COPY --from=build /opt/web-client/build/ /opt/web-client/
ENV PORT 80
EXPOSE 80
ENTRYPOINT ['node']
CMD ['web-client']
ENTRYPOINT ["node", "web-client"]

View File

@ -2,6 +2,7 @@
"name": "web-client",
"version": "0.0.1",
"private": true,
"main": "index.js",
"scripts": {
"dev": "vite dev --port 8080",
"build": "vite build",
@ -38,7 +39,6 @@
},
"type": "module",
"dependencies": {
"luxon": "^3.3.0",
"moment": "^2.29.4"
"luxon": "^3.3.0"
}
}

View File

@ -2,7 +2,7 @@ import { browser } from '$app/environment';
import type { PageLoad } from './$types';
// TODO: change to env var
const API_HOST = `${browser ? '': 'http://local-proxy-client.default'}/api/v1`;
const API_HOST = `${browser ? '': 'http://proxy-client-local'}/api/v1`;
interface SearchPageData {
page: number