flickr-immich-k8s-sync-operator
Kubernetes operator that watches per-user Flickr download Jobs in a namespace, restarts failed Jobs after a configurable delay, and retrieves pod logs and exit codes for failed Jobs before restarting them. Designed to run alongside Immich (self-hosted photo management).
Screenshots
Status
Beta (v0.0.4) — the core job-restart loop is stable and actively deployed. OOMKilled-aware restart logic, structured startup/configuration logging, and full CI (black + mypy + pytest) are in place.
Architecture
- Runs as a single-replica Deployment in a dedicated namespace (default:
flickr-downloader) - Uses the Kubernetes Python client with in-cluster config
- Periodically checks configured Job names for failure conditions
- On failure (after a configurable delay), deletes the Job with
Foregroundpropagation policy and recreates it from a cached manifest - Logs pod exit codes and tail logs before every restart
How it works
- An Ansible playbook (
kubectlstuff_flickr_downloader.yml) creates per-user Flickr download Jobs in theflickr-downloadernamespace - Each Job runs
flickr_downloadwithBACKOFF_EXIT_ON_429=true, so it exits immediately on HTTP 429 rate-limit errors instead of sleeping - Jobs mount host directories for config, backup, and cache per user
- This operator watches all configured Jobs for failure conditions
- When a Job fails, the operator logs pod exit codes and tail logs, waits
RESTART_DELAYseconds (default 1 hour), then deletes and recreates the Job from a cached manifest - The operator uses namespace-scoped RBAC with minimal permissions (Jobs, Pods, Pod logs)
Prerequisites
- A running Kubernetes cluster
- Per-user Flickr download Jobs already deployed (e.g. via the Ansible playbook above) — the operator manages their lifecycle (restart on failure), not initial creation
- An Immich instance (for planned sync functionality)
Configuration
| Variable | Description | Default |
|---|---|---|
LOGURU_LEVEL |
Log verbosity (DEBUG, INFO, WARNING, …) |
DEBUG |
NAMESPACE |
Namespace to watch | flickr-downloader |
JOB_NAMES |
Comma-separated Job names to monitor (required) | — |
CHECK_INTERVAL |
Seconds between check cycles | 60 |
RESTART_DELAY |
Seconds to wait after failure before restart | 3600 |
SKIP_DELAY_ON_OOM |
Skip restart delay when failure reason is OOMKilled |
false |
Kubernetes Deployment
RBAC
The operator requires a ServiceAccount with a Role scoped to the target namespace:
apiVersion: v1
kind: ServiceAccount
metadata:
name: flickr-operator
namespace: flickr-downloader
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: flickr-operator
namespace: flickr-downloader
rules:
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "list", "create", "delete"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "delete"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: flickr-operator
namespace: flickr-downloader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: flickr-operator
subjects:
- kind: ServiceAccount
name: flickr-operator
namespace: flickr-downloader
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: flickr-operator
namespace: flickr-downloader
spec:
replicas: 1
selector:
matchLabels:
app: flickr-operator
template:
metadata:
labels:
app: flickr-operator
spec:
serviceAccountName: flickr-operator
containers:
- name: operator
image: xomoxcc/flickr-immich-k8s-sync-operator:latest
env:
- name: JOB_NAMES
value: "flickr-downloader-alice,flickr-downloader-bob"
- name: LOGURU_LEVEL
value: "DEBUG"
# - name: NAMESPACE
# value: "flickr-downloader" # default
# - name: CHECK_INTERVAL
# value: "60" # default
# - name: RESTART_DELAY
# value: "3600" # default
# - name: SKIP_DELAY_ON_OOM
# value: "false" # default
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 1500m
memory: 128Mi
Installation
From PyPI
pip install flickr-immich-k8s-sync-operator
From source
git clone https://github.com/vroomfondel/flickr-immich-k8s-sync-operator.git
cd flickr-immich-k8s-sync-operator
make venv
source .venv/bin/activate
pip install .
Docker
docker build -t flickr-immich-k8s-sync-operator .
docker run --rm flickr-immich-k8s-sync-operator
Or via Makefile:
make docker
Usage
# Run directly
flickr-immich-k8s-sync-operator
# Or via Python module
python -m flickr_immich_k8s_sync_operator
Development
Makefile targets
| Target | Description |
|---|---|
make venv |
Create virtualenv and install all dependencies |
make tests |
Run pytest |
make lint |
Format code with black (line length 120) |
make isort |
Sort imports with isort |
make tcheck |
Static type checking with mypy |
make commit-checks |
Run pre-commit hooks on all files |
make prepare |
Run tests + commit-checks |
make pypibuild |
Build sdist + wheel with hatch |
make pypipush |
Publish to PyPI with hatch |
make docker |
Build Docker image |
make gitleaks |
Run gitleaks secret scanner via pre-commit |
make update-all-dockerhub-readmes |
Push DOCKERHUB_OVERVIEW.md to Docker Hub repo description |
License
Release files for flickr-immich-k8s-sync-operator 0.0.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| flickr_immich_k8s_sync_operator-0.0.6.tar.gz | 13.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| flickr_immich_k8s_sync_operator-0.0.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 27.7 kB
Release files / flickr_immich_k8s_sync_operator-0.0.6.tar.gz
| Download URL | flickr_immich_k8s_sync_operator-0.0.6.tar.gz |
|---|---|
| Size | 13.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9ec76ec556df6197c66d9fc1876c353bdce1b854da7ed9c7a167f768d2688a4e
|
|
BLAKE2b-256 checksum How to use checksums |
8db01908997306601d5e7b1ccd9b24234bc434c178d033d53f7ca34b6f9d1840
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Hatch/1.16.3 cpython/3.13.7 HTTPX/0.28.1
|
Release files / flickr_immich_k8s_sync_operator-0.0.6-py3-none-any.whl
| Download URL | flickr_immich_k8s_sync_operator-0.0.6-py3-none-any.whl |
|---|---|
| Size | 14.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5596afd4c72a3d60f8a1a8d2364f08369959046c2384983ad16a0d7052a71c70
|
|
BLAKE2b-256 checksum How to use checksums |
4c19fe5fbbd5867baea0df7733b9306dc78da303b02484d962cbd8fb982ba8ac
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Hatch/1.16.3 cpython/3.13.7 HTTPX/0.28.1
|