From 4eb722f393151fda87d3dfbbf95e24d0ce038d76 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Mon, 8 Jun 2026 17:10:11 +0000 Subject: [PATCH] Aptly and community search. --- aptly/app.yaml | 6 + aptly/versions/1/README.md | 123 ++++++++++++++++++ aptly/versions/1/deployment.yaml | 56 ++++++++ aptly/versions/1/ingress.yaml | 25 ++++ aptly/versions/1/kustomization.yaml | 15 +++ aptly/versions/1/manifest.yaml | 10 ++ aptly/versions/1/namespace.yaml | 4 + aptly/versions/1/pvc.yaml | 12 ++ aptly/versions/1/service.yaml | 14 ++ community-search/app.yaml | 4 + community-search/versions/0/deployment.yaml | 84 ++++++++++++ community-search/versions/0/ingress.yaml | 25 ++++ .../versions/0/kustomization.yaml | 15 +++ community-search/versions/0/manifest.yaml | 12 ++ community-search/versions/0/namespace.yaml | 4 + community-search/versions/0/pvc.yaml | 10 ++ community-search/versions/0/service.yaml | 13 ++ 17 files changed, 432 insertions(+) create mode 100644 aptly/app.yaml create mode 100644 aptly/versions/1/README.md create mode 100644 aptly/versions/1/deployment.yaml create mode 100644 aptly/versions/1/ingress.yaml create mode 100644 aptly/versions/1/kustomization.yaml create mode 100644 aptly/versions/1/manifest.yaml create mode 100644 aptly/versions/1/namespace.yaml create mode 100644 aptly/versions/1/pvc.yaml create mode 100644 aptly/versions/1/service.yaml create mode 100644 community-search/app.yaml create mode 100644 community-search/versions/0/deployment.yaml create mode 100644 community-search/versions/0/ingress.yaml create mode 100644 community-search/versions/0/kustomization.yaml create mode 100644 community-search/versions/0/manifest.yaml create mode 100644 community-search/versions/0/namespace.yaml create mode 100644 community-search/versions/0/pvc.yaml create mode 100644 community-search/versions/0/service.yaml diff --git a/aptly/app.yaml b/aptly/app.yaml new file mode 100644 index 0000000..1be27cc --- /dev/null +++ b/aptly/app.yaml @@ -0,0 +1,6 @@ +name: aptly +is: aptly +description: Aptly is a Debian/Ubuntu APT repository management tool for mirroring, snapshotting, and publishing package repositories. +icon: https://github.com/aptly-dev.png +category: infrastructure +latest: "1" diff --git a/aptly/versions/1/README.md b/aptly/versions/1/README.md new file mode 100644 index 0000000..c29014b --- /dev/null +++ b/aptly/versions/1/README.md @@ -0,0 +1,123 @@ +# Aptly + +Aptly is a Debian/Ubuntu APT repository management tool. Use it to mirror upstream repositories, create package snapshots, and publish private or curated APT repositories that your machines can install from. + +## Configuration + +Key settings in your instance's `config.yaml`: + +- **domain** - Where aptly will be accessible (default: `aptly.{your-cloud-domain}`) +- **storage** - Persistent volume size for packages and mirrors (default: `50Gi` — adjust based on how many packages you plan to mirror) + +## Access + +After deployment: +- `https://aptly.{your-cloud-domain}` — Published repository root (for APT clients, no auth required) +- `https://aptly.{your-cloud-domain}/api` — REST API for managing repos, mirrors, and snapshots (requires credentials) + +## Credentials + +The API is protected by HTTP basic authentication. The username defaults to `aptly` (configurable via `apiUser` in `config.yaml`). The password is auto-generated and stored in your instance's `secrets.yaml` under `apps.aptly.apiPassword`. + +To retrieve it: +```bash +wild secret get aptly apiPassword +# or directly: +grep apiPassword path/to/secrets.yaml +``` + +To use the API with curl: +```bash +curl -u aptly:{your-api-password} https://aptly.{your-cloud-domain}/api/version +``` + +The published repository at `/` does not require credentials — APT clients can install packages without authenticating. + +## First-Time Setup + +1. Add and deploy: + ```bash + wild app add aptly + wild app deploy aptly + ``` + +2. Verify the API is responding: + ```bash + curl -u aptly:{your-api-password} https://aptly.{your-cloud-domain}/api/version + ``` + +## Common Workflows + +Aptly is managed entirely through its REST API or the `aptly` CLI (run inside the pod). The REST API docs are at https://www.aptly.info/doc/api/. + +### Running aptly commands inside the pod + +```bash +kubectl -n aptly exec -it deploy/aptly -- bash +``` + +### Mirror a Debian repository + +```bash +# Create a mirror (run inside the pod, or via the REST API) +aptly mirror create debian-bookworm-main http://deb.debian.org/debian bookworm main + +# Download packages +aptly mirror update debian-bookworm-main + +# Snapshot the mirror +aptly snapshot create bookworm-snap from mirror debian-bookworm-main + +# Publish the snapshot +aptly publish snapshot bookworm-snap +``` + +The published repo will be available at `https://aptly.{your-cloud-domain}/debian bookworm main`. + +### Create a private package repository + +```bash +# Create a local repo +aptly repo create my-packages + +# Add packages +aptly repo add my-packages /path/to/package.deb + +# Publish +aptly publish repo my-packages +``` + +### Configure a machine to use the repository + +```bash +# Add the repo to sources.list +echo "deb https://aptly.{your-cloud-domain}/ bookworm main" | \ + sudo tee /etc/apt/sources.list.d/my-aptly.list + +# Import the signing key (generate one first if needed — see GPG section below) +curl -s https://aptly.{your-cloud-domain}/public.key | sudo apt-key add - + +sudo apt update +``` + +## GPG Signing + +Published repositories should be signed with a GPG key. On first use, generate a key inside the pod: + +```bash +kubectl -n aptly exec -it deploy/aptly -- bash + +# Generate a signing key (stored in /opt/aptly/gpg) +gpg --gen-key + +# Export the public key for clients to import +gpg --export --armor > /opt/aptly/public/public.key +``` + +Then include `--distribution`, `--component`, and signing options in your `aptly publish` commands. See https://www.aptly.info/doc/aptly/publish/snapshot/ for details. + +## Notes + +- GPG keys and all aptly data (database, package pool, published repos) are stored on the persistent volume at `/opt/aptly`. +- The REST API (port 8080) and the nginx file server (port 80) both run inside the pod via supervisord. The ingress routes to nginx (port 80). +- `storage` defaults to `50Gi`. A full Debian mirror for a single architecture is ~50–100 GiB; plan accordingly. diff --git a/aptly/versions/1/deployment.yaml b/aptly/versions/1/deployment.yaml new file mode 100644 index 0000000..8e3ce9d --- /dev/null +++ b/aptly/versions/1/deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: aptly +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + component: server + template: + metadata: + labels: + component: server + spec: + securityContext: + seccompProfile: + type: RuntimeDefault + initContainers: + - name: init-htpasswd + image: httpd:alpine + command: + - sh + - -c + - htpasswd -bc /opt/aptly/api.htpasswd "$API_USER" "$API_PASSWORD" + env: + - name: API_USER + value: "{{ .apiUser }}" + - name: API_PASSWORD + valueFrom: + secretKeyRef: + name: aptly-secrets + key: apiPassword + securityContext: + allowPrivilegeEscalation: false + volumeMounts: + - name: data + mountPath: /opt/aptly + containers: + - name: aptly + image: urpylka/aptly:1.6.2 + ports: + - containerPort: 80 + name: http + - containerPort: 8080 + name: api + securityContext: + allowPrivilegeEscalation: false + volumeMounts: + - name: data + mountPath: /opt/aptly + volumes: + - name: data + persistentVolumeClaim: + claimName: aptly-pvc diff --git a/aptly/versions/1/ingress.yaml b/aptly/versions/1/ingress.yaml new file mode 100644 index 0000000..f23359b --- /dev/null +++ b/aptly/versions/1/ingress.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: aptly + annotations: + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} + external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" + external-dns.alpha.kubernetes.io/ttl: "60" +spec: + ingressClassName: traefik + rules: + - host: {{ .domain }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: aptly + port: + number: 80 + tls: + - hosts: + - {{ .domain }} + secretName: {{ .tlsSecretName }} diff --git a/aptly/versions/1/kustomization.yaml b/aptly/versions/1/kustomization.yaml new file mode 100644 index 0000000..0b7c62a --- /dev/null +++ b/aptly/versions/1/kustomization.yaml @@ -0,0 +1,15 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: "{{ .namespace }}" +labels: + - includeSelectors: true + pairs: + app: aptly + managedBy: kustomize + partOf: wild-cloud +resources: + - namespace.yaml + - deployment.yaml + - service.yaml + - ingress.yaml + - pvc.yaml diff --git a/aptly/versions/1/manifest.yaml b/aptly/versions/1/manifest.yaml new file mode 100644 index 0000000..5840313 --- /dev/null +++ b/aptly/versions/1/manifest.yaml @@ -0,0 +1,10 @@ +version: 1.6.2 +defaultConfig: + namespace: aptly + externalDnsDomain: "{{ .cloud.domain }}" + domain: "aptly.{{ .cloud.domain }}" + tlsSecretName: wildcard-wild-cloud-tls + storage: 50Gi + apiUser: aptly +defaultSecrets: + - key: apiPassword diff --git a/aptly/versions/1/namespace.yaml b/aptly/versions/1/namespace.yaml new file mode 100644 index 0000000..b7816b8 --- /dev/null +++ b/aptly/versions/1/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: "{{ .namespace }}" diff --git a/aptly/versions/1/pvc.yaml b/aptly/versions/1/pvc.yaml new file mode 100644 index 0000000..6749790 --- /dev/null +++ b/aptly/versions/1/pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: aptly-pvc +spec: + storageClassName: longhorn + accessModes: + - ReadWriteOnce + volumeMode: Filesystem + resources: + requests: + storage: {{ .storage }} diff --git a/aptly/versions/1/service.yaml b/aptly/versions/1/service.yaml new file mode 100644 index 0000000..29cf9af --- /dev/null +++ b/aptly/versions/1/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: aptly +spec: + ports: + - port: 80 + targetPort: 80 + name: http + - port: 8080 + targetPort: 8080 + name: api + selector: + component: server diff --git a/community-search/app.yaml b/community-search/app.yaml new file mode 100644 index 0000000..5c788dc --- /dev/null +++ b/community-search/app.yaml @@ -0,0 +1,4 @@ +name: community-search +is: community-search +description: Community Search is a federated, self-hosted search engine built on community-curated indexes rather than global web crawling. +latest: "0" diff --git a/community-search/versions/0/deployment.yaml b/community-search/versions/0/deployment.yaml new file mode 100644 index 0000000..117e70d --- /dev/null +++ b/community-search/versions/0/deployment.yaml @@ -0,0 +1,84 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: community-search +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + component: web + template: + metadata: + labels: + component: web + spec: + securityContext: + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + fsGroup: 999 + seccompProfile: + type: RuntimeDefault + containers: + - name: community-search + image: payneio/community-search:0.1.1 + imagePullPolicy: Always + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + ports: + - name: http + containerPort: 8080 + env: + - name: COMMUNITY_SEARCH_BIND_ADDR + value: "0.0.0.0" + - name: COMMUNITY_SEARCH_PORT + value: "8080" + - name: COMMUNITY_SEARCH_DATA_DIR + value: "/data" + - name: COMMUNITY_SEARCH_INDEX_PATH + value: "/data/index" + - name: COMMUNITY_SEARCH_ADMIN_TOKEN + valueFrom: + secretKeyRef: + name: community-search-secrets + key: adminToken + - name: SELF_URL + value: "{{ .selfUrl }}" + - name: SELF_NAME + value: "{{ .selfName }}" + - name: RUST_LOG + value: "community_search=info,tower_http=warn" + volumeMounts: + - name: data + mountPath: /data + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 1 + memory: 1Gi + readinessProbe: + httpGet: + path: /api/collections + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: /api/collections + port: http + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 5 + volumes: + - name: data + persistentVolumeClaim: + claimName: community-search-data diff --git a/community-search/versions/0/ingress.yaml b/community-search/versions/0/ingress.yaml new file mode 100644 index 0000000..b692852 --- /dev/null +++ b/community-search/versions/0/ingress.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: community-search + annotations: + external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} + external-dns.alpha.kubernetes.io/ttl: "60" +spec: + ingressClassName: traefik + rules: + - host: {{ .domain }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: community-search + port: + number: 80 + tls: + - hosts: + - {{ .domain }} + secretName: {{ .tlsSecretName }} diff --git a/community-search/versions/0/kustomization.yaml b/community-search/versions/0/kustomization.yaml new file mode 100644 index 0000000..8967091 --- /dev/null +++ b/community-search/versions/0/kustomization.yaml @@ -0,0 +1,15 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: community-search +labels: + - includeSelectors: true + pairs: + app: community-search + managedBy: kustomize + partOf: wild-cloud +resources: + - namespace.yaml + - deployment.yaml + - service.yaml + - ingress.yaml + - pvc.yaml diff --git a/community-search/versions/0/manifest.yaml b/community-search/versions/0/manifest.yaml new file mode 100644 index 0000000..62a8333 --- /dev/null +++ b/community-search/versions/0/manifest.yaml @@ -0,0 +1,12 @@ +version: 0.1.1-1 +requires: [] +defaultConfig: + namespace: community-search + externalDnsDomain: '{{ .cloud.domain }}' + domain: search.{{ .cloud.domain }} + tlsSecretName: wildcard-wild-cloud-tls + storage: 10Gi + selfUrl: 'https://search.{{ .cloud.domain }}' + selfName: 'Community Search' +defaultSecrets: + - key: adminToken diff --git a/community-search/versions/0/namespace.yaml b/community-search/versions/0/namespace.yaml new file mode 100644 index 0000000..b7816b8 --- /dev/null +++ b/community-search/versions/0/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: "{{ .namespace }}" diff --git a/community-search/versions/0/pvc.yaml b/community-search/versions/0/pvc.yaml new file mode 100644 index 0000000..e424e29 --- /dev/null +++ b/community-search/versions/0/pvc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: community-search-data +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .storage }} diff --git a/community-search/versions/0/service.yaml b/community-search/versions/0/service.yaml new file mode 100644 index 0000000..9c49f80 --- /dev/null +++ b/community-search/versions/0/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: community-search +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 8080 + selector: + component: web