我想通过Docker部署一个由文件uiserverglobal组成的shiny 应用程序.所有文件都在文件夹deploy_test中 我模拟了这个数据集

set.seed(123)
dir.create("deploy_test")
setwd("deploy_test")
mydata_<-data.frame(
  gender=c(rep("Male",50),rep("Female",25)),
  height=c(rnorm(50,1.70,0.05),rnorm(25,1.65,1))
)
saveRDS(mydata_,file = "mydata_.RDS")

以下是我文件的内容:

1. UI

source("global.R")

dashboardPage(
  dashboardHeader(title = "Test of app deployment"),
  dashboardSidebar(
    
    selectInput("gender","Gender",as.character(unique(mydata_$gender)))
  ),
  dashboardBody(
    
    fluidRow(
      column(6,plotOutput(
        "plot1"
      )),
      column(6,plotOutput(
        "plot2"
      ))
    ),
    fluidRow(
      dataTableOutput(
        "table"
      )
    )
  )
)

2. SERVER

source("global.R")

function(input, output, session){
  
  output$plot1<-renderPlot(
    {
      data_<-mydata_%>%filter(
        gender==input$gender
      )
      boxplot(data_$height)
    }
  )
  
  
  output$plot2<-renderPlot(
    {
      data_<-mydata_%>%filter(
        gender==input$gender
      )
      hist(data_$height)
    }
  )
  
  
  output$table<-renderDataTable(
    {
      data_<-mydata_%>%filter(
        gender==input$gender
      )
      data_
    }
  )
  
  
}

3. GLOBAL

library(shinydashboard)
library(shiny)
library(tidyverse)
library(DT)
mydata_<-readRDS("mydata_.RDS")

4. DOCKERFILE

Dockerfile与Shiny的文件夹位于同一个文件夹中:

# Base image
FROM rocker/shiny

#Make a directory in the container
RUN mkdir /home/shiny-app


# Install dependencies
RUN R -e "install.packages(c('tidyverse','shiny','shinydashboard','DT'))"

COPY . /home/shiny-app/

EXPOSE 8180

CMD ["R", "-e", "shiny::runApp('/home/shiny-app')"]

我构建了我的容器,没有任何问题:

docker build -t deploy_test .

当我运行它:

docker run -p  8180:8180 deploy_test

它生成链接: 听http://xxx.x.x.x:xxxx

但当我访问链接时,没有任何东西出现: 我得到:La connexion a échoué

推荐答案

这有几个部分:要么指定runApp(.., host=, port=),要么转换到在父映像中使用内置的shiny—server.

Fix runApp

首先,您expose 了端口8180,但默认值runApp可能是随机分配端口.从?runApp:

    port: The TCP port that the application should listen on. If the
          ‘port’ is not specified, and the ‘shiny.port’ option is set
          (with ‘options(shiny.port = XX)’), then that port will be
          used. Otherwise, use a random port between 3000:8000,
          excluding ports that are blocked by Google Chrome for being
          considered unsafe: 3659, 4045, 5060, 5061, 6000, 6566,
          6665:6669 and 6697. Up to twenty random ports will be tried.

我的猜测是,它不会随机 Select 8180,至少不足以让你依赖它.

第二个问题是使用docker -p的网络端口转发转发到容器主机,但不转发到容器localhost(127.0.0.1).所以我们也应该给你分配一个主持人给你打runApp.TCP/IP网络中的魔术'0.0.0.0'意味着"所有适用的网络接口",其中包括那些您事先不知道的接口(即,Docker容器内的默认路由网络接口).因此,

CMD ["R", "-e", "shiny::runApp('/home/shiny-app',host='0.0.0.0',port=8180)"]

当我这样做时,我能够运行容器并连接到http://localhost:8180和shiny 的应用程序工作.(当然,我修改了shiny 的代码a little,因为我没有你的数据,但这是切线.

FYI,如果你的图像基于FROM rocker/shiny-verse而不是FROM rocker/shiny,你不需要install.packages('tidyverse'),这可以是一个很大的节省.此外,对于rocker/shinyrocker/shiny-verse,你不需要install.packages('shiny'),因为它已经包括在内.保存了两个Package.

Use the built-in shiny-server

使用rocker/shiny-verse的推荐方法是将应用程序放在/srv/shiny-server/appnamegoeshere中,并使用已经功能齐全的shiny—server添加到docker镜像中.

两个好处,一个后果:

  • 优势#1:您可以在一个docker镜像中部署和提供多个应用;
  • 好处2:如果/当shiny失败或退出时,内置shiny服务器将自动重新启动它;当runApp(.)失败时,它将停止.(当然,在代码中存在明显错误的情况下,这是由shiny 的重新启动逻辑控制的.
  • 结果:您的本地浏览器必须在URL中包含应用程序名称,如http://localhost:8180/appnamegoeshere.http://localhost:8180页面是一个大部分静态的登陆页面,表示shiny—server正在工作,默认情况下它不会列出服务器提供的所有应用程序.

这意味着你的Dockerfile可以是这样的:

# Base image
FROM rocker/shiny-verse

# Install dependencies (tidyverse and shiny are already included)
RUN R -e "install.packages(c('shinydashboard', 'DT'))"

# Make a directory in the container
RUN mkdir /srv/shiny-server/myapp
COPY . /srv/shiny-server/myapp

就是这样,没有什么需要得到你需要的一切,因为CMD已经在父映像中定义.因为shiny—server默认为端口3838,所以run命令现在是

docker run -p 3838:3838 deploy_test

本地浏览器使用http://localhost:3838/myapp个浏览器.

(FYI,RUNDockerfile中的其他命令可能会有影响力.例如,如果您更改了任何beforeinstall.packages(.),那么当您重新构建映像时,它将不得不重新安装这些包.由于我们不再需要(重新)安装"tidyverse",这应该是相当小的,但如果你坚持使用rocker/shiny,你必须安装install.packages("tidyverse"),那么这可以节省大量费用.通过将RUNCOPY命令用于该应用afterafterinstall.packages(..),那么如果我们重命名该应用和/或稍后添加更多的docker命令,那么该install.packages步骤被缓存/保留并且不需要被删除.

R相关问答推荐

从多个前置日期中获取最长日期

如何在kableextra调用cell_spec()中忽略NA?

在数学中正确显示摄氏度、开氏度或华氏度

为什么在ggplot2中添加geom_text这么慢?

在R中,如何在每个堆叠的条上放置误差条,特别是当使用facet_grid时?

如何在编辑列时更新可编辑数据表,并使用该表在Shiny中执行连续计算

删除列表中存储的数据帧内和数据帧之间的重复行

R-更新面内部的栅格值

条形图和在Ploly中悬停的问题

将数字转换为分钟和秒

plotly hover文本/工具提示在shiny 中不起作用

过滤名称以特定字符串开头的文件

R -在先前group_by级别汇总时获取最大大小子组的计数

将多个列值转换为二进制

如何将一列中的值拆分到R中各自的列中

将数据集旋转到长格式,用于遵循特定名称模式的所有变量对

通过初始的shiny 应用更新部署的shiny 应用的数据和参数,其中部署的应用程序显示为URL

抽样变换-REXP与RWEIBUR

reshape 数据帧-基于组将行转换为列

使用相对风险回归计算RR