castcaster 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +7 -0
  2. data/bin/castcaster +7 -0
  3. data/lib/castcaster/channel.rb +91 -0
  4. data/lib/castcaster/channel_cli.rb +105 -0
  5. data/lib/castcaster/cli.rb +104 -0
  6. data/lib/castcaster/config.rb +60 -0
  7. data/lib/castcaster/deploy/compose.rb +76 -0
  8. data/lib/castcaster/deploy/ffmpeg_services.rb +73 -0
  9. data/lib/castcaster/deploy/k8s.rb +91 -0
  10. data/lib/castcaster/deploy/swarm.rb +57 -0
  11. data/lib/castcaster/deploy/traefik.rb +80 -0
  12. data/lib/castcaster/deploy.rb +10 -0
  13. data/lib/castcaster/engines/base.rb +55 -0
  14. data/lib/castcaster/engines/nginx_rtmp.rb +23 -0
  15. data/lib/castcaster/engines.rb +17 -0
  16. data/lib/castcaster/ffmpeg_profiles.rb +16 -0
  17. data/lib/castcaster/version.rb +3 -0
  18. data/lib/castcaster.rb +17 -0
  19. data/templates/deploy/docker-compose.yml.erb +18 -0
  20. data/templates/deploy/docker-compose.yml.tera +16 -0
  21. data/templates/deploy/docker-stack.yml.erb +29 -0
  22. data/templates/deploy/docker-stack.yml.tera +26 -0
  23. data/templates/deploy/k8s/configmap.yaml.erb +6 -0
  24. data/templates/deploy/k8s/configmap.yaml.tera +6 -0
  25. data/templates/deploy/k8s/deployment.yaml.erb +77 -0
  26. data/templates/deploy/k8s/deployment.yaml.tera +77 -0
  27. data/templates/deploy/k8s/ingress.yaml.erb +35 -0
  28. data/templates/deploy/k8s/ingress.yaml.tera +35 -0
  29. data/templates/deploy/k8s/pvc.yaml.erb +14 -0
  30. data/templates/deploy/k8s/pvc.yaml.tera +14 -0
  31. data/templates/deploy/k8s/service.yaml.erb +37 -0
  32. data/templates/deploy/k8s/service.yaml.tera +37 -0
  33. data/templates/nginx-rtmp/nginx.conf.erb +110 -0
  34. metadata +91 -0
