用K8S搭建自动追剧工作流


发布于

|

分类

别人都是用Docker,咱有了K8S,就想啥啥啥都用K8S来解决。

想象一下:你想明天抽时间看部电影。打开一个网页,输入电影名称,点击一个按钮。过一会儿(几小时?),这部电影就会出现在你的影音库里,高清、有海报、有字幕、有剧情介绍、有演职员表,没有广告。——是不是很爽?

对于电影和剧,我还是比较传统地喜欢下载下来看:不卡顿、没广告,就这两点已经秒杀无数流媒体和各种小电影网站了。我是真心不喜欢一边看电影,一边飘着各种博彩和色情的小广告。

之前买了Nas,装了Jellyfin,每次都是从威联通的DownloadStation里搜索、下载,甚至需要手动改下文件名,然后Jellyfin负责后续信息匹配、海报墙抓取、字幕下载。稍微有一点点点麻烦。这个春节看到有一些比较成熟的自动工作流,就硬搞了一番。本来各种教程都是Docker的,但,咱不是搞了个K8S集群嘛,闲着也是闲着,就真的用K8S硬搞了一番(虽说和Docker差别不大,就当K8S的练手了)

基本概念

好多文章一上来就开始说刮削(影片信息和海报抓取)的事儿,看得我云里雾里……反正最终是找到个文章给梳理清楚了。

  • BT/PT
    • 额,似乎现在普通人都只知道「百度网盘」、「阿里云盘」了……不像我们这些老人,都是从FlashGet、网络蚂蚁、BT、电驴啥的一路走过来的……下面只是一些简单的科普。
    • 在古早的时候,大家下载资源都是从原始服务器上下载的。比如服务器带宽只有1M,那么N个人下载的话,就是大家在平分这1M带宽,人越多下载越慢。
    • 在200X年的时候,有一项特别牛X的技术出现了:每个人在下载的时候,也当作了一个临时的「服务器」,下载程序会自动搜索所有可用的「服务器」来下载。所以下载人越多,下载速度越快。这就大概就是BT。
    • 这里面就会出现一大堆新名词了,比如「种子」(对于完全没有接触过BT的人来说,你可以理解为一种特殊的下载链接)、「分享率」(你下载了多少数据?又给别人传了多少数据?不能只下载不上传,那样太自私了)啥啥啥的。
    • BT是公开的,拿到「种子」之后就能下载;PT是私有的,一般需要种子+对应网站的用户信息才能下载,并且下载完成后还要强制上传一段时间以保持更高的分享率和赚积分。
    • 一般来说,我们会用Transmission、qBittorrent甚至Aria2来下载BT资源。你说啥?迅雷?求求放过这些吸血的国产软件吧……
  • 索引器
    • 上面BT/PT解决了「下载」本身的问题。那么,下载链接从哪里拿到?
    • 比如,我们经常去逛一些BT站、下载站。对,就是从这里。但是,世界上有成千上万的BT站和下载站,我还要一个一个网站去搜索,看看这个网站里面有没有我们需要的资源么?
    • 于是有了「索引器」。它的作用就是将各个网站的数据,整理成一个统一的格式,方便后续进行统一的搜索。
    • 一般来说,Prowlarr和Jackett这俩软件用得比较多。但我实际体验下来,可能Prowlarr会更方便一点。后续再说。
    • 你说啥?Google?那个太宽泛了。所谓「术业有专攻」。
  • 整套自动流程工作的核心
    • 这个「核心」的作用是,你告诉它「我想看某某某」,它就会去索引器里面进行搜索。如果搜索到了,那么自动获取种子,调用下载器进行下载,下载完成后对文件进行重新整理(比如将千奇百怪的文件名重命名为某种易于识别的统一格式);如果没搜索到,那么将持续监控上述网站,直到有对应资源的时候自动执行上面那一大堆流程。如果你想看的是个剧,那么它还会持续监控更新,一有新集放出,就会第一时间进行下载。
    • 很不幸的是,常用的有俩东西,Radarr负责电影,Sonarr负责电视剧。这俩软件几乎是一个模子刻出来的,但是功能有所区别,就很让人郁闷。
  • 整合前端
    • 来,跟我一起念:Radarr负责电影,Sonarr负责电视剧,Radarr负责电影,Sonarr负责电视剧,Radarr负责电影,Sonarr负责电视剧。记住了么?——那么我想看《老友记》,应该用啥?
    • 那好,Jellyseerr就是屏蔽了这些东西。你只需要在这里面搜索,它会自动区分是电影还是电视剧,然后提交给对应的核心。
  • 影音库
    • 你下载了的电影和剧,就以文件的形式放在硬盘上啊?想看啥自己双击打开?那这体验太差了。影音库的作用就是把所有文件“展示”出来,比如展示成你常见的海报墙,点进去后有各种剧情介绍、有演职人员表和介绍,还能顺带搞下字幕。
    • 对我来说,更大的作用其实是个“播放器”吧,能用网页播放,还能有播放进度同步,在网页上看了一半,在手机上还能接着看,明天在投影仪上依然能接着看。
    • 如果你下载的是4K甚至更高画质,但你出门在外,传输个几十G的文件不方便,那么影音库还可以实时给你转码成1080P,便于手机上播放。
  • 太麻烦了,有点简单点的东西没有?
    • 有,但我没咋搞懂。似乎都是“索引+核心+前端”集成到了一起,你还需要装下载器、影音库
    • NasTools不更新了,我自己没体验
    • MoviePilot,装上后发现我完全不会添加网站。
    • MovieRobot目前收费了,就没再体验

