├── .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 |
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 |
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 |
--------------------------------------------------------------------------------
/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,可直接上传该文件到目标服务器!"
--------------------------------------------------------------------------------