我想通过 Docker 部署一个由文件
ui
、 server
和 global
组成的闪亮应用程序。所有文件都在文件夹中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")
以下是我的文件内容:
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"
)
)
)
)
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_
}
)
}
library(shinydashboard)
library(shiny)
library(tidyverse)
library(DT)
mydata_<-readRDS("mydata_.RDS")
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=)
,要么转向使用父映像中的内置闪亮服务器。
runApp
首先是您公开端口 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.
我的猜测是它不会随机选择 8180,至少不够可靠让你可以依赖它。第二个问题是使用 docker 的
-p
的网络端口转发转发到容器主机,而不是容器的 localhost
(127.0.0.1
)。因此,我们还应该为您的呼叫分配一位主持人 runApp
。也许
CMD ["R", "-e", "shiny::runApp('/home/shiny-app',host='0.0.0.0',port=8180)"]
当我这样做时,我可以运行容器并连接到
http://localhost:8180
并且那个闪亮的应用程序可以工作。 (当然,我稍微修改了闪亮的代码,因为我没有你的数据,但那是无关紧要的。)
仅供参考,如果您的图像基于 FROM rocker/shiny-verse
而不是
FROM rocker/shiny
,则不需要 install.packages('tidyverse')
,这可以节省一大笔钱。另外,使用 rocker/shiny
或 rocker/shiny-verse
,您不需要 install.packages('shiny')
,因为它已经存在了。节省了两个包裹。使用内置的shiny-server
rocker/shiny-verse
的方法是将您的应用程序放入
/srv/shiny-server/appnamegoeshere
中,并使用嵌入到 docker 镜像中的已功能闪亮服务器。两个好处,一个后果:
好处#1:您可以在一个 Docker 镜像中部署和提供多个应用程序;
runApp(.)
http://localhost:8180/appnamegoeshere
http://localhost:8180
页面是一个主要是静态的登陆页面,表示闪亮服务器正在工作,并且默认情况下它不会列出服务器正在提供服务的所有应用程序。
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,所以你的运行命令现在是
docker run -p 3838:3838 deploy_test
并且您的本地浏览器使用
http://localhost:3838/myapp
进行浏览。
(仅供参考,RUN
中的顺序以及
Dockerfile
中的其他命令可能会产生影响。例如,如果您在 install.packages(.)
之前更改任何内容,那么当您重新构建图像时,它必须重新安装这些软件包。由于我们不再需要(重新)安装 "tidyverse"
,这应该是相当小的,但如果您坚持使用 rocker/shiny
并且必须 install.packages("tidyverse")
,那么这可以节省大量资金。通过此应用程序的 RUN
和 COPY
命令after
install.packages(..)
,那么如果我们稍后重命名该应用程序和/或添加更多 docker 命令,则该 install.packages
步骤将被缓存/保留,并且不需要重新运行。)