Skip to content

Instantly share code, notes, and snippets.

@GeorgeSabu
Last active April 3, 2020 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GeorgeSabu/43d3e8437f4b745c96d29b433b9356ee to your computer and use it in GitHub Desktop.
Save GeorgeSabu/43d3e8437f4b745c96d29b433b9356ee to your computer and use it in GitHub Desktop.
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