Nginx + FFmpeg 雖然能在 Ubuntu 下實現將 RSTP 轉成 HLS,若能包成 Docker Image,則其他電腦也能輕易使用此 Server,或者 Deploy 到 K8S。
Version
Nginx 1.17.5
FFmpeg 4.1.5
Dockerfile
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY default.conf /etc/nginx/conf.d/
COPY entrypoint.sh /
RUN apk update
RUN apk add ffmpeg -q
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
第 1 行
FROM nginx:alpine
由於要自行安裝 FFmpeg 並建立 image,因此以 nginx:alpine
為基底。
第 2 行
WORKDIR /usr/share/nginx/html
將預設目錄設定在 /usr/share/nginx/html
,如此當 login 進 container 時預設目錄就在此,方便 debug。
第 4 行
COPY default.conf /etc/nginx/conf.d/
將自定義了 Nginx configuration 檔複製進 image。
第 5 行
COPY entrypoint.sh /
將自定義的 entrypoint.sh
複製進 image。
為什麼要使用 script ? 稍後會解釋
第 7 行
RUN apk update
RUN apk add ffmpeg -q
安裝 FFmpeg。
在 alpine 內只能使用
apk
,不能使用apt-get
第 9 行
RUN chmod +x /entrypoint.sh
賦予 entrypoint.sh
有執行權利。
11 行
ENTRYPOINT ["/entrypoint.sh"]
最後執行 entrypoint.sh
。
Nginx Configuration
default.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
add_header Access-Control-Allow-Origin *;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
第 8 行
add_header Access-Control-Allow-Origin *;
避免 m3u8
與 ts
可下載而無法播放。
Shell Script
run.sh
#!/bin/sh
ffmpeg -fflags nobuffer -rtsp_transport tcp -i $RTSP_URL -vsync 0 -copyts -vcodec copy -movflags frag_keyframe+empty_moov -an -hls_flags delete_segments+append_list -f segment -segment_list_flags live -segment_time $SEGMENT_TIME -segment_list_size 3 -segment_format mpegts -segment_list /usr/share/nginx/html/index.m3u8 -segment_list_type m3u8 -segment_list_entry_prefix $NGINX_URL -segment_wrap $TS_MAX_NUM /usr/share/nginx/html/%04d.ts &
nginx -g 'daemon off;'
FFmpeg 有幾個 argument 必須由 user 設定,可在 shell script 以 $
讀取 environment variable,如此就可在 docker-compose 或 K8S 以 environment variable 設定這些 argument。
由於 FFmpeg 與 Nginx 需同時執行,因此在 ffmpeg
之後加上 &
在背景執行。
藉由 shell script 讀取 environment variable 能力,雖然 dockerfile 在 build-time 產生,但也能讀取到 run-time 的 environment variable
Docker Compose
docker-compose.yml
version: "3"
services:
nginx:
image: nginx-ffmpeg:0.0.1
container_name: MyNginx
restart: always
environment:
- RTSP_URL
- NGINX_URL
- TS_MAX_NUM
- SEGMENT_TIME
ports:
- "80:80"
第 8 行
environment:
- RTSP_URL
- NGINX_URL
- TS_MAX_NUM
- SEGMENT_TIME
宣告剛在 shell script 所使用的 environment variable。
.env
RTSP_URL=rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa
NGINX_URL=http://0.0.0.0/
TS_MAX_NUM=3000
SEGMENT_TIME=1
由 user 設定 environment variable。
TS_MAX_NUM
為最大 ts 數量,可藉由此控制所使用檔案空間
SEGMENT_TIME
可用來 tune latency
NPM Script
{
"name": "nginx-ffmpeg",
"version": "0.1.8",
"private": true,
"scripts": {
"d:build": "docker build -t $npm_package_name:$npm_package_version .",
"d:save": "docker save $npm_package_name:$npm_package_version | gzip > $npm_package_name-$npm_package_version.tar.gz",
"d:login": "docker exec -it MyNginx sh",
"d:log": "docker logs MyNginx",
"d:up": "docker-compose up -d",
"d:down": "docker-compose down"
}
}
將常用 Docker command 以 NPM script 管理。
Conclusion
- 若要在 Dockerfile 讀取 user 設定,可藉由 shell script 讀取 environment variable ,並在 Dockerfile 以
ENTRYPOINT
執行該 script