qbittorrentvpn.yaml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. ---
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5. name: qbittorrentvpn
  6. namespace: plex
  7. spec:
  8. strategy:
  9. type: Recreate
  10. selector:
  11. matchLabels:
  12. app: qbittorrentvpn
  13. replicas: 1
  14. template:
  15. metadata:
  16. labels:
  17. app: qbittorrentvpn
  18. annotations:
  19. backup.velero.io/backup-volumes-excludes: seedbox,media,media2,data-ec,scratch
  20. spec:
  21. affinity:
  22. nodeAffinity:
  23. requiredDuringSchedulingIgnoredDuringExecution:
  24. nodeSelectorTerms:
  25. - matchExpressions:
  26. - key: seedbox
  27. operator: In
  28. values:
  29. - "true"
  30. containers:
  31. - name: qbittorrentvpn
  32. image: binhex/arch-qbittorrentvpn:5.1.4-1-01
  33. ports:
  34. - containerPort: 8080
  35. name: http-web-svc
  36. securityContext:
  37. privileged: true
  38. env:
  39. - name: DEBUG
  40. value: "true"
  41. - name: ENABLE_PRIVOXY
  42. value: "no"
  43. - name: LAN_NETWORK
  44. value: "172.16.69.0/24,10.42.0.0/16"
  45. - name: NAME_SERVERS
  46. value: "209.244.0.3,209.244.0.4"
  47. - name: PGID
  48. value: "1000"
  49. - name: PUID
  50. value: "1000"
  51. - name: STRICT_PORT_FORWARD
  52. value: "yes"
  53. - name: VPN_CLIENT
  54. value: "wireguard"
  55. - name: VPN_ENABLED
  56. value: "yes"
  57. - name: VPN_PROV
  58. value: "airvpn"
  59. - name: VPN_USER
  60. valueFrom:
  61. secretKeyRef:
  62. name: qbittorrentvpn
  63. key: VPN_USER
  64. - name: VPN_PASS
  65. valueFrom:
  66. secretKeyRef:
  67. name: qbittorrentvpn
  68. key: VPN_PASS
  69. livenessProbe:
  70. exec:
  71. command: ["curl", "--fail", "localhost:8080"]
  72. volumeMounts:
  73. - mountPath: "/media"
  74. name: media
  75. - mountPath: "/media2"
  76. name: media2
  77. - mountPath: "/dataec"
  78. name: data-ec
  79. - mountPath: "/config"
  80. name: config
  81. - mountPath: "/scratch"
  82. name: seedbox
  83. volumes:
  84. - name: media
  85. persistentVolumeClaim:
  86. claimName: plex-pvc
  87. - name: media2
  88. persistentVolumeClaim:
  89. claimName: media2-pvc
  90. - name: data-ec
  91. persistentVolumeClaim:
  92. claimName: data-ec-pvc
  93. - name: config
  94. persistentVolumeClaim:
  95. claimName: qbittorrentvpn-pvc
  96. - name: seedbox
  97. hostPath:
  98. path: /seedbox/torrents
  99. type: Directory
  100. ---
  101. apiVersion: v1
  102. kind: Service
  103. metadata:
  104. name: qbittorrentvpn-service
  105. namespace: plex
  106. spec:
  107. selector:
  108. app: qbittorrentvpn
  109. type: ClusterIP
  110. ports:
  111. - name: qbittorrentvpn-web-port
  112. protocol: TCP
  113. port: 8080
  114. targetPort: http-web-svc
  115. ---
  116. apiVersion: networking.k8s.io/v1
  117. kind: Ingress
  118. metadata:
  119. name: qbittorrentvpn
  120. namespace: plex
  121. annotations:
  122. traefik.ingress.kubernetes.io/router.entrypoints: websecure
  123. traefik.ingress.kubernetes.io/router.middlewares: kube-system-lanonly@kubernetescrd
  124. spec:
  125. rules:
  126. - host: qbittorrentvpn.lan.jibby.org
  127. http:
  128. paths:
  129. - path: /
  130. pathType: Prefix
  131. backend:
  132. service:
  133. name: qbittorrentvpn-service
  134. port:
  135. number: 8080
  136. ---
  137. apiVersion: external-secrets.io/v1
  138. kind: ExternalSecret
  139. metadata:
  140. name: qbittorrentvpn
  141. namespace: plex
  142. spec:
  143. target:
  144. name: qbittorrentvpn
  145. deletionPolicy: Delete
  146. template:
  147. type: Opaque
  148. data:
  149. VPN_USER: |-
  150. {{ .username }}
  151. VPN_PASS: |-
  152. {{ .password }}
  153. data:
  154. - secretKey: username
  155. sourceRef:
  156. storeRef:
  157. name: bitwarden-login
  158. kind: ClusterSecretStore
  159. remoteRef:
  160. key: 19b0020e-51d3-42eb-b78b-b1d7012d1a8a
  161. property: username
  162. - secretKey: password
  163. sourceRef:
  164. storeRef:
  165. name: bitwarden-login
  166. kind: ClusterSecretStore
  167. remoteRef:
  168. key: 19b0020e-51d3-42eb-b78b-b1d7012d1a8a
  169. property: password
  170. ---
  171. apiVersion: apps/v1
  172. kind: Deployment
  173. metadata:
  174. name: qbittorrentvpn-exporter
  175. namespace: plex
  176. spec:
  177. strategy:
  178. type: Recreate
  179. selector:
  180. matchLabels:
  181. app: qbittorrentvpn-exporter
  182. replicas: 1
  183. template:
  184. metadata:
  185. labels:
  186. app: qbittorrentvpn-exporter
  187. spec:
  188. containers:
  189. - name: qbittorrentvpn-exporter
  190. image: ghcr.io/esanchezm/prometheus-qbittorrent-exporter:latest
  191. ports:
  192. - containerPort: 8000
  193. name: metrics
  194. env:
  195. - name: QBITTORRENT_HOST
  196. value: qbittorrentvpn.lan.jibby.org
  197. - name: QBITTORRENT_PORT
  198. value: "443"
  199. - name: QBITTORRENT_SSL
  200. value: "True"
  201. - name: QBITTORRENT_USER
  202. valueFrom:
  203. secretKeyRef:
  204. name: qbittorrentvpn-exporter
  205. key: QBITTORRENT_USER
  206. - name: QBITTORRENT_PASS
  207. valueFrom:
  208. secretKeyRef:
  209. name: qbittorrentvpn-exporter
  210. key: QBITTORRENT_PASS
  211. livenessProbe:
  212. exec:
  213. command:
  214. - "/bin/sh"
  215. - "-c"
  216. - 'wget -O - 0.0.0.0:8000 | grep -E "qbittorrent_up\{.* 1.0"'
  217. initialDelaySeconds: 3
  218. timeoutSeconds: 5
  219. periodSeconds: 3
  220. failureThreshold: 15
  221. resources:
  222. requests:
  223. memory: "0"
  224. limits:
  225. memory: "256Mi"
  226. ---
  227. apiVersion: v1
  228. kind: Service
  229. metadata:
  230. name: qbittorrentvpn-exporter-service
  231. namespace: plex
  232. labels:
  233. app: qbittorrentvpn-exporter
  234. spec:
  235. selector:
  236. app: qbittorrentvpn-exporter
  237. type: ClusterIP
  238. ports:
  239. - name: metrics
  240. protocol: TCP
  241. port: 8000
  242. targetPort: metrics
  243. ---
  244. apiVersion: monitoring.coreos.com/v1
  245. kind: PrometheusRule
  246. metadata:
  247. labels:
  248. prometheus: qbittorrent
  249. role: alert-rules
  250. name: prometheus-qbittorrent-rules
  251. namespace: plex
  252. spec:
  253. groups:
  254. - name: ./qbittorrent.rules
  255. rules:
  256. - alert: QbittorrentErroredTorrents
  257. expr: sum(qbittorrent_torrents_count{status="error"}) > 0
  258. ---
  259. apiVersion: external-secrets.io/v1
  260. kind: ExternalSecret
  261. metadata:
  262. name: qbittorrentvpn-exporter
  263. namespace: plex
  264. spec:
  265. target:
  266. name: qbittorrentvpn-exporter
  267. deletionPolicy: Delete
  268. template:
  269. type: Opaque
  270. data:
  271. QBITTORRENT_USER: |-
  272. {{ .username }}
  273. QBITTORRENT_PASS: |-
  274. {{ .password }}
  275. data:
  276. - secretKey: username
  277. sourceRef:
  278. storeRef:
  279. name: bitwarden-login
  280. kind: ClusterSecretStore
  281. remoteRef:
  282. key: 8dd7dfc3-800d-4af5-8a45-b23f0132806c
  283. property: username
  284. - secretKey: password
  285. sourceRef:
  286. storeRef:
  287. name: bitwarden-login
  288. kind: ClusterSecretStore
  289. remoteRef:
  290. key: 8dd7dfc3-800d-4af5-8a45-b23f0132806c
  291. property: password
  292. # qbit_manage to auto-tag by tracker URL
  293. ---
  294. apiVersion: batch/v1
  295. kind: CronJob
  296. metadata:
  297. name: qbittorrentvpn-manage
  298. namespace: plex
  299. spec:
  300. schedule: "*/10 * * * *"
  301. successfulJobsHistoryLimit: 1
  302. failedJobsHistoryLimit: 1
  303. concurrencyPolicy: Forbid
  304. jobTemplate:
  305. spec:
  306. activeDeadlineSeconds: 60
  307. template:
  308. metadata:
  309. labels:
  310. app: qbittorrentvpn-manage
  311. spec:
  312. restartPolicy: OnFailure
  313. containers:
  314. - name: qbittorrentvpn-manage
  315. image: ghcr.io/stuffanthings/qbit_manage:v4.6.5@sha256:4f36632a138b4e5aeab3b765b7f389087bfb140c80dbbec1343eca74dc351245
  316. command:
  317. - python3
  318. - qbit_manage.py
  319. - "--run"
  320. volumeMounts:
  321. - name: config
  322. mountPath: /config/config.yml
  323. subPath: config.yml
  324. volumes:
  325. - name: config
  326. configMap:
  327. name: qbittorrentvpn-manage-config
  328. configMap:
  329. items:
  330. - key: config.yml
  331. path: config.yml
  332. ---
  333. apiVersion: external-secrets.io/v1
  334. kind: ExternalSecret
  335. metadata:
  336. name: qbittorrentvpn-manage
  337. namespace: plex
  338. spec:
  339. target:
  340. name: qbittorrentvpn-manage
  341. deletionPolicy: Delete
  342. template:
  343. type: Opaque
  344. data:
  345. config.yml: |-
  346. {{ .trackertags }}
  347. qbt:
  348. host: https://qbittorrentvpn.lan.jibby.org
  349. user: {{ .username }}
  350. pass: {{ .password }}
  351. commands:
  352. recheck: false
  353. cat_update: false
  354. tag_update: true
  355. rem_unregistered: false
  356. rem_orphaned: false
  357. tag_tracker_error: false
  358. tag_nohardlinks: false
  359. share_limits: false
  360. skip_cleanup: false
  361. dry_run: false
  362. skip_qb_version_check: false
  363. # Not using any of these fields, but they're required for qbit_manage
  364. cat:
  365. tv-sonarr: Uncategorized
  366. completed: /not/using/cat
  367. recyclebin:
  368. enabled: false
  369. save_torrents: false
  370. split_by_category: false
  371. empty_after_x_days:
  372. directory:
  373. root_dir: /not/using/rootdir
  374. torrents_dir:
  375. orphaned:
  376. max_orphaned_files_to_delete: 50
  377. min_file_age_minutes: 0
  378. empty_after_x_days:
  379. exclude_patterns:
  380. settings:
  381. force_auto_tmm: false
  382. tracker_error_tag: issue
  383. nohardlinks_tag: noHL
  384. stalled_tag: stalledDL
  385. share_limits_tag: ~share_limit
  386. share_limits_min_seeding_time_tag: MinSeedTimeNotReached
  387. share_limits_min_num_seeds_tag: MinSeedsNotMet
  388. share_limits_last_active_tag: LastActiveLimitNotReached
  389. cat_filter_completed: true
  390. share_limits_filter_completed: true
  391. tag_nohardlinks_filter_completed: true
  392. rem_unregistered_filter_completed: false
  393. cat_update_all: true
  394. disable_qbt_default_share_limits: true
  395. tag_stalled_torrents: true
  396. rem_unregistered_grace_minutes: 10
  397. rem_unregistered_max_torrents: 10
  398. private_tag:
  399. force_auto_tmm_ignore_tags: []
  400. rem_unregistered_ignore_list: []
  401. webhooks:
  402. error:
  403. run_start:
  404. run_end:
  405. function:
  406. tag_tracker_error:
  407. share_limits:
  408. data:
  409. - secretKey: username
  410. sourceRef:
  411. storeRef:
  412. name: bitwarden-login
  413. kind: ClusterSecretStore
  414. remoteRef:
  415. key: 8dd7dfc3-800d-4af5-8a45-b23f0132806c
  416. property: username
  417. - secretKey: password
  418. sourceRef:
  419. storeRef:
  420. name: bitwarden-login
  421. kind: ClusterSecretStore
  422. remoteRef:
  423. key: 8dd7dfc3-800d-4af5-8a45-b23f0132806c
  424. property: password
  425. - secretKey: trackertags
  426. sourceRef:
  427. storeRef:
  428. name: bitwarden-notes
  429. kind: ClusterSecretStore
  430. remoteRef:
  431. key: 54c175aa-aa4f-4a28-a8f6-b3f80146e440
  432. # Restart qbittorrentvpn reguarly. Sometimes VPN throughput slows down & a restart helps.
  433. #---
  434. #apiVersion: batch/v1
  435. #kind: CronJob
  436. #metadata:
  437. # name: qbittorrentvpn-restart
  438. # namespace: plex
  439. #spec:
  440. # schedule: "*/30 * * * *"
  441. # successfulJobsHistoryLimit: 1
  442. # failedJobsHistoryLimit: 1
  443. # concurrencyPolicy: Forbid
  444. # jobTemplate:
  445. # spec:
  446. # template:
  447. # metadata:
  448. # labels:
  449. # app: qbittorrentvpn-restart
  450. # spec:
  451. # serviceAccountName: qbittorrentvpn-restart-serviceaccount
  452. # securityContext:
  453. # runAsUser: 1000
  454. # runAsGroup: 1000
  455. # restartPolicy: OnFailure
  456. # containers:
  457. # - name: qbittorrentvpn-restart
  458. # image: python:3.14
  459. # command:
  460. # - python3
  461. # - -c
  462. # - |
  463. # import subprocess
  464. # import json
  465. # import pprint
  466. # import urllib.parse
  467. # import sys
  468. # import datetime
  469. #
  470. # # Vars to configure
  471. # namespace = 'plex'
  472. # qparams = {'labelSelector': 'app=qbittorrentvpn'}
  473. # max_runtime = datetime.timedelta(days=3)
  474. #
  475. # # serviceaccount/k8s specific vars. Likely don't need to edit these.
  476. # serviceaccount_dir = '/var/run/secrets/kubernetes.io/serviceaccount'
  477. # apiserver = 'https://kubernetes.default.svc'
  478. #
  479. # token = open(f'{serviceaccount_dir}/token').read()
  480. # result = subprocess.run([
  481. # 'curl',
  482. # '--cacert', f'{serviceaccount_dir}/ca.crt',
  483. # '--header', f'Authorization: Bearer {token}',
  484. # '-X', 'GET',
  485. # f'{apiserver}/api/v1/namespaces/{namespace}/pods?{urllib.parse.urlencode(qparams)}'
  486. # ],
  487. # capture_output=True,
  488. # check=True,
  489. # )
  490. #
  491. # pod_list = json.loads(result.stdout)
  492. # items = pod_list.get('items')
  493. # if items is None or len(items) < 1:
  494. # print(f'No pod found? Exiting. {pod_list=}')
  495. # sys.exit(1)
  496. # if len(items) > 1:
  497. # print(f'>1 pod? Exiting. {items=}, {len(items)=}')
  498. # sys.exit(1)
  499. #
  500. # pod = items[0]
  501. # container_statuses = pod['status']['containerStatuses']
  502. # if len(container_statuses) != 1:
  503. # print(f'len(containerStatuses) != 1? Exiting. {container_statuses=}')
  504. # sys.exit(1)
  505. # running = container_statuses[0]['state'].get('running')
  506. # if not running:
  507. # print(f'Pod not running? Exiting. {container_statuses["state"]=}')
  508. #
  509. # started_at = datetime.datetime.fromisoformat(running["startedAt"])
  510. # runtime = datetime.datetime.now(tz=datetime.UTC) - started_at
  511. # print(f'{runtime=} > {max_runtime=} ? {runtime > max_runtime}')
  512. # if runtime > max_runtime:
  513. # pod_name = pod['metadata']['name']
  514. # print(f'Deleting pod {pod_name}')
  515. # result = subprocess.run([
  516. # 'curl',
  517. # '--cacert', f'{serviceaccount_dir}/ca.crt',
  518. # '--header', f'Authorization: Bearer {token}',
  519. # '-X', 'DELETE',
  520. # f'{apiserver}/api/v1/namespaces/{namespace}/pods/{pod_name}'
  521. # ],
  522. # capture_output=True,
  523. # check=True,
  524. # )
  525. #---
  526. #apiVersion: v1
  527. #kind: ServiceAccount
  528. #metadata:
  529. # name: qbittorrentvpn-restart-serviceaccount
  530. # namespace: plex
  531. #---
  532. #apiVersion: rbac.authorization.k8s.io/v1
  533. #kind: RoleBinding
  534. #metadata:
  535. # name: qbittorrentvpn-restart-serviceaccount-edit
  536. # namespace: plex
  537. #roleRef:
  538. # apiGroup: rbac.authorization.k8s.io
  539. # kind: ClusterRole
  540. # name: edit
  541. #subjects:
  542. #- kind: ServiceAccount
  543. # name: qbittorrentvpn-restart-serviceaccount
  544. # namespace: plex