Added folders as well...

This commit is contained in:
2024-07-04 13:15:34 +02:00
commit f72d79958d
62 changed files with 3248 additions and 0 deletions
+134
View File
@@ -0,0 +1,134 @@
version: "3.7"
services:
bazarr:
container_name: bazarr
image: ghcr.io/hotio/bazarr:latest
network_mode: bridge
restart: unless-stopped
logging:
driver: json-file
ports:
- "6767:6767"
environment:
- PUID=992
- PGID=979
- UMASK=002
- TZ=Europe/Stockholm
volumes:
- "bazarr:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/var/cloud/Media/Film:/media/movies"
- "/var/cloud/Media/Serier:/media/tv"
- "/var/cloud/Media/Trashcan:/media/trash"
- "/var/cloud/transmission/downloads:/data/torrents"
lidarr:
container_name: lidarr
image: ghcr.io/hotio/lidarr:latest
network_mode: bridge
restart: unless-stopped
logging:
driver: json-file
ports:
- "8686:8686"
environment:
- PUID=993
- PGID=979
- UMASK=002
- TZ=Europe/Stockholm
volumes:
- "lidarr:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/var/cloud/Media/Mp3:/media/music"
- "/var/cloud/Media/Trashcan:/media/trash"
- "/var/cloud/transmission/downloads:/data/torrents"
prowlarr:
container_name: prowlarr
image: ghcr.io/hotio/prowlarr:latest
network_mode: bridge
restart: unless-stopped
logging:
driver: json-file
ports:
- "9696:9696"
environment:
- PUID=988
- PGID=979
- UMASK=002
- TZ=Europe/Stockholm
volumes:
- "prowlarr:/config"
- "/etc/localtime:/etc/localtime:ro"
radarr:
container_name: radarr
image: ghcr.io/hotio/radarr:latest
network_mode: bridge
restart: unless-stopped
logging:
driver: json-file
ports:
- "7878:7878"
environment:
- PUID=990
- PGID=979
- UMASK=002
- TZ=Europe/Stockholm
volumes:
- "radarr:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/var/cloud/transmission/downloads:/data/torrents"
- "/var/cloud/Media/Film:/media/movies"
- "/var/cloud/Media/Kids:/media/movies2"
- "/var/cloud/Media/Trashcan/Movies:/media/trash"
readarr:
container_name: readarr
image: ghcr.io/hotio/readarr:latest
network_mode: bridge
restart: unless-stopped
logging:
driver: json-file
ports:
- "8787:8787"
environment:
- PUID=991
- PGID=979
- UMASK=002
- TZ=Europe/Stockholm
volumes:
- "readarr:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/var/cloud/transmission/downloads:/data/torrents"
- "/var/cloud/Media/Books:/media/books"
- "/var/cloud/Media/Trashcan/Books:/media/trash"
sonarr:
container_name: sonarr
image: ghcr.io/hotio/sonarr:latest
network_mode: bridge
restart: unless-stopped
logging:
driver: json-file
ports:
- "8989:8989"
environment:
- PUID=989
- PGID=979
- UMASK=002
- TZ=Europe/Stockholm
volumes:
- "sonarr:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/var/cloud/Media/Serier:/media/tv"
- "/var/cloud/transmission/downloads:/data/torrents"
- "/var/cloud/Media/Trashcan/Series:/media/trash"
volumes:
bazarr:
driver: local
lidarr:
driver: local
prowlarr:
driver: local
radarr:
driver: local
readarr:
driver: local
sonarr:
driver: local
+327
View File
@@ -0,0 +1,327 @@
version: "3.6"
services:
# image used to index torrent links from the internet
prowlarr:
image: linuxserver/prowlarr:latest
container_name: arr-suite-prowlarr
deploy:
placement:
constraints: [node.labels.media_disk == true ]
environment:
- PUID=988
- PGID=979
- UMASK=002
- TZ=Europe/Stockholm
volumes:
- "prowlarr:/config"
- "/etc/localtime:/etc/localtime:ro"
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/prowlarr:/config # database and Prowlarr configs
expose:
- 9696/tcp # web ui
ports:
- 9696:9696/tcp # web ui
restart: unless-stopped
networks:
- traefik-public
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public
- "traefik.http.routers.arr-prowlarr.rule=(Host(`niefelheim.com`) && Path(`/prowlarr`))"
- traefik.http.services.arr-prowlarr.loadbalancer.server.port=9696
#- traefik.http.routers.prowlarr.entrypoints=web
#- traefik.http.routers.prowlarr_https.entrypoints=web-secure
- 'traefik.http.routers.arr-prowlarr_https.rule=(Host(`niefelheim.com`) && Path(`/prowlarr`))'
- traefik.http.routers.arr-prowlarr_https.tls=true
- traefik.http.routers.arr-prowlarr_https.tls.certresolver=le
# # Optional part for traefik middlewares
# - traefik.http.routers.prowlarr.middlewares=local-ipwhitelist@file
# image used to scan for tv shows
sonarr:
image: linuxserver/sonarr:latest
container_name: arr-suite-sonarr
deploy:
placement:
constraints: [node.labels.media_disk == true ]
environment:
- PUID=989
- PGID=979
- TZ=Europe/Stockholm
- UMASK=002
volumes:
- "sonarr:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/var/cloud/Media/Serier:/media/tv"
- "/var/cloud/transmission/downloads:/data/torrents"
- "/var/cloud/Media/Trashcan/Series:/media/trash"
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/sonarr:/config # database and Radarr configs
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/media:/media # location of media and qbittorrent download folder
expose:
- 8989/tcp # web ui
ports:
- 8989:8989/tcp # web ui
restart: unless-stopped
networks:
- traefik-public
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public
- "traefik.http.routers.sonarr.rule=(Host(`niefelheim.com`) && Path(`/sonarr`))"
- traefik.http.services.sonarr.loadbalancer.server.port=8989
# # Optional part for traefik middlewares
# - traefik.http.routers.sonarr.middlewares=local-ipwhitelist@file
# image used to scan for movies
radarr:
image: linuxserver/radarr:latest
container_name: arr-suite-radarr
deploy:
placement:
constraints: [node.labels.media_disk == true ]
environment:
- PUID=990
- PGID=979
- UMASK=002
- TZ=Europe/Stockholm
volumes:
- "radarr:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/var/cloud/transmission/downloads:/data/torrents"
- "/var/cloud/Media/Film:/media/movies"
- "/var/cloud/Media/Kids:/media/movies2"
- "/var/cloud/Media/Trashcan/Movies:/media/trash"
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/radarr:/config
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/media:/media # location of media and qbittorrent download folder
expose:
- 7878/tcp # web ui
ports:
- 7878:7878/tcp # web ui
restart: unless-stopped
networks:
- traefik-public
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- "traefik.http.routers.radarr.rule=(Host(`niefelheim.com`) && Path(`/radarr`))"
- traefik.constraint-label=traefik-public
- traefik.http.services.radarr.loadbalancer.server.port=7878
# # Optional part for traefik middlewares
# - traefik.http.routers.radarr.middlewares=local-ipwhitelist@file
# image used to scan for music
lidarr:
image: linuxserver/lidarr:latest
container_name: arr-suite-lidarr
deploy:
placement:
constraints: [node.label.media_disk == true ]
environment:
- PUID=993
- PGID=979
- TZ=Europe/Stockholm
volumes:
- "lidarr:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/var/cloud/Media/Mp3:/media/music"
- "/var/cloud/Media/Trashcan:/media/trash"
- "/var/cloud/transmission/downloads:/data/torrents"
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/lidarr:/config
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/media:/media # location of media and qbittorrent download folder
expose:
- 8686/tcp # web ui
ports:
- 8686:8686/tcp # web ui
restart: unless-stopped
networks:
- traefik-public
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- "traefik.http.routers.lidarr.rule=(Host(`niefelheim.com`) && Path(`/lidarr`))"
- traefik.constraint-label=traefik-public
- traefik.http.services.lidarr.loadbalancer.server.port=8686
# # Optional part for traefik middlewares
# - traefik.http.routers.lidarr.middlewares=local-ipwhitelist@file
# image used to scan for books
readarr:
image: linuxserver/readarr:develop
container_name: arr-suite-readarr
deploy:
placement:
constraints: [node.label.media_disk == true ]
environment:
- PUID=991
- PGID=979
- TZ=Europe/Stockholm
volumes:
- "readarr:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/var/cloud/transmission/downloads:/data/torrents"
- "/var/cloud/Media/Books:/media/books"
- "/var/cloud/Media/Trashcan/Books:/media/trash"
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/readarr:/config
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/media:/media # location of media and qbittorrent download folder
expose:
- 8787/tcp # web ui
ports:
- 8787:8787/tcp # web ui
restart: unless-stopped
networks:
- traefik-public
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public
- "traefik.http.routers.readarr.rule=(Host(`niefelheim.com`) && Path(`/readarr`))"
- traefik.http.services.readarr.loadbalancer.server.port=8787
# # Optional part for traefik middlewares
# - traefik.http.routers.readarr.middlewares=local-ipwhitelist@file
# image used to bypass cloudflare for prowlarr
#flaresolverr:
#image: flaresolverr/flaresolverr:latest
# container_name: arr-suite-flaresolverr
# environment:
# - LOG_LEVEL=info
# - LOG_HTML=false
# - CAPTCHA_SOLVER=none
# - TZ=Europe/Stockholm
# expose:
# - 8191/tcp # listening port for selenium
# restart: unless-stopped
#networks:
# - traefik-public
# image used for vpn killswitch network
# gluetun:
# image: qmcgaw/gluetun:latest
# container_name: arr-suite-gluetun
# cap_add:
# - NET_ADMIN
# ports:
# - 8080:8080 # qbittorrent http web ui
# environment:
# see https://github.com/qdm12/gluetun-wiki for more details
# example envs based on https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/mullvad.md
# - VPN_SERVICE_PROVIDER=mullvad # define the vpn provider
#- VPN_TYPE=wireguard # define the vpn protocol to use
#- WIREGUARD_PRIVATE_KEY=wOEI9rqqbDwnN8/Bpp22sVz48T71vJ4fYmFWujulwUU= # define your wireguard private key here
#- WIREGUARD_ADDRESSES=10.64.222.21/32 # define the ipv4 vpn network subnet here
#volumes:
#- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/gluetun:/gluetun
#restart: unless-stopped
#networks:
# - traefik-public
#labels:
# - traefik.enable=true
# - traefik.docker.network=traefik-public
# - traefik.http.routers.qbittorrent.rule=Host(`qbittorrent.example.com`)
# - traefik.http.services.qbittorrent.loadbalancer.server.port=8080
# # Optional part for traefik middlewares
# - traefik.http.routers.qbittorrent.middlewares=local-ipwhitelist@file
# image used to download stuff; run over gluetun network (vpn killswitch)
# qbittorrent:
# image: linuxserver/qbittorrent:latest
# container_name: arr-suite-qbittorrent
# environment:
# - PUID=1000
# - PGID=1000
# - TZ=Europe/Stockholm
# - WEBUI_PORT=8080
# volumes:
# - ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/qbittorrent:/config
# - ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/media/downloads:/media/downloads
# depends_on:
# - gluetun
# network_mode: container:arr-suite-gluetun # use the gluetun container network (vpn killswitch)
# restart: unless-stopped
# image used to manage media and stream it
#emby:
# image: linuxserver/emby:latest
# container_name: arr-suite-emby
# environment:
# - PUID=1000
# - PGID=1000
# - TZ=Europe/Stockholm
# volumes:
# - ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/emby:/config # emby data storage location; can grow very large
# - ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/media:/data # media goes here
# #- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/emby/lib:/opt/vc/lib # optional; path for Raspberry Pi OpenMAX libs
# expose:
# - 8096/tcp # http web ui
# - 8920/tcp # https web ui
# ports:
# - 8096:8096/tcp # http web ui
#devices:
# - /dev/dri:/dev/dri #optional
# - /dev/vchiq:/dev/vchiq #optional
# - /dev/video10:/dev/video10 #optional
# - /dev/video11:/dev/video11 #optional
# - /dev/video12:/dev/video12 #optional
# restart: unless-stopped
#networks:
# - traefik-public
#labels:
# - traefik.enable=true
# - traefik.docker.network=traefik-public
# - traefik.http.routers.emby.rule=Host(`emby.example.com`)
# - traefik.http.services.emby.loadbalancer.server.port=8096
# # Optional part for traefik middlewares
# - traefik.http.routers.emby.middlewares=local-ipwhitelist@file
# image used to manage media and stream it
#jellyfin:
# image: linuxserver/jellyfin:latest
# container_name: arr-suite-jellyfin
# environment:
# - PUID=1000
# - PGID=1000
# - TZ=Europe/Stockholm
# volumes:
# - ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/jellyfin:/config # emby data storage location; can grow very large
# - ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/media:/data # media goes here
# #- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/arr-suite/configs/jellyfin/lib:/opt/vc/lib # optional; path for Raspberry Pi OpenMAX libs
# expose:
# - 8096/tcp # http web ui
# ports:
# - 8096:8096/tcp # http web ui
# #devices:
# # - /dev/dri:/dev/dri #optional
# # - /dev/vchiq:/dev/vchiq #optional
# # - /dev/video10:/dev/video10 #optional
# # - /dev/video11:/dev/video11 #optional
# # - /dev/video12:/dev/video12 #optional
# restart: unless-stopped
# #networks:
# # - traefik-public
# #labels:
# # - traefik.enable=true
# # - traefik.docker.network=traefik-public
# # - traefik.http.routers.jellyfin.rule=Host(`jellyfin.example.com`)
# # - traefik.http.services.jellyfin.loadbalancer.server.port=8096
# # # Optional part for traefik middlewares
# # - traefik.http.routers.jellyfin.middlewares=local-ipwhitelist@file
networks:
traefik-public:
external: true
volumes:
#bazarr:
# driver: local
lidarr:
driver: local
prowlarr:
driver: local
readarr:
driver: local
radarr:
driver: local
sonarr:
driver: local
+8
View File
@@ -0,0 +1,8 @@
#!/bin/sh
SCRIPT_DIR=$(dirname -- "$0")
mkdir -p /data/bedrock/server
mkdir -p /data/backup/bedrock
docker stack deploy -c "$SCRIPT_DIR/docker-compose.yml" mc
+140
View File
@@ -0,0 +1,140 @@
version: '3.8'
services:
bedrock:
image: itzg/minecraft-bedrock-server
environment:
# docker image properties
# - UID=485
# - GID=485
- TZ=Europe/Stockholm
- EULA=TRUE
- VERSION=PREVIEW
# Minecraft server.properties parameters
# https://minecraft.fandom.com/wiki/Server.properties#Bedrock_Edition_3
- GAMEMODE=survival
- DIFFICULTY=normal
- "SERVER_NAME=Niefelheim Bedrock server"
- SERVER_PORT=19132
- SERVER_PORT_V6=19131
- ALLOW_CHEATS=true
- ONLINE_MODE=true
- LEVEL_NAME=Dungen
#- OPS=2533274968313137
- OPS=2533274968313137,2535421315133378,2535433533727392
ports:
- target: 19132
published: 19132
protocol: udp
mode: host
networks:
- host
volumes:
- /etc/localtime:/etc/localtime:ro
- server-data:/data
stdin_open: true
tty: true
deploy:
placement:
constraints: [node.labels.Bedrock == true ]
backup:
image: alpinelinux/docker-cli
entrypoint: "sh -c"
command: |
'
DATE_FMT="%Y-%m-%d_%H-%M-%S"
echo "Stopping bedrock service..."
docker service scale $$SERVICE_NAME=0 > /dev/null
for world_dir in /opt/server/worlds/*; do
world_name=$$(basename "$$world_dir")
now=$$(date +$$DATE_FMT)
target="/opt/backups/$$world_name-$$now.tar.gz"
echo "Backing up '$$world_name' to $$target..."
tar -cpzf "$$target" -C "$$world_dir" .
echo "Cleaning up old versions of '$$world_name'..."
find /opt/backups -name "$$world_name-*.tar.gz" -type f -mtime +14 -print -delete
done
echo "Starting bedrock service..."
docker service scale $$SERVICE_NAME=1 > /dev/null
'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- server-data:/opt/server
- backups-data:/opt/backups
environment:
# assumes this is deployed to a stack named "mc"
- SERVICE_NAME=mc_bedrock
deploy:
placement:
constraints:
- node.role == manager
restart_policy:
condition: none
replicas: 0 # none by default; created when cron hits
labels:
# backup and restart daily at 6am
- swarm.cronjob.enable=true
- swarm.cronjob.schedule=0 6 * * *
update:
image: alpinelinux/docker-cli
entrypoint: "sh -c"
command: |
'
# force service update, which causes restart
docker service update $$SERVICE_NAME --force
'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
# assumes this is deployed to a stack named "mc"
- SERVICE_NAME=mc_bedrock
deploy:
placement:
constraints:
- node.role == manager
restart_policy:
condition: none
replicas: 0 # none by fedault; created when cron hits
labels:
# restart daily at 6am to get latest MC version
- swarm.cronjob.enable=false
- swarm.cronjob.schedule=0 6 * * *
cron:
image: crazymax/swarm-cronjob:1.13.0
environment:
- TZ=Europe/Stockholm
- LOG_LEVEL=info
- LOG_JSON=false
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
placement:
constraints:
- node.role == manager
replicas: 0 # disabled; already running in lab stack
networks:
host:
external: true
volumes:
server-data:
driver: local
driver_opts:
type: 'none'
o: 'bind'
device: '/data/bedrock/server'
backups-data:
driver: local
driver_opts:
type: 'none'
o: 'bind'
device: '/data/backup/bedrock'
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
docker exec $(docker ps --filter name=mc_bedrock* --quiet) /usr/local/bin/send-command $1
+6
View File
@@ -0,0 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json";
"extends": [
"config:base"
]
}
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
SCRIPT_DIR=$(dirname -- "$0")
docker stack rm mc
docker volume rm mc_server-data
docker volume rm mc_backups-data
Submodule swarm/matrix-synapse-stack/FinlayDaGeek/afa030c5fbcee99a9961839a554bd8c1 added at cda5d531f4
Submodule swarm/matrix-synapse-stack/twicechild added at 3784ba79a7
+18
View File
@@ -0,0 +1,18 @@
version: "3"
services:
shepherd:
build: .
image: containrrr/shepherd
environment:
TZ: 'Europe/Stockholm'
SLEEP_TIME: '20m'
FILTER_SERVICES: ''
VERBOSE: 'true'
# UPDATE_OPTIONS: '--update-delay=30s'
# ROLLBACK_OPTIONS: '--rollback-delay=0s'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
placement:
constraints:
- node.role == manager
@@ -0,0 +1,9 @@
version: "3.3"
services:
agile-redis:
image: 127.0.0.1:5000/agile-redis
build:
context: ./
dockerfile: ./agile-redis-Dockerfile.yml
ports:
- "6379:6379"
@@ -0,0 +1,9 @@
FROM redis:5
COPY agile-redis-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/agile-redis-entrypoint.sh
VOLUME /etc/redis
ENTRYPOINT ["agile-redis-entrypoint.sh"]
@@ -0,0 +1,16 @@
#!/bin/bash
CONF_FILE=/etc/redis/redis.conf
if [ ! -f $CONF_FILE ]
then
echo "appendonly yes" > $CONF_FILE
if [ -n "$REDIS_MASTER_HOST" ]
then
echo "slaveof $REDIS_MASTER_HOST ${REDIS_MASTER_PORT:-6379}" >> $CONF_FILE
fi
chown redis:redis $CONF_FILE
fi
exec docker-entrypoint.sh redis-server /etc/redis/redis.conf
@@ -0,0 +1,9 @@
version: "3.3"
services:
agile-redis:
image: 127.0.0.1:5000/agile-redis-sentinel
ports:
- '26379:26379'
build:
context: ./
dockerfile: ./agile-redis-sentinel-Dockerfile.yml
@@ -0,0 +1,23 @@
FROM redis:5
EXPOSE 26379
ADD agile-redis-sentinel.conf /etc/redis/sentinel.conf
RUN chown redis:redis /etc/redis/sentinel.conf
ENV REDIS_MASTER_NAME=mymaster \
REDIS_MASTER_HOST=redis-master \
REDIS_MASTER_PORT=6379 \
SENTINEL_QUORUM=2 \
SENTINEL_DOWN_AFTER=30000\
SENTINEL_PARALLEL_SYNC=1 \
SENTINEL_FAILOVER_TIMEOUT=180000
COPY agile-redis-sentinel-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/agile-redis-sentinel-entrypoint.sh
VOLUME /etc/redis
ENTRYPOINT ["agile-redis-sentinel-entrypoint.sh"]
@@ -0,0 +1,9 @@
#!/bin/sh
sed -i "s/\$REDIS_MASTER_NAME/$REDIS_MASTER_NAME/g" /etc/redis/sentinel.conf
sed -i "s/\$REDIS_MASTER_HOST/$REDIS_MASTER_HOST/g" /etc/redis/sentinel.conf
sed -i "s/\$REDIS_MASTER_PORT/$REDIS_MASTER_PORT/g" /etc/redis/sentinel.conf
sed -i "s/\$SENTINEL_QUORUM/$SENTINEL_QUORUM/g" /etc/redis/sentinel.conf
sed -i "s/\$SENTINEL_DOWN_AFTER/$SENTINEL_DOWN_AFTER/g" /etc/redis/sentinel.conf
sed -i "s/\$SENTINEL_PARALLEL_SYNC/$SENTINEL_PARALLEL_SYNC/g" /etc/redis/sentinel.conf
sed -i "s/\$SENTINEL_FAILOVER_TIMEOUT/$SENTINEL_FAILOVER_TIMEOUT/g" /etc/redis/sentinel.conf
exec docker-entrypoint.sh redis-server /etc/redis/sentinel.conf --sentinel
@@ -0,0 +1,195 @@
# Example sentinel.conf (from http://download.redis.io/redis-stable/sentinel.conf)
# *** IMPORTANT ***
#
# By default Sentinel will not be reachable from interfaces different than
# localhost, either use the 'bind' directive to bind to a list of network
# interfaces, or disable protected mode with "protected-mode no" by
# adding it to this configuration file.
#
# Before doing that MAKE SURE the instance is protected from the outside
# world via firewalling or other means.
#
# For example you may use one of the following:
#
# bind 127.0.0.1 192.168.1.1
#
# protected-mode no
# port <sentinel-port>
# The port that this sentinel instance will run on
port 26379
# sentinel announce-ip <ip>
# sentinel announce-port <port>
#
# The above two configuration directives are useful in environments where,
# because of NAT, Sentinel is reachable from outside via a non-local address.
#
# When announce-ip is provided, the Sentinel will claim the specified IP address
# in HELLO messages used to gossip its presence, instead of auto-detecting the
# local address as it usually does.
#
# Similarly when announce-port is provided and is valid and non-zero, Sentinel
# will announce the specified TCP port.
#
# The two options don't need to be used together, if only announce-ip is
# provided, the Sentinel will announce the specified IP and the server port
# as specified by the "port" option. If only announce-port is provided, the
# Sentinel will announce the auto-detected local IP and the specified port.
#
# Example:
#
# sentinel announce-ip $SENTINEL_IP
# dir <working-directory>
# Every long running process should have a well-defined working directory.
# For Redis Sentinel to chdir to /tmp at startup is the simplest thing
# for the process to don't interfere with administrative tasks such as
# unmounting filesystems.
dir /tmp
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
#
# Tells Sentinel to monitor this master, and to consider it in O_DOWN
# (Objectively Down) state only if at least <quorum> sentinels agree.
#
# Note that whatever is the ODOWN quorum, a Sentinel will require to
# be elected by the majority of the known Sentinels in order to
# start a failover, so no failover can be performed in minority.
#
# Slaves are auto-discovered, so you don't need to specify slaves in
# any way. Sentinel itself will rewrite this configuration file adding
# the slaves using additional configuration options.
# Also note that the configuration file is rewritten when a
# slave is promoted to master.
#
# Note: master name should not include special characters or spaces.
# The valid charset is A-z 0-9 and the three characters ".-_".
sentinel monitor $REDIS_MASTER_NAME $REDIS_MASTER_HOST $REDIS_MASTER_PORT $SENTINEL_QUORUM
# sentinel auth-pass <master-name> <password>
#
# Set the password to use to authenticate with the master and slaves.
# Useful if there is a password set in the Redis instances to monitor.
#
# Note that the master password is also used for slaves, so it is not
# possible to set a different password in masters and slaves instances
# if you want to be able to monitor these instances with Sentinel.
#
# However you can have Redis instances without the authentication enabled
# mixed with Redis instances requiring the authentication (as long as the
# password set is the same for all the instances requiring the password) as
# the AUTH command will have no effect in Redis instances with authentication
# switched off.
#
# Example:
#
# sentinel auth-pass $REDIS_MASTER_NAME MySUPER--secret-0123passw0rd
# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# Number of milliseconds the master (or any attached slave or sentinel) should
# be unreachable (as in, not acceptable reply to PING, continuously, for the
# specified period) in order to consider it in S_DOWN state (Subjectively
# Down).
#
# Default is 30 seconds.
sentinel down-after-milliseconds $REDIS_MASTER_NAME $SENTINEL_DOWN_AFTER
# sentinel parallel-syncs <master-name> <numslaves>
#
# How many slaves we can reconfigure to point to the new slave simultaneously
# during the failover. Use a low number if you use the slaves to serve query
# to avoid that all the slaves will be unreachable at about the same
# time while performing the synchronization with the master.
sentinel parallel-syncs $REDIS_MASTER_NAME $SENTINEL_PARALLEL_SYNC
# sentinel failover-timeout <master-name> <milliseconds>
#
# Specifies the failover timeout in milliseconds. It is used in many ways:
#
# - The time needed to re-start a failover after a previous failover was
# already tried against the same master by a given Sentinel, is two
# times the failover timeout.
#
# - The time needed for a slave replicating to a wrong master according
# to a Sentinel current configuration, to be forced to replicate
# with the right master, is exactly the failover timeout (counting since
# the moment a Sentinel detected the misconfiguration).
#
# - The time needed to cancel a failover that is already in progress but
# did not produced any configuration change (SLAVEOF NO ONE yet not
# acknowledged by the promoted slave).
#
# - The maximum time a failover in progress waits for all the slaves to be
# reconfigured as slaves of the new master. However even after this time
# the slaves will be reconfigured by the Sentinels anyway, but not with
# the exact parallel-syncs progression as specified.
#
# Default is 3 minutes.
sentinel failover-timeout $REDIS_MASTER_NAME $SENTINEL_FAILOVER_TIMEOUT
# SCRIPTS EXECUTION
#
# sentinel notification-script and sentinel reconfig-script are used in order
# to configure scripts that are called to notify the system administrator
# or to reconfigure clients after a failover. The scripts are executed
# with the following rules for error handling:
#
# If script exits with "1" the execution is retried later (up to a maximum
# number of times currently set to 10).
#
# If script exits with "2" (or an higher value) the script execution is
# not retried.
#
# If script terminates because it receives a signal the behavior is the same
# as exit code 1.
#
# A script has a maximum running time of 60 seconds. After this limit is
# reached the script is terminated with a SIGKILL and the execution retried.
# NOTIFICATION SCRIPT
#
# sentinel notification-script <master-name> <script-path>
#
# Call the specified notification script for any sentinel event that is
# generated in the WARNING level (for instance -sdown, -odown, and so forth).
# This script should notify the system administrator via email, SMS, or any
# other messaging system, that there is something wrong with the monitored
# Redis systems.
#
# The script is called with just two arguments: the first is the event type
# and the second the event description.
#
# The script must exist and be executable in order for sentinel to start if
# this option is provided.
#
# Example:
#
# sentinel notification-script $REDIS_MASTER_NAME /var/redis/notify.sh
# CLIENTS RECONFIGURATION SCRIPT
#
# sentinel client-reconfig-script <master-name> <script-path>
#
# When the master changed because of a failover a script can be called in
# order to perform application-specific tasks to notify the clients that the
# configuration has changed and the master is at a different address.
#
# The following arguments are passed to the script:
#
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#
# <state> is currently always "failover"
# <role> is either "leader" or "observer"
#
# The arguments from-ip, from-port, to-ip, to-port are used to communicate
# the old address of the master and the new address of the elected slave
# (now a master).
#
# This script should be resistant to multiple invocations.
#
# Example:
#
# sentinel client-reconfig-script $REDIS_MASTER_NAME /var/redis/reconfig.sh
+76
View File
@@ -0,0 +1,76 @@
version: "3.3"
services:
redis-sentinel:
image: 127.0.0.1:5000/agile-redis-sentinel
volumes:
- sentinel-conf:/etc/redis
deploy:
mode: global
environment:
- REDIS_MASTER_HOST=${REDIS_MASTER_IP}
- SENTINEL_DOWN_AFTER=5000
- SENTINEL_FAILOVER=15000
networks:
- host
redis-master:
image: 127.0.0.1:5000/agile-redis
volumes:
- redis-data:/data
- redis-conf:/etc/redis
deploy:
mode: global
placement:
constraints:
- node.hostname == ${REDIS_MASTER_HOSTNAME}
networks:
- host
redis-slave-node1:
image: 127.0.0.1:5000/agile-redis
volumes:
- redis-data:/data
- redis-conf:/etc/redis
environment:
- REDIS_MASTER_HOST=${REDIS_MASTER_IP}
deploy:
mode: global
placement:
constraints:
- node.hostname == ${REDIS_SLAVE_NODE1_HOSTNAME}
networks:
- host
redis-slave-node2:
image: 127.0.0.1:5000/agile-redis
volumes:
- redis-data:/data
- redis-conf:/etc/redis
environment:
- REDIS_MASTER_HOST=${REDIS_MASTER_IP}
deploy:
mode: global
placement:
constraints:
- node.hostname == ${REDIS_SLAVE_NODE2_HOSTNAME}
networks:
- host
agile-python-app:
image: 127.0.0.1:5000/agile-python-app
ports:
- "38000:611"
deploy:
mode: replicated
replicas: 3
environment:
- SENTINEL_HOST=${SENTINEL_IP}
volumes:
redis-data:
redis-conf:
sentinel-conf:
networks:
host:
external: true
+55
View File
@@ -0,0 +1,55 @@
#!/bin/bash
echo "--------------------------------------------------------------------------------------------------------------"
echo " REDIS STACK DEPLOYMENT "
echo "--------------------------------------------------------------------------------------------------------------"
export SENTINEL_HOSTNAME=$1 #serveur17
export REDIS_MASTER_HOSTNAME=$2 #serveur17
export REDIS_SLAVE_NODE1_HOSTNAME=$3 #serveur18
export REDIS_SLAVE_NODE2_HOSTNAME=$4 #serveur19
if [ -z $SENTINEL_HOSTNAME ] || [ -z $REDIS_MASTER_HOSTNAME ] || [ -z $REDIS_SLAVE_NODE1_HOSTNAME ] || [ -z $REDIS_SLAVE_NODE2_HOSTNAME ] ; then
echo "Status: Arguments missing. Cannot continue to build the stack. Missing SENTINEL_HOSTNAME, REDIS_MASTER_HOSTNAME, REDIS_SLAVE_NODE1_HOSTNAME, REDIS_SLAVE_NODE1_HOSTNAME" >&2
exit 1;
fi
echo "1- Start to push on registry the redis docker image which can be used as master or slave in the stack..."
docker compose -f agile-redis-master-slave/agile-redis-Dockercompose.yml build
docker compose -f agile-redis-master-slave/agile-redis-Dockercompose.yml push
echo "(1)End to build and push redis image to registry."
echo "-------------------------------------------------------\n"
echo "2- Start to push on registry the redis docker image which will be used to build sentinel..."
docker compose -f agile-redis-sentinel/agile-redis-sentinel-Dockercompose.yml build
docker compose -f agile-redis-sentinel/agile-redis-sentinel-Dockercompose.yml push
echo "(2)End to build and push redis sentinel image to registry."
echo "-------------------------------------------------------\n"
echo "3- Start to push our python app example on the registry..."
docker compose -f python-app-example/compose-app.yml build
docker compose -f python-app-example/compose-app.yml push
echo "(3)End to push our python app example on the registry."
echo "-------------------------------------------------------\n"
echo "4- Start to deploy the stack..."
export SENTINEL_IP=`docker node inspect --format {{.Status.Addr}} $SENTINEL_HOSTNAME`
export REDIS_MASTER_IP=`docker node inspect --format {{.Status.Addr}} $REDIS_MASTER_HOSTNAME`
echo "Sentinel hostname and IP: $SENTINEL_HOSTNAME - $SENTINEL_IP"
echo "Redis Master hostname and IP: $REDIS_MASTER_HOSTNAME - $REDIS_MASTER_IP"
echo "Redis slave 1 hostname: $REDIS_SLAVE_NODE1_HOSTNAME"
echo "Redis slave 2 hostname: $REDIS_SLAVE_NODE2_HOSTNAME"
docker stack deploy -c agile-redis-stack.yml stackredis
printf "(4)End to deploy the stack... Please wait until the services started\n\n\n"
sleep 3s
printf "Status: The stack deployment has been completed.\n\n"
docker service ls
printf "If all services replicas are not already deployed, please run << docker service ls >> to see if it now completed.\n"
@@ -0,0 +1,24 @@
from pypy:3-6
WORKDIR /usr/src/app
# Bundle app source
COPY app.py /usr/src/app
COPY requirements.txt /usr/src/app
RUN apt-get update
RUN apt-get install -y vim
# install requirements
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
RUN mkdir -p /usr/src/logs
EXPOSE 611
VOLUME ["/usr/src/app"]
ENTRYPOINT ["pypy3", "app.py"]
@@ -0,0 +1,30 @@
import os
from flask import Flask
from redis.sentinel import Sentinel
app = Flask(__name__)
sentinelHost = os.environ.get("SENTINEL_HOST", None)
sentinelPort = int(os.environ.get("SENTINEL_PORT", 26379))
redisMasterName = os.environ.get("REDIS_MASTER_NAME", 'mymaster')
@app.route('/')
def hello():
if sentinelHost is not None and sentinelPort is not None:
try:
sentinel = Sentinel([(sentinelHost, sentinelPort)], socket_timeout=0.1)
redis_master = sentinel.master_for(redisMasterName, socket_timeout=0.1)
redis_slave = sentinel.slave_for(redisMasterName, socket_timeout=0.1)
incr_and_return_count = redis_master.incr('hits')
count_from_slave = redis_slave.get('hits')
return 'Hello World! I have been seen {} times. Yes Yeah\n'.format(count_from_slave)
except Exception as e:
return sentinelHost+ " "+ str(sentinelPort) + 'Exception handled when started to perform actions: Details error {}\n'.format(e)
else:
return 'Environment variable sentinelHost or sentinelPort is not found or empty. \n'
if __name__ == "__main__":
app.run(host="0.0.0.0", port=611, debug=True)
@@ -0,0 +1,7 @@
version: "3.3"
services:
agile-python-app:
image: 127.0.0.1:5000/agile-python-app
build:
context: ./
dockerfile: ./Dockerfile.yml
@@ -0,0 +1,2 @@
flask
redis
+102
View File
@@ -0,0 +1,102 @@
version: '3.3'
services:
traefik:
# Use the latest v3.0 Traefik image available
image: traefik:v3.0
ports:
# Listen on port 80, default for HTTP, necessary to redirect to HTTPS
- 80:80
# Listen on port 443, default for HTTPS
- 443:443
# Listen on port 8080, traefiks web-ui
- 8080:8080
deploy:
placement:
constraints:
# Make the traefik service run only on the node with this label
# as the node with it has the volume for certificates
- node.labels.traefik-public.traefik-public-certificates == true
labels:
# Enable Traefik for this service, to make it available in the public network
- traefik.enable=true
# Use the traefik-public network (declared below)
- traefik.docker-network=traefik-public
# User the custome label "traefik.constraint-label=traefik-public"
# This public Traefik will only use services with this label
# That way you can add other internal Traefik instances per stack if needed
- traefik.constraint-label=traefik-public
# admin-auth middleware with HTTP Basic auth
# Using the environment variables USERNAME and HASHED_PASSOWRD
- traefik.http.middlewares.admin-auth.basicauth.users=${USERNAME?Variable not set}:${HASHED_PASSWORD?Variable not set}
# https-redirect middleware to redirect HTTP to HTTPS
# It can be re-used by other stacks in other Docker Compose files
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
# traefik-http set up only to use the middleware to redirect to https
# Uses the environment variable DOMAIN
- traefik.http.routers.traefik-public-http.rule=Host(`${DOMAIN?Variable not set}`)
- traefik.http.routers.traefik-public-http.entrypoints=http
- traefik.http.routers.traefik-public-http.middlewares=https-redirect
# traefik-https the actual router using HTTPS
# Uses the environment variable DOMAIN
- traefik.http.routers.traefik-public-https.rule=Host(`${DOMAIN?Variable not set}`)
- traefik.http.routers.traefik-public-https.entrypoints=https
- traefik.http.routers.traefik-public-https.tls=true
# Use the special Traefik service api@internal with the web UI/Dashboard
- traefik.http.routers.traefik-public-https.service=api@internal
# Use the "le" (Let's Encrypt) resolver created below
- traefik.http.routers.traefik-public-https.tls.certresolver=le
# Enable HTTP Basic auth, using the middleware created above
- traefik.http.routers.traefik-public-https.middlewares=admin-auth
# Define the port inside of the Docker service to use
- traefik.http.services.traefik-public.loadbalancer.server.port=8080
volumes:
# Add Docker as a mounted volume, so that Traefik can read the labels of other services
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount the volume to store the certificates
- traefik-public-certificates:/certificates
command:
# Enable Docker in Traefik, so that it reads labels from Docker services
- --providers.docker
# Add a constraint to only use services with the label "traefik.constraint-label=traefik-public"
- --providers.docker.constraints=Label(`traefik.constraint-label`, `traefik-public`)
# Do not expose all Docker services, only the ones explicitly exposed
- --providers.docker.exposedbydefault=false
# Enable Docker Swarm mode
- --providers.swarm.endpoint=unix:///var/run/docker.sock
# Create an entrypoint "http" listening on port 80
- --entrypoints.http.address=:80
# Create an entrypoint "https" listening on port 443
- --entrypoints.https.address=:443
# Create the certificate resolver "le" for Let's Encrypt, uses the environment variable EMAIL
- --certificatesresolvers.le.acme.email=${EMAIL?Variable not set}
# Store the Let's Encrypt certificates in the mounted volume
- --certificatesresolvers.le.acme.storage=/certificates/acme.json
# Use the TLS Challenge for Let's Encrypt
- --certificatesresolvers.le.acme.tlschallenge=true
# Enable the access log, with HTTP requests
- --accesslog
# Enable the Traefik log, for configurations and errors
- --log
# Enable the Dashboard and API
- --api=true
- --api.dashboard=true
- --api.insecure=true
networks:
# Use the public network created to be shared between Traefik and
# any other service that needs to be publicly available with HTTPS
- traefik-public
volumes:
# Create a volume to store the certificates, there is a constraint to make sure
# Traefik is always deployed to the same Docker node with the same volume containing
# the HTTPS certificates
traefik-public-certificates:
networks:
# Use the previously created public network "traefik-public", shared with other
# services that need to be publicly available via this Traefik
traefik-public:
external: true