Published: Feb 1, 2024 by Isaac Johnson
Every now and then I like to explore some useful open-source smaller apps. On their own, they may not really warrant a full blog post, but hopefully you see something interesting in the following three: Doku, Noisedash and RecipeSage.
Doku
I became aware of Docku from a MariusHosting post. In that post, he leveraged Portainer to launch it on a NAS.
Let’s first just try locally to see what it is.
If you do not run in priveledged, expect an error:
$ docker run -p 9900:9090 --name dokutest amerkurev/doku
Unable to find image 'amerkurev/doku:latest' locally
latest: Pulling from amerkurev/doku
27cead1e48f5: Pull complete
47d5bd81c760: Pull complete
e4692b1d2d12: Pull complete
575ce9da186e: Pull complete
2ac00e010448: Pull complete
f4aa2870cc5c: Pull complete
6e3d39888231: Pull complete
cdaf8b327cab: Pull complete
abd17ce52993: Pull complete
4f4fb700ef54: Pull complete
Digest: sha256:145084d4d910877e1b0a2ce80da2caca1abbf5ba58ea732c589100b519c5d96b
Status: Downloaded newer image for amerkurev/doku:latest
doku v0.0.16-5eb6b55-20230220T18:49:35
time="2023-12-24T17:54:27Z" level=info msg="docker engine API (1.24)"
time="2023-12-24T17:54:27Z" level=info msg="calculating size of volumes..."
time="2023-12-24T17:54:27Z" level=info msg="starting http server at 0.0.0.0:9090"
time="2023-12-24T17:54:27Z" level=error msg="failed to get the list of containers" err="Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?"
You’ll want to mount the docker sock:
builder@DESKTOP-QADGF36:~$ docker rm dokutest
dokutest
builder@DESKTOP-QADGF36:~$ docker run -p 9900:9090 -v /var/run/docker.sock:/var/run/docker.sock:ro -v /:/hostroot:ro --name dokutest amerkurev/doku
doku v0.0.16-5eb6b55-20230220T18:49:35
time="2023-12-24T17:55:53Z" level=info msg="docker engine API (1.41)"
time="2023-12-24T17:55:53Z" level=info msg="calculating size of volumes..."
time="2023-12-24T17:55:53Z" level=info msg="starting http server at 0.0.0.0:9090"
I can see I’ve been a bit wasteful in images. I guess that is the consequence of being a blogging addict.
Looking at one of the largest, “flamboyant_feynman”, I can see locally that is based on an 18mo old splunk image
$ docker ps -a | grep flamb
4099739a4d41 splunk/splunk:latest "/sbin/entrypoint.sh…" 18 months ago Exited (137) 18 months ago
flamboyant_feynman
I can also view images under the “Images” section as well with sortable columns
If I remove a container
$ docker rm 4099739a4d41
4099739a4d41
$ docker rm flamboyant_feynman
Error: No such container: flamboyant_feynman
I can see it is reflected in the UI on refresh
I can see other wasted space, like docker build caches which could be pruned
Let’s say I want to prune everything older than two years (while 2y and 2Y failed, 24m worked):
$ docker image prune -a --filter "until=24m"
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
untagged: myrunner:latest
untagged: harbor.freshbrewed.science/freshbrewedprivate/myghrunner:1.1.0
untagged: harbor.freshbrewed.science/freshbrewedprivate/myghrunner@sha256:37edf935b9aa0c5e2911f8cd557841d82a65aa9ecf3f9824a0bbb291e11a2f25
deleted: sha256:16fb58a29b01e9b07ac2610fdfbf9ff3eb820026c1230e1214f7f34b49e7b506
untagged: pyplanelist:0.0.4
....snip...
deleted: sha256:ff1d7dfb73bf330b9f447c9cd71c9c6e8bb20821d1a1f253f3a20fc9cd168ebe
deleted: sha256:8d3ac3489996423f53d6087c81180006263b79f206d3fdec9e66f0e27ceb8759
Total reclaimed space: 13.28GB
While I don’t see space reclaimed in the UI, i do see the absence of the older images
A few things don’t work so well. It complains it lacks access to logs and the mounts seem to struggle with Windows locations
Let’s move to Linux where my Dockerhost on 192.168.1.100/99 is really the area of concern.
builder@builder-T100:~$ docker run -d -p 9900:9090 -v /var/run/docker.sock:/var/run/docker.sock:ro -v /:/hostroot:ro --name dokutest amerkurev/doku
Unable to find image 'amerkurev/doku:latest' locally
latest: Pulling from amerkurev/doku
27cead1e48f5: Pull complete
47d5bd81c760: Pull complete
e4692b1d2d12: Pull complete
575ce9da186e: Pull complete
2ac00e010448: Pull complete
f4aa2870cc5c: Pull complete
6e3d39888231: Pull complete
cdaf8b327cab: Pull complete
abd17ce52993: Pull complete
4f4fb700ef54: Pull complete
Digest: sha256:145084d4d910877e1b0a2ce80da2caca1abbf5ba58ea732c589100b519c5d96b
Status: Downloaded newer image for amerkurev/doku:latest
c0c81ce72625b8b5fa9c9de62f59ef269f4ca179d7f16cda00ff740e810550f3
Which shows
In the windows WSL instance, I got a blank page on “containers”, however here I see a few, including some that failed to run listed:
Now, when I view Logs, I can see how much space is being consumed by logs, which I guess is the goal here - find waste.
I should point out there is a dark mode (the little icon on the right of the headings):
While I could externalize this with a Kubernetes externalEndpoint, I think it’s best for just my usage to debug when needed.
Just so you can see the subtle animations, a quick tour:
Noisedash
Another useful tool, that probably could just be an app as well, is Noisedash.
We’ll start, as before, with a quick docker run.
First, I’ll make a couple docker volumes it can use
builder@builder-T100:~$ docker volume create samples
samples
builder@builder-T100:~$ docker volume create noisedb
noisedb
Then I need to creaet a config.json. (default maxSampleSize is 10Gb in bytes)
builder@builder-T100:~/noisedash$ vi config.json
builder@builder-T100:~/noisedash$ cat ./config.json
{
"Server": {
"listeningPort": 1432,
"sessionFileStorePath": "sessions",
"sampleUploadPath": "samples",
"maxSampleSize": 10737418240,
"logFile": "log/noisedash.log",
"tls": false,
"tlsKey": "certs/key.pem",
"tlsCert": "certs/cert.pem"
}
}
Lastly, launch it
builder@builder-T100:~/noisedash$ docker run -d -p 1432:1432 -v noisedb:/var/noisedash/db -v samples:/var/noisedash/samples -v ./config.json:/var/noisedash/config/default.json --name noisedash noisedash/noisedash:latest
Unable to find image 'noisedash/noisedash:latest' locally
latest: Pulling from noisedash/noisedash
311da6c465ea: Pull complete
7e9bf114588c: Pull complete
ffd9397e94b7: Pull complete
513d77925604: Pull complete
ae3b95bbaa61: Pull complete
0e421f66aff4: Pull complete
ca266fd61921: Pull complete
ee7d78be1eb9: Pull complete
48dc19beb3d5: Pull complete
b84e61fa0d30: Pull complete
a8304f1e41a2: Pull complete
521c7274591d: Pull complete
8d6d264b3bff: Pull complete
Digest: sha256:7aab65f9c467a1c036f6ec8510f781afdd42af8b2acaf349ff4c41cebf78c945
Status: Downloaded newer image for noisedash/noisedash:latest
c5654c05d2fabc18211c7ea37fa00ff7a54a57fb0c3450aa68e8fe8da8fcda1b
Visiting the URL, I find I need to register first
Then login
The next part just doesn’t really translate. The microphone had a bit of a hiss, but you get the idea:
I think that’s pretty fun and worth exposing. I can either rewrite it as a Kubernetes native app OR expose through Docker using an external endpoint.
Regardless of which path, I need an A Record first
$ cat r53-noisedash.json
{
"Comment": "CREATE noisedash fb.s A record ",
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "noisedash.freshbrewed.science",
"Type": "A",
"TTL": 300,
"ResourceRecords": [
{
"Value": "75.73.224.240"
}
]
}
}
]
}
$ aws route53 change-resource-record-sets --hosted-zone-id Z39E8QFU0F9PZP --change-batch file://r53-noisedash.json
{
"ChangeInfo": {
"Id": "/change/C070071930KXLJ9OMLS4U",
"Status": "PENDING",
"SubmittedAt": "2023-12-25T14:19:27.111Z",
"Comment": "CREATE noisedash fb.s A record "
}
}
There is a quick trick to getting a docker-compose into Kubernetes YAML if you want to just get the job done fast: Use AI.
It is not perfect, but it gets you started:
The problem with the generated AI YAML is it didn’t create PVCs for the storage.
I tend to just engage with Bing AI (or Copilot - pick a lane, Microsoft, pick a lane):
This is actually pretty close:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: samples-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: noisedash
spec:
replicas: 1
selector:
matchLabels:
app: noisedash
template:
metadata:
labels:
app: noisedash
spec:
containers:
- name: noisedash
image: noisedash/noisedash:latest
ports:
- containerPort: 1432
volumeMounts:
- name: db
mountPath: /var/noisedash/db
- name: samples
mountPath: /var/noisedash/samples
- name: config
mountPath: /var/noisedash/config
volumes:
- name: db
persistentVolumeClaim:
claimName: db-pvc
- name: samples
persistentVolumeClaim:
claimName: samples-pvc
- name: config
hostPath:
path: /path/to/your/config/default.json
---
apiVersion: v1
kind: Service
metadata:
name: noisedash
spec:
selector:
app: noisedash
ports:
- protocol: TCP
port: 80
targetPort: 1432
I just need to add the Ingress at the end
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
labels:
app.kubernetes.io/instance: noisedash
name: noisedashingress
spec:
rules:
- host: noisedash.freshbrewed.science
http:
paths:
- backend:
service:
name: noisedash
port:
number: 80
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- noisedash.freshbrewed.science
secretName: noisedash-tls
Which I can now apply:
$ kubectl apply -f noiseall.yaml
persistentvolumeclaim/db-pvc created
persistentvolumeclaim/samples-pvc created
deployment.apps/noisedash created
service/noisedash created
ingress.networking.k8s.io/noisedashingress created
I realized we neglected to actually handle the settings/configmap
We need to add
---
apiVersion: v1
kind: ConfigMap
metadata:
name: noisedashcfg
data:
config.json: |
{
"Server": {
"listeningPort": 1432,
"sessionFileStorePath": "sessions",
"sampleUploadPath": "samples",
"maxSampleSize": 10737418240,
"logFile": "log/noisedash.log",
"tls": false,
"tlsKey": "certs/key.pem",
"tlsCert": "certs/cert.pem"
}
}
Then change our deployment to use it
- name: config
mountPath: /var/noisedash/config/default.json
subPath: config.jsson
...
- name: config
configMap:
name: noisedashcfg
I deleted the pvcs and pod by hand (they generally don’t resize when using just a kubectl apply on existing PVCs)
noisedash-84c7747f4d-88zp9 0/1 CrashLoopBackOff 6 (2m18s ago) 8m57s
$ kubectl delete pvc db-pvc &
[1] 4035 persistentvolumeclaim "db-pvc" deleted
$ kubectl delete pvc samples-pvc
persistentvolumeclaim "samples-pvc" deleted
$ kubectl delete pod noisedash-84c7747f4d-88zp9
pod "noisedash-84c7747f4d-88zp9" deleted
Then re-applied:
$ kubectl apply -f noiseall.yaml
persistentvolumeclaim/db-pvc created
persistentvolumeclaim/samples-pvc created
deployment.apps/noisedash configured
service/noisedash unchanged
configmap/noisedashcfg created
ingress.networking.k8s.io/noisedashingress unchanged
This time it’s running
$ kubectl get pods -l app=noisedash
NAME READY STATUS RESTARTS AGE
noisedash-74f5697b5-t2lph 1/1 Running 0 112s
And I can sign in
The website is now live at https://noisedash.freshbrewed.science/. Enjoy!
Also, a good OS person creates PRs, so I PR’ed my Manifest back.
Recipesage
RecipeSage is a “Collaborative Recipe Keeper, Meal Planner, and Shopping List Organizer” created by Julian Poy. There is a hosted option at Recipesage.com, but today we’ll explore the self-hosted option.
I’m going to start with the Docker compose version.
Since it (by default) runs on port 3000, I’ll stop gitness locally to free that up
t$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
20903d6f949e pyplanelist:0.0.7 "python app.py" 2 days ago Up 2 days 0.0.0.0:8999->80/tcp pyplanetest
4b36604209fe harness/gitness "/app/gitness server" 2 months ago Up 3 days 0.0.0.0:3000->3000/tcp, 3001/tcp gitness
a613dc3843bd ghcr.io/ajnart/homarr:latest "docker-entrypoint.s…" 5 months ago Up 3 days 0.0.0.0:7575->7575/tcp homarr
cead637ea0a2 louislam/uptime-kuma:1 "/usr/bin/dumb-init …" 21 months ago Up 3 days (healthy) 0.0.0.0:3001->3001/tcp uptime-kuma
$ docker stop gitness
gitness
Then use Docker compose up:
$ git clone https://github.com/julianpoy/RecipeSage-selfhost.git
$ cd RecipeSage-selfhost
$ docker compose up -d
...
[+] Running 12/12
⠿ Network recipesage-selfhost_default Created 0.6s
⠿ Volume "recipesage-selfhost_apimedia" Created 0.0s
⠿ Volume "recipesage-selfhost_typesensedata" Created 0.0s
⠿ Volume "recipesage-selfhost_postgresdata" Created 0.0s
⠿ Container recipesage_browserless Started 3.1s
⠿ Container recipesage_static Started 3.3s
⠿ Container recipesage_classifier Started 2.3s
⠿ Container recipesage_pushpin Started 2.5s
⠿ Container recipesage_typesense Started 2.9s
⠿ Container recipesage_postgres Started 3.1s
⠿ Container recipesage_api Started 2.9s
⠿ Container recipesage_proxy Started 4.1s
This actually launches quite a bit:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
080a234ec2af nginx "/docker-entrypoint.…" 25 seconds ago Up 20 seconds 0.0.0.0:80->80/tcp recipesage_proxy
e327c7250b43 julianpoy/recipesage-selfhost:api-v2.12.10 "docker-entrypoint.s…" 25 seconds ago Up 22 seconds recipesage_api
6f3f3bac1f40 postgres:16 "docker-entrypoint.s…" 26 seconds ago Up 23 seconds 5432/tcp recipesage_postgres
b88923067b29 julianpoy/ingredient-instruction-classifier:1.4.9 "docker-entrypoint.s…" 26 seconds ago Up 23 seconds recipesage_classifier
20f6294c28d8 browserless/chrome:1.57-puppeteer-19.2.2 "./start.sh" 26 seconds ago Up 23 seconds 3000/tcp recipesage_browserless
888f8bf91307 julianpoy/pushpin:2023-09-17 "/bin/sh -c 'sed -i …" 26 seconds ago Up 23 seconds recipesage_pushpin
7fbcd59b1517 typesense/typesense:0.24.1 "/opt/typesense-serv…" 26 seconds ago Up 23 seconds 8108/tcp recipesage_typesense
71698f9fc85b julianpoy/recipesage-selfhost:static-v2.12.10 "/docker-entrypoint.…" 26 seconds ago Up 22 seconds 80/tcp recipesage_static
20903d6f949e pyplanelist:0.0.7 "python app.py" 2 days ago Up 2 days 0.0.0.0:8999->80/tcp pyplanetest
a613dc3843bd ghcr.io/ajnart/homarr:latest "docker-entrypoint.s…" 5 months ago Up 3 days 0.0.0.0:7575->7575/tcp homarr
cead637ea0a2 louislam/uptime-kuma:1 "/usr/bin/dumb-init …" 21 months ago Up 3 days (healthy) 0.0.0.0:3001->3001/tcp uptime-kuma
Since it’s running on Port 80, it’s easy to just check http://localhost
I’ll create an account
However… It just gave me an “error”
I thought, perhaps just the account create didn’t respond with the right code… I’ll try logging in:
but that too didn’t work.
I looked at the API logs and it seems database related
$ docker logs e327c7250b43
Database connection established
POST /users/register?false=false& 500 282.353 ms - 1033
Error
at Query.run (/app/node_modules/sequelize/src/dialects/postgres/query.js:76:25)
at /app/node_modules/sequelize/src/sequelize.js:650:28
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at async PostgresQueryInterface.select (/app/node_modules/sequelize/src/dialects/abstract/query-interface.js:1001:12)
at async Function.findAll (/app/node_modules/sequelize/src/model.js:1824:21)
at async Function.findOne (/app/node_modules/sequelize/src/model.js:1998:12)
at async /app/packages/backend/src/routes/users.js:643:20
at async /app/node_modules/sequelize/src/sequelize.js:1196:18
at async /app/packages/backend/src/routes/users.js:630:19
at async /app/packages/backend/src/utils/wrapRequestWithErrorHandler.js:4:7
Looking at the database logs, it seems it wasn’t properly set up:
$ docker logs 6f3f3bac1f40
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.
The database cluster will be initialized with locale "en_US.utf8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".
Data page checksums are disabled.
fixing permissions on existing directory /var/lib/postgresql/data ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... Etc/UTC
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok
Success. You can now start the database server using:
pg_ctl -D /var/lib/postgresql/data -l logfile start
initdb: warning: enabling "trust" authentication for local connections
initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.
waiting for server to start....2023-12-25 14:55:36.846 UTC [48] LOG: starting PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
2023-12-25 14:55:36.848 UTC [48] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2023-12-25 14:55:36.861 UTC [51] LOG: database system was shut down at 2023-12-25 14:55:36 UTC
2023-12-25 14:55:36.872 UTC [48] LOG: database system is ready to accept connections
done
server started
CREATE DATABASE
/usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
waiting for server to shut down...2023-12-25 14:55:37.180 UTC [48] LOG: received fast shutdown request
.2023-12-25 14:55:37.183 UTC [48] LOG: aborting any active transactions
2023-12-25 14:55:37.185 UTC [48] LOG: background worker "logical replication launcher" (PID 54) exited with exit code 1
2023-12-25 14:55:37.185 UTC [49] LOG: shutting down
2023-12-25 14:55:37.188 UTC [49] LOG: checkpoint starting: shutdown immediate
2023-12-25 14:55:37.317 UTC [49] LOG: checkpoint complete: wrote 923 buffers (5.6%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.022 s, sync=0.102 s, total=0.132 s; sync files=301, longest=0.007 s, average=0.001 s; distance=4257 kB, estimate=4257 kB; lsn=0/1913088, redo lsn=0/1913088
2023-12-25 14:55:37.325 UTC [48] LOG: database system is shut down
done
server stopped
PostgreSQL init process complete; ready for start up.
2023-12-25 14:55:37.430 UTC [1] LOG: starting PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
2023-12-25 14:55:37.436 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
2023-12-25 14:55:37.436 UTC [1] LOG: listening on IPv6 address "::", port 5432
2023-12-25 14:55:37.442 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2023-12-25 14:55:37.448 UTC [64] LOG: database system was shut down at 2023-12-25 14:55:37 UTC
2023-12-25 14:55:37.456 UTC [1] LOG: database system is ready to accept connections
2023-12-25 14:58:26.712 UTC [77] ERROR: relation "Users" does not exist at character 18
2023-12-25 14:58:26.712 UTC [77] STATEMENT: SELECT "id" FROM "Users" AS "User" WHERE "User"."email" = 'isaac.johnson@gmail.com' LIMIT 1;
2023-12-25 14:58:36.195 UTC [77] ERROR: relation "Users" does not exist at character 18
2023-12-25 14:58:36.195 UTC [77] STATEMENT: SELECT "id" FROM "Users" AS "User" WHERE "User"."email" = 'isaac.johnson@gmail.com' LIMIT 1;
2023-12-25 14:59:13.362 UTC [81] ERROR: relation "Users" does not exist at character 18
2023-12-25 14:59:13.362 UTC [81] STATEMENT: SELECT "id" FROM "Users" AS "User" WHERE "User"."email" = 'isaac.johnson@gmail.com' LIMIT 1;
2023-12-25 14:59:17.767 UTC [81] ERROR: relation "Users" does not exist at character 172
2023-12-25 14:59:17.767 UTC [81] STATEMENT: SELECT "id", "name", "handle", "email", "passwordHash", "passwordSalt", "passwordVersion", "lastLogin", "stripeCustomerId", "enableProfile", "createdAt", "updatedAt" FROM "Users" AS "User" WHERE "User"."email" = 'isaac.johnson@gmail.com' LIMIT 1;
2023-12-25 14:59:25.749 UTC [81] ERROR: relation "Users" does not exist at character 172
2023-12-25 14:59:25.749 UTC [81] STATEMENT: SELECT "id", "name", "handle", "email", "passwordHash", "passwordSalt", "passwordVersion", "lastLogin", "stripeCustomerId", "enableProfile", "createdAt", "updatedAt" FROM "Users" AS "User" WHERE "User"."email" = 'isaac.johnson@gmail.com' LIMIT 1;
2023-12-25 14:59:34.422 UTC [81] ERROR: relation "Users" does not exist at character 172
2023-12-25 14:59:34.422 UTC [81] STATEMENT: SELECT "id", "name", "handle", "email", "passwordHash", "passwordSalt", "passwordVersion", "lastLogin", "stripeCustomerId", "enableProfile", "createdAt", "updatedAt" FROM "Users" AS "User" WHERE "User"."email" = 'isaac.johnson@gmail.com' LIMIT 1;
2023-12-25 15:00:37.529 UTC [62] LOG: checkpoint starting: time
2023-12-25 15:00:41.771 UTC [62] LOG: checkpoint complete: wrote 45 buffers (0.3%); 0 WAL file(s) added, 0 removed, 0 recycled; write=4.218 s, sync=0.014 s, total=4.243 s; sync files=12, longest=0.011 s, average=0.002 s; distance=261 kB, estimate=261 kB; lsn=0/19544F8, redo lsn=0/19544C0
I realized I missed a step!
Clearly in the docs, after docker compose, one must manually invoke a migrate
builder@DESKTOP-QADGF36:~/Workspaces/RecipeSage-selfhost$ ./migrate.sh
Performing migrations. This could take up to 1 minute.
{ event: 'migrating', name: '20180903174506-create-user.js' }
{
event: 'migrated',
name: '20180903174506-create-user.js',
durationSeconds: 0.018
}
{ event: 'migrating', name: '20180903225610-create-session.js' }
{
event: 'migrated',
name: '20180903225610-create-session.js',
durationSeconds: 0.011
}
{ event: 'migrating', name: '20180905031747-create-recipe.js' }
{
event: 'migrated',
name: '20180905031747-create-recipe.js',
durationSeconds: 0.011
}
{ event: 'migrating', name: '20180905031929-create-message.js' }
{
event: 'migrated',
name: '20180905031929-create-message.js',
durationSeconds: 0.012
}
{ event: 'migrating', name: '20180905040040-create-meal-plan.js' }
{
event: 'migrated',
name: '20180905040040-create-meal-plan.js',
durationSeconds: 0.01
}
{ event: 'migrating', name: '20180905040042-create-meal-plan-item.js' }
{
event: 'migrated',
name: '20180905040042-create-meal-plan-item.js',
durationSeconds: 0.011
}
{ event: 'migrating', name: '20180905040055-create-shopping-list.js' }
{
event: 'migrated',
name: '20180905040055-create-shopping-list.js',
durationSeconds: 0.011
}
{
event: 'migrating',
name: '20180905040211-create-shopping-list-item.js'
}
{
event: 'migrated',
name: '20180905040211-create-shopping-list-item.js',
durationSeconds: 0.011
}
{ event: 'migrating', name: '20180905042925-create-label.js' }
{
event: 'migrated',
name: '20180905042925-create-label.js',
durationSeconds: 0.008
}
{ event: 'migrating', name: '20180905042940-create-recipe_label.js' }
{
event: 'migrated',
name: '20180905042940-create-recipe_label.js',
durationSeconds: 0.011
}
{
event: 'migrating',
name: '20180909144458-create-meal-plan_collaborator.js'
}
{
event: 'migrated',
name: '20180909144458-create-meal-plan_collaborator.js',
durationSeconds: 0.011
}
{
event: 'migrating',
name: '20180909150203-create-shopping-list_collaborator.js'
}
{
event: 'migrated',
name: '20180909150203-create-shopping-list_collaborator.js',
durationSeconds: 0.011
}
{ event: 'migrating', name: '20180909194501-create-fcm-token.js' }
{
event: 'migrated',
name: '20180909194501-create-fcm-token.js',
durationSeconds: 0.011
}
{ event: 'migrating', name: '20190318151614-add-recipe-indexedAt.js' }
{
event: 'migrated',
name: '20190318151614-add-recipe-indexedAt.js',
durationSeconds: 0.005
}
{
event: 'migrating',
name: '20191020162730-add-user-stripeCustomerId.js'
}
{
event: 'migrated',
name: '20191020162730-add-user-stripeCustomerId.js',
durationSeconds: 0.008
}
{ event: 'migrating', name: '20191020164936-create-stripe-payment.js' }
{
event: 'migrated',
name: '20191020164936-create-stripe-payment.js',
durationSeconds: 0.013
}
{
event: 'migrating',
name: '20191020202716-create-user-subscription.js'
}
{
event: 'migrated',
name: '20191020202716-create-user-subscription.js',
durationSeconds: 0.009
}
{ event: 'migrating', name: '20191022024102-create-image.js' }
{
event: 'migrated',
name: '20191022024102-create-image.js',
durationSeconds: 0.011
}
{ event: 'migrating', name: '20191023020403-create-recipe-image.js' }
{
event: 'migrated',
name: '20191023020403-create-recipe-image.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20191026055147-remove-recipe-image-column.js'
}
{
event: 'migrated',
name: '20191026055147-remove-recipe-image-column.js',
durationSeconds: 0.015
}
{
event: 'migrating',
name: '20200124223957-add-index-recipe_label-recipeId-fkey.js'
}
{
event: 'migrated',
name: '20200124223957-add-index-recipe_label-recipeId-fkey.js',
durationSeconds: 0.01
}
{
event: 'migrating',
name: '20200124223958-add-index-recipe_image-recipeId-fkey.js'
}
{
event: 'migrated',
name: '20200124223958-add-index-recipe_image-recipeId-fkey.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20200124223959-add-index-recipe-userId-fkey.js'
}
{
event: 'migrated',
name: '20200124223959-add-index-recipe-userId-fkey.js',
durationSeconds: 0.009
}
{
event: 'migrating',
name: '20200203223959-add-unique-recipe_labels-recipeId.js'
}
{
event: 'migrated',
name: '20200203223959-add-unique-recipe_labels-recipeId.js',
durationSeconds: 0.01
}
{
event: 'migrating',
name: '20200203223960-add-unique-users-email.js'
}
{
event: 'migrated',
name: '20200203223960-add-unique-users-email.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20200206223979-add-index-recipe_labels-labelId-fkey.js'
}
{
event: 'migrated',
name: '20200206223979-add-index-recipe_labels-labelId-fkey.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20200206223980-add-unique-labels-userId-title.js'
}
Label titles updated: 0
Accounts with labels migrated: 0
{
event: 'migrated',
name: '20200206223980-add-unique-labels-userId-title.js',
durationSeconds: 0.01
}
{
event: 'migrating',
name: '20200206223981-labels-clean-title-commas.js'
}
{
event: 'migrated',
name: '20200206223981-labels-clean-title-commas.js',
durationSeconds: 0.007
}
{ event: 'migrating', name: '20200823174732-create-friendship.js' }
{
event: 'migrated',
name: '20200823174732-create-friendship.js',
durationSeconds: 0.008
}
{ event: 'migrating', name: '20200823175411-create-profile-item.js' }
{
event: 'migrated',
name: '20200823175411-create-profile-item.js',
durationSeconds: 0.011
}
{ event: 'migrating', name: '20200907151614-add-user-handle.js' }
{
event: 'migrated',
name: '20200907151614-add-user-handle.js',
durationSeconds: 0.005
}
{
event: 'migrating',
name: '20200907151615-add-unique-user-handle.js'
}
{
event: 'migrated',
name: '20200907151615-add-unique-user-handle.js',
durationSeconds: 0.007
}
{ event: 'migrating', name: '20200907151616-add-user-social.js' }
{
event: 'migrated',
name: '20200907151616-add-user-social.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20200908020403-create-user-profile-image.js'
}
{
event: 'migrated',
name: '20200908020403-create-user-profile-image.js',
durationSeconds: 0.008
}
{ event: 'migrating', name: '20200908020404-add-unique-friendship.js' }
{
event: 'migrated',
name: '20200908020404-add-unique-friendship.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20210207000000-add-notnull-shopping-list-item-title.js'
}
{
event: 'migrated',
name: '20210207000000-add-notnull-shopping-list-item-title.js',
durationSeconds: 0.006
}
{
event: 'migrating',
name: '20221022000000-add-notnull-shopping-list-item-completed.js'
}
{
event: 'migrated',
name: '20221022000000-add-notnull-shopping-list-item-completed.js',
durationSeconds: 0.005
}
{ event: 'migrating', name: '20221226000000-add-recipe-rating.js' }
{
event: 'migrated',
name: '20221226000000-add-recipe-rating.js',
durationSeconds: 0.006
}
{ event: 'migrating', name: '20221226000000-image-userid-nullable.js' }
{
event: 'migrated',
name: '20221226000000-image-userid-nullable.js',
durationSeconds: 0.006
}
{
event: 'migrating',
name: '20230716223979-add-index-mealplanitems-recipeId.js'
}
{
event: 'migrated',
name: '20230716223979-add-index-mealplanitems-recipeId.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20230716223989-add-index-mealplanitems-mealPlanId.js'
}
{
event: 'migrated',
name: '20230716223989-add-index-mealplanitems-mealPlanId.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20230716233979-add-index-shoppinglistitems-recipeId.js'
}
{
event: 'migrated',
name: '20230716233979-add-index-shoppinglistitems-recipeId.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20230716233989-add-index-shoppinglistitems-shoppingListId.js'
}
{
event: 'migrated',
name: '20230716233989-add-index-shoppinglistitems-shoppingListId.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20230716233997-add-index-recipe_images-imageId.js'
}
{
event: 'migrated',
name: '20230716233997-add-index-recipe_images-imageId.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20230716233998-add-index-images-userId.js'
}
{
event: 'migrated',
name: '20230716233998-add-index-images-userId.js',
durationSeconds: 0.007
}
{
event: 'migrating',
name: '20230716233999-add-index-recipes-fromUserId.js'
}
{
event: 'migrated',
name: '20230716233999-add-index-recipes-fromUserId.js',
durationSeconds: 0.009
}
{
event: 'migrating',
name: '20230717000000-add-index-messages-recipeId.js'
}
{
event: 'migrated',
name: '20230717000000-add-index-messages-recipeId.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20230717000001-add-index-messages-originalRecipeId.js'
}
{
event: 'migrated',
name: '20230717000001-add-index-messages-originalRecipeId.js',
durationSeconds: 0.008
}
{
event: 'migrating',
name: '20231105000001-update-image-userId-fk.js'
}
{
event: 'migrated',
name: '20231105000001-update-image-userId-fk.js',
durationSeconds: 0.007
}
All migrations performed successfully
Migrations complete.
This time it worked just fine
Here I’ll whip up a terrible recipe:
I now have Interview Toast setup in the instance:
Let’s consider what a Kubernetes deployment might look like.
This time, instead of Bing AI, we’ll use kompose
I’ll brew
install the tool:
builder@DESKTOP-QADGF36:~/Workspaces/RecipeSage-selfhost$ brew install kompose
==> Downloading https://ghcr.io/v2/homebrew/portable-ruby/portable-ruby/blobs/sha256:f7be167f7ac4f296b9f4c5874ceeea4aafd9999c3c7f2b0378cae7dd273e2322
Running `brew update --auto-update`...
######################################################################## 100.0%
==> Pouring portable-ruby-3.1.4.x86_64_linux.bottle.tar.gz
==> Auto-updated Homebrew!
Updated 6 taps (codefresh-io/cli, derailed/popeye, derailed/k9s, f1bonacc1/tap, homebrew/core and homebrew/cask).
==> New Formulae
argc cidr dotter ocaml@4 pdfrip retire
cargo-sweep dalfox drogon open-simh purr solo2-cli
chisel-tunnel direwolf glbinding@2 opensca-cli redress yatas
==> New Casks
amie focusrite-control-2 navigraph-simlink screens-assist
anka-build-cloud-controller garmin-basecamp notes-better senabluetoothdevicemanager
anka-build-cloud-registry hapigo nx-studio truhu
blockstream-green heynote october vimcal
brightintosh imazing-profile-editor reader wave
cardo-update keyboard-cowboy roam wiso-steuer-2024
creality-print lw-scanner sakura xact
egovframedev navigraph-charts salt
You have 52 outdated formulae installed.
==> Downloading https://ghcr.io/v2/homebrew/core/kompose/manifests/1.31.2
########################################################################################################################### 100.0%
==> Fetching dependencies for kompose: linux-headers@5.15 and binutils
==> Downloading https://ghcr.io/v2/homebrew/core/linux-headers/5.15/manifests/5.15.145
########################################################################################################################### 100.0%
==> Fetching linux-headers@5.15
==> Downloading https://ghcr.io/v2/homebrew/core/linux-headers/5.15/blobs/sha256:5ff9e9a7fb1c4b0cd7be57f78fb4b274819ee0eef7c28ace0
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/binutils/manifests/2.41_1
########################################################################################################################### 100.0%
==> Fetching binutils
==> Downloading https://ghcr.io/v2/homebrew/core/binutils/blobs/sha256:ff5d14a01dbfc4e423713561d02e704b90577eb32feb7ee276b1a4065eb
########################################################################################################################### 100.0%
==> Fetching kompose
==> Downloading https://ghcr.io/v2/homebrew/core/kompose/blobs/sha256:99550035b8938199c758e0097ffc8ca525a7af19d48080d50955153c6587
########################################################################################################################### 100.0%
==> Installing dependencies for kompose: linux-headers@5.15 and binutils
==> Installing kompose dependency: linux-headers@5.15
==> Downloading https://ghcr.io/v2/homebrew/core/linux-headers/5.15/manifests/5.15.145
Already downloaded: /home/builder/.cache/Homebrew/downloads/13d1e09899f505428b13e23a85789cc43c263c4c5ab626adf8c5ffa8ca8a7f90--linux-headers@5.15-5.15.145.bottle_manifest.json
==> Pouring linux-headers@5.15--5.15.145.x86_64_linux.bottle.tar.gz
🍺 /home/linuxbrew/.linuxbrew/Cellar/linux-headers@5.15/5.15.145: 961 files, 5.7MB
==> Installing kompose dependency: binutils
==> Downloading https://ghcr.io/v2/homebrew/core/binutils/manifests/2.41_1
Already downloaded: /home/builder/.cache/Homebrew/downloads/5719c1ab7c1a761142ecbf7e99d196b1a5e6c1cae43737424dae6237609d4b86--binutils-2.41_1.bottle_manifest.json
==> Pouring binutils--2.41_1.x86_64_linux.bottle.tar.gz
🍺 /home/linuxbrew/.linuxbrew/Cellar/binutils/2.41_1: 4,729 files, 469MB
==> Installing kompose
==> Pouring kompose--1.31.2.x86_64_linux.bottle.tar.gz
==> Caveats
Bash completion has been installed to:
/home/linuxbrew/.linuxbrew/etc/bash_completion.d
==> Summary
🍺 /home/linuxbrew/.linuxbrew/Cellar/kompose/1.31.2: 9 files, 20MB
==> Running `brew cleanup kompose`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
Warning: The following dependents of upgraded formulae are outdated but will not
be upgraded because they are not bottled:
popeye
process-compose
punq
kdash
==> Upgrading 31 dependents of upgraded formulae:
Disable this behaviour by setting HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
alsa-lib 1.2.9 -> 1.2.10, cairo 1.16.0_5 -> 1.18.0, devspace 6.3.2 -> 6.3.7, gawk 5.2.2 -> 5.3.0, gettext 0.21.1 -> 0.22.4, gh 2.32.0 -> 2.40.1, glib 2.78.1 -> 2.78.3, gnutls 3.8.0 -> 3.8.2, harfbuzz 7.3.0 -> 8.3.0, hugo 0.112.3 -> 0.121.1, icu4c 72.1 -> 73.2, jpeg-turbo 2.1.5.1 -> 3.0.0, jq 1.6 -> 1.7.1, kubernetes-cli 1.27.3 -> 1.29.0, libnghttp2 1.53.0 -> 1.58.0, libtiff 4.5.0 -> 4.6.0, libxml2 2.11.4 -> 2.12.3, libxrandr 1.5.3 -> 1.5.4, nettle 3.9 -> 3.9.1, oniguruma 6.9.8 -> 6.9.9, opa 0.53.0 -> 0.60.0, openjdk@11 11.0.19 -> 11.0.21, p11-kit 0.24.1_1 -> 0.25.3, python-yq 3.2.2 -> 3.2.3, python@3.10 3.10.11 -> 3.10.13_1, pyyaml 6.0_1 -> 6.0.1_1, sonar-scanner 4.8.0.2856 -> 5.0.1.3006, unbound 1.17.1 -> 1.19.0, util-linux 2.39.2 -> 2.39.3, vault 1.13.2 -> 1.14.4, yq 4.31.1 -> 4.40.5
==> Downloading https://ghcr.io/v2/homebrew/core/util-linux/manifests/2.39.3
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/glib/manifests/2.78.3
########################################################################################################################### 100.0%
==> Fetching dependencies for glib: util-linux and openssl@3
==> Downloading https://ghcr.io/v2/homebrew/core/util-linux/manifests/2.39.3
Already downloaded: /home/builder/.cache/Homebrew/downloads/41a532ac610c3f3e608ce0c0b34e0cc55ae8d08082fdd609a0568d497ca7dc68--util-linux-2.39.3.bottle_manifest.json
==> Fetching util-linux
==> Downloading https://ghcr.io/v2/homebrew/core/util-linux/blobs/sha256:caccd0657b3b8e6555e63b0b924f76ce211807c18109c491408aa9edb
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/openssl/3/manifests/3.2.0_1
########################################################################################################################### 100.0%
==> Fetching openssl@3
==> Downloading https://ghcr.io/v2/homebrew/core/openssl/3/blobs/sha256:7412ee0230d222844ed3ea22cd356c6e99b4d3c0528800b08e05f51b5e
########################################################################################################################### 100.0%
==> Fetching glib
==> Downloading https://ghcr.io/v2/homebrew/core/glib/blobs/sha256:8657e856d1ea8610a23fccaf0cfa94b3a3271986c54101b69d5734ad1f9b080
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/cairo/manifests/1.18.0
Already downloaded: /home/builder/.cache/Homebrew/downloads/1b8b7f19e38cb0e029497dfe0ad3f3557f605025c5575bdfe86c17b889c6e6d1--cairo-1.18.0.bottle_manifest.json
==> Downloading https://ghcr.io/v2/homebrew/core/icu4c/manifests/73.2
Already downloaded: /home/builder/.cache/Homebrew/downloads/2e5082de52a2c85ae665e51f8d0de0651611397cb02f4b4e2bb37898ba52a629--icu4c-73.2.bottle_manifest.json
==> Fetching icu4c
==> Downloading https://ghcr.io/v2/homebrew/core/icu4c/blobs/sha256:714dc987ca9c9b594e6e17c02640f93b49074f81264be16051a93a8f5f674d
Already downloaded: /home/builder/.cache/Homebrew/downloads/d467742181d935c7e6128244f70d5fced229aaf7d1f2b7af9ae1009f663c0f49--icu4c--73.2.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/harfbuzz/manifests/8.3.0
Already downloaded: /home/builder/.cache/Homebrew/downloads/8fccd91a473694ef9d916ce061ae69cb18243bdab491757fae06fed911dd5b63--harfbuzz-8.3.0.bottle_manifest.json
==> Fetching dependencies for harfbuzz: ca-certificates and cairo
==> Downloading https://ghcr.io/v2/homebrew/core/ca-certificates/manifests/2023-12-12
########################################################################################################################### 100.0%
==> Fetching ca-certificates
==> Downloading https://ghcr.io/v2/homebrew/core/ca-certificates/blobs/sha256:5c99ffd0861f01adc19cab495027024f7d890e42a9e7b689706b
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/cairo/manifests/1.18.0
Already downloaded: /home/builder/.cache/Homebrew/downloads/1b8b7f19e38cb0e029497dfe0ad3f3557f605025c5575bdfe86c17b889c6e6d1--cairo-1.18.0.bottle_manifest.json
==> Fetching cairo
==> Downloading https://ghcr.io/v2/homebrew/core/cairo/blobs/sha256:35cd3a9f81432449e9b0f457a20c8e94e0d2c804da0210a5deffe9e0b8549b
Already downloaded: /home/builder/.cache/Homebrew/downloads/e9accdc16bccef2e5abcb467ff30111310b3f425ef7ba3b32ca56650658a7835--cairo--1.18.0.x86_64_linux.bottle.tar.gz
==> Fetching harfbuzz
==> Downloading https://ghcr.io/v2/homebrew/core/harfbuzz/blobs/sha256:14b087a8f369a66f82888d7cd0d10eafdf3624d292bd1374be89225fc74
Already downloaded: /home/builder/.cache/Homebrew/downloads/febbb52e1ec3b9da06469a27a07714576997bbe95432fb9e3f2b3a69d30ed459--harfbuzz--8.3.0.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/jpeg-turbo/manifests/3.0.0
Already downloaded: /home/builder/.cache/Homebrew/downloads/325e745bcb7840d6a83df7bfcafaa4dbc30b29140f252fb82b7714493df29d6d--jpeg-turbo-3.0.0.bottle_manifest.json
==> Fetching jpeg-turbo
==> Downloading https://ghcr.io/v2/homebrew/core/jpeg-turbo/blobs/sha256:44943f311f5999c84a5f6d3695b0fa96f6f336eb0f50a5a0174df7feb
Already downloaded: /home/builder/.cache/Homebrew/downloads/07522ed0e693cbb4aad5c3962ddaba9db85e6d2855246055d1a957ea6175bc13--jpeg-turbo--3.0.0.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/libtiff/manifests/4.6.0
Already downloaded: /home/builder/.cache/Homebrew/downloads/9c8455a2f6bcea7bf3e3461218fba309141b0b0553b6e1afc5fe64e63caccff3--libtiff-4.6.0.bottle_manifest.json
==> Fetching libtiff
==> Downloading https://ghcr.io/v2/homebrew/core/libtiff/blobs/sha256:9a6e0bb56c39b72a33b0a5629dc3fd49e4f1391513bcf7d04a764523cc03
Already downloaded: /home/builder/.cache/Homebrew/downloads/f2e6d4dae98e74b1a502cfeb93bb624150576d3024ee19ca7687bb1e18e46958--libtiff--4.6.0.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/alsa-lib/manifests/1.2.10
Already downloaded: /home/builder/.cache/Homebrew/downloads/f8e0e4a32aebd4f2125c90c3739136bcf9dbde8c807c8cc515a4558850648c5b--alsa-lib-1.2.10.bottle_manifest.json
==> Fetching alsa-lib
==> Downloading https://ghcr.io/v2/homebrew/core/alsa-lib/blobs/sha256:deec067e633df0a59c1428b8ced127ede44334ce834bb975823fd969bf1
Already downloaded: /home/builder/.cache/Homebrew/downloads/352ac261bab0810167ac73f2933ea888a5829c744d33ae709789ae202451da65--alsa-lib--1.2.10.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/libxrandr/manifests/1.5.4
Already downloaded: /home/builder/.cache/Homebrew/downloads/1fbb247f2abdbccf5d8f0682109acc180855bab14fd80473fbc15f74ebef0dbc--libxrandr-1.5.4.bottle_manifest.json
==> Downloading https://ghcr.io/v2/homebrew/core/openjdk/11/manifests/11.0.21
Already downloaded: /home/builder/.cache/Homebrew/downloads/cc2a280e3d623e1cc5bdcbb047604a548ad30174ad35007de84eb1179ab22665--openjdk@11-11.0.21.bottle_manifest.json
==> Fetching dependencies for openjdk@11: libxrandr and cups
==> Downloading https://ghcr.io/v2/homebrew/core/libxrandr/manifests/1.5.4
Already downloaded: /home/builder/.cache/Homebrew/downloads/1fbb247f2abdbccf5d8f0682109acc180855bab14fd80473fbc15f74ebef0dbc--libxrandr-1.5.4.bottle_manifest.json
==> Fetching libxrandr
==> Downloading https://ghcr.io/v2/homebrew/core/libxrandr/blobs/sha256:c48b622aed3d5e99e225601dca2d129fda08585571d948f8737f3e6a4b
Already downloaded: /home/builder/.cache/Homebrew/downloads/9578c92b41ef412d5c904f8f11092ba784a2a4e54da628b3fc41a5670c697f14--libxrandr--1.5.4.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/cups/manifests/2.4.7
Already downloaded: /home/builder/.cache/Homebrew/downloads/1ebb7c2856d92dc0b096195218281b4cbd6eac0f85459b88ee2cedf1c548ffca--cups-2.4.7.bottle_manifest.json
==> Fetching cups
==> Downloading https://ghcr.io/v2/homebrew/core/cups/blobs/sha256:1e35d934788dd9b07ca70d43210a934b17b894a9b4b1d54bc06224c3fa416f1
Already downloaded: /home/builder/.cache/Homebrew/downloads/988a8b88284a9ff7fbbe580c6da4cda1b13cdd98bf68c7df882e17cf513c18fa--cups--2.4.7.x86_64_linux.bottle.tar.gz
==> Fetching openjdk@11
==> Downloading https://ghcr.io/v2/homebrew/core/openjdk/11/blobs/sha256:1c0235a9aa57f27553c0838c430f12b26cc672c8f8da950cfb5a2bbe3
Already downloaded: /home/builder/.cache/Homebrew/downloads/f34ce846cc220743fce7e94b152401cf4b0c99bce27c3047921410508bb30445--openjdk@11--11.0.21.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/kubernetes-cli/manifests/1.29.0
########################################################################################################################### 100.0%
==> Fetching kubernetes-cli
==> Downloading https://ghcr.io/v2/homebrew/core/kubernetes-cli/blobs/sha256:0fba10c62bc80131fa4eef13a380d870a6355c37eeaae9be40b3e
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/devspace/manifests/6.3.7
########################################################################################################################### 100.0%
==> Fetching devspace
==> Downloading https://ghcr.io/v2/homebrew/core/devspace/blobs/sha256:20e347ff25fead961c1fa582e98a656f0b89ef88a811d6035e6913c8847
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/libxml2/manifests/2.12.3
########################################################################################################################### 100.0%
==> Fetching libxml2
==> Downloading https://ghcr.io/v2/homebrew/core/libxml2/blobs/sha256:be89416eea709ce3efe90ccdd8d5810d2906a625d86186e3308656121243
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/gettext/manifests/0.22.4
########################################################################################################################### 100.0%
==> Fetching gettext
==> Downloading https://ghcr.io/v2/homebrew/core/gettext/blobs/sha256:dc631c067b99d2620dfa6994b89bd6435ab95d4f1e5f19e00eca290df8c3
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/gawk/manifests/5.3.0
Already downloaded: /home/builder/.cache/Homebrew/downloads/a9bb151f02093d3c934a4d4052e99b2255bb438b67350221b0955fa554543528--gawk-5.3.0.bottle_manifest.json
==> Fetching gawk
==> Downloading https://ghcr.io/v2/homebrew/core/gawk/blobs/sha256:3027c2f8c9192fa35085eeadb6c88b1aa9f577660a7955b0a30f7ca2121c34a
Already downloaded: /home/builder/.cache/Homebrew/downloads/3caaf74ea790ba4457c6e3eeba09dea3fccef6e9fe3bd08363b4aac32d4d8b3a--gawk--5.3.0.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/gh/manifests/2.40.1
########################################################################################################################### 100.0%
==> Fetching gh
==> Downloading https://ghcr.io/v2/homebrew/core/gh/blobs/sha256:aeaf38c711233f19b1d2229ce2b67c2ab217a4df60665005b7bf7682ede79bde
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/nettle/manifests/3.9.1
Already downloaded: /home/builder/.cache/Homebrew/downloads/a02ae3a1ecc6cff56e632f6452fd57f3fa72be16cde0b69e5b47747283fd3f6b--nettle-3.9.1.bottle_manifest.json
==> Downloading https://ghcr.io/v2/homebrew/core/p11-kit/manifests/0.25.3
Already downloaded: /home/builder/.cache/Homebrew/downloads/cc547bf2f72da03680090015f5b720aff280ce33de9c33783a69c24fe97a4246--p11-kit-0.25.3.bottle_manifest.json
==> Downloading https://ghcr.io/v2/homebrew/core/libnghttp2/manifests/1.58.0
Already downloaded: /home/builder/.cache/Homebrew/downloads/9b2081d73959d4308c84740344d5f8169bbb9125dd76d20a71556a11a0171253--libnghttp2-1.58.0.bottle_manifest.json
==> Fetching libnghttp2
==> Downloading https://ghcr.io/v2/homebrew/core/libnghttp2/blobs/sha256:1723ddcaacc3ad10052a0cb4e8cc1644f1ddfd6b51a70a3f9a57c98b2
Already downloaded: /home/builder/.cache/Homebrew/downloads/4e42c9e99cc2728437e8fb2755d30d563af5d2608e9d5a21daa1efe25ff59a46--libnghttp2--1.58.0.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/unbound/manifests/1.19.0
Already downloaded: /home/builder/.cache/Homebrew/downloads/5ef4c435591de61234a87b911b8f2793a67aea99fa163a6c156bb9303f7fac11--unbound-1.19.0.bottle_manifest.json
==> Fetching dependencies for unbound: libevent
==> Downloading https://ghcr.io/v2/homebrew/core/libevent/manifests/2.1.12_1
Already downloaded: /home/builder/.cache/Homebrew/downloads/68b113f9ab63db45f4e1860de522ce2ca4fa081eb3c0d5c7d6005a35c3cf8d06--libevent-2.1.12_1.bottle_manifest.json
==> Fetching libevent
==> Downloading https://ghcr.io/v2/homebrew/core/libevent/blobs/sha256:83ef4ce689a91f6fca013d6b4b0b2fcda3706080f8e0cccd056a3d94d6b
Already downloaded: /home/builder/.cache/Homebrew/downloads/694835ad258e8dc6e9758f34fd0f18013d7a61f2a6ac1ca0e481f652d80b086a--libevent--2.1.12_1.x86_64_linux.bottle.tar.gz
==> Fetching unbound
==> Downloading https://ghcr.io/v2/homebrew/core/unbound/blobs/sha256:441cecb4591f00aa52dce8eda2d1b98400f622f73ad6cc64a6c202cd7496
Already downloaded: /home/builder/.cache/Homebrew/downloads/ab177d46ddb8eff68f54a3bea4e69bd4fc1a60b67ed0653c72099f2af95ccae7--unbound--1.19.0.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/gnutls/manifests/3.8.2
Already downloaded: /home/builder/.cache/Homebrew/downloads/451d8f1012df2b218c76390367beb96684e0899d24cb219dfe87eb047945fc14--gnutls-3.8.2.bottle_manifest.json
==> Fetching dependencies for gnutls: nettle and p11-kit
==> Downloading https://ghcr.io/v2/homebrew/core/nettle/manifests/3.9.1
Already downloaded: /home/builder/.cache/Homebrew/downloads/a02ae3a1ecc6cff56e632f6452fd57f3fa72be16cde0b69e5b47747283fd3f6b--nettle-3.9.1.bottle_manifest.json
==> Fetching nettle
==> Downloading https://ghcr.io/v2/homebrew/core/nettle/blobs/sha256:89cb9f1c702bee6f67ef0a3d4c075b6d6b0dddf54853120a33272ce704d5a
Already downloaded: /home/builder/.cache/Homebrew/downloads/4f6411a11bae436aba59c5ddd1fbcc2e5cfcead5ad961d48825b0a6874a810b4--nettle--3.9.1.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/p11-kit/manifests/0.25.3
Already downloaded: /home/builder/.cache/Homebrew/downloads/cc547bf2f72da03680090015f5b720aff280ce33de9c33783a69c24fe97a4246--p11-kit-0.25.3.bottle_manifest.json
==> Fetching p11-kit
==> Downloading https://ghcr.io/v2/homebrew/core/p11-kit/blobs/sha256:4f7ca2105451e0561951b327254cb179505798e8b5c491e9e4ee9124b085
Already downloaded: /home/builder/.cache/Homebrew/downloads/e441dd030a4c5e47b033444568349edf886d873d198246f5059ceb6a0d8da3be--p11-kit--0.25.3.x86_64_linux.bottle.tar.gz
==> Fetching gnutls
==> Downloading https://ghcr.io/v2/homebrew/core/gnutls/blobs/sha256:3827cd32aa6a9cd29a91bf788afa51ac5a88bf87f93355fd0f260a17480ab
Already downloaded: /home/builder/.cache/Homebrew/downloads/ab2b007ff74d0b969784c00add47757d2935c8d00c43a7ad5b353a7072fe59ea--gnutls--3.8.2.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/hugo/manifests/0.121.1
########################################################################################################################### 100.0%
==> Fetching hugo
==> Downloading https://ghcr.io/v2/homebrew/core/hugo/blobs/sha256:5805f549466d9b647a9741eb615efe774f1c5b6bc4d27eb7f7f8a8b3a37f3c5
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/oniguruma/manifests/6.9.9
Already downloaded: /home/builder/.cache/Homebrew/downloads/35140c4d3995b75388bed026ef6d0acbb4d6076047cdcd895bfd996c0c8d6487--oniguruma-6.9.9.bottle_manifest.json
==> Fetching oniguruma
==> Downloading https://ghcr.io/v2/homebrew/core/oniguruma/blobs/sha256:18f0e52bb660582698f390023d5db08208ed468d2f01758018b9ee8c69
Already downloaded: /home/builder/.cache/Homebrew/downloads/18b2f3d05c68f5556cb5915841c3466dd74309703d87d4170663ea9f340d4b07--oniguruma--6.9.9.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/jq/manifests/1.7.1
########################################################################################################################### 100.0%
==> Fetching jq
==> Downloading https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:ed490b627b327b3458a70a78c546be07d57bfc6958921f875b76e85f6be51f47
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/opa/manifests/0.60.0
########################################################################################################################### 100.0%
==> Fetching opa
==> Downloading https://ghcr.io/v2/homebrew/core/opa/blobs/sha256:89595ae6fd5a8f399eb4dd00cffe438fe44073ddefb954f2811e437dcb5b281c
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/pyyaml/manifests/6.0.1_1
Already downloaded: /home/builder/.cache/Homebrew/downloads/bb167293fae0bea9e7a2acd7496bdc04de8fd1d22a0d4c554a42477cda37397a--pyyaml-6.0.1_1.bottle_manifest.json
==> Downloading https://ghcr.io/v2/homebrew/core/python-yq/manifests/3.2.3-3
Already downloaded: /home/builder/.cache/Homebrew/downloads/4e35262202df99b72af260cb317f87c97b3045a9dfa19b92fddd4a23e83834ba--python-yq-3.2.3-3.bottle_manifest.json
==> Fetching dependencies for python-yq: python-argcomplete, python@3.12 and pyyaml
==> Downloading https://ghcr.io/v2/homebrew/core/python-argcomplete/manifests/3.2.1-1
########################################################################################################################### 100.0%
==> Fetching python-argcomplete
==> Downloading https://ghcr.io/v2/homebrew/core/python-argcomplete/blobs/sha256:82d477507c01c441680446607ca80954bfd0e007cf72b338c
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/python/3.12/manifests/3.12.1
########################################################################################################################### 100.0%
==> Fetching python@3.12
==> Downloading https://ghcr.io/v2/homebrew/core/python/3.12/blobs/sha256:719f8a93546953005ad6212199a9c2b0a2bed37fa3c5334752ecdc2d
########################################################################################################################### 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/pyyaml/manifests/6.0.1_1
Already downloaded: /home/builder/.cache/Homebrew/downloads/bb167293fae0bea9e7a2acd7496bdc04de8fd1d22a0d4c554a42477cda37397a--pyyaml-6.0.1_1.bottle_manifest.json
==> Fetching pyyaml
==> Downloading https://ghcr.io/v2/homebrew/core/pyyaml/blobs/sha256:d53f5c35de430f055c83fdbb1e857b3423cbea9c66523f929cb525876ef55
Already downloaded: /home/builder/.cache/Homebrew/downloads/5b88422fd57d9450a7b896afa2e43e9be19e73adc040b076787472a14b05a0c5--pyyaml--6.0.1_1.x86_64_linux.bottle.tar.gz
==> Fetching python-yq
==> Downloading https://ghcr.io/v2/homebrew/core/python-yq/blobs/sha256:63f678c0102d10126d0fd16e95ae98039bfc6ff4088d53ccb64b6b9c37
Already downloaded: /home/builder/.cache/Homebrew/downloads/fbde7202abd607c7311a116e3c5eb75119134ecc4128aec93b24a42630ca1284--python-yq--3.2.3.x86_64_linux.bottle.3.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/python/3.10/manifests/3.10.13_1
Already downloaded: /home/builder/.cache/Homebrew/downloads/a610d721ced33d58a439f710e86510660530bd18118bfcc145eb76722ab06a79--python@3.10-3.10.13_1.bottle_manifest.json
==> Downloading https://ghcr.io/v2/homebrew/core/sonar-scanner/manifests/5.0.1.3006
Already downloaded: /home/builder/.cache/Homebrew/downloads/bde285dde2b469ed3741edde1c6e63c6f5c0d73a261ae95a3f781a3f60be7de2--sonar-scanner-5.0.1.3006.bottle_manifest.json
==> Fetching dependencies for sonar-scanner: openjdk
==> Downloading https://ghcr.io/v2/homebrew/core/openjdk/manifests/21.0.1
Already downloaded: /home/builder/.cache/Homebrew/downloads/bb8a78296beb0d39c64166622e2df1a553bdf78572bac0ce95765a7007a46b8a--openjdk-21.0.1.bottle_manifest.json
==> Fetching openjdk
==> Downloading https://ghcr.io/v2/homebrew/core/openjdk/blobs/sha256:90f191bb2d7a118a3509df17eddcad6ec3be26a13064b10145a26c7de157
Already downloaded: /home/builder/.cache/Homebrew/downloads/4e29e5190abcabaab52998e57d5a98eca856c4086bd95381f010220d49194405--openjdk--21.0.1.x86_64_linux.bottle.tar.gz
==> Fetching sonar-scanner
==> Downloading https://ghcr.io/v2/homebrew/core/sonar-scanner/blobs/sha256:13fadfccf23d8bffe46a1dfac508917900a967c558ba1e59701099
Already downloaded: /home/builder/.cache/Homebrew/downloads/dfeafc91e3fc600c69e85ca68cbc1dc088cf2bbf42c252d49f38575f233dd094--sonar-scanner--5.0.1.3006.all.bottle.tar.gz
Warning: vault has been deprecated because it will change its license to BUSL on the next release!
==> Downloading https://ghcr.io/v2/homebrew/core/vault/manifests/1.14.4
Already downloaded: /home/builder/.cache/Homebrew/downloads/84fb3014e50109659e36e00593d156a6dbf649880ce6a18a51be615c2991b405--vault-1.14.4.bottle_manifest.json
==> Fetching vault
==> Downloading https://ghcr.io/v2/homebrew/core/vault/blobs/sha256:f4518c13f4613bb7adf425c5eabcd4a4cff94fdfe7def03201ac193f10fa7c
Already downloaded: /home/builder/.cache/Homebrew/downloads/e81f25965d2b286041e8123c9d0d654baf23f0b51d360ad73e75006df6c16369--vault--1.14.4.x86_64_linux.bottle.tar.gz
==> Downloading https://ghcr.io/v2/homebrew/core/yq/manifests/4.40.5
########################################################################################################################### 100.0%
==> Fetching yq
==> Downloading https://ghcr.io/v2/homebrew/core/yq/blobs/sha256:c5f992d8e25b2c444253d6e84ab255612c8f724bc1c28f6fdc608263afb23baf
########################################################################################################################### 100.0%
==> Upgrading glib
2.78.1 -> 2.78.3
==> Installing dependencies for glib: util-linux and openssl@3
==> Installing glib dependency: util-linux
==> Downloading https://ghcr.io/v2/homebrew/core/util-linux/manifests/2.39.3
Already downloaded: /home/builder/.cache/Homebrew/downloads/41a532ac610c3f3e608ce0c0b34e0cc55ae8d08082fdd609a0568d497ca7dc68--util-linux-2.39.3.bottle_manifest.json
==> Pouring util-linux--2.39.3.x86_64_linux.bottle.tar.gz
Error: Too many open files @ rb_sysopen - /home/linuxbrew/.linuxbrew/Cellar/util-linux/2.39.3/sbin/swapon
# just verifying since I noticed that fileopen error
$ brew install kompose
Warning: kompose 1.31.2 is already installed and up-to-date.
To reinstall 1.31.2, run:
brew reinstall kompose
Then run to convert
builder@DESKTOP-QADGF36:~/Workspaces/RecipeSage-selfhost$ ls
LICENSE.md README.md activate.sh docker-compose.yml migrate.sh proxy.conf
builder@DESKTOP-QADGF36:~/Workspaces/RecipeSage-selfhost$ kompose convert
WARN Restart policy 'unless-stopped' in service typesense is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service pushpin is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service postgres is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service browserless is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service ingredient-instruction-classifier is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service proxy is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service static is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service api is not supported, convert it to 'always'
WARN Service "api" won't be created because 'ports' is not specified
WARN Service "browserless" won't be created because 'ports' is not specified
WARN Service "ingredient-instruction-classifier" won't be created because 'ports' is not specified
WARN Service "postgres" won't be created because 'ports' is not specified
WARN Volume mount on the host "/home/builder/Workspaces/RecipeSage-selfhost/proxy.conf" isn't supported - ignoring path on the host
WARN Service "pushpin" won't be created because 'ports' is not specified
WARN Service "static" won't be created because 'ports' is not specified
WARN Service "typesense" won't be created because 'ports' is not specified
INFO Kubernetes file "proxy-service.yaml" created
INFO Kubernetes file "api-deployment.yaml" created
INFO Kubernetes file "apimedia-persistentvolumeclaim.yaml" created
INFO Kubernetes file "browserless-deployment.yaml" created
INFO Kubernetes file "ingredient-instruction-classifier-deployment.yaml" created
INFO Kubernetes file "postgres-deployment.yaml" created
INFO Kubernetes file "postgresdata-persistentvolumeclaim.yaml" created
INFO Kubernetes file "proxy-deployment.yaml" created
INFO Kubernetes file "proxy-claim0-persistentvolumeclaim.yaml" created
INFO Kubernetes file "pushpin-deployment.yaml" created
INFO Kubernetes file "static-deployment.yaml" created
INFO Kubernetes file "typesense-deployment.yaml" created
INFO Kubernetes file "typesensedata-persistentvolumeclaim.yaml" created
I can see Kompose really wants the ports explictly called out. We can determine them just by reading the compose YAML or looking at what Docker itself used
I added them to the compose yaml:
version: '3.7'
services:
proxy: # The proxy must not be removed. If needed, point your own proxy to this container, rather than removing this
container_name: recipesage_proxy
image: nginx
volumes:
- ./proxy.conf:/etc/nginx/conf.d/default.conf
ports:
- 80:80
depends_on:
- static
- api
- pushpin
restart: unless-stopped
static: # Hosts frontend assets
container_name: recipesage_static
image: julianpoy/recipesage-selfhost:static-v2.12.10
restart: unless-stopped
ports:
- 80:80
api: # Hosts backend API
container_name: recipesage_api
image: julianpoy/recipesage-selfhost:api-v2.12.10
depends_on:
- postgres
- typesense
- pushpin
- browserless
ports:
- 3000:3000
command: npx ts-node --swc --project packages/backend/tsconfig.json packages/backend/src/bin/www
environment:
- STORAGE_TYPE=filesystem
- FILESYSTEM_STORAGE_PATH=/rs-media
- NODE_ENV=selfhost
- VERBOSE=false
- VERSION=selfhost
- POSTGRES_DB=recipesage_selfhost
- POSTGRES_USER=recipesage_selfhost
- POSTGRES_PASSWORD=recipesage_selfhost
- POSTGRES_PORT=5432
- POSTGRES_HOST=postgres
- POSTGRES_SSL=false
- POSTGRES_LOGGING=false
- DATABASE_URL=postgresql://recipesage_selfhost:recipesage_selfhost@postgres:5432/recipesage_selfhost
- GCM_KEYPAIR
- SENTRY_DSN
- GRIP_URL=http://pushpin:5561/
- GRIP_KEY=changeme
- SEARCH_PROVIDER=typesense
- 'TYPESENSE_NODES=[{"host": "typesense", "port": 8108, "protocol": "http"}]'
- TYPESENSE_API_KEY=recipesage_selfhost
- STRIPE_SK
- STRIPE_WEBHOOK_SECRET
- BROWSERLESS_HOST=browserless
- BROWSERLESS_PORT=3000
- INGREDIENT_INSTRUCTION_CLASSIFIER_URL=http://ingredient-instruction-classifier:3000/
volumes:
- apimedia:/rs-media
restart: unless-stopped
typesense:
container_name: recipesage_typesense
image: typesense/typesense:0.24.1
ports:
- 8108:8108
volumes:
- typesensedata:/data
command: "--data-dir /data --api-key=recipesage_selfhost --enable-cors"
restart: unless-stopped
pushpin: # Provides websocket support
container_name: recipesage_pushpin
image: julianpoy/pushpin:2023-09-17
entrypoint: /bin/sh -c
command:
[
'sed -i "s/sig_key=changeme/sig_key=$$GRIP_KEY/" /etc/pushpin/pushpin.conf && echo "* $${TARGET},over_http" > /etc/pushpin/routes && pushpin --merge-output',
]
environment:
- GRIP_KEY=changeme
- TARGET=api:3000
restart: unless-stopped
ports:
- 7999:7999
postgres: # Database
container_name: recipesage_postgres
image: postgres:16
ports:
- 5432:5432
environment:
- POSTGRES_DB=recipesage_selfhost
- POSTGRES_USER=recipesage_selfhost
- POSTGRES_PASSWORD=recipesage_selfhost
volumes:
- postgresdata:/var/lib/postgresql/data
restart: unless-stopped
browserless: # A headless browser for scraping websites with the auto import tool
container_name: recipesage_browserless
image: browserless/chrome:1.57-puppeteer-19.2.2
ports:
- 3000:3000
environment:
- MAX_CONCURRENT_SESSIONS=3
- MAX_QUEUE_LENGTH=10
restart: unless-stopped
ingredient-instruction-classifier: # A mini server that runs a machine learning model able to classify text for improved automatic import
container_name: recipesage_classifier
image: julianpoy/ingredient-instruction-classifier:1.4.9
environment:
- SENTENCE_EMBEDDING_BATCH_SIZE=200
- PREDICTION_CONCURRENCY=4
restart: unless-stopped
ports:
- 3000:3000
volumes:
apimedia:
driver: local
typesensedata:
driver: local
postgresdata:
driver: local
and tried again
$ kompose convert
WARN Restart policy 'unless-stopped' in service ingredient-instruction-classifier is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service proxy is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service static is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service api is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service typesense is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service pushpin is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service postgres is not supported, convert it to 'always'
WARN Restart policy 'unless-stopped' in service browserless is not supported, convert it to 'always'
WARN Volume mount on the host "/home/builder/Workspaces/RecipeSage-selfhost/proxy.conf" isn't supported - ignoring path on the host
INFO Kubernetes file "api-service.yaml" created
INFO Kubernetes file "browserless-service.yaml" created
INFO Kubernetes file "ingredient-instruction-classifier-service.yaml" created
INFO Kubernetes file "postgres-service.yaml" created
INFO Kubernetes file "proxy-service.yaml" created
INFO Kubernetes file "pushpin-service.yaml" created
INFO Kubernetes file "static-service.yaml" created
INFO Kubernetes file "typesense-service.yaml" created
INFO Kubernetes file "api-deployment.yaml" created
INFO Kubernetes file "apimedia-persistentvolumeclaim.yaml" created
INFO Kubernetes file "browserless-deployment.yaml" created
INFO Kubernetes file "ingredient-instruction-classifier-deployment.yaml" created
INFO Kubernetes file "postgres-deployment.yaml" created
INFO Kubernetes file "postgresdata-persistentvolumeclaim.yaml" created
INFO Kubernetes file "proxy-deployment.yaml" created
INFO Kubernetes file "proxy-claim0-persistentvolumeclaim.yaml" created
INFO Kubernetes file "pushpin-deployment.yaml" created
INFO Kubernetes file "static-deployment.yaml" created
INFO Kubernetes file "typesense-deployment.yaml" created
INFO Kubernetes file "typesensedata-persistentvolumeclaim.yaml" created
The conf we’ll need to sort by hand:
$ kubectl create cm proxycfg --from-file=./proxy.conf --dry-run -o yaml
W1225 09:26:37.830146 14272 helpers.go:692] --dry-run is deprecated and can be replaced with --dry-run=client.
apiVersion: v1
data:
proxy.conf: |
server {
client_max_body_size 1G;
listen 80 default_server;
server_name localhost;
location /grip/ws {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_connect_timeout 1h;
proxy_send_timeout 1h;
proxy_read_timeout 1h;
proxy_pass http://pushpin:7999/ws;
}
# Alias minio in case minio container is not present
set $minio http://minio:9000;
location /minio/ {
rewrite ^/minio/(.*)$ /$1 break;
proxy_pass $minio;
}
location /api/ {
proxy_pass http://api:3000/;
}
location / {
proxy_pass http://static:80/;
}
}
kind: ConfigMap
metadata:
creationTimestamp: null
name: proxycfg
I’ll move all the current k8s files into a folder
builder@DESKTOP-QADGF36:~/Workspaces/RecipeSage-selfhost$ mkdir k8s
builder@DESKTOP-QADGF36:~/Workspaces/RecipeSage-selfhost$ mv *.yaml ./k8s
add that cm
$ kubectl create cm proxycfg --from-file=./proxy.conf --dry-run -o yaml > ./k8s/proxycm.yaml
W1225 09:27:11.517589 14743 helpers.go:692] --dry-run is deprecated and can be replaced with --dry-run=client.
I commented out the PVC for proxy and updated the deploy to use the CM
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kompose.cmd: kompose convert
kompose.version: 1.31.2 (HEAD)
creationTimestamp: null
labels:
io.kompose.service: proxy
name: proxy
spec:
replicas: 1
selector:
matchLabels:
io.kompose.service: proxy
strategy:
type: Recreate
template:
metadata:
annotations:
kompose.cmd: kompose convert
kompose.version: 1.31.2 (HEAD)
creationTimestamp: null
labels:
io.kompose.network/recipesage-selfhost-default: "true"
io.kompose.service: proxy
spec:
containers:
- image: nginx
name: recipesage-proxy
ports:
- containerPort: 80
hostPort: 80
protocol: TCP
resources: {}
volumeMounts:
- name: config
mountPath: /etc/nginx/conf.d/default.conf
subPath: proxy.conf
restartPolicy: Always
volumes:
- name: config
configMap:
name: proxycfg
status: {}
This is a pretty large payload
So I’ll test on my test cluster
builder@DESKTOP-QADGF36:~/Workspaces/RecipeSage-selfhost$ kubectx mac81
Switched to context "mac81".
builder@DESKTOP-QADGF36:~/Workspaces/RecipeSage-selfhost$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
anna-macbookair Ready control-plane,master 12d v1.27.6+k3s1
isaac-macbookpro Ready <none> 12d v1.27.6+k3s1
builder-macbookpro2 Ready <none> 12d v1.27.6+k3s1
builder@DESKTOP-QADGF36:~/Workspaces/RecipeSage-selfhost$ kubectl apply -f ./k8s/
deployment.apps/api created
service/api created
persistentvolumeclaim/apimedia created
deployment.apps/browserless created
service/browserless created
deployment.apps/ingredient-instruction-classifier created
service/ingredient-instruction-classifier created
deployment.apps/postgres created
service/postgres created
persistentvolumeclaim/postgresdata created
deployment.apps/proxy created
service/proxy created
configmap/proxycfg created
deployment.apps/pushpin created
service/pushpin created
deployment.apps/static created
service/static created
deployment.apps/typesense created
service/typesense created
persistentvolumeclaim/typesensedata created
I watched as it brought pods up
Every 2.0s: kubectl get pods DESKTOP-QADGF36: Mon Dec 25 09:35:18 2023
NAME READY STATUS RESTARTS AGE
my-shell 1/1 Running 0 10d
browserless-b4c854-2qp4c 0/1 ContainerCreating 0 87s
ingredient-instruction-classifier-5b8bd9c99d-thqxw 0/1 ContainerCreating 0 87s
proxy-7fcc4d6748-g57x7 0/1 Pending 0 87s
pushpin-7f557dcbf4-v5w5p 0/1 ContainerCreating 0 87s
static-8f77dcd89-trz47 0/1 Pending 0 87s
typesense-5785d4c6b8-4xdf7 0/1 ContainerCreating 0 87s
postgres-788d8cc76-bbpzx 1/1 Running 0 87s
api-767dd95f67-c9jff 1/1 Running 0 87s
The API crashed, but then I realized there are a lot of interdependencies here. It crashed just because the pushpin wasnt up
$ kubectl logs api-767dd95f67-c9jff
Request #1703518539940: Request to Node 0 failed due to "ECONNREFUSED connect ECONNREFUSED 10.43.21.217:8108"
Request #1703518539940: Sleeping for 0.1s and then retrying request...
Request #1703518539940: Request to Node 0 failed due to "ECONNREFUSED connect ECONNREFUSED 10.43.21.217:8108"
Request #1703518539940: Sleeping for 0.1s and then retrying request...
Request #1703518539940: Request to Node 0 failed due to "ECONNREFUSED connect ECONNREFUSED 10.43.21.217:8108"
Request #1703518539940: Sleeping for 0.1s and then retrying request...
Database connection established
Request #1703518539940: Request to Node 0 failed due to "ECONNREFUSED connect ECONNREFUSED 10.43.21.217:8108"
Request #1703518539940: Sleeping for 0.1s and then retrying request...
Request #1703518539940: Request to Node 0 failed due to "ECONNREFUSED connect ECONNREFUSED 10.43.21.217:8108"
Request #1703518539940: Sleeping for 0.1s and then retrying request...
Request #1703518539940: Request to Node 0 failed due to "ECONNREFUSED connect ECONNREFUSED 10.43.21.217:8108"
Request #1703518539940: Sleeping for 0.1s and then retrying request...
Error: connect ECONNREFUSED 10.43.21.217:8108
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16) {
errno: -111,
Let’s check again
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-shell 1/1 Running 0 10d
proxy-7fcc4d6748-g57x7 0/1 Pending 0 3m57s
static-8f77dcd89-trz47 0/1 Pending 0 3m57s
postgres-788d8cc76-bbpzx 1/1 Running 0 3m57s
pushpin-7f557dcbf4-v5w5p 1/1 Running 0 3m57s
typesense-5785d4c6b8-4xdf7 1/1 Running 0 3m57s
ingredient-instruction-classifier-5b8bd9c99d-thqxw 1/1 Running 0 3m57s
api-767dd95f67-c9jff 1/1 Running 4 (92s ago) 3m57s
browserless-b4c854-2qp4c 1/1 Running 0 3m57s
Seems we have some port challenges
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 5m2s default-scheduler 0/3 nodes are available: 3 node(s) didn't have free ports for the requested pod ports. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod..
Warning FailedScheduling 4m56s (x2 over 4m59s) default-scheduler 0/3 nodes are available: 3 node(s) didn't have free ports for the requested pod ports. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod..
I’m going to change the “hostport” settings in proxy and static to 8820, and 8810 then change the services to use them in “targetPort”. The actual destinations on the containers stay port 80 and the service handles port 80 so the in-between doesn’t really matter.
Now we are running
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-shell 1/1 Running 0 10d
postgres-788d8cc76-bbpzx 1/1 Running 0 9m10s
pushpin-7f557dcbf4-v5w5p 1/1 Running 0 9m10s
typesense-5785d4c6b8-4xdf7 1/1 Running 0 9m10s
ingredient-instruction-classifier-5b8bd9c99d-thqxw 1/1 Running 0 9m10s
api-767dd95f67-c9jff 1/1 Running 4 (6m45s ago) 9m10s
browserless-b4c854-2qp4c 1/1 Running 0 9m10s
proxy-78ddd6cd4b-wqc27 1/1 Running 0 61s
static-58d56f54b4-zdqxn 1/1 Running 0 61s
I need to translate the “migrate.sh” to a kubernetes command:
$ cat ./migrate.sh
#!/bin/sh
echo "Performing migrations. This could take up to 1 minute."
docker compose exec api tsx packages/backend/src/migrate
echo "Migrations complete."
Which is pretty straightforward:
$ kubectl exec api-767dd95f67-c9jff tsx "packages/backend/src/migrate"
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
{ event: 'migrating', name: '20180903174506-create-user.js' }
{
event: 'migrated',
name: '20180903174506-create-user.js',
durationSeconds: 0.036
}
{ event: 'migrating', name: '20180903225610-create-session.js' }
{
event: 'migrated',
name: '20180903225610-create-session.js',
durationSeconds: 0.031
}
{ event: 'migrating', name: '20180905031747-create-recipe.js' }
{
event: 'migrated',
name: '20180905031747-create-recipe.js',
durationSeconds: 0.025
}
{ event: 'migrating', name: '20180905031929-create-message.js' }
{
event: 'migrated',
name: '20180905031929-create-message.js',
durationSeconds: 0.025
}
{ event: 'migrating', name: '20180905040040-create-meal-plan.js' }
{
event: 'migrated',
name: '20180905040040-create-meal-plan.js',
durationSeconds: 0.021
}
{ event: 'migrating', name: '20180905040042-create-meal-plan-item.js' }
{
event: 'migrated',
name: '20180905040042-create-meal-plan-item.js',
durationSeconds: 0.036
}
{ event: 'migrating', name: '20180905040055-create-shopping-list.js' }
{
event: 'migrated',
name: '20180905040055-create-shopping-list.js',
durationSeconds: 0.038
}
{
event: 'migrating',
name: '20180905040211-create-shopping-list-item.js'
}
{
event: 'migrated',
name: '20180905040211-create-shopping-list-item.js',
durationSeconds: 0.037
}
{ event: 'migrating', name: '20180905042925-create-label.js' }
{
event: 'migrated',
name: '20180905042925-create-label.js',
durationSeconds: 0.024
}
{ event: 'migrating', name: '20180905042940-create-recipe_label.js' }
{
event: 'migrated',
name: '20180905042940-create-recipe_label.js',
durationSeconds: 0.035
}
{
event: 'migrating',
name: '20180909144458-create-meal-plan_collaborator.js'
}
{
event: 'migrated',
name: '20180909144458-create-meal-plan_collaborator.js',
durationSeconds: 0.033
}
{
event: 'migrating',
name: '20180909150203-create-shopping-list_collaborator.js'
}
{
event: 'migrated',
name: '20180909150203-create-shopping-list_collaborator.js',
durationSeconds: 0.023
}
{ event: 'migrating', name: '20180909194501-create-fcm-token.js' }
{
event: 'migrated',
name: '20180909194501-create-fcm-token.js',
durationSeconds: 0.032
}
{ event: 'migrating', name: '20190318151614-add-recipe-indexedAt.js' }
{
event: 'migrated',
name: '20190318151614-add-recipe-indexedAt.js',
durationSeconds: 0.013
}
{
event: 'migrating',
name: '20191020162730-add-user-stripeCustomerId.js'
}
{
event: 'migrated',
name: '20191020162730-add-user-stripeCustomerId.js',
durationSeconds: 0.019
}
{ event: 'migrating', name: '20191020164936-create-stripe-payment.js' }
{
event: 'migrated',
name: '20191020164936-create-stripe-payment.js',
durationSeconds: 0.042
}
{
event: 'migrating',
name: '20191020202716-create-user-subscription.js'
}
{
event: 'migrated',
name: '20191020202716-create-user-subscription.js',
durationSeconds: 0.031
}
{ event: 'migrating', name: '20191022024102-create-image.js' }
{
event: 'migrated',
name: '20191022024102-create-image.js',
durationSeconds: 0.029
}
{ event: 'migrating', name: '20191023020403-create-recipe-image.js' }
{
event: 'migrated',
name: '20191023020403-create-recipe-image.js',
durationSeconds: 0.036
}
{
event: 'migrating',
name: '20191026055147-remove-recipe-image-column.js'
}
{
event: 'migrated',
name: '20191026055147-remove-recipe-image-column.js',
durationSeconds: 0.054
}
{
event: 'migrating',
name: '20200124223957-add-index-recipe_label-recipeId-fkey.js'
}
{
event: 'migrated',
name: '20200124223957-add-index-recipe_label-recipeId-fkey.js',
durationSeconds: 0.031
}
{
event: 'migrating',
name: '20200124223958-add-index-recipe_image-recipeId-fkey.js'
}
{
event: 'migrated',
name: '20200124223958-add-index-recipe_image-recipeId-fkey.js',
durationSeconds: 0.024
}
{
event: 'migrating',
name: '20200124223959-add-index-recipe-userId-fkey.js'
}
{
event: 'migrated',
name: '20200124223959-add-index-recipe-userId-fkey.js',
durationSeconds: 0.039
}
{
event: 'migrating',
name: '20200203223959-add-unique-recipe_labels-recipeId.js'
}
{
event: 'migrated',
name: '20200203223959-add-unique-recipe_labels-recipeId.js',
durationSeconds: 0.043
}
{
event: 'migrating',
name: '20200203223960-add-unique-users-email.js'
}
{
event: 'migrated',
name: '20200203223960-add-unique-users-email.js',
durationSeconds: 0.028
}
{
event: 'migrating',
name: '20200206223979-add-index-recipe_labels-labelId-fkey.js'
}
{
event: 'migrated',
name: '20200206223979-add-index-recipe_labels-labelId-fkey.js',
durationSeconds: 0.033
}
{
event: 'migrating',
name: '20200206223980-add-unique-labels-userId-title.js'
}
Label titles updated: 0
Accounts with labels migrated: 0
{
event: 'migrated',
name: '20200206223980-add-unique-labels-userId-title.js',
durationSeconds: 0.044
}
{
event: 'migrating',
name: '20200206223981-labels-clean-title-commas.js'
}
{
event: 'migrated',
name: '20200206223981-labels-clean-title-commas.js',
durationSeconds: 0.026
}
{ event: 'migrating', name: '20200823174732-create-friendship.js' }
{
event: 'migrated',
name: '20200823174732-create-friendship.js',
durationSeconds: 0.036
}
{ event: 'migrating', name: '20200823175411-create-profile-item.js' }
{
event: 'migrated',
name: '20200823175411-create-profile-item.js',
durationSeconds: 0.037
}
{ event: 'migrating', name: '20200907151614-add-user-handle.js' }
{
event: 'migrated',
name: '20200907151614-add-user-handle.js',
durationSeconds: 0.022
}
{
event: 'migrating',
name: '20200907151615-add-unique-user-handle.js'
}
{
event: 'migrated',
name: '20200907151615-add-unique-user-handle.js',
durationSeconds: 0.026
}
{ event: 'migrating', name: '20200907151616-add-user-social.js' }
{
event: 'migrated',
name: '20200907151616-add-user-social.js',
durationSeconds: 0.029
}
{
event: 'migrating',
name: '20200908020403-create-user-profile-image.js'
}
{
event: 'migrated',
name: '20200908020403-create-user-profile-image.js',
durationSeconds: 0.034
}
{ event: 'migrating', name: '20200908020404-add-unique-friendship.js' }
{
event: 'migrated',
name: '20200908020404-add-unique-friendship.js',
durationSeconds: 0.027
}
{
event: 'migrating',
name: '20210207000000-add-notnull-shopping-list-item-title.js'
}
{
event: 'migrated',
name: '20210207000000-add-notnull-shopping-list-item-title.js',
durationSeconds: 0.032
}
{
event: 'migrating',
name: '20221022000000-add-notnull-shopping-list-item-completed.js'
}
{
event: 'migrated',
name: '20221022000000-add-notnull-shopping-list-item-completed.js',
durationSeconds: 0.023
}
{ event: 'migrating', name: '20221226000000-add-recipe-rating.js' }
{
event: 'migrated',
name: '20221226000000-add-recipe-rating.js',
durationSeconds: 0.019
}
{ event: 'migrating', name: '20221226000000-image-userid-nullable.js' }
{
event: 'migrated',
name: '20221226000000-image-userid-nullable.js',
durationSeconds: 0.016
}
{
event: 'migrating',
name: '20230716223979-add-index-mealplanitems-recipeId.js'
}
{
event: 'migrated',
name: '20230716223979-add-index-mealplanitems-recipeId.js',
durationSeconds: 0.023
}
{
event: 'migrating',
name: '20230716223989-add-index-mealplanitems-mealPlanId.js'
}
{
event: 'migrated',
name: '20230716223989-add-index-mealplanitems-mealPlanId.js',
durationSeconds: 0.019
}
{
event: 'migrating',
name: '20230716233979-add-index-shoppinglistitems-recipeId.js'
}
{
event: 'migrated',
name: '20230716233979-add-index-shoppinglistitems-recipeId.js',
durationSeconds: 0.023
}
{
event: 'migrating',
name: '20230716233989-add-index-shoppinglistitems-shoppingListId.js'
}
{
event: 'migrated',
name: '20230716233989-add-index-shoppinglistitems-shoppingListId.js',
durationSeconds: 0.022
}
{
event: 'migrating',
name: '20230716233997-add-index-recipe_images-imageId.js'
}
{
event: 'migrated',
name: '20230716233997-add-index-recipe_images-imageId.js',
durationSeconds: 0.021
}
{
event: 'migrating',
name: '20230716233998-add-index-images-userId.js'
}
{
event: 'migrated',
name: '20230716233998-add-index-images-userId.js',
durationSeconds: 0.028
}
{
event: 'migrating',
name: '20230716233999-add-index-recipes-fromUserId.js'
}
{
event: 'migrated',
name: '20230716233999-add-index-recipes-fromUserId.js',
durationSeconds: 0.026
}
{
event: 'migrating',
name: '20230717000000-add-index-messages-recipeId.js'
}
{
event: 'migrated',
name: '20230717000000-add-index-messages-recipeId.js',
durationSeconds: 0.023
}
{
event: 'migrating',
name: '20230717000001-add-index-messages-originalRecipeId.js'
}
{
event: 'migrated',
name: '20230717000001-add-index-messages-originalRecipeId.js',
durationSeconds: 0.013
}
{
event: 'migrating',
name: '20231105000001-update-image-userId-fk.js'
}
{
event: 'migrated',
name: '20231105000001-update-image-userId-fk.js',
durationSeconds: 0.013
}
All migrations performed successfully
It’s not looking too good
Though after a moment, I realized “static” is really the front door service:
However, I got the same error as before:
The error comes from the fact that the “static” pod really wants to talk on the same port over to the proxy
127.0.0.1 - - [25/Dec/2023:15:51:19 +0000] "POST /api/users/register?false=false& HTTP/1.1" 404 555 "http://localhost:8888/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" "-"
127.0.0.1 - - [25/Dec/2023:15:51:24 +0000] "POST /api/users/register?false=false& HTTP/1.1" 404 555 "http://localhost:8888/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" "-"
2023/12/25 15:51:24 [error] 31#31: *9 open() "/usr/share/nginx/html/api/users/register" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: "POST /api/users/register?false=false& HTTP/1.1", host: "localhost:8888", referrer: "http://localhost:8888/"
It took me a bit to figure out how i managed to swap up targetport with hostport instead of containerport. All in, there was a lot of trial and error.
I push an update to a fork of the repo. You can view all the YAML I ended up using here.
Now the question is hosting with an external ingress.
I’ll switch to my primary cluster and create a namespace for this app
builder@DESKTOP-QADGF36:~/Workspaces/idjohnson-recipesage-selfhost$ kubectx mac77
Switched to context "mac77".
builder@DESKTOP-QADGF36:~/Workspaces/idjohnson-recipesage-selfhost$ kubectl create ns recipesage
namespace/recipesage created
I’ll then create the workloads there
$ kubectl apply -n recipesage -f ./kubernetes/
deployment.apps/api created
service/api created
persistentvolumeclaim/apimedia created
deployment.apps/browserless created
service/browserless created
deployment.apps/ingredient-instruction-classifier created
service/ingredient-instruction-classifier created
deployment.apps/postgres created
service/postgres created
persistentvolumeclaim/postgresdata created
deployment.apps/proxy created
service/proxy created
configmap/proxycfg created
deployment.apps/pushpin created
service/pushpin created
deployment.apps/static created
service/static created
deployment.apps/typesense created
service/typesense created
persistentvolumeclaim/typesensedata created
I’ll create the A Record
$ cat r53-recipesage.json
{
"Comment": "CREATE recipes fb.s A record ",
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "recipes.freshbrewed.science",
"Type": "A",
"TTL": 300,
"ResourceRecords": [
{
"Value": "75.73.224.240"
}
]
}
}
]
}
$ aws route53 change-resource-record-sets --hosted-zone-id Z39E8QFU0F9PZP --change-batch file://r53-recipesage.json
{
"ChangeInfo": {
"Id": "/change/C03664723NPE8NG6TKYIC",
"Status": "PENDING",
"SubmittedAt": "2023-12-25T18:49:04.565Z",
"Comment": "CREATE recipes fb.s A record "
}
}
Then an ingress
$ cat ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
ingress.kubernetes.io/proxy-body-size: "0"
ingress.kubernetes.io/ssl-redirect: "true"
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.org/client-max-body-size: "0"
nginx.org/proxy-connect-timeout: "3600"
nginx.org/proxy-read-timeout: "3600"
creationTimestamp: "2023-11-21T00:30:38Z"
generation: 1
labels:
app.kubernetes.io/name: recipesage
name: recipesingress
namespace: recipesage
spec:
rules:
- host: recipes.freshbrewed.science
http:
paths:
- backend:
service:
name: proxy
port:
number: 8820
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- recipes.freshbrewed.science
secretName: recipes-tls
$ kubectl apply -f ingress.yaml
ingress.networking.k8s.io/recipesingress created
I was a bit worried about the impact to the cluster, so I checked Datadog:
Pod utilization went up a bit
I also saw a spike in availability of pods as they started to launch
We can’t forget to do the data migrate.
Here is a one-liner you can use as well (though change namespace if appropriate)
$ kubectl exec -n recipesage `kubectl get pods -l io.kompose.service=api -n recipesage -o jsonpath='{.items[*].metadata.name}'` tsx "packages/backend/src/migrate"
Which applied
$ kubectl exec -n recipesage `kubectl get pods -l io.kompose.service=api -n recipesage -o jsonpath='{.items[*].metadata.name}'` tsx "packages/backend/src/migrate"
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
{ event: 'migrating', name: '20180903174506-create-user.js' }
{
event: 'migrated',
name: '20180903174506-create-user.js',
durationSeconds: 0.045
}
{ event: 'migrating', name: '20180903225610-create-session.js' }
{
event: 'migrated',
name: '20180903225610-create-session.js',
durationSeconds: 0.023
}
{ event: 'migrating', name: '20180905031747-create-recipe.js' }
{
event: 'migrated',
name: '20180905031747-create-recipe.js',
durationSeconds: 0.017
}
{ event: 'migrating', name: '20180905031929-create-message.js' }
{
event: 'migrated',
name: '20180905031929-create-message.js',
durationSeconds: 0.026
}
{ event: 'migrating', name: '20180905040040-create-meal-plan.js' }
{
event: 'migrated',
name: '20180905040040-create-meal-plan.js',
durationSeconds: 0.028
}
{ event: 'migrating', name: '20180905040042-create-meal-plan-item.js' }
{
event: 'migrated',
name: '20180905040042-create-meal-plan-item.js',
durationSeconds: 0.017
}
{ event: 'migrating', name: '20180905040055-create-shopping-list.js' }
{
event: 'migrated',
name: '20180905040055-create-shopping-list.js',
durationSeconds: 0.026
}
{
event: 'migrating',
name: '20180905040211-create-shopping-list-item.js'
}
{
event: 'migrated',
name: '20180905040211-create-shopping-list-item.js',
durationSeconds: 0.029
}
{ event: 'migrating', name: '20180905042925-create-label.js' }
{
event: 'migrated',
name: '20180905042925-create-label.js',
durationSeconds: 0.023
}
{ event: 'migrating', name: '20180905042940-create-recipe_label.js' }
{
event: 'migrated',
name: '20180905042940-create-recipe_label.js',
durationSeconds: 0.019
}
{
event: 'migrating',
name: '20180909144458-create-meal-plan_collaborator.js'
}
{
event: 'migrated',
name: '20180909144458-create-meal-plan_collaborator.js',
durationSeconds: 0.018
}
{
event: 'migrating',
name: '20180909150203-create-shopping-list_collaborator.js'
}
{
event: 'migrated',
name: '20180909150203-create-shopping-list_collaborator.js',
durationSeconds: 0.025
}
{ event: 'migrating', name: '20180909194501-create-fcm-token.js' }
{
event: 'migrated',
name: '20180909194501-create-fcm-token.js',
durationSeconds: 0.021
}
{ event: 'migrating', name: '20190318151614-add-recipe-indexedAt.js' }
{
event: 'migrated',
name: '20190318151614-add-recipe-indexedAt.js',
durationSeconds: 0.01
}
{
event: 'migrating',
name: '20191020162730-add-user-stripeCustomerId.js'
}
{
event: 'migrated',
name: '20191020162730-add-user-stripeCustomerId.js',
durationSeconds: 0.013
}
{ event: 'migrating', name: '20191020164936-create-stripe-payment.js' }
{
event: 'migrated',
name: '20191020164936-create-stripe-payment.js',
durationSeconds: 0.026
}
{
event: 'migrating',
name: '20191020202716-create-user-subscription.js'
}
{
event: 'migrated',
name: '20191020202716-create-user-subscription.js',
durationSeconds: 0.021
}
{ event: 'migrating', name: '20191022024102-create-image.js' }
{
event: 'migrated',
name: '20191022024102-create-image.js',
durationSeconds: 0.025
}
{ event: 'migrating', name: '20191023020403-create-recipe-image.js' }
{
event: 'migrated',
name: '20191023020403-create-recipe-image.js',
durationSeconds: 0.013
}
{
event: 'migrating',
name: '20191026055147-remove-recipe-image-column.js'
}
{
event: 'migrated',
name: '20191026055147-remove-recipe-image-column.js',
durationSeconds: 0.02
}
{
event: 'migrating',
name: '20200124223957-add-index-recipe_label-recipeId-fkey.js'
}
{
event: 'migrated',
name: '20200124223957-add-index-recipe_label-recipeId-fkey.js',
durationSeconds: 0.012
}
{
event: 'migrating',
name: '20200124223958-add-index-recipe_image-recipeId-fkey.js'
}
{
event: 'migrated',
name: '20200124223958-add-index-recipe_image-recipeId-fkey.js',
durationSeconds: 0.015
}
{
event: 'migrating',
name: '20200124223959-add-index-recipe-userId-fkey.js'
}
{
event: 'migrated',
name: '20200124223959-add-index-recipe-userId-fkey.js',
durationSeconds: 0.019
}
{
event: 'migrating',
name: '20200203223959-add-unique-recipe_labels-recipeId.js'
}
{
event: 'migrated',
name: '20200203223959-add-unique-recipe_labels-recipeId.js',
durationSeconds: 0.023
}
{
event: 'migrating',
name: '20200203223960-add-unique-users-email.js'
}
{
event: 'migrated',
name: '20200203223960-add-unique-users-email.js',
durationSeconds: 0.018
}
{
event: 'migrating',
name: '20200206223979-add-index-recipe_labels-labelId-fkey.js'
}
{
event: 'migrated',
name: '20200206223979-add-index-recipe_labels-labelId-fkey.js',
durationSeconds: 0.01
}
{
event: 'migrating',
name: '20200206223980-add-unique-labels-userId-title.js'
}
Label titles updated: 0
Accounts with labels migrated: 0
{
event: 'migrated',
name: '20200206223980-add-unique-labels-userId-title.js',
durationSeconds: 0.015
}
{
event: 'migrating',
name: '20200206223981-labels-clean-title-commas.js'
}
{
event: 'migrated',
name: '20200206223981-labels-clean-title-commas.js',
durationSeconds: 0.01
}
{ event: 'migrating', name: '20200823174732-create-friendship.js' }
{
event: 'migrated',
name: '20200823174732-create-friendship.js',
durationSeconds: 0.018
}
{ event: 'migrating', name: '20200823175411-create-profile-item.js' }
{
event: 'migrated',
name: '20200823175411-create-profile-item.js',
durationSeconds: 0.058
}
{ event: 'migrating', name: '20200907151614-add-user-handle.js' }
{
event: 'migrated',
name: '20200907151614-add-user-handle.js',
durationSeconds: 0.02
}
{
event: 'migrating',
name: '20200907151615-add-unique-user-handle.js'
}
{
event: 'migrated',
name: '20200907151615-add-unique-user-handle.js',
durationSeconds: 0.031
}
{ event: 'migrating', name: '20200907151616-add-user-social.js' }
{
event: 'migrated',
name: '20200907151616-add-user-social.js',
durationSeconds: 0.023
}
{
event: 'migrating',
name: '20200908020403-create-user-profile-image.js'
}
{
event: 'migrated',
name: '20200908020403-create-user-profile-image.js',
durationSeconds: 0.026
}
{ event: 'migrating', name: '20200908020404-add-unique-friendship.js' }
{
event: 'migrated',
name: '20200908020404-add-unique-friendship.js',
durationSeconds: 0.021
}
{
event: 'migrating',
name: '20210207000000-add-notnull-shopping-list-item-title.js'
}
{
event: 'migrated',
name: '20210207000000-add-notnull-shopping-list-item-title.js',
durationSeconds: 0.013
}
{
event: 'migrating',
name: '20221022000000-add-notnull-shopping-list-item-completed.js'
}
{
event: 'migrated',
name: '20221022000000-add-notnull-shopping-list-item-completed.js',
durationSeconds: 0.01
}
{ event: 'migrating', name: '20221226000000-add-recipe-rating.js' }
{
event: 'migrated',
name: '20221226000000-add-recipe-rating.js',
durationSeconds: 0.009
}
{ event: 'migrating', name: '20221226000000-image-userid-nullable.js' }
{
event: 'migrated',
name: '20221226000000-image-userid-nullable.js',
durationSeconds: 0.01
}
{
event: 'migrating',
name: '20230716223979-add-index-mealplanitems-recipeId.js'
}
{
event: 'migrated',
name: '20230716223979-add-index-mealplanitems-recipeId.js',
durationSeconds: 0.01
}
{
event: 'migrating',
name: '20230716223989-add-index-mealplanitems-mealPlanId.js'
}
{
event: 'migrated',
name: '20230716223989-add-index-mealplanitems-mealPlanId.js',
durationSeconds: 0.009
}
{
event: 'migrating',
name: '20230716233979-add-index-shoppinglistitems-recipeId.js'
}
{
event: 'migrated',
name: '20230716233979-add-index-shoppinglistitems-recipeId.js',
durationSeconds: 0.02
}
{
event: 'migrating',
name: '20230716233989-add-index-shoppinglistitems-shoppingListId.js'
}
{
event: 'migrated',
name: '20230716233989-add-index-shoppinglistitems-shoppingListId.js',
durationSeconds: 0.022
}
{
event: 'migrating',
name: '20230716233997-add-index-recipe_images-imageId.js'
}
{
event: 'migrated',
name: '20230716233997-add-index-recipe_images-imageId.js',
durationSeconds: 0.017
}
{
event: 'migrating',
name: '20230716233998-add-index-images-userId.js'
}
{
event: 'migrated',
name: '20230716233998-add-index-images-userId.js',
durationSeconds: 0.012
}
{
event: 'migrating',
name: '20230716233999-add-index-recipes-fromUserId.js'
}
{
event: 'migrated',
name: '20230716233999-add-index-recipes-fromUserId.js',
durationSeconds: 0.01
}
{
event: 'migrating',
name: '20230717000000-add-index-messages-recipeId.js'
}
{
event: 'migrated',
name: '20230717000000-add-index-messages-recipeId.js',
durationSeconds: 0.01
}
{
event: 'migrating',
name: '20230717000001-add-index-messages-originalRecipeId.js'
}
{
event: 'migrated',
name: '20230717000001-add-index-messages-originalRecipeId.js',
durationSeconds: 0.014
}
{
event: 'migrating',
name: '20231105000001-update-image-userId-fk.js'
}
{
event: 'migrated',
name: '20231105000001-update-image-userId-fk.js',
durationSeconds: 0.015
}
All migrations performed successfully
I now have a fully functional RecipeSage site at https://recipes.freshbrewed.science/
Summary
Hopefully you found something useful, be it Docku for monitoring Docker storage, Noisedash, a simple and easy to use white noise generator or RecipeSage for collecting and sharing recipes.
You should be able to use my instances presently at:
Though, of course the point is to show people how to host themselves.
I will, for now, leave RecipeSage, but it did jump the pod count a bit in the production cluster: