├── .editorconfig ├── .gitignore ├── README.md ├── README_EN.md ├── assets └── swanlab.svg ├── docker ├── README.md ├── README_EN.md ├── docker-compose.yaml ├── install-dockerhub.sh ├── install.sh └── upgrade.sh └── scripts ├── install-docker-compose.sh ├── install-docker.sh └── pull-images.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = false 9 | max_line_length = 120 10 | tab_width = 2 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Misc 2 | .idea 3 | .DS_Store 4 | .vscode 5 | .zed 6 | 7 | # Playground 8 | playground 9 | 10 | # Sensitive information 11 | .key 12 | data 13 | .env 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | SwanLab 4 | 5 |
Self-Hosted SwanLab 6 |

7 | 8 |
9 | 10 | [![][dockerhub-shield]][dockerhub-link] 11 | 12 |
13 | 14 | [English](./README_EN.md) 15 | 16 | ## 版本更新 17 | 18 | ### v1.2 (2025.5.30) 19 | - Feature: 上线折线图创建和编辑功能,配置图表功能增加数据源选择功能,支持单张图表显示不同的指标 20 | - Feature: 支持在实验添加Tag标签 21 | - Feature: 支持折线图Log Scale;支持分组拖拽;增加swanlab.OpenApi开放接口 22 | - Feature: 新增「默认空间」和「默认可见性」配置,用于指定项目默认创建在对应的组织下 23 | - Optimize: 优化大量指标上传导致部分数据丢失的问题 24 | - Optimize: 大幅优化指标上传的性能问题 25 | - BugFix: 修复实验无法自动关闭的问题 26 | 27 | > 🤔**如何从旧版本升级**:同步项目仓库后,执行 `cd docker && ./upgrade.sh` 可升级至 `v1.2` 版本 28 | 29 | ### v1.1 (2025.4.27) 30 | swanlab相关镜像已更新至v1.1版本,初次使用的用户直接运行`install.sh` 即可享用v1.1版本,原v1版本用户可直接运行`docker/upgrade.sh`对`docker-compose.yaml`进行升级重启。 31 | 32 | 33 | 34 | ## 快速部署 35 | 36 | ### 1. 手动部署 37 | 38 | 克隆仓库: 39 | 40 | ```bash 41 | git clone https://github.com/swanhubx/self-hosted.git 42 | cd self-hosted/docker 43 | ``` 44 | 45 | 使用 [DockerHub](https://hub.docker.com/search?q=swanlab) 镜像源部署: 46 | 47 | ```bash 48 | ./install-dockerhub.sh 49 | ``` 50 | 51 | 中国地区快速部署: 52 | 53 | ```bash 54 | ./install.sh 55 | ``` 56 | 57 | ### 2. 一键脚本部署 58 | 59 | 使用 [DockerHub](https://hub.docker.com/search?q=swanlab) 镜像源部署: 60 | 61 | ```bash 62 | curl -sO https://raw.githubusercontent.com/swanhubx/self-hosted/main/docker/install-dockerhub.sh && bash install.sh 63 | ``` 64 | 65 | 中国地区快速部署: 66 | 67 | ```bash 68 | curl -sO https://raw.githubusercontent.com/swanhubx/self-hosted/main/docker/install.sh && bash install.sh 69 | ``` 70 | 71 | 详细内容参考:[docker/README.md](./docker/README.md) 72 | 73 | ## 更新版本 74 | 75 | 克隆仓库同步最新的代码后,进入 `docker` 目录执行 `./upgrade.sh` 实现升级重启到最新版本。 76 | 77 | ## 开始使用 78 | 79 | 请参考:[教程文档](https://docs.swanlab.cn/guide_cloud/self_host/docker-deploy.html) 80 | 81 | 82 | 83 | [dockerhub-shield]: https://img.shields.io/docker/v/swanlab/swanlab-next?color=369eff&label=docker&labelColor=black&logoColor=white&style=flat-square 84 | [dockerhub-link]: https://hub.docker.com/r/swanlab/swanlab-next/tags -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | SwanLab 4 | 5 |
Self-Hosted SwanLab 6 |

