Omicscloud Docker配置

来自OmicsWiki
Liuhebin讨论 | 贡献2026年5月22日 (五) 08:34的版本
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳到导航 跳到搜索

OmicsCloud Docker 部署说明

本文档用于说明 OmicsCloud Docker 镜像的构建、离线打包、迁移部署、常见配置和排错方法。

OmicsCloud 镜像把应用代码打进 Docker image,运行时可变内容放在镜像外部:

  • 配置文件:docker/conf/conf
  • 密钥文件:etc/config/key.pemetc/config/pubkey.pem
  • MariaDB
  • LDAP
  • 用户项目数据、共享目录、GO/KEGG/STRING 等外部数据库资源

注意:容器内部仍然使用 /home/saitoasuka/... 路径,这是因为 OmicsCloud 旧代码里有固定路径依赖。目标 VM 的 Linux 用户名不需要叫 saitoasuka

一、部署方式选择

场景 推荐方式 主要命令
有网络、可以从 GitHub 构建 在线构建 docker compose build omicscloud-app
当前 VM 已有测试通过的容器,需要迁移到其他机器 制作离线包 docker commitdocker savetar
新 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.1db_port=1430ldap://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 中 functionexport_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\")" '

十一、重新入队失败项目

如果代码或配置修好后,需要重新跑失败项目,可以把 functionexport_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 commitdocker save
  • 如果使用 host network 模式,宿主机 3838 端口必须空闲。