Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
b5ed25d542
|
|||
|
448eada6e9
|
|||
|
bdbd9f9e57
|
|||
|
66df86f1aa
|
|||
|
24a5f988a3
|
|||
|
28f93bd9a6
|
|||
|
70847623e8
|
|||
|
68d051c36e
|
|||
|
1456237de2
|
|||
|
fbc5ea4428
|
|||
|
c49b6b979d
|
|||
|
10bf297543
|
|||
|
4d2cfe8030
|
|||
|
ea700fc0fe
|
|||
|
13de506761
|
|||
|
7e5a0bcebd
|
|||
|
2f3bea76f4
|
|||
|
f1bd94b35b
|
|||
|
55bc7ce0f8
|
|||
|
907aea1f9e
|
|||
|
833c5218eb
|
14
.env.example
14
.env.example
@@ -1,5 +1,13 @@
|
|||||||
IPTV_ENV=dev
|
IPTV_ENV=dev
|
||||||
|
|
||||||
REDIS_UID=1000
|
KEYDB_UID=1000
|
||||||
REDIS_GID=1000
|
KEYDB_GID=1000
|
||||||
REDIS_PORT=6379
|
KEYDB_PORT=6379
|
||||||
|
KEYDB_USERNAME=
|
||||||
|
KEYDB_PASSWORD=
|
||||||
|
|
||||||
|
CHECKER_DB=0
|
||||||
|
CHECKER_TTL=1800
|
||||||
|
CHECKER_WAIT=60
|
||||||
|
CHECKER_INIFILE=/app/playlists.ini
|
||||||
|
CHECKER_TAGFILE=/app/channels.json
|
||||||
|
|||||||
21
.gitignore
vendored
21
.gitignore
vendored
@@ -1,16 +1,19 @@
|
|||||||
/.idea
|
/.idea/
|
||||||
/.vscode
|
/.vscode/
|
||||||
downloaded/
|
/docker/keydb/data/*
|
||||||
/svc-*
|
/log/**/*
|
||||||
/tools
|
/iptvc/
|
||||||
/tmp
|
/web/
|
||||||
|
/docs/
|
||||||
|
/playlists/
|
||||||
|
/tools/
|
||||||
|
/.profile/
|
||||||
|
/tmp/
|
||||||
|
|
||||||
*.log
|
|
||||||
.env
|
.env
|
||||||
|
*.log
|
||||||
*.m3u
|
*.m3u
|
||||||
*.m3u.*
|
|
||||||
*.m3u8
|
*.m3u8
|
||||||
*.m3u8.*
|
|
||||||
*.rdb
|
*.rdb
|
||||||
|
|
||||||
!/**/.gitkeep
|
!/**/.gitkeep
|
||||||
|
|||||||
50
README.md
50
README.md
@@ -1,38 +1,54 @@
|
|||||||
# Инфраструктурный слой проекта iptv.axenov.dev
|
# Инфраструктурный слой проекта m3u.su
|
||||||
|
|
||||||
> **Адрес**: https://iptv.axenov.dev
|
Docker-окружение для работы проекта m3u.su.
|
||||||
> **FAQ**: https://iptv.axenov.dev/faq
|
|
||||||
> **Исходный код**: https://git.axenov.dev/IPTV
|
|
||||||
|
|
||||||
Содержит docker-окружение для запуска проекта iptv.axenov.dev.
|
> **Веб-сайт:** [m3u.su](https://m3u.su)
|
||||||
|
> **Документация:** [m3u.su/docs](https://m3u.su/docs)
|
||||||
|
> Исходный код: [git.axenov.dev/IPTV](https://git.axenov.dev/IPTV)
|
||||||
|
> Telegram-канал: [@iptv_aggregator](https://t.me/iptv_aggregator)
|
||||||
|
> Обсуждение: [@iptv_aggregator_chat](https://t.me/iptv_aggregator_chat)
|
||||||
|
> Бот: [@iptv_aggregator_bot](https://t.me/iptv_aggregator_bot)
|
||||||
|
|
||||||
## Использованный стек
|
## Использованный стек
|
||||||
|
|
||||||
* [docker compose](https://docs.docker.com/compose/)
|
* [docker compose](https://docs.docker.com/compose/)
|
||||||
* [php8.3-fpm](https://www.php.net/releases/8.3/ru.php)
|
* [php8.4-fpm](https://www.php.net/releases/8.4/ru.php)
|
||||||
* [nginx](https://nginx.org/ru/)
|
* [nginx](https://nginx.org/ru/)
|
||||||
* [keydb](https://docs.keydb.dev/docs/)
|
* [keydb](https://docs.keydb.dev/docs/)
|
||||||
|
* [iptvc](https://git.axenov.dev/IPTV/iptvc)
|
||||||
* bash
|
* bash
|
||||||
|
|
||||||
## Установка и настройка
|
## Установка и настройка
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://git.axenov.dev/IPTV/docker.git iptv
|
wget -O - https://git.axenov.dev/IPTV/iptv-docker/raw/branch/master/iptv | bash -s - init
|
||||||
cp .env.example .env
|
|
||||||
git clone https://git.axenov.dev/IPTV/svc-main.git
|
|
||||||
cp svc-main/.env.example svc-main/.env
|
|
||||||
docker exec -it iptv-php composer i
|
|
||||||
docker compose up -d --build
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Описание переменных окружения
|
## Cкрипт [`iptv`](./iptv)
|
||||||
|
|
||||||
* `IPTV_ENV` -- окружение для развёртывания: это имена директорий и/или префиксы имён конфигов, которые будут проброшены в контейнеры;
|
Это инструмент, который позволяет быстро управлять локальной средой `lis-docker`:
|
||||||
* `REDIS_UID`, `REDIS_GID` -- ID поьзователя/группы для разрешения владельца файлов и директорий keydb;
|
* инициализировать с нуля, как в примере выше;
|
||||||
* `REDIS_PORT` -- порт keydb, который будет проброшен на хост.
|
* управлять образами и контейнерами среды.
|
||||||
|
|
||||||
|
> Управление средой не всегда удобно через команды git и docker, поэтому рекомендуется использовать `./iptv`.
|
||||||
|
|
||||||
### Reverse-proxy
|
Набери `./iptv help` для справки по использованию.
|
||||||
|
|
||||||
|
При доработке используй [линтер](https://www.shellcheck.net): `shellcheck -s bash iptv`
|
||||||
|
|
||||||
|
## Описание переменных окружения
|
||||||
|
|
||||||
|
* `IPTV_ENV` — окружение для развёртывания: это имена директорий и/или префиксы имён конфигов, которые будут проброшены в контейнеры;
|
||||||
|
* `KEYDB_UID`, `KEYDB_GID` — ID пользователя/группы для разрешения владельца файлов и директорий keydb;
|
||||||
|
* `KEYDB_PORT` — порт keydb, который будет проброшен на хост.
|
||||||
|
* `KEYDB_USERNAME`, `KEYDB_PASSWORD` — реквизиты доступа к keydb;
|
||||||
|
* `CHECKER_DB` — БД keydb для хранения кеша проверенных плейлистов;
|
||||||
|
* `CHECKER_TTL` — время жизни кеша проверенных плейлистов;
|
||||||
|
* `CHECKER_WAIT` — кол-во секунд между запусками iptvc;
|
||||||
|
* `CHECKER_INIFILE` — путь к файлу списка плейлистов внутри контейнера;
|
||||||
|
* `CHECKER_TAGFILE` — путь к файлу списка тегов внутри контейнера.
|
||||||
|
|
||||||
|
## Reverse-proxy
|
||||||
|
|
||||||
На сервере опционально можно настроить реверс-прокси до контейнера веб-сервиса, например, чтобы настроить доступ по доменному имени, изменить порт, подключить SSL-сертификаты или др.
|
На сервере опционально можно настроить реверс-прокси до контейнера веб-сервиса, например, чтобы настроить доступ по доменному имени, изменить порт, подключить SSL-сертификаты или др.
|
||||||
|
|
||||||
|
|||||||
81
compose.yml
81
compose.yml
@@ -1,5 +1,7 @@
|
|||||||
|
name: iptv
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
iptv:
|
iptv-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
x-common-attributes: &common-attributes
|
x-common-attributes: &common-attributes
|
||||||
@@ -12,48 +14,81 @@ x-common-attributes: &common-attributes
|
|||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
- /etc/timezone:/etc/timezone:ro
|
- /etc/timezone:/etc/timezone:ro
|
||||||
networks:
|
networks:
|
||||||
- iptv
|
- iptv-network
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
nginx:
|
||||||
|
<<: *common-attributes
|
||||||
|
container_name: iptv-nginx
|
||||||
|
image: nginx:latest
|
||||||
|
pull_policy: always
|
||||||
|
volumes:
|
||||||
|
- ./docker/nginx/vhost.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
|
- ./log/nginx:/var/log/nginx:rw
|
||||||
|
- ./web:/var/www:ro
|
||||||
|
ports:
|
||||||
|
- 3000:80
|
||||||
|
depends_on:
|
||||||
|
- web
|
||||||
|
|
||||||
keydb:
|
keydb:
|
||||||
<<: *common-attributes
|
<<: *common-attributes
|
||||||
container_name: iptv-keydb
|
container_name: iptv-keydb
|
||||||
image: eqalpha/keydb:latest
|
image: eqalpha/keydb:latest
|
||||||
user: "${REDIS_UID}:${REDIS_GID}"
|
pull_policy: always
|
||||||
|
user: ${KEYDB_UID}:${KEYDB_GID}
|
||||||
|
entrypoint: ["sh", "/entrypoint.sh"]
|
||||||
volumes:
|
volumes:
|
||||||
|
- ./docker/keydb/entrypoint.sh:/entrypoint.sh
|
||||||
- ./docker/keydb/keydb.conf:/etc/keydb/keydb.conf
|
- ./docker/keydb/keydb.conf:/etc/keydb/keydb.conf
|
||||||
- ./docker/keydb/data/:/data:rw
|
- ./docker/keydb/data/:/data:rw
|
||||||
- ./log/keydb:/var/log/keydb/:rw
|
|
||||||
ports:
|
ports:
|
||||||
- "${REDIS_PORT:-6379}:6379"
|
- ${KEYDB_PORT:-6379}:6379
|
||||||
|
|
||||||
php:
|
web:
|
||||||
<<: *common-attributes
|
<<: *common-attributes
|
||||||
container_name: iptv-php
|
container_name: iptv-web
|
||||||
|
build:
|
||||||
|
context: ./web
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: iptv-web-${IPTV_ENV}
|
||||||
environment:
|
environment:
|
||||||
- PHP_IDE_CONFIG=serverName=iptv.local
|
- PHP_IDE_CONFIG=serverName=iptv.local
|
||||||
build:
|
|
||||||
dockerfile: docker/php/${IPTV_ENV}/dockerfile
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/php/${IPTV_ENV}/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro
|
- ./web/docker/${IPTV_ENV}/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro
|
||||||
- ./docker/php/${IPTV_ENV}/php.ini:/usr/local/etc/php/conf.d/php.ini:ro
|
- ./web/docker/${IPTV_ENV}/php.ini:/usr/local/etc/php/conf.d/php.ini:ro
|
||||||
|
- ./playlists/playlists.ini:/var/www/config/playlists.ini
|
||||||
- ./log/php:/var/log/php:rw
|
- ./log/php:/var/log/php:rw
|
||||||
- ./svc-main:/var/www:rw
|
- ./web:/var/www:rw
|
||||||
depends_on:
|
depends_on:
|
||||||
- keydb
|
- keydb
|
||||||
|
|
||||||
nginx:
|
checker:
|
||||||
<<: *common-attributes
|
<<: *common-attributes
|
||||||
container_name: iptv-nginx
|
container_name: iptv-checker
|
||||||
image: nginx:latest
|
image: git.axenov.dev/iptv/iptvc:latest
|
||||||
|
build:
|
||||||
|
context: ./iptvc
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
command: ["check", "--repeat", "0", "--every", "${CHECKER_WAIT:-60}"]
|
||||||
|
environment:
|
||||||
|
- CACHE_ENABLED=true
|
||||||
|
- CACHE_HOST=iptv-keydb
|
||||||
|
- CACHE_PORT=${KEYDB_PORT:-6379}
|
||||||
|
- CACHE_USERNAME=${KEYDB_USERNAME}
|
||||||
|
- CACHE_PASSWORD=${KEYDB_PASSWORD}
|
||||||
|
- CACHE_DB=${CHECKER_DB:-0}
|
||||||
|
- CACHE_TTL=${CHECKER_TTL:-1800}
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/nginx/vhost.conf:/etc/nginx/conf.d/default.conf:ro
|
- ./playlists/playlists.ini:/app/playlists.ini
|
||||||
- ./log/nginx:/var/log/nginx:rw
|
- ./playlists/channels.json:/app/channels.json
|
||||||
- ./svc-main:/var/www:ro
|
|
||||||
|
docs:
|
||||||
|
<<: *common-attributes
|
||||||
|
container_name: iptv-docs
|
||||||
|
image: git.axenov.dev/iptv/iptv-docs:latest
|
||||||
|
build:
|
||||||
|
context: ./docs
|
||||||
|
dockerfile: Dockerfile
|
||||||
ports:
|
ports:
|
||||||
- "8080:80"
|
- 3001:80
|
||||||
links:
|
|
||||||
- php
|
|
||||||
depends_on:
|
|
||||||
- php
|
|
||||||
|
|||||||
4
docker/keydb/entrypoint.sh
Normal file
4
docker/keydb/entrypoint.sh
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
trap 'echo "Received SIGTERM, saving KeyDB data..."; keydb-cli SAVE; echo "Data saved. Exiting."; exit 0' TERM
|
||||||
|
echo "[entrypoint] Starting KeyDB..."
|
||||||
|
exec keydb-server /etc/keydb/keydb.conf "$@"
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,14 @@
|
|||||||
server {
|
server {
|
||||||
server_name iptv.local;
|
server_name iptv.local;
|
||||||
listen 80;
|
listen 80;
|
||||||
root /var/www/public;
|
index index.html index.php;
|
||||||
index index.php;
|
# access_log /var/log/nginx/access.log;
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
add_header Access-Control-Allow-Origin '*';
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
|
||||||
|
add_header Access-Control-Allow-Headers "*";
|
||||||
|
add_header Access-Control-Allow-Credentials "true";
|
||||||
|
|
||||||
gzip on;
|
gzip on;
|
||||||
gzip_vary on;
|
gzip_vary on;
|
||||||
gzip_proxied any;
|
gzip_proxied any;
|
||||||
@@ -10,17 +16,31 @@ server {
|
|||||||
gzip_buffers 16 8k;
|
gzip_buffers 16 8k;
|
||||||
gzip_http_version 1.1;
|
gzip_http_version 1.1;
|
||||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||||
location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
|
|
||||||
access_log off;
|
location = /docs {
|
||||||
expires max;
|
return 301 /docs/;
|
||||||
log_not_found off;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location ^~ /docs/ {
|
||||||
|
proxy_pass http://docs:80/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_read_timeout 300;
|
||||||
|
proxy_connect_timeout 300;
|
||||||
|
proxy_send_timeout 300;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
|
root /var/www/public;
|
||||||
try_files $uri $uri/ /index.php$is_args$args;
|
try_files $uri $uri/ /index.php$is_args$args;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ \.php$ {
|
location ~ \.php$ {
|
||||||
|
root /var/www/public;
|
||||||
try_files $uri /index.php =404;
|
try_files $uri /index.php =404;
|
||||||
fastcgi_pass php:9000;
|
fastcgi_pass web:9000;
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
@@ -28,6 +48,20 @@ server {
|
|||||||
fastcgi_hide_header X-Powered-By;
|
fastcgi_hide_header X-Powered-By;
|
||||||
fastcgi_read_timeout 300;
|
fastcgi_read_timeout 300;
|
||||||
proxy_read_timeout 300;
|
proxy_read_timeout 300;
|
||||||
|
proxy_connect_timeout 300;
|
||||||
|
proxy_send_timeout 300;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
location ~* \.(jpg|jpeg|gif|css|png|ttf|woff|svg|js|ico)$ {
|
||||||
|
access_log off;
|
||||||
|
expires max;
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(jpg|jpeg|gif|css|png|ttf|woff|svg|js|ico)$ {
|
||||||
|
root /var/www/public;
|
||||||
|
access_log off;
|
||||||
|
expires max;
|
||||||
|
log_not_found off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
FROM php:8.3-fpm
|
|
||||||
|
|
||||||
RUN apt update && \
|
|
||||||
apt upgrade -y && \
|
|
||||||
apt install -y git unzip 7zip
|
|
||||||
|
|
||||||
# https://pecl.php.net/package/xdebug
|
|
||||||
# https://pecl.php.net/package/redis
|
|
||||||
RUN pecl channel-update pecl.php.net && \
|
|
||||||
pecl install xdebug-3.4.1 redis && \
|
|
||||||
docker-php-ext-enable redis && \
|
|
||||||
mkdir -p /var/run/php && \
|
|
||||||
mkdir -p /var/log/php && \
|
|
||||||
chmod -R 777 /var/log/php
|
|
||||||
|
|
||||||
COPY --from=composer /usr/bin/composer /usr/local/bin/composer
|
|
||||||
|
|
||||||
EXPOSE 9000
|
|
||||||
WORKDIR /var/www
|
|
||||||
CMD composer install
|
|
||||||
ENTRYPOINT php-fpm
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[PHP]
|
|
||||||
error_reporting = E_ALL
|
|
||||||
expose_php = Off
|
|
||||||
file_uploads = Off
|
|
||||||
max_execution_time=-1
|
|
||||||
memory_limit = 512M
|
|
||||||
|
|
||||||
[opcache]
|
|
||||||
opcache.enable = 1
|
|
||||||
opcache.enable_cli = 1
|
|
||||||
opcache.memory_consumption = 128
|
|
||||||
opcache.max_accelerated_files = 30000
|
|
||||||
opcache.revalidate_freq = 0
|
|
||||||
opcache.jit_buffer_size = 64M
|
|
||||||
opcache.jit = tracing
|
|
||||||
|
|
||||||
[xdebug]
|
|
||||||
; https://xdebug.org/docs/all_settings
|
|
||||||
zend_extension = xdebug.so
|
|
||||||
xdebug.mode = debug
|
|
||||||
xdebug.start_with_request = yes
|
|
||||||
xdebug.trigger_value = go
|
|
||||||
xdebug.client_host = host.docker.internal
|
|
||||||
xdebug.REQUEST = *
|
|
||||||
xdebug.SESSION = *
|
|
||||||
xdebug.SERVER = *
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
[www]
|
|
||||||
user = www-data
|
|
||||||
group = www-data
|
|
||||||
listen = 127.0.0.1:9000
|
|
||||||
pm = dynamic
|
|
||||||
pm.max_children = 5
|
|
||||||
pm.start_servers = 2
|
|
||||||
pm.min_spare_servers = 1
|
|
||||||
pm.max_spare_servers = 3
|
|
||||||
pm.max_requests = 50
|
|
||||||
pm.status_path = /status
|
|
||||||
ping.path = /ping
|
|
||||||
ping.response = pong
|
|
||||||
access.log = /var/log/php/$pool.access.log
|
|
||||||
;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{milli}d %{kilo}M %C%%"
|
|
||||||
; chroot = /var/www
|
|
||||||
; chdir = /var/www
|
|
||||||
php_flag[display_errors] = on
|
|
||||||
php_admin_value[error_log] = /var/log/php/$pool.error.log
|
|
||||||
php_admin_flag[log_errors] = on
|
|
||||||
php_admin_value[memory_limit] = 512M
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
FROM php:8.3-fpm
|
|
||||||
|
|
||||||
RUN apt update && \
|
|
||||||
apt upgrade -y && \
|
|
||||||
apt install -y git
|
|
||||||
|
|
||||||
# https://pecl.php.net/package/redis
|
|
||||||
RUN pecl channel-update pecl.php.net && \
|
|
||||||
pecl install redis && \
|
|
||||||
docker-php-ext-enable redis && \
|
|
||||||
mkdir -p /var/log/php && \
|
|
||||||
chmod -R 777 /var/log/php && \
|
|
||||||
git config --global --add safe.directory /var/www
|
|
||||||
|
|
||||||
COPY --from=composer /usr/bin/composer /usr/local/bin/composer
|
|
||||||
|
|
||||||
USER www-data
|
|
||||||
EXPOSE 9000
|
|
||||||
WORKDIR /var/www
|
|
||||||
CMD composer install --no-dev --optimize-autoloader
|
|
||||||
ENTRYPOINT php-fpm
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
[PHP]
|
|
||||||
error_reporting = E_ALL
|
|
||||||
expose_php = Off
|
|
||||||
file_uploads = Off
|
|
||||||
memory_limit = 512M
|
|
||||||
; upload_max_filesize=10M
|
|
||||||
; post_max_size=10M
|
|
||||||
|
|
||||||
[opcache]
|
|
||||||
opcache.enable = 1
|
|
||||||
opcache.enable_cli = 1
|
|
||||||
opcache.memory_consumption = 128
|
|
||||||
opcache.max_accelerated_files = 30000
|
|
||||||
opcache.revalidate_freq = 0
|
|
||||||
opcache.jit_buffer_size = 64M
|
|
||||||
opcache.jit = tracing
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
[www]
|
|
||||||
user = www-data
|
|
||||||
group = www-data
|
|
||||||
listen = 127.0.0.1:9000
|
|
||||||
pm = dynamic
|
|
||||||
pm.max_children = 5
|
|
||||||
pm.start_servers = 2
|
|
||||||
pm.min_spare_servers = 1
|
|
||||||
pm.max_spare_servers = 3
|
|
||||||
pm.max_requests = 50
|
|
||||||
pm.status_path = /status
|
|
||||||
ping.path = /ping
|
|
||||||
ping.response = pong
|
|
||||||
access.log = /var/log/php/$pool.access.log
|
|
||||||
;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{milli}d %{kilo}M %C%%"
|
|
||||||
; chroot = /var/www
|
|
||||||
; chdir = /var/www
|
|
||||||
php_flag[display_errors] = on
|
|
||||||
php_admin_value[error_log] = /var/log/php/$pool.error.log
|
|
||||||
php_admin_flag[log_errors] = on
|
|
||||||
php_admin_value[memory_limit] = 512M
|
|
||||||
872
iptv
872
iptv
@@ -1,32 +1,852 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
# https://gist.github.com/anthonyaxenov/89c99e09ddb195985707e2b24a57257d
|
##########################################################################################
|
||||||
|
# Скрипт управления проектом iptv.axenov.dev
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 Антон Аксенов <anthonyaxenov@gmail.com>
|
||||||
|
# MIT License, see LICENSE file for more info.
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
CONTAINER="iptv-php" # the name of the container in which to 'exec' something
|
# shellcheck disable=SC2015,SC2103,SC2164,SC2155
|
||||||
CONFIG="$(dirname $([ -L $0 ] && readlink -f $0 || echo $0))/docker-compose.yml" # path to compose yml file
|
set -o pipefail
|
||||||
CMD="docker compose -f $CONFIG" # docker-compose command
|
|
||||||
APP_URL='http://localhost:8080/'
|
|
||||||
|
|
||||||
open_browser() {
|
########################################################
|
||||||
if which xdg-open > /dev/null; then
|
# Служебные исходные переменные
|
||||||
xdg-open "$1" </dev/null >/dev/null 2>&1 & disown
|
########################################################
|
||||||
elif which gnome-open > /dev/null; then
|
|
||||||
gnome-open "$1" </dev/null >/dev/null 2>&1 & disown
|
if [[ "${BASH_SOURCE[*]}" ]]; then
|
||||||
|
[[ "${BASH_SOURCE[0]}" != "$0" ]] && echo "*** Команда source iptv запрещена ***" && exit 40
|
||||||
|
ROOT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
else
|
||||||
|
# script running from stdin
|
||||||
|
ROOT_PATH="$(pwd)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
IPTV_PROJECTS=("web" "playlists")
|
||||||
|
IPTV_GITEA_URL_SSH="git@git.axenov.dev:IPTV"
|
||||||
|
IPTV_GITEA_URL_HTTPS="https://git.axenov.dev/IPTV"
|
||||||
|
IPTV_DOCKER_URL_SSH="$IPTV_GITEA_URL_SSH/iptv-docker.git"
|
||||||
|
|
||||||
|
for sig in SIGHUP SIGINT SIGQUIT SIGABRT SIGKILL SIGTERM SIGTSTP; do
|
||||||
|
# https://faculty.cs.niu.edu/~hutchins/csci480/signals.htm
|
||||||
|
# shellcheck disable=SC2064
|
||||||
|
trap "set +x && echo && echo && echo '*** Прервано сигналом $sig, остановка ***' && exit" $sig
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ $IPTV_DEBUG == 1 ]] && DEBUG_MODE=1
|
||||||
|
[[ $IPTV_DEBUG -gt 1 ]] && set -x
|
||||||
|
|
||||||
|
RAW_ARGS=("$@")
|
||||||
|
COMMAND="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Ввод/вывод
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
which tput > /dev/null 2>&1 && [ "$(tput -T"$TERM" colors)" -gt 8 ] && CAN_USE_COLORS=1 || CAN_USE_COLORS=0
|
||||||
|
IPTV_COLORS=${IPTV_COLORS:-$CAN_USE_COLORS}
|
||||||
|
[[ $IPTV_COLORS == 1 ]] && FBOLD="$(tput bold)" || FBOLD=''
|
||||||
|
[[ $IPTV_COLORS == 1 ]] && FDIM="$(tput dim)" || FDIM=''
|
||||||
|
[[ $IPTV_COLORS == 1 ]] && FRESET="$(tput sgr0)" || FRESET=''
|
||||||
|
|
||||||
|
ask() {
|
||||||
|
IFS= read -rp "$(print "${FBOLD}$1" ): " "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
print() {
|
||||||
|
echo -e "$*${FRESET}"
|
||||||
|
}
|
||||||
|
|
||||||
|
debug() {
|
||||||
|
[[ "$DEBUG_MODE" != 1 ]] && return
|
||||||
|
|
||||||
|
if [ "$2" ]; then
|
||||||
|
print "${FDIM}> ${FUNCNAME[1]:-?}():${BASH_LINENO:-?}\t$* ${FRESET}" >&2
|
||||||
|
else
|
||||||
|
print "${FDIM}> $* ${FRESET}" >&2
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$1" in
|
var_dump() {
|
||||||
'' | 'help' ) echo -e "Provide one of operations: \t init, start, stop, up, down, restart, rebuild, open";
|
debug "$1 = ${!1}"
|
||||||
echo "Otherwise all args will passed to 'docker exec -ti $CONTAINER ...'" ;;
|
}
|
||||||
'init' ) cp src/.env.example src/.env && \
|
|
||||||
./iptv up && \
|
inform() {
|
||||||
./iptv composer i && \
|
print "$*${FRESET}"
|
||||||
echo "Project started successfully! $APP_URL" ;;
|
}
|
||||||
'up' ) $CMD up -d --build && ./iptv open ;; # build and start containers
|
|
||||||
'down' ) $CMD down --remove-orphans ;; # stop and remove containers
|
subtitle() {
|
||||||
'start' ) $CMD start ;; # start containers
|
echo
|
||||||
'stop' ) $CMD stop ;; # stop containers
|
inform "${FBOLD}$*${FRESET}"
|
||||||
'restart' ) $CMD stop && $CMD start ;; # restart containers
|
}
|
||||||
'rebuild' ) $CMD down --remove-orphans && $CMD up -d --build ;; # rebuild containers
|
|
||||||
'open' ) open_browser $APP_URL && echo -e "\nYou're welcome!\n\t$APP_URL" ;;
|
title() {
|
||||||
* ) docker exec -ti $CONTAINER $* ;; # exec anything else in container
|
subtitle "$@"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
success() {
|
||||||
|
print "${FBOLD}$*${FRESET}"
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
print "${FBOLD}Внимание!${FRESET} $*${FRESET}"
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
print "${FBOLD}Ошибка:${FRESET} $*${FRESET}" >&2
|
||||||
|
print_stacktrace
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
error "${1:-halted}"
|
||||||
|
exit "${2:-255}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_stacktrace() {
|
||||||
|
[[ "$DEBUG_MODE" != 1 ]] && return
|
||||||
|
|
||||||
|
local i
|
||||||
|
local stack_size=${#FUNCNAME[@]}
|
||||||
|
debug "Callstack:"
|
||||||
|
# for (( i=$stack_size-1; i>=1; i-- )); do
|
||||||
|
for (( i=1; i<stack_size; i++ )); do
|
||||||
|
local func="${FUNCNAME[$i]}"
|
||||||
|
[ "$func" = "" ] && func=MAIN
|
||||||
|
local linen="${BASH_LINENO[$(( i - 1 ))]}"
|
||||||
|
local src="${BASH_SOURCE[$i]}"
|
||||||
|
[ "$src" = "" ] && src=non_file_source
|
||||||
|
debug " at $func $src:$linen"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Базовые хелперы
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
# Возвращает абсолютный путь до $1
|
||||||
|
abspath() {
|
||||||
|
realpath -q "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Проверяет, указывает ли путь $1 на директорию
|
||||||
|
is_dir() {
|
||||||
|
[ -d "$(abspath "$1")" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Проверяет, указывает ли путь $1 на файл
|
||||||
|
is_file() {
|
||||||
|
[ -f "$(abspath "$1")" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Проверяет существование функции с именем $1
|
||||||
|
is_function() {
|
||||||
|
declare -F "$1" > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Проверяет соответствие строки $1 регулярному выражению $2
|
||||||
|
regex_match() {
|
||||||
|
[[ "$1" =~ ^$2$ ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Проверяет соответствие строки $1 регулярному выражению $2 с помощью grep
|
||||||
|
grep_match() {
|
||||||
|
printf "%s" "$1" | grep -qE "$2" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Возвращает название текущей ОС
|
||||||
|
get_os() {
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Linux*) echo Linux ;;
|
||||||
|
Darwin*) echo Macos ;;
|
||||||
|
CYGWIN*) echo Cygwin ;;
|
||||||
|
MINGW*) echo MinGw ;;
|
||||||
|
MSYS_NT*) echo Git ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Обрезает пробельные символы с начала и с конца строки
|
||||||
|
trim() {
|
||||||
|
echo "$1" | xargs
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Функции парсинга аргументов
|
||||||
|
# https://gist.axenov.dev/anthony/sh-args
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
# Парсит короткий аргумент
|
||||||
|
arg() {
|
||||||
|
[ "$1" ] || { echo "Argument name is not specified!" >&2 && exit 1; }
|
||||||
|
local arg_name="${1:0:1}" # first character of argument name to find
|
||||||
|
local is_flag="$2" || 0 # 1 if we need just find a flag, 0 to get a value
|
||||||
|
local var_name="$3" || 0 # variable name to return value into or 0 to echo it in stdout
|
||||||
|
local value= # initialize empty value to check if we found one later
|
||||||
|
local arg_found=0 # marker of found argument
|
||||||
|
|
||||||
|
for idx in "${!RAW_ARGS[@]}"; do # going through all args
|
||||||
|
local arg_search=${RAW_ARGS[idx]} # get current argument
|
||||||
|
|
||||||
|
# skip $arg_search if it starts with '--' or letter
|
||||||
|
grep_match "$arg_search" "^(\w|--)" && continue
|
||||||
|
|
||||||
|
# clear $arg_search from special and duplicate characters, e.g. 'fas-)dfs' will become 'fasd'
|
||||||
|
local arg_chars="$(printf "%s" "$arg_search" \
|
||||||
|
| tr -s "[$arg_search]" 2>/dev/null \
|
||||||
|
| tr -d "[:punct:][:blank:]" 2>/dev/null)"
|
||||||
|
|
||||||
|
# if $arg_name is not one of $arg_chars the skip it
|
||||||
|
grep_match "-$arg_name" "^-[$arg_chars]$" || continue
|
||||||
|
arg_found=1
|
||||||
|
|
||||||
|
# then return '1'|'0' back into $value if we need flag or next arg value otherwise
|
||||||
|
[[ "$is_flag" == 1 ]] && value=1 || value="${RAW_ARGS[idx+1]}"
|
||||||
|
break
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ "$is_flag" == 1 ]] && [[ -z "$value" ]] && value=0;
|
||||||
|
|
||||||
|
# if value we found is empty or looks like another argument then exit with error message
|
||||||
|
if [ "$arg_found" = 1 ] && ! grep_match "$value" "^[[:graph:]]+$" || grep_match "$value" "^--?\w+$"; then
|
||||||
|
echo "ERROR: Argument '-$arg_name' must have correct value!" >&2 && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# return '$value' back into $var_name (if exists) or echo in stdout
|
||||||
|
[ "$var_name" ] && eval "$var_name='$value'" || echo "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Парсит длинный аргумент
|
||||||
|
argl() {
|
||||||
|
[ "$1" ] || { echo "Argument name is not specified!" >&2 && exit 1; }
|
||||||
|
local arg_name="$1" # argument name to find
|
||||||
|
local is_flag="$2" || 0 # 1 if we need just find a flag, 0 to get a value
|
||||||
|
local var_name="$3" || 0 # variable name to return value into or 0 to echo it in stdout
|
||||||
|
local value= # initialize empty value to check if we found one later
|
||||||
|
local arg_found=0 # marker of found argument
|
||||||
|
|
||||||
|
for idx in "${!RAW_ARGS[@]}"; do # going through all args
|
||||||
|
local arg_search="${RAW_ARGS[idx]}" # get current argument
|
||||||
|
|
||||||
|
if [ "$arg_search" = "--$arg_name" ]; then # if current arg begins with two dashes
|
||||||
|
# then return '1' back into $value if we need flag or next arg value otherwise
|
||||||
|
[[ "$is_flag" == 1 ]] && value=1 || value="${RAW_ARGS[idx+1]}"
|
||||||
|
break # stop the loop
|
||||||
|
elif grep_match "$arg_search" "^--$arg_name=.+$"; then # check if $arg like '--foo=bar'
|
||||||
|
# then return '1' back into $value if we need flag or part from '=' to arg's end as value otherwise
|
||||||
|
[[ "$is_flag" == 1 ]] && value=1 || value="${arg_search#*=}"
|
||||||
|
break # stop the loop
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ "$is_flag" == 1 ]] && [[ -z "$value" ]] && value=0;
|
||||||
|
|
||||||
|
# if value we found is empty or looks like another argument then exit with error message
|
||||||
|
if [ "$arg_found" = 1 ] && ! grep_match "$value" "^[[:graph:]]+$" || grep_match "$value" "^--?\w+$"; then
|
||||||
|
echo "ERROR: Argument '--$arg_name' must have correct value!" >&2 && exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
# return '$value' back into $var_name (if exists) or echo in stdout
|
||||||
|
[ "$var_name" ] && eval "$var_name='$value'" || echo "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Функции контроля системных пакетов
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
# Проверяет наличие команды в системе
|
||||||
|
installed() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Проверяет наличие пакета в системе
|
||||||
|
installed_pkg() {
|
||||||
|
dpkg --list | grep -qw "ii $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Требует наличие пакета в системе
|
||||||
|
require() {
|
||||||
|
sw=()
|
||||||
|
for package in "$@"; do
|
||||||
|
# if ! installed "$package" && ! installed_pkg "$package"; then
|
||||||
|
if ! installed "$package"; then
|
||||||
|
sw+=("$package")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ ${#sw[@]} -gt 0 ]; then
|
||||||
|
die "Это ПО должно быть установлено в системе:\n${sw[*]}" 200
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Функции для работы с git
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
# Проверяет, является ли директория git-репозиторием
|
||||||
|
git.is_repo() {
|
||||||
|
require git
|
||||||
|
is_dir "$1/" && is_dir "$1/.git/"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Клонирует репозиторий
|
||||||
|
git.clone() {
|
||||||
|
require git
|
||||||
|
cmd="git clone $*"
|
||||||
|
debug "Команда: $cmd"
|
||||||
|
$cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Функции для работы с docker
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
# Вызывает корректную команду docker compose
|
||||||
|
docker.compose() {
|
||||||
|
require docker
|
||||||
|
|
||||||
|
args=${*/--profiles=[a-zA-Z_,0-9]*/}
|
||||||
|
|
||||||
|
if docker compose &>/dev/null; then
|
||||||
|
local cmd="docker compose $args"
|
||||||
|
elif installed_pkg "docker-compose"; then
|
||||||
|
local cmd="docker-compose $args"
|
||||||
|
warn
|
||||||
|
warn "docker-compose v1 устарел и не поддерживается, его поведение непредсказуемо."
|
||||||
|
warn "Обнови docker согласно документации: https://docs.docker.com/engine/install/"
|
||||||
|
warn
|
||||||
|
else
|
||||||
|
error "Должен быть установлен docker-compose-plugin!"
|
||||||
|
die "Установи docker согласно документации: https://docs.docker.com/engine/install/" 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
debug "Команда: $cmd"
|
||||||
|
$cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
# Выводит информацию о контейнере
|
||||||
|
docker.inspect() {
|
||||||
|
cmd="docker inspect $*"
|
||||||
|
debug "Команда: $cmd"
|
||||||
|
$cmd 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Строит образы согласно файлов iptv-docker/docker-compose*.yml
|
||||||
|
docker.build_base_images() {
|
||||||
|
# for file in compose*.yml; do
|
||||||
|
# subtitle "Построение базовых образов: $file"
|
||||||
|
# docker.compose -f "$file" build
|
||||||
|
# done
|
||||||
|
subtitle "Построение образов"
|
||||||
|
docker.compose build
|
||||||
|
[ ! -d web/cache/views ] && mkdir -p web/cache/views
|
||||||
|
|
||||||
|
success "Базовые образы построены"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Выполняет команду в контейнере от имени root
|
||||||
|
docker.exec() {
|
||||||
|
cmd="docker exec -u root -it $*"
|
||||||
|
debug "Команда: $cmd"
|
||||||
|
$cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
# Выполняет команду в контейнере от имени www-data
|
||||||
|
docker.exec_www() {
|
||||||
|
cmd="docker exec -u www-data -it $*"
|
||||||
|
debug "Команда: $cmd"
|
||||||
|
$cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Хелперы для обработки команд
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
# Возвращает ssh-адрес к репозиторию проекта
|
||||||
|
project_url_ssh() {
|
||||||
|
echo "$IPTV_GITEA_URL_SSH/$1.git"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Возвращает https-адрес к репозиторию проекта
|
||||||
|
project_url_https() {
|
||||||
|
echo "$IPTV_GITEA_URL_HTTPS/$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Копирует .env.example в .env, если возможно
|
||||||
|
prepare_dot_env() {
|
||||||
|
if is_file .env.example && ! is_file .env; then
|
||||||
|
debug "Копирование .env.example => .env"
|
||||||
|
cp .env.example .env
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Клонирует проект
|
||||||
|
project_clone() {
|
||||||
|
local repo_url="$1"; shift
|
||||||
|
local repo_path="$1"; shift
|
||||||
|
|
||||||
|
if git.is_repo "$repo_path"; then
|
||||||
|
debug "Репозиторий уже существует: $repo_path"
|
||||||
|
else
|
||||||
|
debug "Репозиторий будет склонирован: $repo_path"
|
||||||
|
git.clone "$repo_url" "$repo_path" "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Проверяет передачу флагов -h|--help в команду и выводит справку
|
||||||
|
process_help_arg() {
|
||||||
|
command="${FUNCNAME[1]}"
|
||||||
|
need_help=$(arg help 1)
|
||||||
|
[[ "$need_help" -eq 0 ]] && need_help=$(argl help 1)
|
||||||
|
[[ "$need_help" -eq 1 ]] && help "$command"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Выводит список сервисов
|
||||||
|
list_services_compose() {
|
||||||
|
services=$(docker.compose --profile full config --services | sort)
|
||||||
|
IFS=$'\n' sorted=("${services[@]}")
|
||||||
|
unset IFS
|
||||||
|
for name in "${sorted[@]}"; do
|
||||||
|
print " $name"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Возвращает корректное название сервиса из композа
|
||||||
|
find_service_compose() {
|
||||||
|
svc="$1"
|
||||||
|
[ -z "$svc" ] && die "неизвестный сервис" 2
|
||||||
|
|
||||||
|
for known in $(docker.compose config --services); do
|
||||||
|
if [ "$known" = "$svc" ]; then
|
||||||
|
debug "Сервис '$known' найден в композе"
|
||||||
|
echo "$known"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
debug "Сервис '$svc' не найден в композе"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Возвращает корректные названия сервисов из композа
|
||||||
|
find_services_compose() {
|
||||||
|
local services=''
|
||||||
|
|
||||||
|
[ "$*" ] && for svc in "$@"; do
|
||||||
|
grep_match "$svc" "^--?.*" && continue
|
||||||
|
svc="$(find_service_compose "${svc/iptv-/}")"
|
||||||
|
services="$services $svc"
|
||||||
|
done
|
||||||
|
|
||||||
|
trim "$services"
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Главные функции обработки команд
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
# Инициализирует репозиторий iptv-docker и все вложенные в него
|
||||||
|
init() {
|
||||||
|
process_help_arg
|
||||||
|
local docker_repo_path=$ROOT_PATH
|
||||||
|
local basename=$(basename "$docker_repo_path")
|
||||||
|
if [ ! "$basename" = "iptv-docker" ]; then
|
||||||
|
# это наиболее надёжный способ понять откуда запускается скрипт
|
||||||
|
docker_repo_path="$docker_repo_path/iptv-docker"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#TODO установка ПО
|
||||||
|
|
||||||
|
subtitle "Подготовка локальной среды..."
|
||||||
|
|
||||||
|
project_clone "$IPTV_DOCKER_URL_SSH" "$docker_repo_path"
|
||||||
|
|
||||||
|
cd "$docker_repo_path"
|
||||||
|
prepare_dot_env
|
||||||
|
|
||||||
|
local counter=1
|
||||||
|
local repo_count=${#IPTV_PROJECTS[@]}
|
||||||
|
for repo_name in "${IPTV_PROJECTS[@]}"; do
|
||||||
|
local project_repo_path="$docker_repo_path/$repo_name"
|
||||||
|
subtitle "[$counter/$repo_count] Подготовка репозитория ${FBOLD}$repo_name${FRESET}..."
|
||||||
|
|
||||||
|
local project_repo_url=$(project_url_https "$repo_name")
|
||||||
|
debug "Известная ссылка на репозиторий: $project_repo_url"
|
||||||
|
|
||||||
|
project_clone "$project_repo_url" "$project_repo_path"
|
||||||
|
cd "$project_repo_path"
|
||||||
|
|
||||||
|
prepare_dot_env
|
||||||
|
|
||||||
|
cd - >/dev/null
|
||||||
|
success "Репозиторий $repo_name готов"
|
||||||
|
counter=$((counter+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
success "Локальная среда развёрнута: $docker_repo_path"
|
||||||
|
|
||||||
|
cd "$docker_repo_path"
|
||||||
|
docker.build_base_images && up
|
||||||
|
|
||||||
|
success "Проверь корректность значений, указанных в файлах .env, и выполни ${FBOLD}./iptv rebuild${FRESET} при необходимости."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Создаёт и запускает контейнеры
|
||||||
|
up() {
|
||||||
|
process_help_arg
|
||||||
|
subtitle "Создание и запуск контейнеров"
|
||||||
|
|
||||||
|
local services=''
|
||||||
|
[ "$*" ] && services="$(find_services_compose "$@")"
|
||||||
|
|
||||||
|
[ ! -d web/cache/views ] && mkdir -p web/cache/views
|
||||||
|
docker.compose up "$services" --build --detach --remove-orphans && \
|
||||||
|
success 'Среда запущена успешно'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Запускает созданные контейнеры
|
||||||
|
start() {
|
||||||
|
process_help_arg
|
||||||
|
subtitle "Запуск созданных ранее контейнеров"
|
||||||
|
|
||||||
|
profiles="$(argl profiles 0)"
|
||||||
|
|
||||||
|
local services=''
|
||||||
|
[ "$*" ] && services="$(find_services_compose "$@")"
|
||||||
|
|
||||||
|
COMPOSE_PROFILES="$profiles" docker.compose start "$services" && \
|
||||||
|
success 'Среда запущена успешно'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Останавливает и удаляет контейнеры
|
||||||
|
down() {
|
||||||
|
process_help_arg
|
||||||
|
subtitle "Остановка и удаление контейнеров"
|
||||||
|
|
||||||
|
local services=''
|
||||||
|
[ "$*" ] && services="$(find_services_compose "$@")"
|
||||||
|
|
||||||
|
docker.compose down "$services" --remove-orphans && \
|
||||||
|
success 'Среда остановлена успешно'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Останавливает контейнеры
|
||||||
|
stop() {
|
||||||
|
process_help_arg
|
||||||
|
subtitle "Остановка контейнеров"
|
||||||
|
|
||||||
|
profiles=$(argl profiles 0)
|
||||||
|
[[ -z "$profiles" ]] && profiles="full"
|
||||||
|
|
||||||
|
local services=''
|
||||||
|
[ "$*" ] && services="$(find_services_compose "$@")"
|
||||||
|
|
||||||
|
COMPOSE_PROFILES="$profiles" docker.compose stop "$services" && \
|
||||||
|
success 'Среда остановлена успешно'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Останавливает, удаляет, создаёт и запускает контейнеры
|
||||||
|
rebuild() {
|
||||||
|
process_help_arg
|
||||||
|
|
||||||
|
is_full=$(arg full 1)
|
||||||
|
[ "$is_full" = 0 ] && is_full=$(argl full 1)
|
||||||
|
|
||||||
|
[ -n "$*" ] && down "$@" || down
|
||||||
|
[ "$is_full" = 1 ] && docker.build_base_images
|
||||||
|
|
||||||
|
up "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Останавливает и запускает созданные контейнеры
|
||||||
|
restart() {
|
||||||
|
process_help_arg
|
||||||
|
stop "$@" && start "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Останавливает среду, удаляет все контейнеры и образы
|
||||||
|
purge() {
|
||||||
|
process_help_arg
|
||||||
|
|
||||||
|
subtitle "Удаление docker-образов и контейнеров"
|
||||||
|
|
||||||
|
down
|
||||||
|
docker rmi "$(docker image list | grep iptv- | awk '{print $3}')"
|
||||||
|
docker system prune --all --force
|
||||||
|
|
||||||
|
success 'Образы удалены успешно'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Выполняет команду в контейнере
|
||||||
|
exec() {
|
||||||
|
process_help_arg
|
||||||
|
as_root=0
|
||||||
|
svc="$1"
|
||||||
|
regex_match "$svc" "--?r(oot)?" && { as_root=1; shift; svc="$1"; }
|
||||||
|
|
||||||
|
svc_correct="iptv-$(find_service_compose "$svc")"
|
||||||
|
command=("${@:2}")
|
||||||
|
regex_match "${command[0]}" "--?r(oot)?" && { as_root=1; unset "command[0]"; }
|
||||||
|
|
||||||
|
[[ -z "${command[*]}" ]] && die "не указана команда для выполнения в контейнере"
|
||||||
|
|
||||||
|
#TODO многострочные команды прокидываются корректно, но выполняется только первая строка?
|
||||||
|
if [[ "$as_root" == 1 ]]; then
|
||||||
|
docker.exec "$svc_correct" "${command[*]}"
|
||||||
|
else
|
||||||
|
docker.exec_www "$svc_correct" "${command[*]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Выводит логи сервиса
|
||||||
|
logs() {
|
||||||
|
process_help_arg
|
||||||
|
[ -z "$1" ] && die "не указан сервис" 8
|
||||||
|
|
||||||
|
svc=$(find_service_compose "$1")
|
||||||
|
[ -z "$svc" ] && die "неизвестный сервис" 3
|
||||||
|
|
||||||
|
subtitle "Логи сервиса $svc"
|
||||||
|
|
||||||
|
shift
|
||||||
|
cmd="docker logs $svc $*"
|
||||||
|
debug "Команда: $cmd"
|
||||||
|
$cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
# Выводит статистику потребления ресурсов контейнерами
|
||||||
|
stats() {
|
||||||
|
subtitle "Состояние контейнеров"
|
||||||
|
|
||||||
|
docker.compose stats "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Команды справки
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
help() {
|
||||||
|
print "${FBOLD}Среда разработки iptv.axenov.dev"
|
||||||
|
is_function "help.$1" && help."$1" && exit
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv КОМАНДА [АРГУМЕНТЫ]"
|
||||||
|
print
|
||||||
|
print "Доступные КОМАНДЫ:"
|
||||||
|
print " h|help - вывести это сообщение и выйти"
|
||||||
|
print " init - инициализировать окружение"
|
||||||
|
print " u|up - построить образы, контейнеры и запустить их"
|
||||||
|
print " start - запустить построенные ранее контейнеры"
|
||||||
|
print " d|down - остановить и удалить контейнеры"
|
||||||
|
print " stop - остановить контейнеры"
|
||||||
|
print " r|rebuild - выполнить 'down' и 'up'"
|
||||||
|
print " restart - выполнить 'stop' и 'start'"
|
||||||
|
print " purge - удалить контейнеры и образы"
|
||||||
|
print " update - обновить репозитории"
|
||||||
|
print " info - вывести версии ПО контейнера сервиса"
|
||||||
|
print " f|flame - сгенерировать флеймграф из трейса xdebug"
|
||||||
|
print " fix - исправить некоторые проблемы окружения"
|
||||||
|
print " exec - выполнить произвольную команду в контейнере"
|
||||||
|
print " logs - вывести логи контейнера"
|
||||||
|
print " profiles - вывести список профилей"
|
||||||
|
print " services - вывести список сервисов профиля"
|
||||||
|
print " info - вывести информацию о ПО в контейнере"
|
||||||
|
print " status - вывести статус сервиса и его репозитория"
|
||||||
|
print " stats - вывести информацию о потреблении ресурсов окружением"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести справку по любой КОМАНДЕ"
|
||||||
|
print
|
||||||
|
print "Любая КОМАНДА может также иметь свои АРГУМЕНТЫ."
|
||||||
|
print "Некоторые КОМАНДЫ могут также поддерживать АРГУМЕНТЫ 'docker' и его субсомманд."
|
||||||
|
print
|
||||||
|
print "См. './iptv help КОМАНДА' или './iptv КОМАНДА -h|--help' для справки."
|
||||||
|
}
|
||||||
|
|
||||||
|
help.help() {
|
||||||
|
print "КОМАНДА: help"
|
||||||
|
print "Отображает справку по скрипту и его командам."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv help [КОМАНДА]"
|
||||||
|
print " ./iptv КОМАНДА [-h|--help]"
|
||||||
|
print
|
||||||
|
print "Если КОМАНДА не указана, будет отображена справка по скрипту со списком допустимых КОМАНД."
|
||||||
|
}
|
||||||
|
|
||||||
|
help.init() {
|
||||||
|
print "КОМАНДА: init"
|
||||||
|
print "Инициализирует окружение разработки. Клонирует репозиторий iptv-docker, клонирует"
|
||||||
|
print "внутрь исходники всех сервисов и создаёт заготовки файлов .env для них. Можно"
|
||||||
|
print "использовать для подгрузки свежих сервисов, ещё не развёрнутых локально."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv init [АРГУМЕНТЫ]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -n|--name ИМЯ - установить ИМЯ в качестве имени пользователя git"
|
||||||
|
print " -e|--email ПОЧТА - установить ПОЧТУ в качестве email пользователя git"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
print
|
||||||
|
print "Если --name и/или --email не переданы, то данные будут взяты из глобального конфига git."
|
||||||
|
print
|
||||||
|
print "ИМЯ и ПОЧТА проверяются на валидность:"
|
||||||
|
print " - ИМЯ должно содержать имя и фамилию на кириллице, разделённые пробелом;"
|
||||||
|
print " - ПОЧТА должна быть корпоративной (@bars.group или @bars-open.ru)."
|
||||||
|
print
|
||||||
|
print "Если ИМЯ или ПОЧТА некорректны, КОМАНДА завершится с ошибкой и предложением передать"
|
||||||
|
print "явно ИМЯ и ПОЧТУ с помощью аргументов."
|
||||||
|
print
|
||||||
|
print "После выполнения КОМАНДЫ необходимо указать корректные данные в файлах .env сервисов."
|
||||||
|
}
|
||||||
|
|
||||||
|
help.up() {
|
||||||
|
print "КОМАНДА: up"
|
||||||
|
print "Выполняет перестроение образов (включая базовые, при необходимости)"
|
||||||
|
print "создание и запуск контейнеров."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv up [АРГУМЕНТЫ] [СЕРВИСЫ...]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
print
|
||||||
|
print "Если указан один и более СЕРВИСОВ, то КОМАНДА будет применена только к ним."
|
||||||
|
print
|
||||||
|
print "СЕРВИСЫ можно передавать без префикса 'iptv-'"
|
||||||
|
}
|
||||||
|
|
||||||
|
help.start() {
|
||||||
|
print "КОМАНДА: start"
|
||||||
|
print "Выполняет запуск построенных ранее контейнеров."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv start [АРГУМЕНТЫ] [СЕРВИСЫ...]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
print
|
||||||
|
print "Если указан один и более СЕРВИСОВ, то КОМАНДА будет применена только к ним."
|
||||||
|
print
|
||||||
|
print "СЕРВИСЫ можно передавать без префикса 'iptv-'"
|
||||||
|
}
|
||||||
|
|
||||||
|
help.down() {
|
||||||
|
print "КОМАНДА: down"
|
||||||
|
print "Выполняет остановку и удаление запущенных контейнеров."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv down [АРГУМЕНТЫ] [СЕРВИСЫ...]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
print
|
||||||
|
print "Если указан один и более СЕРВИСОВ, то КОМАНДА будет применена только к ним."
|
||||||
|
print
|
||||||
|
print "СЕРВИСЫ можно передавать без префикса 'iptv-'"
|
||||||
|
}
|
||||||
|
|
||||||
|
help.stop() {
|
||||||
|
print "КОМАНДА: stop"
|
||||||
|
print "Выполняет остановку запущенных контейнеров."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv stop [АРГУМЕНТЫ] [СЕРВИСЫ...]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
print
|
||||||
|
print "Если указан один и более СЕРВИСОВ, то КОМАНДА будет применена только к ним."
|
||||||
|
print
|
||||||
|
print "СЕРВИСЫ можно передавать без префикса 'iptv-'"
|
||||||
|
}
|
||||||
|
|
||||||
|
help.rebuild() {
|
||||||
|
print "КОМАНДА: rebuild"
|
||||||
|
print "Выполняет 'down' и 'up'."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv rebuild [АРГУМЕНТЫ] [СЕРВИСЫ...]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
print
|
||||||
|
print "Если указан один и более СЕРВИСОВ, то КОМАНДА будет применена только к ним."
|
||||||
|
print
|
||||||
|
print "СЕРВИСЫ можно передавать без префикса 'iptv-'"
|
||||||
|
}
|
||||||
|
|
||||||
|
help.restart() {
|
||||||
|
print "КОМАНДА: restart"
|
||||||
|
print "Выполняет 'stop' и 'start'."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv restart [АРГУМЕНТЫ] [СЕРВИСЫ...]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
print
|
||||||
|
print "Если указан один и более СЕРВИСОВ, то КОМАНДА будет применена только к ним."
|
||||||
|
print
|
||||||
|
print "СЕРВИСЫ можно передавать без префикса 'iptv-'"
|
||||||
|
}
|
||||||
|
|
||||||
|
help.purge() {
|
||||||
|
print "КОМАНДА: purge"
|
||||||
|
print "Удаляет все образы и контейнеры 'iptv-*'."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv purge [АРГУМЕНТЫ]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
}
|
||||||
|
|
||||||
|
help.logs() {
|
||||||
|
print "КОМАНДА: logs"
|
||||||
|
print "Выводит логи указанного СЕРВИСА."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv logs СЕРВИС [АРГУМЕНТЫ]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
print
|
||||||
|
print "Поддерживаются АРГУМЕНТЫ 'docker logs'."
|
||||||
|
print
|
||||||
|
print "СЕРВИС можно передавать без префикса 'iptv-'"
|
||||||
|
}
|
||||||
|
|
||||||
|
help.stats() {
|
||||||
|
print "КОМАНДА: stats"
|
||||||
|
print "Выводит потребление ресурсов окружением разработки."
|
||||||
|
print
|
||||||
|
print "Использование:"
|
||||||
|
print " ./iptv stats [АРГУМЕНТЫ]"
|
||||||
|
print
|
||||||
|
print "Доступные АРГУМЕНТЫ:"
|
||||||
|
print " -h|--help - вывести это сообщение и выйти"
|
||||||
|
print
|
||||||
|
print "Поддерживаются АРГУМЕНТЫ 'docker compose stats'."
|
||||||
|
print "Рекомендуется использовать вместе с '--no-stream'."
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Точка входа
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
debug "Директория выполнения: $ROOT_PATH/$IPTV_DIR"
|
||||||
|
|
||||||
|
case "$COMMAND" in
|
||||||
|
h|help ) help "$1" ;;
|
||||||
|
init ) init "$@" ;;
|
||||||
|
u|up ) up "$@" ;;
|
||||||
|
start ) start "$@" ;;
|
||||||
|
d|down ) down "$@" ;;
|
||||||
|
stop ) stop "$@" ;;
|
||||||
|
r|rebuild ) rebuild "$@" ;;
|
||||||
|
restart ) restart "$@" ;;
|
||||||
|
exec ) exec "$@" ;;
|
||||||
|
purge ) purge ;;
|
||||||
|
logs ) logs "$@" ;;
|
||||||
|
stats ) stats "$@" ;;
|
||||||
|
* ) die "неизвестная команда. Смотри './iptv help' для справки." ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
Reference in New Issue
Block a user