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.
- checksums.yaml +7 -0
- data/bin/castcaster +7 -0
- data/lib/castcaster/channel.rb +91 -0
- data/lib/castcaster/channel_cli.rb +105 -0
- data/lib/castcaster/cli.rb +104 -0
- data/lib/castcaster/config.rb +60 -0
- data/lib/castcaster/deploy/compose.rb +76 -0
- data/lib/castcaster/deploy/ffmpeg_services.rb +73 -0
- data/lib/castcaster/deploy/k8s.rb +91 -0
- data/lib/castcaster/deploy/swarm.rb +57 -0
- data/lib/castcaster/deploy/traefik.rb +80 -0
- data/lib/castcaster/deploy.rb +10 -0
- data/lib/castcaster/engines/base.rb +55 -0
- data/lib/castcaster/engines/nginx_rtmp.rb +23 -0
- data/lib/castcaster/engines.rb +17 -0
- data/lib/castcaster/ffmpeg_profiles.rb +16 -0
- data/lib/castcaster/version.rb +3 -0
- data/lib/castcaster.rb +17 -0
- data/templates/deploy/docker-compose.yml.erb +18 -0
- data/templates/deploy/docker-compose.yml.tera +16 -0
- data/templates/deploy/docker-stack.yml.erb +29 -0
- data/templates/deploy/docker-stack.yml.tera +26 -0
- data/templates/deploy/k8s/configmap.yaml.erb +6 -0
- data/templates/deploy/k8s/configmap.yaml.tera +6 -0
- data/templates/deploy/k8s/deployment.yaml.erb +77 -0
- data/templates/deploy/k8s/deployment.yaml.tera +77 -0
- data/templates/deploy/k8s/ingress.yaml.erb +35 -0
- data/templates/deploy/k8s/ingress.yaml.tera +35 -0
- data/templates/deploy/k8s/pvc.yaml.erb +14 -0
- data/templates/deploy/k8s/pvc.yaml.tera +14 -0
- data/templates/deploy/k8s/service.yaml.erb +37 -0
- data/templates/deploy/k8s/service.yaml.tera +37 -0
- data/templates/nginx-rtmp/nginx.conf.erb +110 -0
- 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,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
|
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
|