Added folders as well...
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
Executable
+8
@@ -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
|
||||
@@ -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'
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker exec $(docker ps --filter name=mc_bedrock* --quiet) /usr/local/bin/send-command $1
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json";
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
}
|
||||
@@ -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
+1
Submodule swarm/matrix-synapse-stack/twicechild added at 3784ba79a7
@@ -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
|
||||
@@ -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
|
||||
Executable
+55
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user