0Pricing
R Academy · 강의

Shiny 앱 배포

shinyapps.io, Shiny Server 및 Docker 컨테이너 환경에 앱을 게시합니다.

Shiny 앱 배포은(는) CoddyKit의 무료 R Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 R Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

배포 옵션 개요

Shiny 앱은 예산, 예상 트래픽, 제어 요구 사항에 따라 여러 플랫폼에 배포할 수 있습니다:

  • shinyapps.io: Posit에서 관리하는 클라우드 호스팅으로, 가장 쉽고 무료 요금제가 제공됩니다.
  • Shiny Server (오픈 소스): Linux에서 직접 호스팅하며 무료입니다.
  • Posit Connect: 상용 엔터프라이즈급 플랫폼으로, R Markdown과 Plumber도 지원합니다.
  • Docker + rocker/shiny: 이식성과 제어력이 가장 뛰어납니다.
# Summary of deployment options and their trade-offs:
# shinyapps.io: managed, auto-scaling, per-instance pricing
# Shiny Server: self-hosted, unlimited users, needs sysadmin
# Posit Connect: enterprise SSO, scheduling, REST APIs
# Docker: any cloud provider, reproducible environments

cat('Choose based on: scale, budget, infra control needs')

배포를 위한 app.R 구조

배포 가능한 Shiny 앱은 ui와 server를 모두 포함하는 단일 app.R 파일을 사용하거나, ui.R과 server.R 두 파일을 사용해야 합니다. 모든 패키지 의존성은 파일 상단에서 library()로 선언해야 합니다. 데이터 파일은 앱과 같은 디렉터리에 두거나 앱을 기준으로 접근할 수 있는 위치에 있어야 합니다.

# Minimal app.R for deployment
library(shiny)
library(ggplot2)
library(dplyr)

# Load data relative to app directory
data <- readRDS('data/processed_data.rds')

ui <- fluidPage(
  titlePanel('My Deployed App'),
  sidebarLayout(
    sidebarPanel(selectInput('var', 'Variable:', choices = names(data))),
    mainPanel(plotOutput('main_plot'))
  )
)

server <- function(input, output, session) {
  output$main_plot <- renderPlot({
    ggplot(data, aes_string(x = input$var)) + geom_histogram()
  })
}

shinyApp(ui, server)

rsconnect::deployApp()

rsconnect 패키지는 shinyapps.io와 Posit Connect로의 배포를 처리합니다. 먼저 계정 자격 증명을 구성한 다음, 앱 디렉터리에서 rsconnect::deployApp()을 호출합니다. 이 함수는 모든 R 파일, 데이터, 매니페스트를 자동으로 하나로 묶습니다.

library(rsconnect)

# One-time setup: link your shinyapps.io account
# rsconnect::setAccountInfo(
#   name   = 'your_account_name',
#   token  = 'YOUR_TOKEN',
#   secret = 'YOUR_SECRET'
# )

# Deploy the app in the current directory
rsconnect::deployApp(
  appDir  = '.',          # or 'path/to/app'
  appName = 'my_analysis_app',
  forceUpdate = TRUE
)

shinyapps.io 설정

shinyapps.io는 공개 URL을 가장 빠르게 만들 수 있는 방법입니다. shinyapps.io에서 무료 계정을 만들고, 대시보드에서 토큰과 비밀 키를 복사한 다음 setAccountInfo()를 호출합니다. 무료 요금제에서는 앱 5개와 월간 활성 시간 25시간을 사용할 수 있습니다.

library(rsconnect)

# Copy credentials from shinyapps.io -> Account -> Tokens
rsconnect::setAccountInfo(
  name   = 'your_username',
  token  = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  secret = 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'
)

# Verify the connection
rsconnect::accountInfo()

# List currently deployed apps
rsconnect::applications()

Shiny Server 오픈 소스

Shiny Server는 Linux(Ubuntu/RHEL)에서 실행되며 /srv/shiny-server/ 디렉터리에서 Shiny 앱을 제공합니다. 각 하위 디렉터리는 http://server:3838/subdirname/의 앱이 됩니다. 무료이며 서버 용량이 허용하는 범위에서 동시 사용자를 무제한으로 지원합니다.