用K8S搭建

我搭建的是prowlarr+radarr+sonarr+jellyseerr+jellyfin的组合,大致是这个效果

我自己是把Transmission直接装到了nas上,然后其他所有东西都放在我的K8S专用小主机上。

存储

我是将存储分成了两部分:nas存储,和config存储。nas用于存视频文件本身,用nfs的方式挂载给其他应用;config存储直接使用k8s的pv/pvc,反正都那些config也占不了多大地儿。

PV/PVC很好说,随便搞一搞就是了

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: movie-stack
spec:
  resources:
    requests:
      storage: 1Gi
  accessModes:
    - ReadWriteMany

那么之后写Deployment的时候,里面的 volumes 段我是这么写的:

volumes:
  - name: movie-stack # 用于存储各种配置
    persistentVolumeClaim:
      claimName: movie-stack
  - name: nfs-media # NAS的NFS共享,用于存放影视数据
    nfs:
      path: /Media # NFS 共享目录
      server: 192.168.1.250 # IP of my NAS

各种组件

先来写个架子:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: movie-stack
spec:
  replicas: 1
  selector:
    matchLabels:
      app: movie-stack
  template:
    metadata:
      labels:
        app: movie-stack
    spec:
      containers:

看到最后的containers了么?下面各种yaml都是从这里接上的。比如最后可能的形态是:

apiVersion: apps/v1
... # 省略一大堆
spec:
  ... # 省略一大堆
  template:
    ... # 省略一些
    containers:
      - name: flaresolverr
        ... # flaresolverr的各种配置
      - name: prowlarr
        ... # prowlarr 的各种配置
      - ...
    volumes:
      - name: movie-stack
        ...
      - name: nfs-media
        ...

下载器

我用的是transmission。目前主流可以选transmission、qBittorrent,甚至可以选Aria2。如果你有群晖,那么甚至可以直接用群晖自带的download station(威联通的download station似乎不支持)。你还可以直接使用群晖或者威联通软件中心里面安装的Transmission。

我是这样想的:我的k8s集群和nas是完全分开的设备,但是下载器要大量读写存储,所以要离存储近一点。所以我直接把transmission安装在了nas上,用挂载volume的方式直接读写磁盘。比较逆天的是,我用了一块很老的ssd作为临时盘,下载完成后选择直接复制到机械硬盘上,不知道能不能减少一点对机械硬盘的损害。

version: "3"
services:
  transmission:
    image: lscr.io/linuxserver/transmission:latest
    container_name: transmission
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
      - TRANSMISSION_WEB_HOME= #optional
      - USER=admin #optional
      - PASS=password #optional
      - WHITELIST= #optional
      - PEERPORT= #optional
      - HOST_WHITELIST= #optional
    volumes:
      - /share/Media/transmission/seeds:/watch
      - /share/Media/transmission/config:/config
      - /share/Media:/downloads
    ports:
      - 9091:9091
      - 51413:51413
      - 51413:51413/udp
    restart: unless-stopped

然后新建俩文件夹,一个叫movie用于放电影,一个叫series用于放剧集。

索引器

比较知名的有两个,一个是jackett,另一个是prowlarr。我刚刚开始用,只是觉得prowlarr可以把添加进来的网站自动推送给后面的radarr和sonarr,并且它和后续几个应用几乎是同一个模子刻出来的,体验比较统一一些,更何况它还有中文。那,就,它,了。

据说jackett对PT支持会更好一些。但是它没中文,还得把各种站点信息手动复制给radarr和sonarr,不适合我这种懒人,所以我就没管它

containers:
  # 资源索引器(BT)
  - name: prowlarr
    image: linuxserver/prowlarr
    imagePullPolicy: IfNotPresent
    ports:
      - name: prowlarr-web
        containerPort: 9696
        protocol: TCP
    volumeMounts:
      - name: movie-stack
        subPath: prowlarr/config
        mountPath: /config

