Aptly and community search.

This commit is contained in:
2026-06-08 17:10:11 +00:00
parent 8117fb8175
commit 4eb722f393
17 changed files with 432 additions and 0 deletions

6
aptly/app.yaml Normal file
View File

@@ -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"

123
aptly/versions/1/README.md Normal file
View File

@@ -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 ~50100 GiB; plan accordingly.

View File

@@ -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

View File

@@ -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 }}

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: "{{ .namespace }}"

12
aptly/versions/1/pvc.yaml Normal file
View File

@@ -0,0 +1,12 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: aptly-pvc
spec:
storageClassName: longhorn
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: {{ .storage }}

View File

@@ -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