Omicscloud Docker配置
OmicsCloud Docker 部署说明
本文档用于说明 OmicsCloud Docker 镜像的构建、离线打包、迁移部署、常见配置和排错方法。
OmicsCloud 镜像把应用代码打进 Docker image,运行时可变内容放在镜像外部:
- 配置文件:
docker/conf/conf - 密钥文件:
etc/config/key.pem、etc/config/pubkey.pem - MariaDB
- LDAP
- 用户项目数据、共享目录、GO/KEGG/STRING 等外部数据库资源
注意:容器内部仍然使用 /home/saitoasuka/... 路径,这是因为 OmicsCloud 旧代码里有固定路径依赖。目标 VM 的 Linux 用户名不需要叫 saitoasuka。
一、部署方式选择
| 场景 | 推荐方式 | 主要命令 |
|---|---|---|
| 有网络、可以从 GitHub 构建 | 在线构建 | docker compose build omicscloud-app
|
| 当前 VM 已有测试通过的容器,需要迁移到其他机器 | 制作离线包 | docker commit、docker save、tar
|
| 新 VM 无网络,或不想重新安装 R 包 | 离线恢复 | docker load 后运行 deploy-restore-hostnet.sh
|
| MariaDB/LDAP 是普通网络服务,容器能直接访问 | 默认 bridge 模式 | docker compose up -d --no-build omicscloud-app
|
MariaDB/LDAP 只监听宿主机本地地址,例如 127.0.0.1:1430
|
host network 模式 | bash deploy-restore-hostnet.sh
|
核心区别:
docker-compose.yml:默认 bridge 网络部署。docker-compose.hostnet.yml:用于旧 VM,容器共享宿主机网络,方便访问宿主机本地 MariaDB/LDAP。deploy-restore-hostnet.sh:离线恢复脚本,会自动改配置、处理端口、权限和基础检查。
二、文件分组说明
Docker 构建和运行文件
Dockerfile.app:完整应用镜像构建文件。Dockerfile.app.offline:基于本地已有 base image 重新构建应用层。docker-compose.yml:默认 bridge 模式 compose。docker/shiny-server.conf:Shiny Server 配置。docker/start-omicscloud.sh:容器启动脚本,同时启动 Shiny Server 和后台 worker。docker/conf/conf.example:Docker 部署配置模板。.env.example:端口、挂载目录、镜像名等环境变量模板。
离线恢复相关文件
docker-compose.hostnet.yml:host network 模式 compose。deploy-restore-hostnet.sh:离线恢复部署脚本。
生成出来的离线包文件
这些文件不提交到 Git 仓库,由打包命令生成:
~/Downloads/omicscloud-offline-20260521/ omicscloud-images-20260521.tar.gz omicscloud-compose-20260521.tar.gz RESTORE.txt
离线包包含 Docker 镜像和部署源码配置,但不包含大型外部运行资源,例如:
/home/saitoasuka/mnt/omicscloud/data /home/saitoasuka/mnt/share /home/saitoasuka/mnt/database
这些目录需要在目标 VM 上单独准备或挂载。
三、在线构建启动
适合有网络、可以重新构建镜像的机器。
cd ~/Downloads/omicscloud docker compose build omicscloud-app docker compose up -d omicscloud-app
如果当前用户没有 Docker 权限,命令前加 sudo。
访问地址:
http://localhost:3839/ http://localhost:3839/index/ http://localhost:3839/dashboard/
注意:
docker compose up -d omicscloud-app不会自动重新构建镜像。- 修改应用代码、Dockerfile 或启动脚本后,需要重新执行
docker compose build omicscloud-app。 - 容器不会实时同步宿主机源码,源码是在 build 阶段复制进镜像的。
- 后台分析 worker 日志在:
/var/log/shiny-server/omicscloud-worker.log。
四、制作离线包
适合当前 VM 已经有测试通过的 omicscloud-app 容器,需要迁移到另一台 VM。
cd ~/Downloads/omicscloud stamp=20260521 bundle=~/Downloads/omicscloud-offline-$stamp mkdir -p "$bundle" # 把当前测试通过的容器固化成镜像 sudo docker commit omicscloud-app omicscloud-app:local sudo docker tag omicscloud-app:local omicscloud-app-base:$stamp # 导出镜像 sudo docker save omicscloud-app:local omicscloud-app-base:$stamp \ | gzip -c > "$bundle/omicscloud-images-$stamp.tar.gz" # 打包部署源码和配置 tar \ --exclude='.git' \ --exclude='*.tar.gz' \ -czf "$bundle/omicscloud-compose-$stamp.tar.gz" \ -C ~/Downloads omicscloud cat > "$bundle/RESTORE.txt" <<EOF Restore OmicsCloud offline package 1. Load image: gunzip -c omicscloud-images-$stamp.tar.gz | sudo docker load 2. Extract compose/source: mkdir -p ~/Downloads/omicscloud-restore-test tar -xzf omicscloud-compose-$stamp.tar.gz -C ~/Downloads/omicscloud-restore-test --strip-components=1 3. Start app: cd ~/Downloads/omicscloud-restore-test bash deploy-restore-hostnet.sh 4. Verify: sudo docker compose -f docker-compose.hostnet.yml ps EOF ls -lh "$bundle"
打包后检查:
ls -lh "$bundle" tar -tzf "$bundle/omicscloud-compose-$stamp.tar.gz" | head gunzip -t "$bundle/omicscloud-images-$stamp.tar.gz"
离线包必须包含:
omicscloud-images-<date>.tar.gz omicscloud-compose-<date>.tar.gz RESTORE.txt
源码包里应该包含:
omicscloud/docker-compose.hostnet.yml omicscloud/deploy-restore-hostnet.sh
五、从离线包部署
在新 VM 上,先加载镜像,再启动服务。--no-build 要求本机已经存在镜像,否则会报 No such image: omicscloud-app:local。
cd ~/Downloads/omicscloud-offline-20260521 gunzip -c omicscloud-images-20260521.tar.gz | sudo docker load mkdir -p ~/Downloads/omicscloud-restore-test tar -xzf omicscloud-compose-20260521.tar.gz \ -C ~/Downloads/omicscloud-restore-test \ --strip-components=1 cd ~/Downloads/omicscloud-restore-test bash deploy-restore-hostnet.sh
deploy-restore-hostnet.sh 会处理:
- 停止宿主机已有的
shiny-server,释放3838端口。 - 自动识别当前 VM IP,写入
server_href。 - 默认写入
db_host=127.0.0.1、db_port=1430、ldap://127.0.0.1:389。 - 创建外部数据目录、共享目录、数据库目录。
- 把用户数据目录和共享目录授权给容器内
shiny用户,默认 UID/GID 为999:999。 - 启动
docker-compose.hostnet.yml。 - 检查 MariaDB、LDAP、HTTP 和数据目录写权限。
如果目标 VM 配置不同,可以覆盖变量:
# MariaDB 使用 3306 DB_PORT=3306 bash deploy-restore-hostnet.sh # MariaDB 在其他服务器,LDAP 在本机 DB_HOST=192.168.2.50 DB_PORT=3306 bash deploy-restore-hostnet.sh # MariaDB 和 LDAP 都在其他服务器 DB_HOST=192.168.2.50 DB_PORT=3306 LDAP_URL=ldap://192.168.2.50:389 bash deploy-restore-hostnet.sh # 自动识别 IP 不对时,手动指定访问 IP HOST_IP=192.168.2.112 bash deploy-restore-hostnet.sh
部署后访问:
http://<HOST_IP>:3838/index/ http://<HOST_IP>:3838/dashboard/
六、外部目录要求
运行时至少需要以下目录:
/home/saitoasuka/mnt/omicscloud/data /home/saitoasuka/mnt/share /home/saitoasuka/mnt/database
容器内固定挂载路径:
用户项目数据: /home/saitoasuka/mnt/omicscloud/data 共享目录: /home/saitoasuka/mnt/share 数据库资源: /home/saitoasuka/mnt/database
/home/saitoasuka/mnt/database 应包含:
find_enrichment.py go.obo go-basic.obo acc_list/ KEGG/ STRING/
KEGG 图相关路径示例:
KEGG/KEGG_xml/hsa/ KEGG/KEGG_png/hsa/
检查示例:
sudo docker exec -it omicscloud-app bash -lc ' ls -lh /home/saitoasuka/mnt/database/find_enrichment.py ls -lh /home/saitoasuka/mnt/database/go.obo ls -lh /home/saitoasuka/mnt/database/go-basic.obo ls -lh /home/saitoasuka/mnt/database/KEGG/KEGG_png/hsa/hsa04610.png ls -lh /home/saitoasuka/mnt/database/KEGG/KEGG_xml/hsa/hsa04610.xml '
七、权限要求
容器内 Shiny 运行用户通常是:
uid=999(shiny) gid=999(shiny)
项目数据目录必须允许该用户写入。检查:
sudo docker exec -it omicscloud-app id shiny sudo docker exec -it omicscloud-app bash -lc ' su -s /bin/bash -m shiny -c " mkdir -p /home/saitoasuka/mnt/omicscloud/data/1/shiny-write-test date > /home/saitoasuka/mnt/omicscloud/data/1/shiny-write-test/check.txt cat /home/saitoasuka/mnt/omicscloud/data/1/shiny-write-test/check.txt " '
如果报 Permission denied,在宿主机上修复真实挂载源目录:
sudo docker inspect omicscloud-app --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'
sudo chown -R 999:999 /home/saitoasuka/mnt/omicscloud/data /home/saitoasuka/mnt/share sudo chmod -R u+rwX,g+rwX /home/saitoasuka/mnt/omicscloud/data /home/saitoasuka/mnt/share
八、常用检查命令
查看容器状态:
sudo docker compose -f docker-compose.hostnet.yml ps sudo docker logs omicscloud-app --tail 200
查看最新 Shiny 页面日志:
sudo docker exec -it omicscloud-app bash -lc ' f=$(ls -t /var/log/shiny-server/dashboard-shiny-*.log 2>/dev/null | head -n 1) echo "$f" tail -n 200 "$f" '
查看后台 worker 日志:
sudo docker exec -it omicscloud-app bash -lc ' tail -n 200 /var/log/shiny-server/omicscloud-worker.log '
查看后台分析进程:
sudo docker exec -it omicscloud-app bash -lc ' ps -ef | grep -E "omicscloud-server|proteome_script|metabolite_script|liptpp_script" | grep -v grep || true '
检查 DB/LDAP:
sudo docker exec -it omicscloud-app bash -lc ' Rscript -e " library(DBI); library(RMariaDB); library(readr); library(tibble) conf <- deframe(read_tsv(\"/home/saitoasuka/shiny-server/omicscloud/etc/config/conf\", col_names=FALSE, show_col_types=FALSE)) con <- dbConnect(RMariaDB::MariaDB(), dbname=\"userdb\", host=conf[[\"db_host\"]], port=as.integer(conf[[\"db_port\"]]), user=conf[[\"db_user\"]], password=conf[[\"db_pswd\"]]) print(dbGetQuery(con, \"show tables\")) dbDisconnect(con) " ldapsearch -x -H ldap://127.0.0.1:389 -s base -b "" namingContexts '
检查关键 R 包:
sudo docker exec -it omicscloud-app bash -lc ' Rscript -e "library(reactwidgets); cat(\"reactwidgets ok\n\")" Rscript -e "library(pdftools); library(rgl); library(htmlwidgets); cat(\"report packages ok\n\")" '
九、项目失败时如何定位
如果 Dashboard 中 function 或 export_report 变红,先查项目错误日志:
uid=<project_uid>
sudo docker exec -it omicscloud-app bash -lc "
p=/home/saitoasuka/mnt/omicscloud/data/1/$uid
tail -n 220 \"\$p/${uid}_error_log.txt\" 2>/dev/null || true
grep -nE 'Error:|Error in|错误|Execution halted|停止执行|无法|No such|cannot|failed|Killed|OOM|Access denied|Permission denied|NA/KEGG_png|reactwidgets|acc_list|gzfile|open the connection' \"\$p/${uid}_error_log.txt\" 2>/dev/null | tail -120 || true
"
查看数据库中的项目状态:
sudo docker exec -it omicscloud-app bash -lc ' Rscript -e " library(DBI); library(RMariaDB); library(readr); library(tibble) conf <- deframe(read_tsv(\"/home/saitoasuka/shiny-server/omicscloud/etc/config/conf\", col_names=FALSE, show_col_types=FALSE)) con <- dbConnect(RMariaDB::MariaDB(), dbname=\"omicscloud_db\", host=conf[[\"db_host\"]], port=as.integer(conf[[\"db_port\"]]), user=conf[[\"db_user\"]], password=conf[[\"db_pswd\"]]) print(dbGetQuery(con, \"select uid, work, status, updated_at from project_info order by updated_at desc limit 30\"), row.names=FALSE) dbDisconnect(con) " '
状态含义:
5:完成。2:运行中。4:失败。7:等待。
十、常见问题
1. No such image: omicscloud-app:local
原因:新 VM 没有加载离线镜像。
处理:
gunzip -c omicscloud-images-20260521.tar.gz | sudo docker load sudo docker image ls | grep omicscloud
2. 3838 端口被占用
原因:宿主机已有 shiny-server 占用 3838。
检查:
sudo ss -lntp | grep ':3838'
处理:
sudo systemctl stop shiny-server sudo docker compose -f docker-compose.hostnet.yml up -d --no-build omicscloud-app
3. 页面能打开,但登录失败
通常是 MariaDB 或 LDAP 没连上。
检查:
sudo docker exec -it omicscloud-app bash -lc ' grep -nE "^(db_host|db_port|db_user|ldap_server_url|server_href)" /home/saitoasuka/shiny-server/omicscloud/etc/config/conf '
host network 模式下,如果 MariaDB 在宿主机本地 127.0.0.1:1430,推荐:
db_host 127.0.0.1 db_port 1430 ldap_server_url ldap://127.0.0.1:389
4. function/export_report 失败,日志里连接 127.0.0.1:3306
错误示例:
task 1 failed - "Failed to connect: Can't connect to MySQL server on '127.0.0.1:3306' (111)"
原因:旧代码中有数据库端口硬编码为 3306,但当前 VM 的 MariaDB 实际是 1430。
修复原则:代码中数据库连接必须使用 arg_list"db_port",不要写死 3306。
应检查:
sudo docker exec -it omicscloud-app bash -lc ' grep -n "port = 3306\|connect_speciesdb_info\|connect_kegg_db" /home/saitoasuka/shiny-server/omicscloud/etc/dep/proteome_quant_lib.r '
修复后应看到类似:
port = arg_list[["db_port"]] user = arg_list[["db_user"]] password = arg_list[["db_pswd"]]
5. Permission denied 或 para.Rdata 无法写入
错误示例:
cannot create file ... reason 'Permission denied' cannot open compressed file ... para.Rdata
原因:宿主机挂载目录不是容器 shiny 用户可写。
处理:
sudo chown -R 999:999 /home/saitoasuka/mnt/omicscloud/data /home/saitoasuka/mnt/share sudo chmod -R u+rwX,g+rwX /home/saitoasuka/mnt/omicscloud/data /home/saitoasuka/mnt/share
6. KEGG 路径出现 NA/KEGG_png
错误示例:
无法打开文件 'NA/KEGG_png/hsa/hsa04610.png'
原因:KEGG XML/PNG 路径为空或数据库挂载不完整。 检查:
sudo docker exec -it omicscloud-app bash -lc ' ls -lh /home/saitoasuka/mnt/database/KEGG/KEGG_png/hsa/hsa04610.png ls -lh /home/saitoasuka/mnt/database/KEGG/KEGG_xml/hsa/hsa04610.xml '
7. 缺少 reactwidgets
错误示例:
there is no package called 'reactwidgets'
处理:使用已经包含 reactwidgets 的镜像重新打包/部署。检查:
sudo docker exec -it omicscloud-app bash -lc ' Rscript -e "library(reactwidgets); cat(\"reactwidgets ok\n\")" '
十一、重新入队失败项目
如果代码或配置修好后,需要重新跑失败项目,可以把 function 和 export_report 状态改回 0。
uid=<project_uid>
sudo docker exec -it omicscloud-app bash -lc "
Rscript -e \"
library(DBI); library(RMariaDB); library(readr); library(tibble)
uid <- '$uid'
conf <- deframe(read_tsv('/home/saitoasuka/shiny-server/omicscloud/etc/config/conf', col_names=FALSE, show_col_types=FALSE))
con <- dbConnect(RMariaDB::MariaDB(), dbname='omicscloud_db', host=conf[['db_host']], port=as.integer(conf[['db_port']]), user=conf[['db_user']], password=conf[['db_pswd']])
dbExecute(con, 'update project_info set status=0 where uid=? and work in (\\\"function\\\", \\\"export_report\\\")', params=list(uid))
print(dbGetQuery(con, 'select work,status,updated_at from project_info where uid=? order by updated_at', params=list(uid)), row.names=FALSE)
dbDisconnect(con)
\"
"
十二、生产注意事项
- 不要把生产数据库密码直接写到 Wiki 页面。
docker/conf/conf中的真实密码应只保存在部署目录。- 离线包不包含用户项目数据和数据库资源,迁移时需要单独准备。
- 每次热修复容器后,如果要迁移到其他机器,需要重新
docker commit和docker save。 - 如果使用 host network 模式,宿主机
3838端口必须空闲。