Shiny App Docker template
#################### R version that is needed ################## | |
FROM rocker/r-ver:<r-version> | |
RUN apt-get update && apt-get install --no-install-recommends -y \ | |
gdebi-core \ | |
pandoc \ | |
pandoc-citeproc \ | |
libcurl4-gnutls-dev \ | |
default-jre-headless \ | |
libcairo2-dev \ | |
libxt-dev \ | |
libssl-dev \ | |
libxml2-dev \ | |
libnetcdf-dev \ | |
software-properties-common \ | |
libmagick++-dev \ | |
libpoppler-cpp-dev \ | |
libpq-dev \ | |
curl \ | |
xtail \ | |
wget \ | |
python2.7 \ | |
python-pip \ | |
python3-pip \ | |
libpython-dev \ | |
libpython3-dev \ | |
python3-setuptools && \ | |
pip3 install virtualenv wheel && \ | |
pip3 install awscli --upgrade --user && \ | |
wget --no-verbose https://s3.amazonaws.com/rstudio-shiny-server-os-build/ubuntu-14.04/x86_64/VERSION -O "version.txt" && \ | |
VERSION=$(cat version.txt) && \ | |
wget --no-verbose "https://s3.amazonaws.com/rstudio-shiny-server-os-build/ubuntu-14.04/x86_64/shiny-server-$VERSION-amd64.deb" -O ss-latest.deb && \ | |
gdebi -n ss-latest.deb && \ | |
rm -f version.txt ss-latest.deb && \ | |
R -e "install.packages('remotes', repos='https://cloud.r-project.org/');remotes::install_github('GeorgeSabu/packrat')" && \ | |
apt-get clean && \ | |
apt-get --purge -y remove python-pip python3-pip wget software-properties-common && \ | |
apt-get -y autoremove && rm -rf /var/lib/apt/lists/* | |
RUN apt-get update && \ | |
apt-get install --no-install-recommends -y \ | |
make \ | |
build-essential \ | |
zlib1g-dev \ | |
libbz2-dev \ | |
libreadline-dev \ | |
libsqlite3-dev \ | |
wget \ | |
curl \ | |
llvm \ | |
git \ | |
libncurses5-dev \ | |
libncursesw5-dev \ | |
xz-utils \ | |
tk-dev \ | |
libffi-dev \ | |
liblzma-dev \ | |
libssl-dev \ | |
python-openssl | |
USER shiny | |
RUN curl https://pyenv.run | bash && \ | |
echo 'export PATH="/home/shiny/.pyenv/bin:$PATH"' >> ~/.bash_profile && \ | |
echo 'export CONFIGURE_OPTS="--enable-shared"' >> ~/.bash_profile | |
ENV CONFIGURE_OPTS="--enable-shared" | |
RUN . ~/.bash_profile && pyenv init - && pyenv virtualenv-init - | |
RUN . ~/.bash_profile && pyenv install 2.7.16 | |
RUN . ~/.bash_profile && pyenv install 3.5.9 | |
RUN . ~/.bash_profile && pyenv install 3.6.10 | |
RUN . ~/.bash_profile && pyenv install 3.7.6 | |
RUN . ~/.bash_profile && pyenv install 3.8.1 | |
################################ Your docker code ########################## | |
# Things not to do | |
# 1. Don’t install R python2 python3 | |
# What can be done | |
# 1. Copy this docker file template and test it locally with things that you guys need | |
# 2. Install custom dependencies/languages that are needed specifically for your shiny apps | |
########################################################################## | |
USER root | |
RUN apt-get update && apt-get -y install gnupg && \ | |
curl -sL https://deb.nodesource.com/setup_10.x | bash - && \ | |
apt-get -y install nodejs && \ | |
npm install -g @elucidatainc/pollycli && \ | |
polly --version | |
COPY ./ui.R ./server.R /srv/ | |
# Copy configuration files into the Docker image | |
COPY ./shiny-server.conf /etc/shiny-server/shiny-server.conf | |
# Make the ShinyApp available at port 80 | |
EXPOSE 3838 | |
ENV EXEC_MODE server | |
# Copy further configuration files into the Docker image | |
COPY ./shiny-server.sh /usr/bin/shiny-server.sh | |
COPY ./packratRestore.R /usr/bin/packratRestore.R | |
RUN ["chmod", "+x", "/usr/bin/shiny-server.sh"] | |
CMD ["/usr/bin/shiny-server.sh"] | |
makePythonEnv <- function() { | |
envPath <- tryCatch( | |
{ | |
gsub("'", "", strsplit(gsub(".*\\(|\\).*", "", gsub("\"", "'", system("grep -r --exclude-dir='packrat' --exclude='packratRestore.R' 'use_virtualenv' *.R", intern=TRUE)[[1]], fixed = TRUE)), ",")[[1]][1]) | |
}, error = function(cond) { | |
NULL | |
} | |
) | |
if (!identical(envPath, NULL)) { | |
if (file.exists('./requirements3.txt')) { | |
print(substring(envPath, 3)) | |
command <- paste0("/bin/su -c '. ~/.bash_profile && pyenv virtualenv 3.8.1 ", substring(envPath, 3), "' - shiny") | |
system(command, intern=TRUE) | |
command <- paste0('/home/shiny/.pyenv/versions/3.8.1/envs/', substring(envPath, 3), "/bin/pip install -r ./requirements3.txt") | |
system(command, intern=TRUE) | |
command <- paste0('mv /home/shiny/.pyenv/versions/3.8.1/envs/', substring(envPath, 3), " .") | |
system(command, intern=TRUE) | |
} else if (file.exists('./requirements2.txt')) { | |
print(substring(envPath, 3)) | |
command <- paste0("/bin/su -c '. ~/.bash_profile && pyenv virtualenv 2.7.16 ", substring(envPath, 3), "' - shiny") | |
system(command, intern=TRUE) | |
command <- paste0('/home/shiny/.pyenv/versions/2.7.16/envs/', substring(envPath, 3), "/bin/pip install -r ./requirements2.txt") | |
system(command, intern=TRUE) | |
command <- paste0('mv /home/shiny/.pyenv/versions/2.7.16/envs/', substring(envPath, 3), " .") | |
system(command, intern=TRUE) | |
} else if (file.exists('./requirements2.7.txt')) { | |
print(substring(envPath, 3)) | |
command <- paste0("/bin/su -c '. ~/.bash_profile && pyenv virtualenv 2.7.16 ", substring(envPath, 3), "' - shiny") | |
system(command, intern=TRUE) | |
command <- paste0('/home/shiny/.pyenv/versions/2.7.16/envs/', substring(envPath, 3), "/bin/pip install -r ./requirements2.7.txt") | |
system(command, intern=TRUE) | |
command <- paste0('mv /home/shiny/.pyenv/versions/2.7.16/envs/', substring(envPath, 3), " .") | |
system(command, intern=TRUE) | |
} else if (file.exists('./requirements3.5.txt')) { | |
print(substring(envPath, 3)) | |
command <- paste0("/bin/su -c '. ~/.bash_profile && pyenv virtualenv 3.5.9 ", substring(envPath, 3), "' - shiny") | |
command <- paste0("virtualenv ", envPath, " -p ~/.pyenv/versions/3.5.9/bin/python") | |
system(command, intern=TRUE) | |
command <- paste0('/home/shiny/.pyenv/versions/3.5.9/envs/', substring(envPath, 3), "/bin/pip install -r ./requirements3.5.txt") | |
system(command, intern=TRUE) | |
command <- paste0('mv /home/shiny/.pyenv/versions/3.5.9/envs/', substring(envPath, 3), " .") | |
system(command, intern=TRUE) | |
} else if (file.exists('./requirements3.6.txt')) { | |
print(substring(envPath, 3)) | |
command <- paste0("/bin/su -c '. ~/.bash_profile && pyenv virtualenv 3.6.10 ", substring(envPath, 3), "' - shiny") | |
system(command, intern=TRUE) | |
command <- paste0('/home/shiny/.pyenv/versions/3.6.10/envs/', substring(envPath, 3), "/bin/pip install -r ./requirements3.6.txt") | |
system(command, intern=TRUE) | |
command <- paste0('mv /home/shiny/.pyenv/versions/3.6.10/envs/', substring(envPath, 3), " .") | |
system(command, intern=TRUE) | |
} else if (file.exists('./requirements3.7.txt')) { | |
print(substring(envPath, 3)) | |
command <- paste0("/bin/su -c '. ~/.bash_profile && pyenv virtualenv 3.7.6 ", substring(envPath, 3), "' - shiny") | |
system(command, intern=TRUE) | |
command <- paste0('/home/shiny/.pyenv/versions/3.7.6/envs/', substring(envPath, 3), "/bin/pip install -r ./requirements3.7.txt") | |
system(command, intern=TRUE) | |
command <- paste0('mv /home/shiny/.pyenv/versions/3.7.6/envs/', substring(envPath, 3), " .") | |
system(command, intern=TRUE) | |
} else if (file.exists('./requirements3.8.txt')) { | |
print(substring(envPath, 3)) | |
command <- paste0("/bin/su -c '. ~/.bash_profile && pyenv virtualenv 3.8.1 ", substring(envPath, 3), "' - shiny") | |
system(command, intern=TRUE) | |
command <- paste0('/home/shiny/.pyenv/versions/3.8.1/envs/', substring(envPath, 3), "/bin/pip install -r ./requirements3.8.txt") | |
system(command, intern=TRUE) | |
command <- paste0('mv /home/shiny/.pyenv/versions/3.8.1/envs/', substring(envPath, 3), " .") | |
system(command, intern=TRUE) | |
} else { | |
stop("Python version not supported. Python versions supported are 2.7, 3.5, 3.6, 3.7, 3.8. | |
Requirements files should be with the following naming. | |
requirements3.txt --> 3.8.1 | |
requirements2.txt --> 2.7.16 | |
requirements2.7.txt --> 2.7.16 | |
requirements3.5.txt --> 3.5.9 | |
requirements3.6.txt --> 3.6.10 | |
requirements3.7.txt --> 3.7.6 | |
requirements3.8.txt --> 3.8.1 | |
") | |
} | |
} | |
return(envPath) | |
} | |
pollyEnvRestore <- function() { | |
packrat::restore() | |
folderName <- makePythonEnv() | |
print(folderName) | |
} | |
system("mv Rprofile .Rprofile") | |
pollyEnvRestore() |
library(shiny) | |
# Define server logic required to generate and plot a random distribution | |
shinyServer(function(input, output) { | |
# Expression that generates a plot of the distribution. The expression | |
# is wrapped in a call to renderPlot to indicate that: | |
# | |
# 1) It is "reactive" and therefore should be automatically | |
# re-executed when inputs change | |
# 2) Its output type is a plot | |
# | |
output$distPlot <- renderPlot({ | |
# generate an rnorm distribution and plot it | |
dist <- rnorm(input$obs) | |
hist(dist) | |
}) | |
}) |
# Define the user we should use when spawning R Shiny processes | |
run_as shiny; | |
# Define a top-level server which will listen on a port | |
server { | |
# Instruct this server to listen on port 80. The app at dokku-alt need expose PORT 80, or 500 e etc. See the docs | |
listen 3838; | |
# Define the location available at the base URL | |
location / { | |
# Run this location in 'site_dir' mode, which hosts the entire directory | |
# tree at '/srv/shiny-server' | |
site_dir /srv/shiny-apps; | |
bookmark_state_dir /srv/bookmarks; | |
app_init_timeout 1800; | |
app_idle_timeout 1800; | |
# Define where we should put the log files for this location | |
log_dir /var/log/shiny-server; | |
# Should we list the contents of a (non-Shiny-App) directory when the user | |
# visits the corresponding URL? | |
directory_index on; | |
} | |
} |
#!/bin/sh | |
# Make sure the directory for individual app logs exists | |
mkdir -p /var/log/shiny-server | |
chown shiny.shiny /var/log/shiny-server | |
# Equality Comparison | |
if [ $EXEC_MODE = "server" ] | |
then | |
echo ${OPEN_APP_ID} | |
mkdir -p /srv/shiny-apps/ | |
echo "hello" > /srv/shiny-apps/index.html | |
APP_NAME=$(echo ${OPEN_APP_ID} | cut -d/ -f6) | |
echo ${APP_NAME} | |
mkdir -p /srv/shiny-apps/${APP_NAME} | |
#Making the packrat to get the files and copy the files | |
echo "#### -- Packrat Autoloader (version 0.5.0-21) -- #### | |
if (!file.exists('./.server')) { | |
system('cp /srv/applicationPath/${APP_NAME}/${APP_NAME}.tar.gz .') | |
system('tar -zxf ${APP_NAME}.tar.gz', intern = TRUE) | |
system('rm ${APP_NAME}.tar.gz', intern = TRUE) | |
} | |
source('packrat/init.R') | |
#### -- End Packrat Autoloader -- #### | |
" > /srv/shiny-apps/${APP_NAME}/.Rprofile | |
cp /srv/ui.R /srv/shiny-apps/${APP_NAME}/ | |
cp /srv/server.R /srv/shiny-apps/${APP_NAME}/ | |
chmod 777 -R /srv/shiny-apps/${APP_NAME} | |
# Making the logs | |
exec xtail /var/log/shiny-server/ & | |
exec shiny-server >> /var/log/shiny-server.log 2>&1 | |
else | |
cd /srv | |
mv /usr/bin/packratRestore.R /srv | |
mv .Rprofile Rprofile | |
Rscript packratRestore.R 2>&1 | tee r_python_build.log | |
R_FAILED_BUILD_OUT=$(cat r_python_build.log | grep "FAILED" || true) | |
R_FAILED_BUILD_OUT_PACKAGE=$(cat r_python_build.log | grep "Error:" || true) | |
PYTHON_ERROR_BUILD_OUT=$(cat r_python_build.log | grep "ERROR" || true) | |
if [ -z "$R_FAILED_BUILD_OUT" ] | |
then | |
echo "R package build successful" | |
else | |
if [ "$R_BUILD_CHECK" = "skip" ] | |
then | |
echo "Error in R build" | |
else | |
echo "Error in R build" | |
exit 1 | |
fi | |
fi | |
if [ -z "$R_FAILED_BUILD_OUT_PACKAGE" ] | |
then | |
echo "R package build successful" | |
else | |
if [ "$R_BUILD_CHECK" = "skip" ] | |
then | |
echo "Error in R build" | |
else | |
echo "Error in R build" | |
exit 1 | |
fi | |
fi | |
if [ -z "$PYTHON_ERROR_BUILD_OUT" ] | |
then | |
echo "Python package build successful" | |
else | |
if [ "$PYTHON_BUILD_CHECK" = "skip" ] | |
then | |
echo "Error in python build" | |
else | |
echo "Error in python build" | |
exit 1 | |
fi | |
fi | |
rm packratRestore.R | |
fi |
library(shiny) | |
# Define UI for application that plots random distributions | |
shinyUI(fluidPage( | |
# Application title | |
titlePanel("Hello Shiny!"), | |
# Sidebar with a slider input for number of observations | |
sidebarLayout( | |
sidebarPanel( | |
sliderInput("obs", | |
"Number of observations:", | |
min = 1, | |
max = 1000, | |
value = 500) | |
), | |
# Show a plot of the generated distribution | |
mainPanel( | |
plotOutput("distPlot") | |
) | |
) | |
)) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment