487 lines
13 KiB
Bash
487 lines
13 KiB
Bash
#!/bin/bash
|
|
#
|
|
# Plane Service
|
|
|
|
PATH=$HOME/.docker/cli-plugins:/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
|
|
# FIXME plane's nginx proxy has a few additional rules that we may
|
|
# need to port to Traefik:
|
|
# add_header X-Content-Type-Options "nosniff" always;
|
|
# add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
|
# add_header Permissions-Policy "interest-cohort=()" always;
|
|
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
# add_header X-Forwarded-Proto "$scheme";
|
|
# add_header X-Forwarded-Host "$host";
|
|
# add_header X-Forwarded-For "$proxy_add_x_forwarded_for";
|
|
# add_header X-Real-IP "$remote_addr";
|
|
|
|
config_plane() {
|
|
echo -ne "\n* Configuring /federated/apps/plane container.."
|
|
|
|
if [ ! -d "/federated/apps/plane" ]; then
|
|
mkdir -p /federated/apps/plane/data/plane &> /dev/null
|
|
fi
|
|
|
|
POSTGRES_PASSWORD=$(create_password)
|
|
|
|
USE_TRAEFIK=true
|
|
|
|
cat >/federated/apps/plane/plane.env <<'EOF'
|
|
APP_DOMAIN=plane.@DOMAIN@
|
|
APP_RELEASE=stable
|
|
|
|
WEB_REPLICAS=1
|
|
SPACE_REPLICAS=1
|
|
ADMIN_REPLICAS=1
|
|
API_REPLICAS=1
|
|
|
|
NGINX_PORT=80
|
|
WEB_URL=http://${APP_DOMAIN}
|
|
DEBUG=0
|
|
SENTRY_DSN=
|
|
SENTRY_ENVIRONMENT=production
|
|
CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN}
|
|
API_BASE_URL=http://api:8000
|
|
|
|
#DB SETTINGS
|
|
PGHOST=postgresql
|
|
PGDATABASE=plane
|
|
POSTGRES_USER=plane
|
|
POSTGRES_PASSWORD=@POSTGRES_PASSWORD@
|
|
POSTGRES_DB=plane
|
|
POSTGRES_PORT=5432
|
|
PGDATA=/var/lib/postgresql/data
|
|
DATABASE_URL=
|
|
|
|
# REDIS SETTINGS
|
|
REDIS_HOST=plane-redis
|
|
REDIS_PORT=6379
|
|
REDIS_URL=
|
|
|
|
# RabbitMQ Settings
|
|
RABBITMQ_HOST=plane-mq
|
|
RABBITMQ_PORT=5672
|
|
RABBITMQ_USER=plane
|
|
RABBITMQ_PASSWORD=plane
|
|
RABBITMQ_VHOST=plane
|
|
AMQP_URL=
|
|
|
|
# Secret Key
|
|
SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
|
|
|
|
# DATA STORE SETTINGS
|
|
USE_MINIO=1
|
|
AWS_REGION=
|
|
AWS_ACCESS_KEY_ID=access-key
|
|
AWS_SECRET_ACCESS_KEY=secret-key
|
|
AWS_S3_ENDPOINT_URL=http://plane-minio:9000
|
|
AWS_S3_BUCKET_NAME=uploads
|
|
MINIO_ROOT_USER=access-key
|
|
MINIO_ROOT_PASSWORD=secret-key
|
|
BUCKET_NAME=uploads
|
|
FILE_SIZE_LIMIT=5242880
|
|
|
|
# Gunicorn Workers
|
|
GUNICORN_WORKERS=1
|
|
|
|
# UNCOMMENT `DOCKER_PLATFORM` IF YOU ARE ON `ARM64` AND DOCKER IMAGE IS NOT AVAILABLE FOR RESPECTIVE `APP_RELEASE`
|
|
# DOCKER_PLATFORM=linux/amd64
|
|
|
|
DOCKERHUB_USER=makeplane
|
|
PULL_POLICY=if_not_present
|
|
CUSTOM_BUILD=false
|
|
EOF
|
|
|
|
cat > /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
x-app-env: &app-env
|
|
environment:
|
|
- NGINX_PORT=${NGINX_PORT:-80}
|
|
- WEB_URL=${WEB_URL:-http://localhost}
|
|
- DEBUG=${DEBUG:-0}
|
|
- SENTRY_DSN=${SENTRY_DSN:-""}
|
|
- SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT:-"production"}
|
|
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-}
|
|
# Gunicorn Workers
|
|
- GUNICORN_WORKERS=${GUNICORN_WORKERS:-1}
|
|
#DB SETTINGS
|
|
- PGHOST=${PGHOST:-postgresql}
|
|
- PGDATABASE=${PGDATABASE:-plane}
|
|
- POSTGRES_USER=${POSTGRES_USER:-plane}
|
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-@POSTGRES_PASSWORD@}
|
|
- POSTGRES_DB=${POSTGRES_DB:-plane}
|
|
- POSTGRES_PORT=${POSTGRES_PORT:-5432}
|
|
- PGDATA=${PGDATA:-/var/lib/postgresql/data}
|
|
- DATABASE_URL=${DATABASE_URL:-postgresql://plane:@POSTGRES_PASSWORD@@postgresql/plane}
|
|
# REDIS SETTINGS
|
|
- REDIS_HOST=${REDIS_HOST:-plane-redis}
|
|
- REDIS_PORT=${REDIS_PORT:-6379}
|
|
- REDIS_URL=${REDIS_URL:-redis://plane-redis:6379/}
|
|
|
|
# RabbitMQ Settings
|
|
- RABBITMQ_HOST=${RABBITMQ_HOST:-plane-mq}
|
|
- RABBITMQ_PORT=${RABBITMQ_PORT:-5672}
|
|
- RABBITMQ_DEFAULT_USER=${RABBITMQ_USER:-plane}
|
|
- RABBITMQ_DEFAULT_PASS=${RABBITMQ_PASSWORD:-plane}
|
|
- RABBITMQ_DEFAULT_VHOST=${RABBITMQ_VHOST:-plane}
|
|
- RABBITMQ_VHOST=${RABBITMQ_VHOST:-plane}
|
|
- AMQP_URL=${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane}
|
|
# Application secret
|
|
- SECRET_KEY=${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
|
|
# DATA STORE SETTINGS
|
|
- USE_MINIO=${USE_MINIO:-1}
|
|
- AWS_REGION=${AWS_REGION:-}
|
|
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-"access-key"}
|
|
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-"secret-key"}
|
|
- AWS_S3_ENDPOINT_URL=${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
|
|
- AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME:-uploads}
|
|
- MINIO_ROOT_USER=${MINIO_ROOT_USER:-"access-key"}
|
|
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-"secret-key"}
|
|
- BUCKET_NAME=${BUCKET_NAME:-uploads}
|
|
- FILE_SIZE_LIMIT=${FILE_SIZE_LIMIT:-5242880}
|
|
# Live server env
|
|
- API_BASE_URL=${API_BASE_URL:-http://api:8000}
|
|
|
|
services:
|
|
web:
|
|
<<: *app-env
|
|
image: ${DOCKERHUB_USER:-makeplane}/plane-frontend:${APP_RELEASE:-stable}
|
|
platform: ${DOCKER_PLATFORM:-}
|
|
expose:
|
|
- 3000
|
|
ports:
|
|
- 3000:3000
|
|
env_file:
|
|
- ./plane.env
|
|
EOF
|
|
|
|
if $USE_TRAEFIK; then
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.web.rule=Host(`plane.@DOMAIN@`)"
|
|
- "traefik.http.routers.web.entrypoints=websecure"
|
|
- "traefik.http.routers.web.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.web.loadbalancer.server.port=3000"
|
|
EOF
|
|
fi
|
|
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.50
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
command: node web/server.js web
|
|
deploy:
|
|
replicas: ${WEB_REPLICAS:-1}
|
|
depends_on:
|
|
- api
|
|
- worker
|
|
|
|
space:
|
|
<<: *app-env
|
|
image: ${DOCKERHUB_USER:-makeplane}/plane-space:${APP_RELEASE:-stable}
|
|
platform: ${DOCKER_PLATFORM:-}
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.51
|
|
EOF
|
|
|
|
if $USE_TRAEFIK; then
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.space.rule=Host(`plane.@DOMAIN@`) && PathPrefix(`/spaces`)"
|
|
- "traefik.http.routers.space.entrypoints=websecure"
|
|
- "traefik.http.routers.space.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.space.loadbalancer.server.port=3000"
|
|
EOF
|
|
fi
|
|
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
command: node space/server.js space
|
|
deploy:
|
|
replicas: ${SPACE_REPLICAS:-1}
|
|
depends_on:
|
|
- api
|
|
- worker
|
|
- web
|
|
|
|
admin:
|
|
<<: *app-env
|
|
image: ${DOCKERHUB_USER:-makeplane}/plane-admin:${APP_RELEASE:-stable}
|
|
platform: ${DOCKER_PLATFORM:-}
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.52
|
|
EOF
|
|
|
|
if $USE_TRAEFIK; then
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.admin.rule=Host(`plane.@DOMAIN@`) && PathPrefix(`/god-mode`)"
|
|
- "traefik.http.routers.admin.entrypoints=websecure"
|
|
- "traefik.http.routers.admin.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.admin.loadbalancer.server.port=3000"
|
|
EOF
|
|
fi
|
|
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
command: node admin/server.js admin
|
|
deploy:
|
|
replicas: ${ADMIN_REPLICAS:-1}
|
|
depends_on:
|
|
- api
|
|
- web
|
|
|
|
live:
|
|
<<: *app-env
|
|
image: ${DOCKERHUB_USER:-makeplane}/plane-live:${APP_RELEASE:-stable}
|
|
platform: ${DOCKER_PLATFORM:-}
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.53
|
|
EOF
|
|
|
|
if $USE_TRAEFIK; then
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.live.rule=Host(`plane.@DOMAIN@`) && PathPrefix(`/live`)"
|
|
- "traefik.http.routers.live.entrypoints=websecure"
|
|
- "traefik.http.routers.live.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.live.loadbalancer.server.port=3000"
|
|
EOF
|
|
fi
|
|
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
command: node live/dist/server.js live
|
|
deploy:
|
|
replicas: ${LIVE_REPLICAS:-1}
|
|
depends_on:
|
|
- api
|
|
- web
|
|
|
|
api:
|
|
<<: *app-env
|
|
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
|
|
platform: ${DOCKER_PLATFORM:-}
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.54
|
|
EOF
|
|
|
|
if $USE_TRAEFIK; then
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.api.rule=Host(`plane.@DOMAIN@`) && (PathPrefix(`/api`) || PathPrefix(`/auth`))"
|
|
- "traefik.http.routers.api.entrypoints=websecure"
|
|
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.api.loadbalancer.server.port=8000"
|
|
EOF
|
|
fi
|
|
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
command: ./bin/docker-entrypoint-api.sh
|
|
deploy:
|
|
replicas: ${API_REPLICAS:-1}
|
|
volumes:
|
|
- logs_api:/code/plane/logs
|
|
depends_on:
|
|
- plane-redis
|
|
- plane-mq
|
|
|
|
|
|
worker:
|
|
<<: *app-env
|
|
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
|
|
platform: ${DOCKER_PLATFORM:-}
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.55
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
command: ./bin/docker-entrypoint-worker.sh
|
|
volumes:
|
|
- logs_worker:/code/plane/logs
|
|
depends_on:
|
|
- api
|
|
- plane-redis
|
|
- plane-mq
|
|
|
|
beat-worker:
|
|
<<: *app-env
|
|
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
|
|
platform: ${DOCKER_PLATFORM:-}
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.56
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
command: ./bin/docker-entrypoint-beat.sh
|
|
volumes:
|
|
- logs_beat-worker:/code/plane/logs
|
|
depends_on:
|
|
- api
|
|
- plane-redis
|
|
- plane-mq
|
|
|
|
migrator:
|
|
<<: *app-env
|
|
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
|
|
platform: ${DOCKER_PLATFORM:-}
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.57
|
|
pull_policy: if_not_present
|
|
restart: "no"
|
|
command: ./bin/docker-entrypoint-migrator.sh
|
|
volumes:
|
|
- logs_migrator:/code/plane/logs
|
|
depends_on:
|
|
- plane-redis
|
|
|
|
plane-redis:
|
|
<<: *app-env
|
|
image: valkey/valkey:7.2.5-alpine
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.58
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
volumes:
|
|
- redisdata:/data
|
|
|
|
plane-mq:
|
|
<<: *app-env
|
|
image: rabbitmq:3.13.6-management-alpine
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.59
|
|
restart: always
|
|
volumes:
|
|
- rabbitmq_data:/var/lib/rabbitmq
|
|
|
|
plane-minio:
|
|
<<: *app-env
|
|
image: minio/minio:latest
|
|
env_file:
|
|
- ./plane.env
|
|
networks:
|
|
core:
|
|
ipv4_address: 192.168.0.60
|
|
EOF
|
|
|
|
if $USE_TRAEFIK; then
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.uploads.rule=Host(`plane.@DOMAIN@`) && PathPrefix(`/uploads`)"
|
|
- "traefik.http.routers.uploads.entrypoints=websecure"
|
|
- "traefik.http.routers.uploads.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.uploads.loadbalancer.server.port=9000"
|
|
EOF
|
|
fi
|
|
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
command: server /export --console-address ":9090"
|
|
volumes:
|
|
- uploads:/export
|
|
EOF
|
|
|
|
if ! $USE_TRAEFIK; then
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
proxy:
|
|
<<: *app-env
|
|
image: ${DOCKERHUB_USER:-makeplane}/plane-proxy:${APP_RELEASE:-stable}
|
|
env_file:
|
|
- ./plane.env
|
|
platform: ${DOCKER_PLATFORM:-}
|
|
pull_policy: if_not_present
|
|
restart: unless-stopped
|
|
ports:
|
|
- ${NGINX_PORT}:80
|
|
depends_on:
|
|
- web
|
|
- api
|
|
- space
|
|
EOF
|
|
fi
|
|
|
|
cat >> /federated/apps/plane/docker-compose.yml <<'EOF'
|
|
volumes:
|
|
redisdata:
|
|
|
|
uploads:
|
|
logs_api:
|
|
logs_worker:
|
|
logs_beat-worker:
|
|
logs_migrator:
|
|
rabbitmq_data:
|
|
|
|
networks:
|
|
core:
|
|
external: true
|
|
EOF
|
|
sed -i -e "s,@DOMAIN@,${DOMAIN},g" \
|
|
-e "s,@POSTGRES_PASSWORD@,${POSTGRES_PASSWORD},g" \
|
|
/federated/apps/plane/docker-compose.yml \
|
|
/federated/apps/plane/plane.env
|
|
|
|
set -x
|
|
# Create database and user in postgresql
|
|
docker exec postgresql psql -U postgres -c "CREATE DATABASE plane" &> /dev/null
|
|
docker exec postgresql psql -U postgres -c "CREATE USER plane WITH PASSWORD '${POSTGRES_PASSWORD}'" &> /dev/null
|
|
docker exec postgresql psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE plane TO plane" &> /dev/null
|
|
set +x
|
|
|
|
unset POSTGRES_PASSWORD
|
|
|
|
cat > /federated/apps/plane/.env <<EOF
|
|
#IMAGE_VERSION="v1.11.33"
|
|
EOF
|
|
chmod 600 /federated/apps/plane/.env
|
|
|
|
echo -ne "done."
|
|
}
|
|
start_plane() {
|
|
# Start service with command to make sure it's up before proceeding
|
|
# start_service "plane" "nc -z 192.168.0.48 80 &> /dev/null" "7"
|
|
echo -ne "done."
|
|
}
|
|
uninstall_plane() {
|
|
docker exec postgresql psql -U postgres -c "DROP DATABASE plane" &> /dev/null
|
|
docker exec postgresql psql -U postgres -c "DROP USER plane" &> /dev/null
|
|
rm -rf /federated/apps/plane
|
|
}
|