7 | 8 |
9 | 10 | [![][dockerhub-shield]][dockerhub-link] 11 | 12 |
13 | 14 | [中文](./README.md) 15 | 16 | 17 | 18 | ## Quick Deployment 19 | 20 | ### 1. Manual Deployment 21 | 22 | Clone the repository: 23 | 24 | ```bash 25 | git clone https://github.com/swanhubx/self-hosted.git 26 | cd self-hosted/docker 27 | ``` 28 | 29 | Deploy from [DockerHub](https://hub.docker.com/search?q=swanlab): 30 | 31 | ```bash 32 | ./install-dockerhub.sh 33 | ``` 34 | 35 | For faster deployment in China: 36 | 37 | ```bash 38 | ./install.sh 39 | ``` 40 | 41 | ### 2. One-Click Script Deployment 42 | 43 | Deploy from [DockerHub](https://hub.docker.com/search?q=swanlab): 44 | 45 | ```bash 46 | curl -sO https://raw.githubusercontent.com/swanhubx/self-hosted/main/docker/install-dockerhub.sh && bash install.sh 47 | ``` 48 | 49 | For faster deployment in China: 50 | 51 | ```bash 52 | curl -sO https://raw.githubusercontent.com/swanhubx/self-hosted/main/docker/install.sh && bash install.sh 53 | ``` 54 | 55 | For more details, refer to: [docker/README.md](./docker/README.md) 56 | 57 | ## Start Using 58 | 59 | Refer to:[Document](https://docs.swanlab.cn/guide_cloud/self_host/docker-deploy.html) 60 | 61 | 62 | [dockerhub-shield]: https://img.shields.io/docker/v/swanlab/swanlab-next?color=369eff&label=docker&labelColor=black&logoColor=white&style=flat-square 63 | [dockerhub-link]: https://hub.docker.com/r/swanlab/swanlab-next/tags -------------------------------------------------------------------------------- /assets/swanlab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | ## 通过 Docker 部署 2 | 3 | [English](./README_EN.md) 4 | 5 | > 首先需要确保你的服务器上安装有 [docker](https://docs.docker.com/engine/install/)。如果未安装,可以参考[文档](https://yeasy.gitbook.io/docker_practice/install),或者使用我们提供的安装脚本 [scripts/install-docker.sh](../scripts/install-docker.sh)。 6 | > 若你的服务器上未安装Docker Compose插件,可以参考[官方地址](https://github.com/docker/compose/)进行下载安装,或者使用我们提供的安装脚本 [scripts/install-docker-compose.sh](../scripts/install-docker-compose.sh)。 7 | 8 | ### 在线部署 9 | 服务器可以联网时,直接执行 `./install.sh` 脚本即可开始部署。部署成功后会看到下面的 **SwanLab** 标志。 10 | 11 | ```bash 12 | $ ./install.sh 13 | 14 | ... 15 | _____ _ _ 16 | / ____| | | | | 17 | | (_____ ____ _ _ __ | | __ _| |__ 18 | \___ \ \ /\ / / _` | '_ \| | / _` | '_ \ 19 | ____) \ V V / (_| | | | | |___| (_| | |_) | 20 | |_____/ \_/\_/ \__,_|_| |_|______\__,_|_.__/ 21 | 22 | Self-Hosted Docker v1.0 - @SwanLab 23 | 24 | 🎉 Wow, the installation is complete. Everything is perfect. 25 | 🥰 Congratulations, self-hosted SwanLab can be accessed using {IP}:8000 26 | ``` 27 | 28 | > `install.sh` 使用国内镜像源,如果是需要使用 [DockerHub](https://hub.docker.com/explore) 源,则可以使用 `install-dockerhub.sh` 脚本部署 29 | 30 | ### 离线部署 31 | 32 | 1. 在联网机器上下载镜像,运行脚本 [scripts/pull-images.sh](../scripts/pull-images.sh),该脚本运行结束后会在当前下生成`swanlab_images.tar`文件,该文件包含所有镜像的压缩包。**请确保下载的机器上含有Docker运行环境。** 33 | 2. 将 `swanlab_images.tar` 文件上传到目标机器上。(可配合`sftp`工具) 34 | 3. 在目标服务器上运行 `docker load -i swanlab_images.tar` 加载镜像,等待加载成功后可以通过 `docker images` 命令查看镜像列表,将会显示所有镜像。 35 | 4. 然后跟上述在线部署一样执行 `./install.sh` 即可部署安装。 36 | 37 | ### 可配置项 38 | 39 | 脚本执行过程中会提示两个可配置项: 40 | 41 | 1. 数据保存路径,默认为 `./data`,建议选择一个固定的路径用于长期保存,例如 `/data`。 42 | 2. 服务暴露端口,默认为 `8000`,如果是在公网服务器上可以设置为 `80`。 43 | 44 | 如果不需要交互式配置,脚本还提供了三个命令行选项: 45 | 46 | - `-d`:用于指定数据保存路径 47 | - `-p`:服务暴露的端口 48 | - `-s`:用于跳过交互式配置。如果不希望交互式配置,则比如添加 `-s` 49 | 50 | 例如指定保存路径为 `/data`,同时暴露的端口为 `80`: 51 | 52 | ```bash 53 | $ ./install.sh -d /data -p 80 -s 54 | ``` 55 | 56 | ### 执行结果 57 | 58 | 脚本执行成功后,将会创建一个 `swanlab/` 目录,并在目录下生成两个文件: 59 | 60 | - `docker-compose.yaml`:用于 Docker Compose 的配置文件 61 | - `.env`:对应的密钥文件,保存数据库对应的初始化密码 62 | 63 | 在 `swanlab` 目录下执行 `docker compose ps -a` 可以查看所有容器的运行状态: 64 | 65 | ```bash 66 | $ docker compose ps -a (base) 67 | NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS 68 | swanlab-clickhouse ccr.ccs.tencentyun.com/self-hosted/clickhouse:24.3 "/entrypoint.sh" clickhouse 22 minutes ago Up 22 minutes (healthy) 8123/tcp, 9000/tcp, 9009/tcp 69 | swanlab-cloud ccr.ccs.tencentyun.com/self-hosted/swanlab-cloud:v1 "/docker-entrypoint.…" swanlab-cloud 22 minutes ago Up 21 minutes 80/tcp 70 | swanlab-fluentbit ccr.ccs.tencentyun.com/self-hosted/fluent-bit:3.0 "/fluent-bit/bin/flu…" fluent-bit 22 minutes ago Up 22 minutes 2020/tcp 71 | swanlab-house ccr.ccs.tencentyun.com/self-hosted/swanlab-house:v1 "./app" swanlab-house 22 minutes ago Up 21 minutes (healthy) 3000/tcp 72 | swanlab-logrotate ccr.ccs.tencentyun.com/self-hosted/logrotate:v1 "/sbin/tini -- /usr/…" logrotate 22 minutes ago Up 22 minutes 73 | swanlab-minio ccr.ccs.tencentyun.com/self-hosted/minio:RELEASE.2025-02-28T09-55-16Z "/usr/bin/docker-ent…" minio 22 minutes ago Up 22 minutes (healthy) 9000/tcp 74 | swanlab-next ccr.ccs.tencentyun.com/self-hosted/swanlab-next:v1 "docker-entrypoint.s…" swanlab-next 22 minutes ago Up 21 minutes 3000/tcp 75 | swanlab-postgres ccr.ccs.tencentyun.com/self-hosted/postgres:16.1 "docker-entrypoint.s…" postgres 22 minutes ago Up 22 minutes (healthy) 5432/tcp 76 | swanlab-redis ccr.ccs.tencentyun.com/self-hosted/redis-stack-server:7.2.0-v15 "/entrypoint.sh" redis 22 minutes ago Up 22 minutes (healthy) 6379/tcp 77 | swanlab-server ccr.ccs.tencentyun.com/self-hosted/swanlab-server:v1 "docker-entrypoint.s…" swanlab-server 22 minutes ago Up 21 minutes (healthy) 3000/tcp 78 | swanlab-traefik ccr.ccs.tencentyun.com/self-hosted/traefik:v3.0 "/entrypoint.sh trae…" traefik 22 minutes ago Up 22 minutes (healthy) 0.0.0.0:8000->80/tcp, [::]:8000->80/tcp 79 | ``` 80 | 81 | 通过执行 `docker compose logs ` 可以查看每个容器的日志。 82 | 83 | ### 升级 84 | 85 | 执行 `./upgrade.sh` 可以进行无缝升级。可使用`./upgrade.sh file_path`来进行升级,`file_path`为`docker-compose.yaml`文件路径。,默认为`swanlab/docker-compose.yaml` -------------------------------------------------------------------------------- /docker/README_EN.md: -------------------------------------------------------------------------------- 1 | ## Deployment via Docker 2 | 3 | [中文](./README.md) 4 | > First, make sure you have [docker](https://docs.docker.com/engine/install/) installed on your server. If not installed, you can refer to the [documentation](https://docs.docker.com/engine/install/), or use our installation script [scripts/install-docker.sh](../scripts/install-docker.sh). 5 | > If your server does not have Docker Compose plugin, you can refer to the [documentation](https://github.com/docker/compose/) for downloading and installing. Alternatively, you can use our provided installation script [scripts/install-docker-compose.sh](../scripts/install-docker-compose.sh). 6 | 7 | ### Online Deployment 8 | When the server can be connected to the network, simply execute the `./install-dockerhub.sh` script to start deployment. After successful deployment, you will see the **SwanLab** logo below. 9 | 10 | ```bash 11 | $ ./install.sh 12 | 13 | ... 14 | _____ _ _ 15 | / ____| | | | | 16 | | (_____ ____ _ _ __ | | __ _| |__ 17 | \___ \ \ /\ / / _` | '_ \| | / _` | '_ \ 18 | ____) \ V V / (_| | | | | |___| (_| | |_) | 19 | |_____/ \_/\_/ \__,_|_| |_|______\__,_|_.__/ 20 | 21 | Self-Hosted Docker v1.0 - @SwanLab 22 | 23 | 🎉 Wow, the installation is complete. Everything is perfect. 24 | 🥰 Congratulations, self-hosted SwanLab can be accessed using {IP}:8000 25 | ``` 26 | 27 | ### Offline Deployment 28 | 29 | 1. **Download Images on a Networked Machine:** On a machine with internet access and a Docker environment, download the necessary images by running the script located at `scripts/pull-images.sh`. After the script completes, it will generate a file named `swanlab_images.tar` in the current directory. This file contains the compressed archive of all the required images. **Please ensure that the machine used for downloading has Docker properly installed and running.** 30 | 2. **Transfer the Archive to the Target Machine:** Upload the `swanlab_images.tar` file to your target machine. (You can use tools like `sftp` for this purpose). 31 | 3. **Load Images on the Target Machine:** On the target server, run the command `docker load -i swanlab_images.tar` to load the images from the archive. After the loading process is complete, you can verify the image list using the `docker images` command. It should display all the images contained in the archive. 32 | 4. **Install SwanLab:** Proceed with the installation by executing `./install.sh`, following the same steps as the online deployment method. 33 | 34 | ### Configurable Items 35 | 36 | The script will prompt for two configurable items during execution: 37 | 38 | 1. Data storage path, default is `./data`. It's recommended to choose a fixed path for long-term storage, such as `/data`. 39 | 2. Service exposure port, default is `8000`. If deployed on a public server, it can be set to `80`. 40 | 41 | If interactive configuration is not needed, the script also provides three command line options: 42 | 43 | - `-d`: Specify the data storage path 44 | - `-p`: Service exposure port 45 | - `-s`: Skip interactive configuration. If you don't want interactive configuration, you must add `-s` 46 | 47 | For example, to specify the storage path as `/data` and expose port `80`: 48 | 49 | ```bash 50 | $ ./install.sh -d /data -p 80 -s 51 | ``` 52 | 53 | ### Execution Results 54 | 55 | After successful script execution, a `swanlab/` directory will be created, and two files will be generated in the current directory: 56 | 57 | - `docker-compose.yaml`: Configuration file for Docker Compose 58 | - `.env`: Corresponding key file, storing the initialization password for the database 59 | 60 | Execute `docker compose ps -a` in the current directory to check the running status of all containers: 61 | 62 | ```bash 63 | $ docker compose ps -a (base) 64 | NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS 65 | swanlab-clickhouse ccr.ccs.tencentyun.com/self-hosted/clickhouse:24.3 "/entrypoint.sh" clickhouse 22 minutes ago Up 22 minutes (healthy) 8123/tcp, 9000/tcp, 9009/tcp 66 | swanlab-cloud ccr.ccs.tencentyun.com/self-hosted/swanlab-cloud:v1 "/docker-entrypoint.…" swanlab-cloud 22 minutes ago Up 21 minutes 80/tcp 67 | swanlab-fluentbit ccr.ccs.tencentyun.com/self-hosted/fluent-bit:3.0 "/fluent-bit/bin/flu…" fluent-bit 22 minutes ago Up 22 minutes 2020/tcp 68 | swanlab-house ccr.ccs.tencentyun.com/self-hosted/swanlab-house:v1 "./app" swanlab-house 22 minutes ago Up 21 minutes (healthy) 3000/tcp 69 | swanlab-logrotate ccr.ccs.tencentyun.com/self-hosted/logrotate:v1 "/sbin/tini -- /usr/…" logrotate 22 minutes ago Up 22 minutes 70 | swanlab-minio ccr.ccs.tencentyun.com/self-hosted/minio:RELEASE.2025-02-28T09-55-16Z "/usr/bin/docker-ent…" minio 22 minutes ago Up 22 minutes (healthy) 9000/tcp 71 | swanlab-next ccr.ccs.tencentyun.com/self-hosted/swanlab-next:v1 "docker-entrypoint.s…" swanlab-next 22 minutes ago Up 21 minutes 3000/tcp 72 | swanlab-postgres ccr.ccs.tencentyun.com/self-hosted/postgres:16.1 "docker-entrypoint.s…" postgres 22 minutes ago Up 22 minutes (healthy) 5432/tcp 73 | swanlab-redis ccr.ccs.tencentyun.com/self-hosted/redis-stack-server:7.2.0-v15 "/entrypoint.sh" redis 22 minutes ago Up 22 minutes (healthy) 6379/tcp 74 | swanlab-server ccr.ccs.tencentyun.com/self-hosted/swanlab-server:v1 "docker-entrypoint.s…" swanlab-server 22 minutes ago Up 21 minutes (healthy) 3000/tcp 75 | swanlab-traefik ccr.ccs.tencentyun.com/self-hosted/traefik:v3.0 "/entrypoint.sh trae…" traefik 22 minutes ago Up 22 minutes (healthy) 0.0.0.0:8000->80/tcp, [::]:8000->80/tcp 76 | ``` 77 | 78 | You can view the logs of each container by executing `docker compose logs `. 79 | 80 | ### Upgrade 81 | 82 | Execute `./upgrade.sh` to upgrade seamlessly. -------------------------------------------------------------------------------- /docker/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | networks: 2 | swanlab-net: 3 | name: swanlab-net 4 | 5 | volumes: 6 | swanlab-house: 7 | name: swanlab-house 8 | fluent-bit: 9 | name: fluent-bit 10 | 11 | x-common: &common 12 | networks: 13 | - swanlab-net 14 | restart: unless-stopped 15 | logging: 16 | options: 17 | max-size: 50m 18 | max-file: "3" 19 | 20 | services: 21 | # Gateway 22 | traefik: 23 | <<: *common 24 | image: ccr.ccs.tencentyun.com/self-hosted/traefik:v3.0 25 | container_name: swanlab-traefik 26 | ports: 27 | - "8000:80" 28 | volumes: 29 | - /var/run/docker.sock:/var/run/docker.sock 30 | healthcheck: 31 | test: ["CMD", "wget", "--spider", "-q", "0.0.0.0:8080/ping"] 32 | interval: 10s 33 | timeout: 5s 34 | retries: 3 35 | # Databases 36 | postgres: 37 | <<: *common 38 | image: ccr.ccs.tencentyun.com/self-hosted/postgres:16.1 39 | container_name: swanlab-postgres 40 | environment: 41 | TZ: UTC 42 | POSTGRES_USER: swanlab 43 | POSTGRES_PASSWORD: swanlab-postgres 44 | POSTGRES_DB: app 45 | volumes: 46 | - ./data/postgres/data:/var/lib/postgresql/data 47 | healthcheck: 48 | test: ["CMD-SHELL", "pg_isready"] 49 | interval: 10s 50 | timeout: 5s 51 | retries: 5 52 | redis: 53 | <<: *common 54 | image: ccr.ccs.tencentyun.com/self-hosted/redis-stack-server:7.2.0-v15 55 | container_name: swanlab-redis 56 | volumes: 57 | - ./data/redis:/data 58 | healthcheck: 59 | test: ["CMD", "redis-cli", "ping"] 60 | interval: 10s 61 | timeout: 5s 62 | retries: 3 63 | clickhouse: 64 | <<: *common 65 | image: ccr.ccs.tencentyun.com/self-hosted/clickhouse:24.3 66 | container_name: swanlab-clickhouse 67 | volumes: 68 | - ./data/clickhouse:/var/lib/clickhouse/ 69 | environment: 70 | TZ: UTC 71 | CLICKHOUSE_USER: swanlab 72 | CLICKHOUSE_PASSWORD: swanlab-clickhouse 73 | CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1 74 | healthcheck: 75 | test: ["CMD", "wget", "--spider", "-q", "0.0.0.0:8123/ping"] 76 | interval: 10s 77 | timeout: 5s 78 | retries: 3 79 | logrotate: 80 | <<: *common 81 | image: ccr.ccs.tencentyun.com/self-hosted/logrotate:v1 82 | container_name: swanlab-logrotate 83 | volumes: 84 | - swanlab-house:/data 85 | environment: 86 | LOGS_DIRECTORIES: "/data" 87 | LOGROTATE_COPIES: 25 88 | LOGROTATE_SIZE: "25M" 89 | LOGROTATE_CRONSCHEDULE: "*/20 * * * * *" 90 | LOGROTATE_INTERVAL: daily 91 | labels: 92 | - "traefik.enable=false" 93 | fluent-bit: 94 | <<: *common 95 | image: ccr.ccs.tencentyun.com/self-hosted/fluent-bit:3.0 96 | container_name: swanlab-fluentbit 97 | command: ["fluent-bit/bin/fluent-bit", "-c", "/conf/fluent-bit.conf"] 98 | volumes: 99 | - fluent-bit:/data 100 | - swanlab-house:/metrics 101 | environment: 102 | LOG_PATH: /metrics/*.log 103 | CLICKHOUSE_HOST: clickhouse 104 | CLICKHOUSE_PORT: 8123 105 | CLICKHOUSE_USER: swanlab 106 | CLICKHOUSE_PASS: swanlab-clickhouse 107 | minio: 108 | <<: *common 109 | image: ccr.ccs.tencentyun.com/self-hosted/minio:RELEASE.2025-02-28T09-55-16Z 110 | container_name: swanlab-minio 111 | volumes: 112 | - ./data/minio:/data 113 | environment: 114 | MINIO_ROOT_USER: swanlab 115 | MINIO_ROOT_PASSWORD: swanlab-minio 116 | labels: 117 | - "traefik.http.services.minio.loadbalancer.server.port=9000" 118 | - "traefik.http.routers.minio1.rule=PathPrefix(`/swanlab-public`)" 119 | - "traefik.http.routers.minio1.middlewares=minio-host@file" 120 | - "traefik.http.routers.minio2.rule=PathPrefix(`/swanlab-private`)" 121 | - "traefik.http.routers.minio2.middlewares=minio-host@file" 122 | command: server /data --console-address ":9001" 123 | healthcheck: 124 | test: ["CMD", "mc", "ready", "local"] 125 | interval: 10s 126 | timeout: 5s 127 | retries: 3 128 | create-buckets: 129 | image: ccr.ccs.tencentyun.com/self-hosted/minio-mc:RELEASE.2025-04-08T15-39-49Z 130 | container_name: swanlab-minio-mc 131 | networks: 132 | - swanlab-net 133 | depends_on: 134 | minio: 135 | condition: service_healthy 136 | entrypoint: > 137 | /bin/sh -c " 138 | mc alias set myminio http://minio:9000 swanlab swanlab-minio 139 | # private bucket 140 | mc mb --ignore-existing myminio/swanlab-private 141 | mc anonymous set private myminio/swanlab-private 142 | # public bucket 143 | mc mb --ignore-existing myminio/swanlab-public 144 | mc anonymous set public myminio/swanlab-public 145 | " 146 | # swanlab services 147 | swanlab-server: 148 | <<: *common 149 | image: swanlab/swanlab-server:v1.2 150 | container_name: swanlab-server 151 | depends_on: 152 | postgres: 153 | condition: service_healthy 154 | redis: 155 | condition: service_healthy 156 | environment: 157 | - DATABASE_URL=postgresql://swanlab:swanlab-postgres@postgres:5432/app?schema=public 158 | - DATABASE_URL_REPLICA=postgresql://swanlab:swanlab-postgres@postgres:5432/app?schema=public 159 | - REDIS_URL=redis://default@redis:6379 160 | - SERVER_PREFIX=/api 161 | - ACCESS_KEY=swanlab 162 | - SECRET_KEY=swanlab-minio 163 | - VERSION=1.2.0 164 | labels: 165 | - "traefik.http.routers.swanlab-server.rule=PathPrefix(`/api`)" 166 | - "traefik.http.routers.swanlab-server.middlewares=preprocess@file" 167 | command: bash -c "npx prisma migrate deploy && node migrate.js && pm2-runtime app.js" 168 | healthcheck: 169 | test: ["CMD", "wget", "--spider", "-q", "0.0.0.0:3000/api/"] 170 | interval: 10s 171 | timeout: 5s 172 | retries: 3 173 | swanlab-house: 174 | <<: *common 175 | image: ccr.ccs.tencentyun.com/self-hosted/swanlab-house:v1.2 176 | container_name: swanlab-house 177 | depends_on: 178 | clickhouse: 179 | condition: service_healthy 180 | redis: 181 | condition: service_healthy 182 | environment: 183 | - SH_API_PREFIX=/api/house 184 | - SH_LOG_PATH=/data/metrics.log 185 | - SH_DATABASE_URL=tcp://swanlab:swanlab-clickhouse@clickhouse:9000/app 186 | - SH_SERVER_URL=http://swanlab-server:3000/api 187 | - SH_MINIO_SECRET_ID=swanlab 188 | - SH_MINIO_SECRET_KEY=swanlab-minio 189 | - SH_DISTRIBUTED_ENABLE=true 190 | - SH_REDIS_URL=redis://default@redis:6379 191 | labels: 192 | - "traefik.http.routers.swanlab-house.rule=PathPrefix(`/api/house`) || PathPrefix(`/api/internal`)" 193 | - "traefik.http.routers.swanlab-house.middlewares=preprocess@file" 194 | volumes: 195 | - swanlab-house:/data 196 | healthcheck: 197 | test: ["CMD", "wget", "--spider", "-q", "0.0.0.0:3000/api/house/health"] 198 | interval: 10s 199 | timeout: 5s 200 | retries: 3 201 | swanlab-cloud: 202 | <<: *common 203 | image: ccr.ccs.tencentyun.com/self-hosted/swanlab-cloud:v1.2 204 | container_name: swanlab-cloud 205 | depends_on: 206 | swanlab-server: 207 | condition: service_healthy 208 | swanlab-next: 209 | <<: *common 210 | image: ccr.ccs.tencentyun.com/self-hosted/swanlab-next:v1.2 211 | container_name: swanlab-next 212 | depends_on: 213 | swanlab-server: 214 | condition: service_healthy 215 | environment: 216 | - NEXT_CLOUD_URL=http://swanlab-cloud:80 217 | labels: 218 | - "traefik.http.routers.swanlab-next.rule=PathPrefix(`/`)" 219 | -------------------------------------------------------------------------------- /docker/install-dockerhub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # some fancy scripts 4 | red=$(tput setaf 1) 5 | green=$(tput setaf 2) 6 | yellow=$(tput setaf 3) 7 | bold=$(tput bold) 8 | reset=$(tput sgr0) 9 | 10 | # ----------------------------------------------- 11 | # The following are all the parameters that can be set. 12 | # the path to store data 13 | # shell flag: -d, such as: -d /path/to/data 14 | DATA_PATH="./data" 15 | # the port to expose, and port 8000 is the default network port for web servers using HTTP. 16 | # shell flag: -p, such as: -p 8080 17 | EXPOSE_PORT=8000 18 | # skip input, default is 0 19 | # shell flag: -s, if -s is added, no manual input is required 20 | SKIP_INPUT=0 21 | 22 | while getopts ":d:p:" opt; do 23 | case ${opt} in 24 | d ) 25 | DATA_PATH="$OPTARG" 26 | ;; 27 | p ) 28 | EXPOSE_PORT="$OPTARG" 29 | ;; 30 | s ) 31 | SKIP_INPUT=1 32 | ;; 33 | \? ) 34 | echo "🧐 Invalid option: -$OPTARG" >&2 35 | exit 1 36 | ;; 37 | : ) 38 | echo "🧐 Option -$OPTARG need a parameter." >&2 39 | exit 1 40 | ;; 41 | esac 42 | done 43 | 44 | # ----------------------------------------------- 45 | 46 | # check if docker is installed 47 | if ! command -v docker &>/dev/null; then 48 | echo "😰 ${red}Docker is not installed.${reset}" 49 | echo "😁 ${bold}Please use the install script (${green}install-docker.sh${reset})${bold} located in the scripts directory.${reset}" 50 | echo 51 | exit 1 52 | fi 53 | 54 | echo "🤩 ${bold}Docker is installed, so let's get started.${reset}" 55 | 56 | # check if docker daemon is running 57 | echo "🧐 Checking if Docker is running..." 58 | docker_not_running=0 59 | 60 | # Different platform methods 61 | if [[ "$(uname -s)" == "Linux" ]]; then 62 | # Linux use systemctl to check 63 | if ! systemctl is-active docker >/dev/null 2>&1; then 64 | docker_not_running=1 65 | fi 66 | else 67 | # macOs/Windows use docker info to check 68 | if ! docker info >/dev/null 2>&1; then 69 | docker_not_running=1 70 | fi 71 | fi 72 | 73 | if [[ $docker_not_running -eq 1 ]]; then 74 | echo "😰 ${red}Docker daemon is not running.${reset}" 75 | if [[ "$(uname -s)" == "Linux" ]]; then 76 | # Linux systems provide options for automatic startup 77 | read -p "😁 ${bold}Would you like to start Docker now? (y/n): " START_DOCKER 78 | if [[ "$START_DOCKER" =~ ^[Yy]$ ]]; then 79 | if ! systemctl start docker; then 80 | echo "❌ ${red}Failed to start Docker. You may need to run with sudo.${reset}" 81 | exit 1 82 | fi 83 | echo "🚀 Starting Docker service..." 84 | # waiting Docker startup 85 | max_attempts=5 86 | attempt=1 87 | while [ $attempt -le $max_attempts ]; do 88 | if systemctl is-active --quiet docker; then 89 | echo "✅ ${green}Docker started successfully!${reset}" 90 | break 91 | fi 92 | sleep 1 93 | ((attempt++)) 94 | done 95 | 96 | # final check 97 | if ! systemctl is-active --quiet docker; then 98 | echo "❌ ${red}Docker failed to start after $max_attempts second attempts${reset}" 99 | exit 1 100 | fi 101 | else 102 | echo "👋 ${yellow}Operation canceled. Docker must be running to continue.${reset}" 103 | exit 1 104 | fi 105 | else 106 | # macOS/Windows systems don't provide automatic startup options 107 | echo "💡 ${yellow}Please start Docker Desktop manually and ensure it's running:" 108 | echo "1. Open Docker Desktop application" 109 | echo "2. Wait until the whale icon shows \"Docker Desktop is running\"" 110 | echo "3. Rerun this installation script${reset}" 111 | exit 1 112 | fi 113 | fi 114 | 115 | mkdir -p swanlab && cd swanlab 116 | 117 | # Select whether to use this configuration 118 | if [ ! -f .env ] && [ "$SKIP_INPUT" -eq 0 ]; then 119 | # ---- DATA_PATH 120 | echo 121 | read -p "1. Use the default path (${bold}$DATA_PATH${reset})? (y/n): " USE_DEFAULT 122 | 123 | # Process the user's choice 124 | if [[ -n "$USE_DEFAULT" && ! "$USE_DEFAULT" =~ ^[Yy]$ ]]; then 125 | read -p " Enter a custom path: " DATA_PATH 126 | fi 127 | # Trim the end of `/` 128 | DATA_PATH=$(echo "$DATA_PATH" | sed 's:/*$::') 129 | echo " The selected path is: ${green}$DATA_PATH${reset}" 130 | 131 | # ---- EXPOSE_PORT 132 | read -p "2. Use the default port (${bold}$EXPOSE_PORT${reset})? (y/n): " USE_DEFAULT1 133 | 134 | # Process the user's choice 135 | if [[ -n "$USE_DEFAULT1" && ! "$USE_DEFAULT1" =~ ^[Yy]$ ]]; then 136 | read -p " Enter a custom port: " EXPOSE_PORT 137 | fi 138 | echo " The exposed port is: ${green}$EXPOSE_PORT${reset} 139 | " 140 | fi 141 | 142 | # random 12-digit password include numbers, uppercase and lowercase letters 143 | random_password() { 144 | openssl rand -base64 12 | tr -dc 'a-zA-Z0-9' | cut -c1-10 145 | } 146 | 147 | POSTGRES_PASSWORD=$(random_password) 148 | CLICKHOUSE_PASSWORD=$(random_password) 149 | MINIO_ROOT_PASSWORD=$(random_password) 150 | 151 | if [ ! -f ".env" ]; then 152 | echo "🤐 Create .env file in current directory to save keys" 153 | echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" > .env 154 | echo "CLICKHOUSE_PASSWORD=$CLICKHOUSE_PASSWORD" >> .env 155 | echo "MINIO_ROOT_PASSWORD=$MINIO_ROOT_PASSWORD" >> .env 156 | echo "DATA_PATH=$DATA_PATH" >> .env 157 | echo "EXPOSE_PORT=$EXPOSE_PORT" >> .env 158 | fi 159 | 160 | export $(grep -v '^#' .env | xargs) 161 | 162 | echo "🥳 Everything's ready for execution." 163 | 164 | # create docker-compose.yaml 165 | [ -f "docker-compose.yaml" ] && rm docker-compose.yaml 166 | cat > docker-compose.yaml < 303 | /bin/sh -c " 304 | mc alias set myminio http://minio:9000 swanlab ${MINIO_ROOT_PASSWORD} 305 | # private bucket 306 | mc mb --ignore-existing myminio/swanlab-private 307 | mc anonymous set private myminio/swanlab-private 308 | # public bucket 309 | mc mb --ignore-existing myminio/swanlab-public 310 | mc anonymous set public myminio/swanlab-public 311 | " 312 | # swanlab services 313 | swanlab-server: 314 | <<: *common 315 | image: swanlab/swanlab-server:v1.2 316 | container_name: swanlab-server 317 | depends_on: 318 | postgres: 319 | condition: service_healthy 320 | redis: 321 | condition: service_healthy 322 | environment: 323 | - DATABASE_URL=postgresql://swanlab:${POSTGRES_PASSWORD}@postgres:5432/app?schema=public 324 | - DATABASE_URL_REPLICA=postgresql://swanlab:${POSTGRES_PASSWORD}@postgres:5432/app?schema=public 325 | - REDIS_URL=redis://default@redis:6379 326 | - SERVER_PREFIX=/api 327 | - ACCESS_KEY=swanlab 328 | - SECRET_KEY=${MINIO_ROOT_PASSWORD} 329 | - VERSION=1.2.0 330 | labels: 331 | - "traefik.http.routers.swanlab-server.rule=PathPrefix(\`/api\`)" 332 | - "traefik.http.routers.swanlab-server.middlewares=preprocess@file" 333 | command: bash -c "npx prisma migrate deploy && node migrate.js && pm2-runtime app.js" 334 | healthcheck: 335 | test: ["CMD", "wget", "--spider", "-q", "0.0.0.0:3000/api/"] 336 | interval: 10s 337 | timeout: 5s 338 | retries: 3 339 | swanlab-house: 340 | <<: *common 341 | image: swanlab/swanlab-house:v1.2 342 | container_name: swanlab-house 343 | depends_on: 344 | clickhouse: 345 | condition: service_healthy 346 | redis: 347 | condition: service_healthy 348 | environment: 349 | - SH_API_PREFIX=/api/house 350 | - SH_LOG_PATH=/data/metrics.log 351 | - SH_DATABASE_URL=tcp://swanlab:${CLICKHOUSE_PASSWORD}@clickhouse:9000/app 352 | - SH_SERVER_URL=http://swanlab-server:3000/api 353 | - SH_MINIO_SECRET_ID=swanlab 354 | - SH_MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD} 355 | - SH_DISTRIBUTED_ENABLE=true 356 | - SH_REDIS_URL=redis://default@redis:6379 357 | labels: 358 | - "traefik.http.routers.swanlab-house.rule=PathPrefix(\`/api/house\`) || PathPrefix(\`/api/internal\`)" 359 | - "traefik.http.routers.swanlab-house.middlewares=preprocess@file" 360 | volumes: 361 | - swanlab-house:/data 362 | healthcheck: 363 | test: ["CMD", "wget", "--spider", "-q", "0.0.0.0:3000/api/house/health"] 364 | interval: 10s 365 | timeout: 5s 366 | retries: 3 367 | swanlab-cloud: 368 | <<: *common 369 | image: swanlab/swanlab-cloud:v1.2 370 | container_name: swanlab-cloud 371 | depends_on: 372 | swanlab-server: 373 | condition: service_healthy 374 | swanlab-next: 375 | <<: *common 376 | image: swanlab/swanlab-next:v1.2 377 | container_name: swanlab-next 378 | depends_on: 379 | swanlab-server: 380 | condition: service_healthy 381 | environment: 382 | - NEXT_CLOUD_URL=http://swanlab-cloud:80 383 | labels: 384 | - "traefik.http.routers.swanlab-next.rule=PathPrefix(\`/\`)" 385 | EOF 386 | 387 | # start docker services 388 | docker compose up -d 389 | 390 | echo -e "${green}${bold}" 391 | echo " _____ _ _ "; 392 | echo " / ____| | | | | "; 393 | echo " | (_____ ____ _ _ __ | | __ _| |__ "; 394 | echo " \___ \ \ /\ / / _\` | '_ \| | / _\` | '_ \ "; 395 | echo " ____) \ V V / (_| | | | | |___| (_| | |_) |"; 396 | echo " |_____/ \_/\_/ \__,_|_| |_|______\__,_|_.__/ "; 397 | echo " "; 398 | echo " Self-Hosted Docker v1.2 - @SwanLab" 399 | echo -e "${reset}" 400 | echo "🎉 Wow, the installation is complete. Everything is perfect." 401 | echo "🥰 Congratulations, self-hosted SwanLab can be accessed using ${green}{IP}:${EXPOSE_PORT}${reset}" 402 | echo "" -------------------------------------------------------------------------------- /docker/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # some fancy scripts 4 | red=$(tput setaf 1) 5 | green=$(tput setaf 2) 6 | yellow=$(tput setaf 3) 7 | bold=$(tput bold) 8 | reset=$(tput sgr0) 9 | 10 | # ----------------------------------------------- 11 | # The following are all the parameters that can be set. 12 | # the path to store data 13 | # shell flag: -d, such as: -d /path/to/data 14 | DATA_PATH="./data" 15 | # the port to expose, and port 8000 is the default network port for web servers using HTTP. 16 | # shell flag: -p, such as: -p 8080 17 | EXPOSE_PORT=8000 18 | # skip input, default is 0 19 | # shell flag: -s, if -s is added, no manual input is required 20 | SKIP_INPUT=0 21 | 22 | while getopts ":d:p:" opt; do 23 | case ${opt} in 24 | d ) 25 | DATA_PATH="$OPTARG" 26 | ;; 27 | p ) 28 | EXPOSE_PORT="$OPTARG" 29 | ;; 30 | s ) 31 | SKIP_INPUT=1 32 | ;; 33 | \? ) 34 | echo "🧐 Invalid option: -$OPTARG" >&2 35 | exit 1 36 | ;; 37 | : ) 38 | echo "🧐 Option -$OPTARG need a parameter." >&2 39 | exit 1 40 | ;; 41 | esac 42 | done 43 | 44 | # ----------------------------------------------- 45 | 46 | # check if docker is installed 47 | if ! command -v docker &>/dev/null; then 48 | echo "😰 ${red}Docker is not installed.${reset}" 49 | echo "😁 ${bold}Please use the install script (${green}install-docker.sh${reset})${bold} located in the scripts directory.${reset}" 50 | echo 51 | exit 1 52 | fi 53 | 54 | echo "🤩 ${bold}Docker is installed, so let's get started.${reset}" 55 | 56 | # check if docker compose is installed 57 | if ! docker compose version &>/dev/null; then 58 | echo "😰 ${yellow}Docker Compose may not install ${reset}" 59 | 60 | if [[ "$(uname -s)" == "Linux" ]]; then 61 | echo "😁 ${bold}You can use the install script (${green}install-docker-compose.sh${reset})${bold} located in the scripts directory.${reset}" 62 | else 63 | echo "🧐 ${red}macOS/Windows detected: Docker Compose is included in Docker Desktop. Please install Docker Desktop${reset}" 64 | exit 1 65 | fi 66 | fi 67 | 68 | 69 | # check if docker daemon is running 70 | echo "🧐 Checking if Docker is running..." 71 | docker_not_running=1 72 | 73 | if docker info >/dev/null 2>&1; then 74 | docker_not_running=0 75 | fi 76 | 77 | if [[ $docker_not_running -eq 1 ]]; then 78 | echo "😰 ${red}Docker daemon is not running.${reset}" 79 | if [[ "$(uname -s)" == "Linux" ]]; then 80 | # Linux systems provide options for automatic startup 81 | read -p "😁 ${bold}Would you like to start Docker now? (y/n): " START_DOCKER 82 | if [[ "$START_DOCKER" =~ ^[Yy]$ ]]; then 83 | if ! systemctl start docker; then 84 | echo "❌ ${red}Failed to start Docker. You may need to run with sudo.${reset}" 85 | exit 1 86 | fi 87 | echo "🚀 Starting Docker service..." 88 | # waiting Docker startup 89 | max_attempts=5 90 | attempt=1 91 | while [ $attempt -le $max_attempts ]; do 92 | if systemctl is-active --quiet docker; then 93 | echo "✅ ${green}Docker started successfully!${reset}" 94 | break 95 | fi 96 | sleep 1 97 | ((attempt++)) 98 | done 99 | 100 | # final check 101 | if ! systemctl is-active --quiet docker; then 102 | echo "❌ ${red}Docker failed to start after $max_attempts second attempts${reset}" 103 | exit 1 104 | fi 105 | else 106 | echo "👋 ${yellow}Operation canceled. Docker must be running to continue.${reset}" 107 | exit 1 108 | fi 109 | else 110 | # macOS/Windows systems don't provide automatic startup options 111 | echo "💡 ${yellow}Please start Docker Desktop manually and ensure it's running:" 112 | echo "1. Open Docker Desktop application" 113 | echo "2. Wait until the whale icon shows \"Docker Desktop is running\"" 114 | echo "3. Rerun this installation script${reset}" 115 | exit 1 116 | fi 117 | fi 118 | 119 | mkdir -p swanlab && cd swanlab 120 | 121 | # Select whether to use this configuration 122 | if [ ! -f .env ] && [ "$SKIP_INPUT" -eq 0 ]; then 123 | # ---- DATA_PATH 124 | echo 125 | read -p "1. Use the default path (${bold}$DATA_PATH${reset})? (y/n): " USE_DEFAULT 126 | 127 | # Process the user's choice 128 | if [[ -n "$USE_DEFAULT" && ! "$USE_DEFAULT" =~ ^[Yy]$ ]]; then 129 | read -p " Enter a custom path: " DATA_PATH 130 | fi 131 | # Trim the end of `/` 132 | DATA_PATH=$(echo "$DATA_PATH" | sed 's:/*$::') 133 | echo " The selected path is: ${green}$DATA_PATH${reset}" 134 | 135 | # ---- EXPOSE_PORT 136 | read -p "2. Use the default port (${bold}$EXPOSE_PORT${reset})? (y/n): " USE_DEFAULT1 137 | 138 | # Process the user's choice 139 | if [[ -n "$USE_DEFAULT1" && ! "$USE_DEFAULT1" =~ ^[Yy]$ ]]; then 140 | read -p " Enter a custom port: " EXPOSE_PORT 141 | fi 142 | echo " The exposed port is: ${green}$EXPOSE_PORT${reset} 143 | " 144 | fi 145 | 146 | # random 12-digit password include numbers, uppercase and lowercase letters 147 | random_password() { 148 | openssl rand -base64 12 | tr -dc 'a-zA-Z0-9' | cut -c1-10 149 | } 150 | 151 | POSTGRES_PASSWORD=$(random_password) 152 | CLICKHOUSE_PASSWORD=$(random_password) 153 | MINIO_ROOT_PASSWORD=$(random_password) 154 | 155 | if [ ! -f ".env" ]; then 156 | echo "🤐 Create .env file in current directory to save keys" 157 | echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" > .env 158 | echo "CLICKHOUSE_PASSWORD=$CLICKHOUSE_PASSWORD" >> .env 159 | echo "MINIO_ROOT_PASSWORD=$MINIO_ROOT_PASSWORD" >> .env 160 | echo "DATA_PATH=$DATA_PATH" >> .env 161 | echo "EXPOSE_PORT=$EXPOSE_PORT" >> .env 162 | fi 163 | 164 | export $(grep -v '^#' .env | xargs) 165 | 166 | echo "🥳 Everything's ready for execution." 167 | 168 | # create docker-compose.yaml 169 | [ -f "docker-compose.yaml" ] && rm docker-compose.yaml 170 | cat > docker-compose.yaml < 307 | /bin/sh -c " 308 | mc alias set myminio http://minio:9000 swanlab ${MINIO_ROOT_PASSWORD} 309 | # private bucket 310 | mc mb --ignore-existing myminio/swanlab-private 311 | mc anonymous set private myminio/swanlab-private 312 | # public bucket 313 | mc mb --ignore-existing myminio/swanlab-public 314 | mc anonymous set public myminio/swanlab-public 315 | " 316 | # swanlab services 317 | swanlab-server: 318 | <<: *common 319 | image: ccr.ccs.tencentyun.com/self-hosted/swanlab-server:v1.2 320 | container_name: swanlab-server 321 | depends_on: 322 | postgres: 323 | condition: service_healthy 324 | redis: 325 | condition: service_healthy 326 | environment: 327 | - DATABASE_URL=postgresql://swanlab:${POSTGRES_PASSWORD}@postgres:5432/app?schema=public 328 | - DATABASE_URL_REPLICA=postgresql://swanlab:${POSTGRES_PASSWORD}@postgres:5432/app?schema=public 329 | - REDIS_URL=redis://default@redis:6379 330 | - SERVER_PREFIX=/api 331 | - ACCESS_KEY=swanlab 332 | - SECRET_KEY=${MINIO_ROOT_PASSWORD} 333 | - VERSION=1.2.0 334 | labels: 335 | - "traefik.http.routers.swanlab-server.rule=PathPrefix(\`/api\`)" 336 | - "traefik.http.routers.swanlab-server.middlewares=preprocess@file" 337 | command: bash -c "npx prisma migrate deploy && node migrate.js && pm2-runtime app.js" 338 | healthcheck: 339 | test: ["CMD", "wget", "--spider", "-q", "0.0.0.0:3000/api/"] 340 | interval: 10s 341 | timeout: 5s 342 | retries: 3 343 | swanlab-house: 344 | <<: *common 345 | image: ccr.ccs.tencentyun.com/self-hosted/swanlab-house:v1.2 346 | container_name: swanlab-house 347 | depends_on: 348 | clickhouse: 349 | condition: service_healthy 350 | redis: 351 | condition: service_healthy 352 | environment: 353 | - SH_API_PREFIX=/api/house 354 | - SH_LOG_PATH=/data/metrics.log 355 | - SH_DATABASE_URL=tcp://swanlab:${CLICKHOUSE_PASSWORD}@clickhouse:9000/app 356 | - SH_SERVER_URL=http://swanlab-server:3000/api 357 | - SH_MINIO_SECRET_ID=swanlab 358 | - SH_MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD} 359 | - SH_DISTRIBUTED_ENABLE=true 360 | - SH_REDIS_URL=redis://default@redis:6379 361 | labels: 362 | - "traefik.http.routers.swanlab-house.rule=PathPrefix(\`/api/house\`) || PathPrefix(\`/api/internal\`)" 363 | - "traefik.http.routers.swanlab-house.middlewares=preprocess@file" 364 | volumes: 365 | - swanlab-house:/data 366 | healthcheck: 367 | test: ["CMD", "wget", "--spider", "-q", "0.0.0.0:3000/api/house/health"] 368 | interval: 10s 369 | timeout: 5s 370 | retries: 3 371 | swanlab-cloud: 372 | <<: *common 373 | image: ccr.ccs.tencentyun.com/self-hosted/swanlab-cloud:v1.2 374 | container_name: swanlab-cloud 375 | depends_on: 376 | swanlab-server: 377 | condition: service_healthy 378 | swanlab-next: 379 | <<: *common 380 | image: ccr.ccs.tencentyun.com/self-hosted/swanlab-next:v1.2 381 | container_name: swanlab-next 382 | depends_on: 383 | swanlab-server: 384 | condition: service_healthy 385 | environment: 386 | - NEXT_CLOUD_URL=http://swanlab-cloud:80 387 | labels: 388 | - "traefik.http.routers.swanlab-next.rule=PathPrefix(\`/\`)" 389 | EOF 390 | 391 | # start docker services 392 | docker compose up -d 393 | 394 | echo -e "${green}${bold}" 395 | echo " _____ _ _ "; 396 | echo " / ____| | | | | "; 397 | echo " | (_____ ____ _ _ __ | | __ _| |__ "; 398 | echo " \___ \ \ /\ / / _\` | '_ \| | / _\` | '_ \ "; 399 | echo " ____) \ V V / (_| | | | | |___| (_| | |_) |"; 400 | echo " |_____/ \_/\_/ \__,_|_| |_|______\__,_|_.__/ "; 401 | echo " "; 402 | echo " Self-Hosted Docker v1.2 - @SwanLab" 403 | echo -e "${reset}" 404 | echo "🎉 Wow, the installation is complete. Everything is perfect." 405 | echo "🥰 Congratulations, self-hosted SwanLab can be accessed using ${green}{IP}:${EXPOSE_PORT}${reset}" 406 | echo "" -------------------------------------------------------------------------------- /docker/upgrade.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # update docker-compose.yaml swanlab.* image version 4 | 5 | COMPOSE_FILE="${1:-swanlab/docker-compose.yaml}" 6 | # update swanlab-server replica database config 7 | add_replica_env() { 8 | sed -i.bak -E ' 9 | /^[[:space:]]*swanlab-server:/,/^$/ { 10 | /environment:/,/^[[:space:]]*- / { 11 | /^[[:space:]]*- DATABASE_URL=/ { 12 | p 13 | s/DATABASE_URL=/DATABASE_URL_REPLICA=/ 14 | } 15 | } 16 | } 17 | ' swanlab/docker-compose.yaml 18 | } 19 | 20 | # add new variable for containers config 21 | add_new_var() { 22 | # Arguments: 23 | # : service name 24 | # : label key 25 | # : new variable 26 | local service_name="$1" 27 | local label_key="$2" 28 | local new_val="$3" 29 | local file_path="$COMPOSE_FILE" 30 | # check arguments 31 | if [[ -z "$service_name" || -z "$new_val" ]]; then 32 | echo "error: must input service name and new environment variable" >&2 33 | return 1 34 | fi 35 | 36 | # mktemp 37 | local tmp_file 38 | tmp_file=$(mktemp) || { 39 | echo "can not make temp file" >&2 40 | return 2 41 | } 42 | # do awk operation 43 | awk -v service="$service_name" \ 44 | -v label="$label_key" \ 45 | -v val="$new_val" ' 46 | BEGIN { in_service=0; inserted=0 } 47 | $0 ~ "^ " service ":$" { in_service=1 } 48 | /^ [a-zA-Z-]+:/ && !( $0 ~ "^ " service ":$") { in_service=0 } 49 | in_service && $0 ~ "^ " label ":" { 50 | print $0 51 | print " - " val 52 | inserted=1 53 | next 54 | } 55 | { print } 56 | ' "$file_path" > "$tmp_file" 57 | 58 | # replace file 59 | if ! mv "$tmp_file" "$file_path"; then 60 | echo "replace fail, update docker-compose.yaml locate on ${tmp_file} " >&2 61 | return 3 62 | fi 63 | } 64 | 65 | # update swanlab-server command config 66 | update_server_command() { 67 | sed -i.bak ' 68 | /^[[:space:]]*command: bash -c "npx prisma migrate deploy && pm2-runtime app.js"/ { 69 | s/&& pm2-runtime app.js"/\&\& node migrate.js \&\& pm2-runtime app.js"/ 70 | } 71 | ' "$COMPOSE_FILE" 72 | } 73 | 74 | # change version 75 | update_version() { 76 | local version="$1" 77 | 78 | if [ -z "$version" ]; then 79 | echo "Error: Version number is required." 80 | return 1 81 | fi 82 | 83 | sed -i.bak -E " 84 | /^[[:space:]]+image: .*swanlab-.*:v[^:]+$/ { 85 | s/(:v)[^:]+$/\1${version}/ 86 | } 87 | " "$COMPOSE_FILE" 88 | } 89 | 90 | # check docker-compose.yaml exists 91 | if [ ! -f "$COMPOSE_FILE" ]; then 92 | echo "docker-compose.yaml not found, please run install.sh directly" 93 | exit 1 94 | fi 95 | 96 | # confirm information 97 | read -p "Updating the container version will restart docker compose. Do you agree? [y/N] " confirm 98 | 99 | 100 | # check y or Y 101 | if [[ "$confirm" == [yY] || "$confirm" == [yY][eE][sS] ]]; then 102 | echo "begin update" 103 | # update all containers version 104 | update_version "1.2" 105 | 106 | # update DATABASE_URL_REPLICA 107 | if ! grep -q "DATABASE_URL_REPLICA" "$COMPOSE_FILE"; then 108 | add_replica_env 109 | fi 110 | 111 | # update swanlab-server command 112 | if ! grep -q "node migrate.js" "$COMPOSE_FILE"; then 113 | update_server_command 114 | fi 115 | 116 | # delete backup 117 | rm -f "${COMPOSE_FILE}.bak" 118 | 119 | # add new variable for containers config, it only can be added once and can not be update existing 120 | # add swanlab-house environment variable 121 | if ! grep -q "SH_DISTRIBUTED_ENABLE" "$COMPOSE_FILE"; then 122 | add_new_var "swanlab-house" "environment" "SH_DISTRIBUTED_ENABLE=true" 123 | fi 124 | if ! grep -q "SH_REDIS_URL" "$COMPOSE_FILE"; then 125 | add_new_var "swanlab-house" "environment" "SH_REDIS_URL=redis://default@redis:6379" 126 | fi 127 | # add swanlab-server environment variable 128 | if ! grep -q "VERSION" "$COMPOSE_FILE"; then 129 | add_new_var "swanlab-server" "environment" "VERSION=1.2.0" 130 | fi 131 | 132 | # add missing minio middleware if needed 133 | if ! grep -q "traefik.http.routers.minio2.middlewares=minio-host@file" "$COMPOSE_FILE"; then 134 | add_new_var "minio" "labels" "\"traefik.http.routers.minio2.middlewares=minio-host@file\"" 135 | fi 136 | # restart docker-compose 137 | docker compose -f swanlab/docker-compose.yaml up -d 138 | echo "finish update" 139 | else 140 | echo "update canceled" 141 | exit 1 142 | fi 143 | -------------------------------------------------------------------------------- /scripts/install-docker-compose.sh: -------------------------------------------------------------------------------- 1 | if ! docker compose version &>/dev/null; then 2 | echo "🧐 ${yellow}Docker Compose not found, start installation...${reset}" 3 | 4 | if [[ "$(uname -s)" == "Linux" ]]; then 5 | if [ -f /etc/os-release ]; then 6 | source /etc/os-release 7 | case "$ID" in 8 | ubuntu) 9 | echo "🔧 ${yellow}Adding Docker repository with Aliyun mirror...${reset}" 10 | sudo mkdir -p /etc/apt/keyrings 11 | curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 12 | echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $VERSION_CODENAME stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null 13 | 14 | echo "🔄 ${yellow}Updating package lists...${reset}" 15 | sudo apt-get update -qq || { 16 | echo "❌ ${red}Failed to update package lists${reset}"; 17 | exit 1; 18 | } 19 | 20 | echo "📦 ${yellow}Installing docker-compose-plugin...${reset}" 21 | sudo apt-get install -qq -y docker-compose-plugin || { 22 | echo "❌ ${red}Installation failed, please check network connection${reset}"; 23 | exit 1; 24 | } 25 | ;; 26 | 27 | centos) 28 | echo "🔧 ${yellow}Adding Docker repository with Aliyun mirror for CentOS...${reset}" 29 | sudo yum install -y yum-utils 30 | sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 31 | 32 | echo "🔄 ${yellow}Updating yum cache...${reset}" 33 | sudo yum makecache fast -q || { 34 | echo "❌ ${red}Failed to update yum cache${reset}"; 35 | exit 1; 36 | } 37 | 38 | echo "📦 ${yellow}Installing docker-compose-plugin...${reset}" 39 | sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin || { 40 | echo "❌ ${red}Installation failed, please check network connection${reset}"; 41 | exit 1; 42 | } 43 | 44 | echo "🚀 ${yellow}Starting Docker service...${reset}" 45 | sudo systemctl enable --now docker 46 | ;; 47 | 48 | *) 49 | echo "❌ ${red}Automatic installation only supported on Ubuntu/CentOS${reset}" 50 | exit 1 51 | ;; 52 | esac 53 | 54 | echo "✅ ${green}docker-compose-plugin installed successfully!${reset}" 55 | else 56 | echo "❌ ${red}Unsupported Linux distribution${reset}" 57 | exit 1 58 | fi 59 | else 60 | echo "❌ ${red}macOS/Windows detected: Docker Compose is included in Docker Desktop. Please install Docker Desktop${reset}" 61 | exit 1 62 | fi 63 | fi 64 | -------------------------------------------------------------------------------- /scripts/install-docker.sh: -------------------------------------------------------------------------------- 1 | sudo apt update 2 | yes | sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release 3 | curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 4 | echo \ 5 | "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \ 6 | $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 7 | sudo apt update 8 | yes | sudo apt install docker-ce docker-ce-cli containerd.io 9 | # add the current user to the docker group 10 | sudo usermod -aG docker $USER -------------------------------------------------------------------------------- /scripts/pull-images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 定义要下载的镜像列表 4 | images=( 5 | "ccr.ccs.tencentyun.com/self-hosted/traefik:v3.0" 6 | "ccr.ccs.tencentyun.com/self-hosted/postgres:16.1" 7 | "ccr.ccs.tencentyun.com/self-hosted/redis-stack-server:7.2.0-v15" 8 | "ccr.ccs.tencentyun.com/self-hosted/clickhouse:24.3" 9 | "ccr.ccs.tencentyun.com/self-hosted/logrotate:v1" 10 | "ccr.ccs.tencentyun.com/self-hosted/fluent-bit:3.0" 11 | "ccr.ccs.tencentyun.com/self-hosted/minio:RELEASE.2025-02-28T09-55-16Z" 12 | "ccr.ccs.tencentyun.com/self-hosted/minio-mc:RELEASE.2025-04-08T15-39-49Z" 13 | "ccr.ccs.tencentyun.com/self-hosted/swanlab-server:v1.2" 14 | "ccr.ccs.tencentyun.com/self-hosted/swanlab-house:v1.2" 15 | "ccr.ccs.tencentyun.com/self-hosted/swanlab-cloud:v1.2" 16 | "ccr.ccs.tencentyun.com/self-hosted/swanlab-next:v1.2" 17 | ) 18 | 19 | # 下载镜像 20 | for image in "${images[@]}"; do 21 | docker pull "$image" 22 | done 23 | 24 | # 保存镜像到文件 25 | echo "正在打包所有镜像到 swanlab_images.tar..." 26 | docker save -o ./swanlab_images.tar "${images[@]}" 27 | 28 | echo "所有镜像都打包至 swanlab_images.tar,可直接上传该文件到目标服务器!" --------------------------------------------------------------------------------