顺带,有些资源站点设置了CloudFlare质询(5秒盾)来防御DDOS或者爬虫。那么为了能让这些站点也能工作,我们还需要再部署个flaresolverr

containers:
  # FlareSolverr 解决 CloudFlare 5秒盾
  - name: flaresolverr
    image: flaresolverr/flaresolverr
    imagePullPolicy: IfNotPresent
    ports:
      - name: flaresolver-web # 不能超过15个字
        containerPort: 8191
        protocol: TCP

当然,你要是想部署个jackett,也很简单:

containers:
  - name: jackett
    image: linuxserver/jackett
    imagePullPolicy: IfNotPresent
    ports:
      - name: jackett-web
        containerPort: 9117
        protocol: TCP
    volumeMounts:
      - name: movie-stack
        subPath: jackett/config
        mountPath: /config

核心组件

我们需要同时部署radarr和sonarr

containers:
  # 资源刮削器(电影)
  - name: radarr
    image: linuxserver/radarr
    imagePullPolicy: IfNotPresent
    ports:
      - name: radarr-web
        containerPort: 7878
        protocol: TCP
    volumeMounts:
      - name: movie-stack
        subPath: radarr/config
        mountPath: /config
      - name: nfs-media
        mountPath: /media

  # 资源刮削器(电视剧&动漫)
  - name: sonarr
    image: linuxserver/sonarr
    imagePullPolicy: IfNotPresent
    ports:
      - name: sonarr-web
        containerPort: 8989
        protocol: TCP
    volumeMounts:
      - name: movie-stack
        subPath: sonarr/config
        mountPath: /config
      - name: nfs-media
        mountPath: /media

聚合搜索前端

我用的是jellyseerr,它可以和jellyfin配合。

containers:
  # 资源聚合搜索
  - name: jellyseerr
    image: fallenbagel/jellyseerr
    imagePullPolicy: IfNotPresent
    ports:
      - name: jellyseerr-web
        containerPort: 5055
        protocol: TCP
    volumeMounts:
      - name: movie-stack
        subPath: jellyseerr/config
        mountPath: /app/config

影音库

我用的是Jellyfin,更详细的步骤可以参考之前的教程

containers:
  - name: jellyfin
    image: jellyfin/jellyfin
    imagePullPolicy: IfNotPresent
    ports:
      - name: jellyfin-web
        containerPort: 8096
        protocol: TCP
    env:
      - name: TZ
        value: Asia/Shanghai
    securityContext:
      privileged: true 
    volumeMounts:
      - name: movie-stack
        mountPath: /config
        subPath: jellyfin/config
      - name: device-dri
        mountPath: /dev/dri
      - name: nfs-media
        mountPath: /media
volumes:
  - name: device-dri
    hostPath:
      path: /dev/dri
securityContext:
  supplementalGroups:
    - 44 # video
    - 103 # input
    - 106 # render

UID/GID权限

上面几个应用都说,最好不要用默认用户和组来运行。

LinuxServer的应用,需要设置PUID和PGID这两个环境变量。最好再顺手设置一下时区,大概搞成这样:

containers:
  - name: xxx
    image: xxx
    imagePullPolicy: IfNotPresent
    ports:
      ...
    env:
      - name: PUID
        value: "1000"
      - name: PGID
        value: "100"
      - name: TZ
        value: Asia/Shanghai
    volumeMounts:
      ...

jellyfin,需要在container那里设置成这个样子:

containers:
  - name: jellyfin
    image: jellyfin/jellyfin
    imagePullPolicy: IfNotPresent
    ports:
      ...
    env:
      - name: TZ
        value: Asia/Shanghai
      - name: HTTP_PROXY
        value: http://192.168.1.1:7890
      - name: HTTPS_PROXY
        value: http://192.168.1.1:7890
      - name: NO_PROXY
        value: "127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,100.64.0.0/10,localhost,*.local,::ffff:0:0:0:0/1,::ffff:128:0:0:0/1,*.local,*.lan,*.homelab"
    securityContext:
      privileged: true
      runAsUser: 1000
      runAsGroup: 100
    volumeMounts:
      - ...

所以,能不能统一在spec里面设置securityContext?不行。这样的话,LinuxServer的各种应用会报无法启动。看起来好像是LinuxServer里都有一个类似于Loader的东西,它必须是root启动。

Service

都是一些端口啥的。如果你用了jackett,自己补一下就是了。

kind: Service
apiVersion: v1
metadata:
  name: movie-stack
  namespace: docker
