1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ShinyアプリをGoogle Cloudにデプロイする

Posted at

Rでふるさと納税のマップを眺めるshinyアプリを作成したので、これをGoogle Cloudにデプロイしてみました。

https://furusato-map-oxbrmwzuuq-dt.a.run.app

Google Cloudにデプロイする手順を備忘録として記録しておきます。以下の2つのページを参考にデプロイしています。

Dockerizing and Deploying a Shiny Dashboard on Google Cloud

Deploying an R Shiny Dashboard on GCP Cloud Run

app.Rの準備

Shinyアプリは3ファイル(global.R, ui.R, server.R)から1ファイル(app.R)に変更します。最終行にshinyApp(ui = ui, server = server)を加えます。

app.R
library(tidyverse)
library(shiny)
library(sf)
library(shinythemes)
library(leaflet)

options(scipen=100) # 桁の大きい数値を指数表示にしない

vec <- 
  c("pop", "pop_M", "pop_F", "pop_2015", "pop_change", "pop_change_rate",
    "pop_density", "household", "Number_donations_accepted", "Donation_amount_accepted",
    "Number_donations_from_outside", "Donation_amount_from_outside", "Costs_procure_gifts",
    "Costs_return_gifts", "Costs_PR", "Costs_settlement", "Costs_Administration",
    "Costs_others", "Total_costs", "Donation_amount_per_pop", "Donation_number_per_pop")

names(vec) <- 
  c("人口(2020年)", "男性人口", "女性人口", "人口(2015年)", "5年間の人口増減数", 
    "5年間の人口増減率", "人口密度", "世帯数", "受け入れた寄付件数", "受け入れた寄附金額", 
    "市町村外から受け入れた寄付件数", "市町村外から受け入れた寄付金額", "返礼品等の調達に係る費用",
    "返礼品等の送付に係る費用", "広報に係る費用", "決済等に係る費用", "事務に係る費用", 
    "その他の費用", "費用合計", "一人当たりの市町村外から受け入れた寄付金額",
    "一人当たりの市町村外から受け入れた寄付件数")

vec_nin <- c("pop", "pop_M", "pop_F", "pop_2015", "pop_change", "pop_density")
vec_ken <- c("Number_donations_accepted", "Number_donations_from_outside", "Donation_number_per_pop")
vec_yen <- c(
  "Donation_amount_accepted", "Donation_amount_from_outside", "Costs_procure_gifts",
  "Costs_return_gifts", "Costs_PR", "Costs_settlement", "Costs_Administration",
  "Costs_others", "Total_costs", "Donation_amount_per_pop")

ui <- fluidPage(
    theme = shinytheme("united"),
    
    titlePanel("ふるさと納税データマップ"),
    
    tabsetPanel(
      tabPanel(
        "マップ",
        div(leafletOutput("leafletPlot", height="100%"), style = "height: 86vh"),
        
        absolutePanel(top = 120, right=20, 
                selectInput(
                  "year", "年度",
                  c("2017", "2018", "2019", "2020", "2021", "2022", "2023"), selected="2023"),
                
                selectInput(
                  "col_id", "表示する項目",
                  c("人口(2020年)", "男性人口", "女性人口", "人口(2015年)", "5年間の人口増減数", 
                    "5年間の人口増減率", "人口密度", "世帯数", "受け入れた寄付件数", "受け入れた寄附金額", 
                    "市町村外から受け入れた寄付件数", "市町村外から受け入れた寄付金額", "返礼品等の調達に係る費用",
                    "返礼品等の送付に係る費用", "広報に係る費用", "決済等に係る費用", "事務に係る費用", 
                    "その他の費用", "費用合計", "一人当たりの市町村外から受け入れた寄付金額",
                    "一人当たりの市町村外から受け入れた寄付件数"), selected="一人当たりの市町村外から受け入れた寄付金額", width="600px")
          ),
        
        tags$footer("一人あたりの値は2020年人口を利用して計算しているため、正確ではありません。")
      ),
        
      tabPanel(
        "参考文献等",
        br(),
        p("出典:調査項目を調べる-国勢調査(総務省)令和2年国勢調査 人口等基本集計 (主な内容:男女・年齢・配偶関係,世帯の構成,住居の状態,母子・父子世帯,国籍など)"),
        tags$a(href="https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00200521&tstat=000001136464&cycle=0&tclass1=000001136466&tclass2val=0&metadata=1&data=1", "政府統計の総合窓口(e-Stat)該当ページ"),
        br(),
        br(),
        p("出典:国土交通省国土数値情報ダウンロードサイト 行政区域データ(2024年) 全国データ"),
        tags$a(href="https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-2024.html", "国土数値情報ダウンロードサイト 該当ページ"),
        br(),
        br(),
        p("出典:総務省 ふるさと納税ポータルサイト 関連資料 受入額の実績等"),
        tags$a(href="https://www.soumu.go.jp/main_sosiki/jichi_zeisei/czaisei/czaisei_seido/furusato/archive/", "ふるさと納税ポータルサイト 該当ページ")
      )
    )
  )