# Install Shiny Server on Ubuntu:
# sudo apt-get install r-base
# sudo R -e 'install.packages(c("shiny", "rmarkdown"))'
# wget https://download3.rstudio.org/ubuntu-20.04/x86_64/shiny-server-1.5.21.1012-amd64.deb
# sudo dpkg -i shiny-server-1.5.21.1012-amd64.deb

# Deploy an app:
# sudo cp -r /path/to/myapp /srv/shiny-server/myapp
# Access at: http://your-server:3838/myapp

# Config file: /etc/shiny-server/shiny-server.conf
cat('Shiny Server config controls ports, auth, and app paths')

rocker/shiny를 사용한 Docker

rocker/shiny Docker 이미지는 미리 구성된 Shiny Server를 제공합니다. 앱 디렉터리를 컨테이너에 마운트하면 즉시 앱을 제공할 수 있습니다. Docker를 사용하면 재현성이 보장되므로 동일한 이미지가 어떤 호스트에서도 동일하게 실행됩니다.

# Dockerfile for a custom Shiny app
# FROM rocker/shiny:4.4.0
#
# # Install R package dependencies
# RUN R -e 'install.packages(c("ggplot2","dplyr","DT"))'
#
# # Copy app files
# COPY myapp/ /srv/shiny-server/myapp/
#
# EXPOSE 3838

# Build and run:
# docker build -t my-shiny-app .
# docker run -p 3838:3838 my-shiny-app

# Access at: http://localhost:3838/myapp

재현 가능한 의존성을 위한 renv

renv는 정확한 패키지 버전을 기록하는 잠금 파일(renv.lock)과 함께 프로젝트 수준의 패키지 라이브러리를 만듭니다. 배포할 때 이 잠금 파일을 사용하면 서버나 Docker 이미지에 개발 중 사용한 것과 정확히 동일한 패키지 버전이 설치됩니다.

library(renv)

# Initialise renv in the project (creates renv.lock)
renv::init()

# After installing/updating packages, record the state
renv::snapshot()

# On the server: restore exact versions from lockfile
renv::restore()

# Check lockfile for a specific package version
renv::dependencies()  # lists all used packages

구성을 위한 환경 변수

API 키, 데이터베이스 비밀번호 또는 환경별 설정을 앱 코드에 절대 직접 입력하지 마십시오. Sys.getenv('VAR_NAME', unset = NA)로 읽는 환경 변수를 사용하십시오. 로컬에서는 .Renviron에 설정하고, 운영 환경에서는 호스팅 플랫폼의 환경 구성에 설정하십시오.

# In .Renviron (never commit this file):
# DB_HOST=prod-db.example.com
# DB_PASSWORD=secret123
# API_KEY=key_abc

# In app.R:
db_host <- Sys.getenv('DB_HOST',     unset = 'localhost')
db_pass <- Sys.getenv('DB_PASSWORD', unset = '')
api_key <- Sys.getenv('API_KEY',     unset = '')

if (api_key == '') {
  warning('API_KEY not set — some features disabled')
}

Posit Connect 개요

Posit Connect는 Shiny 앱, R Markdown 문서, Plumber API 등을 배포하기 위한 엔터프라이즈 플랫폼입니다. 다음 기능을 지원합니다:

  • LDAP 또는 SAML을 통한 통합 로그인(SSO)
  • R Markdown 보고서의 예약 실행
  • 앱 수준의 접근 제어
  • 자동 확장 및 부하 분산

배포에는 shinyapps.io와 동일한 rsconnect::deployApp() 작업 흐름을 사용합니다.

library(rsconnect)

# Configure connection to Posit Connect server
rsconnect::addServer(
  url  = 'https://connect.yourcompany.com',
  name = 'my_connect_server'
)

# Authenticate with API key
rsconnect::connectApiUser(
  account = 'jsmith',
  server  = 'my_connect_server',
  apiKey  = Sys.getenv('CONNECT_API_KEY')
)

# Deploy
rsconnect::deployApp(server = 'my_connect_server')

배포 전 점검 목록

Shiny 앱을 운영 환경에 배포하기 전에 다음을 확인하십시오:

  • 모든 파일 경로가 절대 경로가 아닌 상대 경로인지 확인합니다.
  • 민감한 데이터(API 키, 비밀번호)를 환경 변수에서 읽는지 확인합니다.
  • 패키지 의존성이 library() 또는 renv.lock으로 명시되어 있는지 확인합니다.
  • 대용량 데이터 파일을 server.R 상단에서 한 번만 로드하는지 확인합니다(반응형 코드 내부가 아님).
  • 오류 메시지가 최종 사용자에게 내부 정보를 노출하지 않는지 확인합니다.