spec:
  selector:
    app: movie-stack
  ports:
    - name: jackett-web
      port: 9117
      targetPort: 9117
      protocol: TCP
    - name: prowlarr-web
      port: 9696
      targetPort: 9696
      protocol: TCP
    - name: radarr-web
      port: 7878
      targetPort: 7878
      protocol: TCP
    - name: sonarr-web
      port: 8989
      targetPort: 8989
      protocol: TCP
    - name: jellyseerr-web
      port: 5055
      targetPort: 5055
      protocol: TCP
    - name: jellyfin-web
      port: 8096
      targetPort: 8096
      protocol: TCP
  type: LoadBalancer
  sessionAffinity: ClientIP

Ingress

负责配置域名啊啥的,这样就不用记IP和端口了。如果你用了jackett,同样的照猫画虎自己补一下就是了。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: movie-stack
spec:
  rules:
    - host: prowlarr.homelab
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: movie-stack
                port:
                  name: prowlarr-web
    - host: radarr.homelab
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: movie-stack
                port:
                  name: radarr-web
    - host: sonarr.homelab
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: movie-stack
                port:
                  name: sonarr-web
    - host: jellyseerr.homelab
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: movie-stack
                port:
                  name: jellyseerr-web
    - host: jellyfin.home
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: movie-stack
                port:
                  name: jellyfin-web

感觉写好长……其实有些东西是想用子域名来搞的,但是我不会😂或者是,部署出来后跳转啥啥的处理不好。那就一个东西一个域名吧。

部署

好了,这一大堆东西,呼呼啦啦用kubectl apply -f xxxx.yaml一顿运行,应该就能跑起来了。

连调

prowlarr

  1. 先配置用户名和密码。
  2. 「设置-索引器」那里,添加一个类型为「FlareSolverr」的搜刮器代理,标签随便写,例如叫cloudflare。其他都可以保持默认。
  3. 点击「索引器」,添加索引器。先从BT开始吧就……Privacy选「public」即可。如果遇到提示说需要FlareSolver,那么在「标签」那里填上你刚才创建的FlareSolver标签(比如,我设置的是cloudflare)就好了。

radarr & sonarr

这俩的设置方法一模一样。

  1. 先设置用户名和密码。
  2. 去「设置-媒体管理」那里把自动重命名打开。
  3. 去「下载客户端」那里,把单独部署的Transmission的地址给写上。端口是9091,用户名密码都是你自己设置的。
  4. 这个页面下面有个「远程路径映射」。这里的意思是,你的Transmission和radarr/sonarr不在一起对吧,我现在在Transmission里面可以看到一个/path/to/some/file,那么在radarr/sonarr看来,这个文件的路径会是什么?可能是/some/other/path/file。哎,这俩文件,是同一个么?——有了路径映射,我就可以说,现在有这么一个文件夹,在transmission里面看来路径是/path/to/some,在radarr/sonarr里面看来路径是some/other/path。那么我们点加号,选择对应的下载器,填上路径映射,就好了。
  5. 去「通用」那里,找到「API Key」,复制下来

回到prowlarr继续设置

  1. 去「设置-应用程序」,点击那个大加号,选择radarr或sonarr。
  2. 下面有俩地址,一个是prowlarr地址,一个是radarr或sonarr的地址。如果你是照着我的yaml来走的,那么这一步就都是localhost,端口号也都是默认的。
  3. 最后只需要把API Key填上去,就好了。

jellyfin

它啊,没啥好说的。按照上面的设置,核显解码啥啥啥的应该都能用。

挂上代理之后,建议安装下那些字幕插件。这样可以自动下载字幕。

我看有好多人是单独又部署了个ChineseSubtitle啥啥啥的,我觉得……没啥必要😂Jellyfin+插件就能解决这个事儿了。咱要求没那么高。

jellyseerr

  1. 登录的时候会让你填jellyfin的地址,填http://localhost:8096即可。
  2. 去「设定-jellyfin」,外网地址可以填http://jellyfin.homelab。或者留空也成。
  3. 去「设定-服务器」,分别添加Radarr和Sonarr。主机名和IP地址都直接填localhost。记得勾选上「默认服务器」。

好了,到这里,一切都设置完毕了。在jellyfin里面搜索个还算热门的东西(比如《沙丘》),点击「提交请求」,然后去Radarr或Sonarr里面看看有没有「监控中」,去Transmission里面看看有没有在下载,等下载完毕后看看有没有自动出现在Jellyfin中(可能需要等Jellyfin自动刷新。或者去Jellyfin的后台手动更新一下媒体库试试)


哦对了,我发现用这套东西下载下来的电影都贼大。我自己喜欢1080P的,一部电影大概也就1G,但是这套东西下载下来的1080P要接近40G,恐怖。还没找到怎么减小电影体积。

看着上面各种设置,其实大概15分钟就能搭建起来。真的,和搭建个Wordpress差不多。

另外再次声明,我用K8S部署完全是春节期间吃饱了撑的。其实用Docker部署足以。

参考资料


评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注