server <- shinyServer(
    function(input, output, session) {

    output$leafletPlot <- renderLeaflet({
    
    geofile <- paste0("furusato", input$year, ".geojson")  
    
    geo <- st_read(geofile)

    geo <- geo |> filter(!st_is_empty(geo)) # geometryにemptyがあるとleafletで取り扱いできない
    
    col_selected <- vec[input$col_id]
    
    val <- geo[col_selected]  |> st_drop_geometry() |> unlist()
    
    if(col_selected %in% vec_nin){
      char_val <- 
        paste0(format(val, big.mark = ",", scientific = F) |> str_trim(), "人")
    } else if(col_selected %in% vec_ken){
      char_val <- 
        paste0(format(val |> round(2), big.mark = ",", scientific = F) |> str_trim(), "件")
    } else if(col_selected %in% vec_yen){
      char_val <- 
        paste0(format(val |> round(2), big.mark = ",", scientific = F) |> str_trim(), "円")
    } else if(col_selected == "pop_change_rate"){
      char_val <- 
        paste0(val |> round(2), "%")
    } else if(col_selected == "household"){
      char_val <- 
        paste0(format(val, big.mark = ",", scientific = F) |> str_trim(), "軒")
    }
    
    bins <- quantile(val |> na.omit(), probs=seq(0, 1, by=0.1)) |> round(5)
    pal <- colorBin("Spectral", domain = val, bins = bins, reverse=TRUE)
    
    geo |> 
      leaflet() |> 
      addProviderTiles(providers$OpenStreetMap) |> 
      setView(137.5, 37.5, zoom = 6) |> 
      addPolygons(
        fillColor = ~pal(val),
        weight = 1,
        opacity = 1,
        color = "white",
        dashArray = "3",
        fillOpacity = 0.5,
        highlightOptions = highlightOptions(
          weight = 5,
          color = "#666",
          dashArray = "",
          fillOpacity = 0.3,
          bringToFront = TRUE),
        label = map2_chr(geo$city, char_val, paste),
        labelOptions = labelOptions(
          style = list("font-weight" = "normal", padding = "3px 8px"),
          textsize = "15px",
          direction = "auto")) |> 
      addLegend(pal = pal, values = ~val, opacity = 0.7, title = names(vec)[input$col_id],
                position = "bottomright")
    })
  }
)

shinyApp(ui = ui, server = server)

Dockerfileの準備

次にrocker::shiny-verseを参照して、Dockerfileを準備します。

Dockerfile
FROM rocker/shiny-verse:latest

RUN apt-get update && apt-get install -y \
    curl \
    sudo \
    pandoc \
    pandoc-citeproc \
    libcurl4-gnutls-dev \
    libcairo2-dev \
    libxt-dev \
    libssl-dev \
    libssh2-1-dev\
    libssl3 \ # 以下の行がないとsfのインストールがうまくいかない
    libgdal-dev \
    libproj-dev \
    libgeos-dev \
    libudunits2-dev \
    netcdf-bin \
    libharfbuzz-dev \ 
    libfribidi-dev \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/ \
    && rm -rf /tmp/downloaded_packages/ /tmp/*.rds

RUN R -e "install.packages('shiny')"
RUN R -e "install.packages('shinythemes')"
RUN R -e "install.packages('tidyverse')"
RUN R -e "install.packages('sf', dependencies = TRUE)"
RUN R -e "install.packages('leaflet', dependencies = TRUE)"
RUN R -e "install.packages('units', dependencies = TRUE)"

RUN rm -rf /tmp/downloaded_packages/ /tmp/*.rds

COPY shiny-server.conf  /etc/shiny-server/shiny-server.conf

COPY app /srv/shiny-server/

RUN rm /srv/shiny-server/index.html

EXPOSE 3838

COPY shiny-server.sh /usr/bin/shiny-server.sh

RUN ["chmod", "+x", "/usr/bin/shiny-server.sh"]

USER shiny

CMD ["/usr/bin/shiny-server"]

上記のDockerfileは参考ページのものほとんどそのままです。libgdal-devなどがsfのインストールに必須で、無いとShiny Serverを立ち上げた時にエラーとなります。

別途上記参考ページに記載されているshiny-server.shとshiny-server.confを準備します。ファイル構造は以下の通りです。

furusato
|- app
| |- app.R
| |- furusato2017.geojson
| |- furusato2018.geojson
| |- furusato2019.geojson
| |- furusato2020.geojson
| |- furusato2021.geojson
| |- furusato2022.geojson
| |- furusato2023.geojson
| - Dockerfile
| - shiny-server.conf
| - shiny-server.sh

Dockerのビルドとローカル環境での確認

Dockerをbuildし、ローカル環境でdocker runしてShinyアプリが動くかどうか確認します。

docker build -t furusato_map .

# ローカルでDockerを走らせて様子を見る
docker run -e APPLICATION_LOGS_TO_STDOUT=true --user shiny -p 3838:3838 furusato_map

この段階で問題なければ、Google Cloudの設定に移行します。

gcloud CLIのインストールと準備

まずはshellからgcloudコマンドラインを使えるようにするため、gcloud CLIをインストールします。インストールは以下のサイトに従い行います。

gcloud CLI をインストールする

次に、Auth loginを行い、Google Cloudのdockerの設定を行います。

gcloud services enable containerregistry.googleapis.com # Artifact Registryを有効化
gcloud auth login 
gcloud auth configure-docker

Google CloudでプロジェクトIDを調べておき、docker pushでファイルをGoogle Cloudに移行します。

docker tag {REGION}-docker.pkg/dev/{PROJECT_ID}/furusato/furusato_map:v1.0 gcr.io/{PROJECT_ID}/furusato/furusato_map:v1.0
docker push gcr.io/{PROJECT_ID}/furusato/furusato_map:v1.0

ここからはGoogle Cloudのページで作業します。プロジェクトのページを開き、Cloud Runを選択します。サービスの作成を選択し、先ほどdocker pushで移行したイメージを選択します。サービス名、リージョンを選択し、コンテナのポートは3838とします。メモリとCPUを最小にするとleafletが動かないため、メモリを2GB、CPUを2とし、作成します。うまくイメージが作成されると、URLが示されるのでそのURLに移動するとShinyアプリがWeb上で確認できるようになります。

app_image.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?