Fix asciinema S3 deployment
This commit is contained in:
1 parent
9d0e7f5c95
commit
9fd543ddcb
4 files changed
+25
-73
No files matched your search
@@ -11,13 +11,13 @@ asciinema has two durable data sets:
|
||||
searchable terminal text, and stream state. Its 8 Gi RBD claim uses the
|
||||
retained `rook-ceph-block-ec` StorageClass.
|
||||
- The private Rook Ceph RGW bucket `asciinema` stores uploaded asciicast files.
|
||||
Downloads use expiring pre-signed URLs through `https://s3.brunner.ninja`.
|
||||
The server reads casts through the cluster-local RGW Service and serves them
|
||||
from the asciinema endpoint.
|
||||
|
||||
The public RGW ingress rejects ExAws signatures for some mutating methods, so
|
||||
`custom.exs` uses the cluster-local RGW Service for server-side writes, moves,
|
||||
and deletes while generating browser-visible pre-signed GET URLs with the
|
||||
public endpoint. This mirrors the internal/public endpoint split used by other
|
||||
S3-backed applications in the cluster.
|
||||
All S3 operations use the cluster-local RGW Service. Although the S3 adapter
|
||||
generates a pre-signed URL when reading a recording, asciinema consumes that URL
|
||||
server-side to populate its local cache; it is not sent to the browser. Keeping
|
||||
the URL internal also avoids routing storage reads through Traefik.
|
||||
|
||||
The application needs neither Redis nor Valkey. Its cache and temporary upload
|
||||
workspace are bounded `emptyDir` volumes and may be discarded when the pod
|
||||
|
||||
+2
-65
@@ -11,12 +11,9 @@ data:
|
||||
TZ: Europe/Vienna
|
||||
DB_POOL_SIZE: "5"
|
||||
S3_BUCKET: asciinema
|
||||
# Mutating requests bypass the ingress because RGW rejects some ExAws
|
||||
# DELETE/HEAD signatures after they pass through the public proxy.
|
||||
# asciinema downloads stored casts server-side before serving them. Keep all
|
||||
# S3 operations on the cluster-local RGW endpoint; no public S3 URL is needed.
|
||||
S3_ENDPOINT: http://rook-ceph-rgw-my-store.rook-ceph.svc.cluster.local
|
||||
# The custom adapter uses this endpoint only when producing browser-visible
|
||||
# pre-signed GET URLs.
|
||||
S3_PUBLIC_ENDPOINT: https://s3.brunner.ninja
|
||||
S3_REGION: keller
|
||||
SMTP_HOST: smtp-relay.gmail.com
|
||||
SMTP_PORT: "587"
|
||||
@@ -36,59 +33,6 @@ data:
|
||||
# instance should remain single-user.
|
||||
SIGN_UP_DISABLED: "false"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: asciinema-custom-config
|
||||
namespace: asciinema
|
||||
labels:
|
||||
app.kubernetes.io/name: asciinema
|
||||
data:
|
||||
custom.exs: |
|
||||
import Config
|
||||
|
||||
# asciinema has one S3 endpoint setting for both internal operations and
|
||||
# browser-facing pre-signed URLs. Ceph RGW in this cluster needs separate
|
||||
# endpoints, so delegate all mutations to the upstream adapter and only
|
||||
# customize URL generation.
|
||||
defmodule Asciinema.FileStore.SplitEndpointS3 do
|
||||
@behaviour Asciinema.FileStore
|
||||
|
||||
alias ExAws.{Config, S3}
|
||||
|
||||
@impl true
|
||||
def uri(path) do
|
||||
endpoint = System.fetch_env!("S3_PUBLIC_ENDPOINT") |> URI.parse()
|
||||
|
||||
config =
|
||||
:s3
|
||||
|> Config.new()
|
||||
|> Map.put(:scheme, "#{endpoint.scheme}://")
|
||||
|> Map.put(:host, endpoint.host)
|
||||
|> Map.put(:port, endpoint.port)
|
||||
|
||||
{:ok, url} =
|
||||
S3.presigned_url(config, :get, bucket(), "uploads/" <> path)
|
||||
|
||||
url
|
||||
end
|
||||
|
||||
@impl true
|
||||
defdelegate put_file(dst_path, src_local_path, content_type),
|
||||
to: Asciinema.FileStore.S3
|
||||
|
||||
@impl true
|
||||
defdelegate move_file(from_path, to_path), to: Asciinema.FileStore.S3
|
||||
|
||||
@impl true
|
||||
defdelegate delete_file(path), to: Asciinema.FileStore.S3
|
||||
|
||||
defp bucket, do: System.fetch_env!("S3_BUCKET")
|
||||
end
|
||||
|
||||
config :asciinema, Asciinema.FileStore,
|
||||
adapter: Asciinema.FileStore.SplitEndpointS3
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -200,19 +144,12 @@ spec:
|
||||
volumeMounts:
|
||||
- name: cache
|
||||
mountPath: /var/cache/asciinema
|
||||
- name: custom-config
|
||||
mountPath: /opt/app/etc/custom.exs
|
||||
subPath: custom.exs
|
||||
readOnly: true
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- name: cache
|
||||
emptyDir:
|
||||
sizeLimit: 2Gi
|
||||
- name: custom-config
|
||||
configMap:
|
||||
name: asciinema-custom-config
|
||||
- name: tmp
|
||||
emptyDir:
|
||||
sizeLimit: 512Mi
|
||||
|
||||
@@ -20,7 +20,6 @@ rules:
|
||||
- configmaps
|
||||
resourceNames:
|
||||
- asciinema
|
||||
- asciinema-custom-config
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
|
||||
@@ -33,6 +33,18 @@ if grep -Eqi 'redis|valkey' \
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -Eq 'S3_PUBLIC_ENDPOINT|SplitEndpointS3|asciinema-custom-config' \
|
||||
"${project_dir}/asciinema.yaml"; then
|
||||
echo "asciinema must use the cluster-local RGW endpoint for server-side reads." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq 'S3_ENDPOINT: http://rook-ceph-rgw-my-store.rook-ceph.svc.cluster.local' \
|
||||
"${project_dir}/asciinema.yaml"; then
|
||||
echo "asciinema must use the cluster-local RGW Service." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
validate_file() {
|
||||
local manifest=$1
|
||||
shift
|
||||
@@ -43,8 +55,12 @@ validate_file() {
|
||||
docker run --rm --interactive \
|
||||
ghcr.io/yannh/kubeconform:v0.7.0@sha256:85dbef6b4b312b99133decc9c6fc9495e9fc5f92293d4ff3b7e1b30f5611823c \
|
||||
-strict -summary "$@" < "${manifest}"
|
||||
elif command -v podman >/dev/null 2>&1; then
|
||||
podman run --rm --interactive \
|
||||
ghcr.io/yannh/kubeconform:v0.7.0@sha256:85dbef6b4b312b99133decc9c6fc9495e9fc5f92293d4ff3b7e1b30f5611823c \
|
||||
-strict -summary "$@" < "${manifest}"
|
||||
else
|
||||
echo "Required command not found: install kubeconform or Docker" >&2
|
||||
echo "Required command not found: install kubeconform, Docker, or Podman" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user