@@ -0,0 +1,80 @@
1
+ module CastCaster
2
+ module Deploy
3
+ class Traefik
4
+ def initialize(cfg)
5
+ @cfg = cfg
6
+ @domain = cfg.fetch('domain', 'stream.example.com')
7
+ @email = cfg.fetch('acme_email', 'admin@example.com')
8
+ end
9
+
10
+ def service_definition
11
+ {
12
+ 'traefik' => {
13
+ 'image' => 'traefik:v3.0',
14
+ 'restart' => 'unless-stopped',
15
+ 'ports' => ['80:80', '443:443'],
16
+ 'depends_on' => ['nginx'],
17
+ 'volumes' => [
18
+ 'traefik-certificates:/certificates',
19
+ "./traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro"
20
+ ],
21
+ 'command' => "\"--providers.file.filename=/etc/traefik/dynamic.yml\",\"--entrypoints.http.address=:80\",\"--entrypoints.https.address=:443\",\"--certificatesresolvers.le.acme.email=#{@email}\",\"--certificatesresolvers.le.acme.storage=/certificates/acme.json\",\"--certificatesresolvers.le.acme.tlschallenge=true\",\"--accesslog\",\"--log\""
22
+ }
23
+ }
24
+ end
25
+
26
+ private
27
+
28
+ def dynamic_config
29
+ <<~YAML
30
+ http:
31
+ routers:
32
+ stream:
33
+ rule: "Host(`#{@domain}`) || Host(`www.#{@domain}`)"
34
+ entrypoints:
35
+ - http
36
+ middlewares:
37
+ - https-redirect
38
+ service: nginx
39
+ stream-secure:
40
+ rule: "Host(`#{@domain}`) || Host(`www.#{@domain}`)"
41
+ entrypoints:
42
+ - https
43
+ tls:
44
+ certresolver: le
45
+ service: nginx
46
+ webui:
47
+ rule: "Host(`manage.#{@domain}`)"
48
+ entrypoints:
49
+ - http
50
+ middlewares:
51
+ - https-redirect
52
+ service: webui
53
+ webui-secure:
54
+ rule: "Host(`manage.#{@domain}`)"
55
+ entrypoints:
56
+ - https
57
+ tls:
58
+ certresolver: le
59
+ service: webui
60
+
61
+ middlewares:
62
+ https-redirect:
63
+ redirectscheme:
64
+ scheme: https
65
+ permanent: true
66
+
67
+ services:
68
+ nginx:
69
+ loadBalancer:
70
+ servers:
71
+ - url: "http://nginx:8080"
72
+ webui:
73
+ loadBalancer:
74
+ servers:
75
+ - url: "http://webui:8081"
76
+ YAML
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'deploy/ffmpeg_services'
2
+ require_relative 'deploy/compose'
3
+ require_relative 'deploy/swarm'
4
+ require_relative 'deploy/k8s'
5
+ require_relative 'deploy/traefik'
6
+
7
+ module CastCaster
8
+ module Deploy
9
+ end
10
+ end
@@ -0,0 +1,55 @@
1
+ require 'erb'
2
+
3
+ class TemplateContext
4
+ def initialize(vars)
5
+ @vars = vars
6
+ end
7
+ def get_binding
8
+ @vars.each { |k, v| singleton_class.define_method(k) { v } }
9
+ binding
10
+ end
11
+ end
12
+
13
+ module CastCaster
14
+ module Engines
15
+ class Base
16
+ attr_reader :name, :config
17
+
18
+ def initialize(name, config)
19
+ @name = name
20
+ @config = config
21
+ end
22
+
23
+ def config_preview
24
+ generate_config
25
+ File.read(config_file)
26
+ end
27
+
28
+ def config_file
29
+ project = @config.fetch('project_dir', Dir.pwd)
30
+ File.join(project, 'nginx', "#{name}.conf")
31
+ end
32
+
33
+ def hls_dir
34
+ @config.fetch('hls_dir', File.join(project_dir, 'hls'))
35
+ end
36
+
37
+ protected
38
+
39
+ def project_dir
40
+ @config.fetch('project_dir', Dir.pwd)
41
+ end
42
+
43
+ def render_template(template_name, vars = {})
44
+ path = File.expand_path(File.join(__dir__, '..', '..', '..', 'templates', template_name))
45
+ erb = ERB.new(File.read(path), trim_mode: '-')
46
+ ctx = TemplateContext.new(vars.merge(config: @config))
47
+ erb.result(ctx.get_binding)
48
+ end
49
+
50
+ def generate_config
51
+ raise NotImplementedError
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,23 @@
1
+ module CastCaster
2
+ module Engines
3
+ class NginxRTMP < Base
4
+ IMAGE = 'ghcr.io/lax/castcaster-nginx'
5
+
6
+ def config_file
7
+ File.join(project_dir, 'nginx', 'nginx.conf')
8
+ end
9
+
10
+ private
11
+
12
+ def generate_config
13
+ FileUtils.mkdir_p(File.join(project_dir, 'nginx'))
14
+ channels = Channel.all
15
+ conf = render_template('nginx-rtmp/nginx.conf.erb',
16
+ hls_dir: '/var/lib/castcaster/hls',
17
+ channels: channels.map(&:to_h)
18
+ )
19
+ File.write(config_file, conf)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'engines/base'
2
+
3
+ module CastCaster
4
+ module Engines
5
+ autoload :NginxRTMP, 'castcaster/engines/nginx_rtmp'
6
+
7
+ REGISTRY = {
8
+ 'nginx-rtmp' => NginxRTMP
9
+ }.freeze
10
+
11
+ def self.create(name, config)
12
+ klass = REGISTRY[name]
13
+ raise CastCaster::Error, "Unknown engine: #{name}" unless klass
14
+ klass.new(name, config)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module CastCaster
2
+ module FFmpegProfiles
3
+ PRESETS = {
4
+ '360p' => { bitrate: '512k', maxrate: '512k', bufsize: '768k', resolution: '640x360', audio: '64k' },
5
+ '480p' => { bitrate: '1024k', maxrate: '1024k', bufsize: '1536k', resolution: '854x480', audio: '96k' },
6
+ '576p' => { bitrate: '1248k', maxrate: '1248k', bufsize: '1872k', resolution: '1024x576', audio: '96k' },
7
+ '720p' => { bitrate: '2048k', maxrate: '2048k', bufsize: '3072k', resolution: '1280x720', audio: '128k' },
8
+ '1080p' => { bitrate: '3000k', maxrate: '3000k', bufsize: '4500k', resolution: '1920x1080',audio: '128k' }
9
+ }.freeze
10
+
11
+ RELAY_DEFAULTS = {
12
+ 'bitrate' => '1000k',
13
+ 'profiles' => ''
14
+ }.freeze
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module CastCaster
2
+ VERSION = '0.0.1'
3
+ end
data/lib/castcaster.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'yaml'
4
+ require 'securerandom'
5
+
6
+ module CastCaster
7
+ class Error < StandardError; end
8
+
9
+ autoload :CLI, 'castcaster/cli'
10
+ autoload :Channel, 'castcaster/channel'
11
+ autoload :ChannelCLI, 'castcaster/channel_cli'
12
+ autoload :Config, 'castcaster/config'
13
+ autoload :Deploy, 'castcaster/deploy'
14
+ autoload :Engines, 'castcaster/engines'
15
+ autoload :FFmpegProfiles,'castcaster/ffmpeg_profiles'
16
+ autoload :VERSION, 'castcaster/version'
17
+ end
@@ -0,0 +1,18 @@
1
+ # Generated by castcaster
2
+ services:
3
+ <% services.each do |name, svc| %>
4
+ <%= name %>:
5
+ image: <%= svc['image'] %>
6
+ restart: <%= svc['restart'] %><% if svc['command'] %>
7
+ command: [<%= svc['command'].is_a?(Array) ? svc['command'].map { |c| "\"#{c}\"" }.join(', ') : svc['command'] %>]<% end %><% if svc['ports'] && !svc['ports'].empty? %>
8
+ ports:<% svc['ports'].each do |p| %>
9
+ - "<%= p %>"<% end %><% end %><% if svc['volumes'] && !svc['volumes'].empty? %>
10
+ volumes:<% svc['volumes'].each do |v| %>
11
+ - "<%= v %>"<% end %><% end %><% if svc['depends_on'] && !svc['depends_on'].empty? %>
12
+ depends_on:<% svc['depends_on'].each do |d| %>
13
+ - <%= d %><% end %><% end %><% if svc['environment'] && !svc['environment'].empty? %>
14
+ environment:<% svc['environment'].each do |k, v| %>
15
+ <%= k %>: "<%= v %>"<% end %><% end %><% if svc['labels'] && !svc['labels'].empty? %>
16
+ labels:<% svc['labels'].each do |k, v| %>
17
+ "<%= k %>": "<%= v %>"<% end %><% end %>
18
+ <% end %>
@@ -0,0 +1,16 @@
1
+ # Generated by castcaster
2
+ services:{% for name, svc in services %}
3
+ {{ name }}:
4
+ image: {{ svc.image }}
5
+ restart: {{ svc.restart }}{% if svc.command %}
6
+ command: [{{ svc.command }}]{% endif %}{% if svc.ports %}
7
+ ports:{% for p in svc.ports %}
8
+ - "{{ p }}"{% endfor %}{% endif %}{% if svc.volumes %}
9
+ volumes:{% for v in svc.volumes %}
10
+ - "{{ v }}"{% endfor %}{% endif %}{% if svc.depends_on %}
11
+ depends_on:{% for d in svc.depends_on %}
12
+ - {{ d }}{% endfor %}{% endif %}{% if svc.environment %}
13
+ environment:{% for k, v in svc.environment %}
14
+ {{ k }}: "{{ v }}"{% endfor %}{% endif %}{% if svc.labels %}
15
+ labels:{% for k, v in svc.labels %}
16
+ "{{ k }}": "{{ v }}"{% endfor %}{% endif %}{% endfor %}
@@ -0,0 +1,29 @@
1
+ # Generated by castcaster (Docker Swarm mode)
2
+ version: '3.8'
3
+ services:
4
+ <% services.each do |name, svc| %>
5
+ <%= name %>:
6
+ image: <%= svc['image'] %>
7
+ restart: <%= svc['restart'] %><% if svc['command'] %>
8
+ entrypoint: [<%= svc['command'].is_a?(Array) ? svc['command'].map { |c| "\"#{c}\"" }.join(', ') : svc['command'] %>]<% end %><% if svc['ports'] && !svc['ports'].empty? %>
9
+ ports:<% svc['ports'].each do |p| %>
10
+ - target: <%= p.split(':')[1] || p.split(':')[0] %>
11
+ published: <%= p.split(':')[0] %>
12
+ mode: host<% end %><% end %><% if svc['volumes'] && !svc['volumes'].empty? %>
13
+ volumes:<% svc['volumes'].each do |v| %>
14
+ - <%= v %><% end %><% end %><% if svc['depends_on'] && !svc['depends_on'].empty? %>
15
+ depends_on:<% svc['depends_on'].each do |d| %>
16
+ - <%= d %><% end %><% end %><% if svc['environment'] && !svc['environment'].empty? %>
17
+ environment:<% svc['environment'].each do |k, v| %>
18
+ <%= k %>: "<%= v %>"<% end %><% end %><% if svc['labels'] && !svc['labels'].empty? %>
19
+ deploy:
20
+ labels:<% svc['labels'].each do |k, v| %>
21
+ <%= k %>: "<%= v %>"<% end %><% end %><% if svc['networks'] && !svc['networks'].empty? %>
22
+ networks:<% svc['networks'].each do |n| %>
23
+ - <%= n %><% end %><% end %>
24
+ <% end %>
25
+ <% if traefik_public %>
26
+ networks:
27
+ traefik-public:
28
+ external: true
29
+ <% end %>
@@ -0,0 +1,26 @@
1
+ # Generated by castcaster (Docker Swarm mode)
2
+ version: '3.8'
3
+ services:{% for name, svc in services %}
4
+ {{ name }}:
5
+ image: {{ svc.image }}
6
+ restart: {{ svc.restart }}{% if svc.command %}
7
+ entrypoint: [{{ svc.command }}]{% endif %}{% if svc.ports %}
8
+ ports:{% for p in svc.ports %}
9
+ {%- set parts = p | split(pat=":") %}
10
+ - target: {{ parts[1] | default(value=parts[0]) }}
11
+ published: {{ parts[0] }}
12
+ mode: host{% endfor %}{% endif %}{% if svc.volumes %}
13
+ volumes:{% for v in svc.volumes %}
14
+ - {{ v }}{% endfor %}{% endif %}{% if svc.depends_on %}
15
+ depends_on:{% for d in svc.depends_on %}
16
+ - {{ d }}{% endfor %}{% endif %}{% if svc.environment %}
17
+ environment:{% for k, v in svc.environment %}
18
+ {{ k }}: "{{ v }}"{% endfor %}{% endif %}{% if svc.labels %}
19
+ deploy:
20
+ labels:{% for k, v in svc.labels %}
21
+ {{ k }}: "{{ v }}"{% endfor %}{% endif %}{% if svc.networks %}
22
+ networks:{% for n in svc.networks %}
23
+ - {{ n }}{% endfor %}{% endif %}{% endfor %}{% if traefik_public %}
24
+ networks:
25
+ traefik-public:
26
+ external: true{% endif %}
@@ -0,0 +1,6 @@
1
+ # Generated by castcaster (Kubernetes)
2
+ # Apply nginx config: kubectl create configmap <%= app %>-config --from-file=nginx.conf=<%= nginx_conf_path %>
3
+ #
4
+ # Apply channel files: kubectl create configmap <%= app %>-channels --from-file=<%= channels_dir %>
5
+ #
6
+ # Then deploy: kubectl apply -f deployment.yaml
@@ -0,0 +1,6 @@
1
+ # Generated by castcaster (Kubernetes)
2
+ # Apply nginx config: kubectl create configmap {{ app }}-config --from-file=nginx.conf={{ nginx_conf_path }}
3
+ #
4
+ # Apply channel files: kubectl create configmap {{ app }}-channels --from-file={{ channels_dir }}
5
+ #
6
+ # Then deploy: kubectl apply -f deployment.yaml
@@ -0,0 +1,77 @@
1
+ # Generated by castcaster (Kubernetes)
2
+ apiVersion: apps/v1
3
+ kind: Deployment
4
+ metadata:
5
+ name: <%= app %>-stream
6
+ labels:
7
+ app: <%= app %>
8
+ component: stream
9
+ spec:
10
+ replicas: 1
11
+ selector:
12
+ matchLabels:
13
+ app: <%= app %>
14
+ component: stream
15
+ template:
16
+ metadata:
17
+ labels:
18
+ app: <%= app %>
19
+ component: stream
20
+ spec:
21
+ containers:
22
+ - name: stream
23
+ image: <%= engine_image %>
24
+ ports:
25
+ - containerPort: 1935
26
+ name: rtmp
27
+ - containerPort: 8080
28
+ name: http
29
+ volumeMounts:
30
+ - name: config
31
+ mountPath: /conf
32
+ - name: hls
33
+ mountPath: <%= hls_dir %>
34
+ volumes:
35
+ - name: config
36
+ configMap:
37
+ name: <%= app %>-config
38
+ - name: hls
39
+ persistentVolumeClaim:
40
+ claimName: <%= app %>-hls
41
+ ---
42
+ apiVersion: apps/v1
43
+ kind: Deployment
44
+ metadata:
45
+ name: <%= app %>-webui
46
+ labels:
47
+ app: <%= app %>
48
+ component: webui
49
+ spec:
50
+ replicas: 1
51
+ selector:
52
+ matchLabels:
53
+ app: <%= app %>
54
+ component: webui
55
+ template:
56
+ metadata:
57
+ labels:
58
+ app: <%= app %>
59
+ component: webui
60
+ spec:
61
+ containers:
62
+ - name: webui
63
+ image: <%= webui_image %>
64
+ ports:
65
+ - containerPort: 8080
66
+ env:
67
+ - name: STREAM_ENGINE
68
+ value: "<%= engine_name %>"
69
+ - name: STREAM_ENGINE_URL
70
+ value: "http://<%= app %>-stream:80"
71
+ volumeMounts:
72
+ - name: channels
73
+ mountPath: /channels
74
+ volumes:
75
+ - name: channels
76
+ configMap:
77
+ name: <%= app %>-channels
@@ -0,0 +1,77 @@
1
+ # Generated by castcaster (Kubernetes)
2
+ apiVersion: apps/v1
3
+ kind: Deployment
4
+ metadata:
5
+ name: {{ app }}-stream
6
+ labels:
7
+ app: {{ app }}
8
+ component: stream
9
+ spec:
10
+ replicas: 1
11
+ selector:
12
+ matchLabels:
13
+ app: {{ app }}
14
+ component: stream
15
+ template:
16
+ metadata:
17
+ labels:
18
+ app: {{ app }}
19
+ component: stream
20
+ spec:
21
+ containers:
22
+ - name: stream
23
+ image: {{ engine_image }}
24
+ ports:
25
+ - containerPort: 1935
26
+ name: rtmp
27
+ - containerPort: 8080
28
+ name: http
29
+ volumeMounts:
30
+ - name: config
31
+ mountPath: /conf
32
+ - name: hls
33
+ mountPath: {{ hls_dir }}
34
+ volumes:
35
+ - name: config
36
+ configMap:
37
+ name: {{ app }}-config
38
+ - name: hls
39
+ persistentVolumeClaim:
40
+ claimName: {{ app }}-hls
41
+ ---
42
+ apiVersion: apps/v1
43
+ kind: Deployment
44
+ metadata:
45
+ name: {{ app }}-webui
46
+ labels:
47
+ app: {{ app }}
48
+ component: webui
49
+ spec:
50
+ replicas: 1
51
+ selector:
52
+ matchLabels:
53
+ app: {{ app }}
54
+ component: webui
55
+ template:
56
+ metadata:
57
+ labels:
58
+ app: {{ app }}
59
+ component: webui
60
+ spec:
61
+ containers:
62
+ - name: webui
63
+ image: {{ webui_image }}
64
+ ports:
65
+ - containerPort: 8080
66
+ env:
67
+ - name: STREAM_ENGINE
68
+ value: "{{ engine_name }}"
69
+ - name: STREAM_ENGINE_URL
70
+ value: "http://{{ app }}-stream:80"
71
+ volumeMounts:
72
+ - name: channels
73
+ mountPath: /channels
74
+ volumes:
75
+ - name: channels
76
+ configMap:
77
+ name: {{ app }}-channels
@@ -0,0 +1,35 @@
1
+ # Generated by castcaster (Kubernetes + Traefik)
2
+ apiVersion: networking.k8s.io/v1
3
+ kind: Ingress
4
+ metadata:
5
+ name: <%= app %>-ingress
6
+ annotations:
7
+ kubernetes.io/ingress.class: traefik
8
+ cert-manager.io/cluster-issuer: letsencrypt-prod
9
+ spec:
10
+ tls:
11
+ - hosts:
12
+ - <%= domain %>
13
+ - manage.<%= domain %>
14
+ secretName: <%= app %>-tls
15
+ rules:
16
+ - host: <%= domain %>
17
+ http:
18
+ paths:
19
+ - pathType: Prefix
20
+ path: "/"
21
+ backend:
22
+ service:
23
+ name: <%= app %>-stream
24
+ port:
25
+ number: 80
26
+ - host: manage.<%= domain %>
27
+ http:
28
+ paths:
29
+ - pathType: Prefix
30
+ path: "/"
31
+ backend:
32
+ service:
33
+ name: <%= app %>-webui
34
+ port:
35
+ number: <%= webui_port %>
@@ -0,0 +1,35 @@
1
+ # Generated by castcaster (Kubernetes + Traefik)
2
+ apiVersion: networking.k8s.io/v1
3
+ kind: Ingress
4
+ metadata:
5
+ name: {{ app }}-ingress
6
+ annotations:
7
+ kubernetes.io/ingress.class: traefik
8
+ cert-manager.io/cluster-issuer: letsencrypt-prod
9
+ spec:
10
+ tls:
11
+ - hosts:
12
+ - {{ domain }}
13
+ - manage.{{ domain }}
14
+ secretName: {{ app }}-tls
15
+ rules:
16
+ - host: {{ domain }}
17
+ http:
18
+ paths:
19
+ - pathType: Prefix
20
+ path: "/"
21
+ backend:
22
+ service:
23
+ name: {{ app }}-stream
24
+ port:
25
+ number: 80
26
+ - host: manage.{{ domain }}
27
+ http:
28
+ paths:
29
+ - pathType: Prefix
30
+ path: "/"
31
+ backend:
32
+ service:
33
+ name: {{ app }}-webui
34
+ port:
35
+ number: {{ webui_port }}
@@ -0,0 +1,14 @@
1
+ # Generated by castcaster (Kubernetes)
2
+ apiVersion: v1
3
+ kind: PersistentVolumeClaim
4
+ metadata:
5
+ name: <%= app %>-hls
6
+ labels:
7
+ app: <%= app %>
8
+ component: storage
9
+ spec:
10
+ accessModes:
11
+ - ReadWriteOnce
12
+ resources:
13
+ requests:
14
+ storage: 10Gi
@@ -0,0 +1,14 @@
1
+ # Generated by castcaster (Kubernetes)
2
+ apiVersion: v1
3
+ kind: PersistentVolumeClaim
4
+ metadata:
5
+ name: {{ app }}-hls
6
+ labels:
7
+ app: {{ app }}
8
+ component: storage
9
+ spec:
10
+ accessModes:
11
+ - ReadWriteOnce
12
+ resources:
13
+ requests:
14
+ storage: 10Gi
@@ -0,0 +1,37 @@
1
+ # Generated by castcaster (Kubernetes)
2
+ apiVersion: v1
3
+ kind: Service
4
+ metadata:
5
+ name: <%= app %>-stream
6
+ labels:
7
+ app: <%= app %>
8
+ component: stream
9
+ spec:
10
+ selector:
11
+ app: <%= app %>
12
+ component: stream
13
+ ports:
14
+ - port: 1935
15
+ targetPort: 1935
16
+ name: rtmp
17
+ - port: <%= web_port %>
18
+ targetPort: 8080
19
+ name: http
20
+ type: LoadBalancer
21
+ ---
22
+ apiVersion: v1
23
+ kind: Service
24
+ metadata:
25
+ name: <%= app %>-webui
26
+ labels:
27
+ app: <%= app %>
28
+ component: webui
29
+ spec:
30
+ selector:
31
+ app: <%= app %>
32
+ component: webui
33
+ ports:
34
+ - port: <%= webui_port %>
35
+ targetPort: 8080
36
+ name: web
37
+ type: LoadBalancer
@@ -0,0 +1,37 @@
1
+ # Generated by castcaster (Kubernetes)
2
+ apiVersion: v1
3
+ kind: Service
4
+ metadata:
5
+ name: {{ app }}-stream
6
+ labels:
7
+ app: {{ app }}
8
+ component: stream
9
+ spec:
10
+ selector:
11
+ app: {{ app }}
12
+ component: stream
13
+ ports:
14
+ - port: 1935
15
+ targetPort: 1935
16
+ name: rtmp
17
+ - port: {{ web_port }}
18
+ targetPort: 8080
19
+ name: http
20
+ type: LoadBalancer
21
+ ---
22
+ apiVersion: v1
23
+ kind: Service
24
+ metadata:
25
+ name: {{ app }}-webui
26
+ labels:
27
+ app: {{ app }}
28
+ component: webui
29
+ spec:
30
+ selector:
31
+ app: {{ app }}
32
+ component: webui
33
+ ports:
34
+ - port: {{ webui_port }}
35
+ targetPort: 8080
36
+ name: web
37
+ type: LoadBalancer