# Production-hardened app.R patterns

# Load data once at startup (not per-session)
app_data <- readRDS('data/processed.rds')  # outside server()

server <- function(input, output, session) {
  # Reference app_data directly — already in memory
  output$plot <- renderPlot({
    subset_data <- app_data[app_data$group == input$grp, ]
    plot(subset_data$x, subset_data$y)
  })

  # Sanitise error messages
  tryCatch({
    risky_operation()
  }, error = function(e) {
    showNotification('An error occurred.', type = 'error')
    # log the real error internally, not to user
    message('Error: ', conditionMessage(e))
  })
}

확장 시 고려 사항

Shiny 앱은 세션을 기반으로 작동하므로 각 사용자에게 고유한 R 프로세스(또는 작업자)가 할당됩니다. 확장 전략은 다음과 같습니다:

  • 세션마다 계산하는 대신 시작 시 미리 계산된 데이터를 로드합니다.
  • 여러 세션에서 공유되는 비용이 큰 계산에는 bindCache()를 사용하여 반응형 캐싱을 적용합니다.
  • 여러 작업자: Shiny Server Pro와 Posit Connect는 병렬 R 프로세스를 생성합니다.
  • 데이터베이스 백엔드: 동시에 데이터베이스에 접근할 때 DBI/pool을 사용합니다.
library(shiny)
library(pool)

# Create a database connection pool at startup
# (shared across all sessions)
pool <- dbPool(
  drv      = RPostgres::Postgres(),
  host     = Sys.getenv('DB_HOST'),
  dbname   = 'analytics',
  user     = Sys.getenv('DB_USER'),
  password = Sys.getenv('DB_PASSWORD'),
  minSize  = 2,
  maxSize  = 10
)

onStop(function() { poolClose(pool) })

server <- function(input, output, session) {
  output$tbl <- renderTable({
    dbGetQuery(pool, 'SELECT * FROM metrics LIMIT 100')
  })
}

빠른 확인

배포된 Shiny 앱에서 API 키와 데이터베이스 비밀번호를 처리하는 권장 방법은 무엇입니까?

Shiny 앱 배포 복습

Shiny 앱 배포의 핵심 내용:

  • 배포 옵션: shinyapps.io(가장 쉬움), Shiny Server(직접 호스팅), Posit Connect(엔터프라이즈), Docker.
  • app.R에서 모든 의존성을 library()로 선언해야 하며, 재현 가능한 버전 관리를 위해 renv::snapshot()을 사용합니다.
  • rsconnect::deployApp()은 shinyapps.io 또는 Posit Connect로 전송할 파일을 하나로 묶어 배포합니다.
  • rocker/shiny를 사용한 Docker는 최고의 이식성을 제공합니다.
  • 자격 증명에는 Sys.getenv()를 사용하고, 비밀 정보를 코드에 직접 입력하지 마십시오.
  • 세션 간에 공유할 수 있도록 대규모 데이터 세트를 시작 시(server() 외부에서) 로드합니다.
  • 동시 데이터베이스 접근에는 연결 풀(pool 패키지)을 사용합니다.
# Minimal production-ready structure
# myapp/
#   app.R           <- ui + server + shinyApp()
#   data/           <- processed datasets
#   R/              <- modules and helpers
#   renv.lock       <- package version snapshot
#   .Renviron       <- local env vars (gitignored)

# Deploy:
library(rsconnect)
rsconnect::deployApp(
  appDir  = 'myapp',
  appName = 'my_production_app'
)

자주 묻는 질문

“Shiny 앱 배포” 강의는 무료인가요?

네 — “Shiny 앱 배포” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 R Academy 강의 전체를 잠금 해제할 수 있습니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“Shiny 앱 배포”에서 뭘 배우나요?

shinyapps.io, Shiny Server 및 Docker 컨테이너 환경에 앱을 게시합니다. 브라우저에서 직접 실행하는 실습 코드로 R Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

R Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 R Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“Shiny 앱 배포” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 R Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 R Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 반응형 프로그래밍 심화
  2. 코드 재사용을 위한 Shiny 모듈
  3. renderUI와 insertUI를 활용한 동적 UI
  4. Shiny 앱 배포
← R Academy(으)로 돌아가기