ShinyProxyをCloud9で動かす

# はじめに
統計解析向けに使われるR言語をWebアプリ化できるShinyというパッケージがあります。
この課題を解決できる`ShinyProxy`というものを触ってみましたので、記事にしました。

# 参考

https://qiita.com/okiyuki99/items/428226aa402dd335764e

https://www.shinyproxy.io/documentation/getting-started/


https://www.kenwuyang.com/en/post/deploying-shiny-apps-or-interactice-documents-with-shinyproxy-docker-and-aws/

# Shinyの課題
[参考に紹介したQiitaの記事](https://qiita.com/okiyuki99/items/428226aa402dd335764e#shiny-server-%E3%81%AE%E9%81%8B%E7%94%A8%E4%B8%8A%E3%81%AE%E8%AA%B2%E9%A1%8C)から引用します。

> OSSのShiny Serverでは、1つのShinyappが 1 processで動くため、複数人のユーザでアクセスすると、急に動きがもっさりしがちです。例えば、ユーザA、Bの順でアクセスして、データをロードしはじめると、ユーザAの処理が終わるまで、ユーザBは待たないといけないので、待っている間ストレスがかかります


# ShinyProxyでの解決
ShinyProxyでは以下のようなことを行って、先の課題を解決しています。

1. Shinyのアプリをdockerイメージで用意します
1. 上記イメージを使うよう、ShinyProxyで設定します
1. ShinyProxyでユーザを認証し、ユーザごとにコンテナを起動してくれます

## 余談：その他の解法
ShinyProxyは自前でサーバを運用・管理する必要がありますが、以下のサービスを使えばサーバの管理も不要のようです。

https://www.shinyapps.io/

認証機能込みのSTANDARDプランだと、月額16,000円くらいです。サーバ管理から解放されることを考えるとよい値段と思います。


# やってみた

Cloud9のインスタンスは、コンテナを使うので`t3.small`にしました。

## Standaloneモードで実行
Standaloneモードは、ホスト上でShinyProxyを動かすものになります。

まず[公式のGetting Started](https://www.shinyproxy.io/documentation/getting-started/)に従ってやっていきます。
Javaの確認です。
```
$ java -version
openjdk version "11.0.18" 2023-01-17 LTS
OpenJDK Runtime Environment Corretto-11.0.18.10.1 (build 11.0.18+10-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.18.10.1 (build 11.0.18+10-LTS, mixed mode)
```
DockerはCloud9だとインストール済みなので、Docker startup optionsに続きます。
こちらは、以下のサイトを参考にしました。

https://www.kenwuyang.com/en/post/deploying-shiny-apps-or-interactice-documents-with-shinyproxy-docker-and-aws/

```
# 新規作成
$ mkdir /etc/systemd/system/docker.service.d
$ sudo vi /etc/systemd/system/docker.service.d/override.conf

# 以下の内容を追加
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H unix:// -D -H tcp://127.0.0.1:2375

# 以下のコマンドを実行
$ sudo systemctl enable docker.service
$ sudo systemctl status docker.service
$ sudo systemctl start docker.service
$ sudo systemctl stop docker.service
$ sudo systemctl restart docker.service
$ sudo docker version
```
### ShinyProxyを実行

ShinyProxyを実行するには、rpmファイルをダウンロードしてインストールする方法と、jarファイルを実行する方法があります。

```:jarファイルを直接実行する場合
$ wget https://github.com/openanalytics/shinyproxy/releases/download/v3.0.1/shinyproxy-3.0.1.jar

$ java -jar shinyproxy-3.0.1.jar 
```

```:インストールする場合
$ https://www.shinyproxy.io/downloads/shinyproxy_3.0.1_x86_64.rpm
$ sudo yum localinstall ./shinyproxy_3.0.1_x86_64.rpm 

$ sudo systemctl enable shinyproxy
$ sudo systemctl start shinyproxy
$ sudo systemctl status shinyproxy
# 止める場合
$ sudo systemctl status shinyproxy
```

プレビューで見てみますと、ログイン画面がでました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/52c661af-5c9b-7d81-7aeb-08127b5a8bfe.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/95413b61-763f-8a21-9d59-28bd14d4d7b7.png)

一旦、CTRL-Cで止めます。

### デモ用ShinyアプリのイメージをPULL
```
$ docker pull openanalytics/shinyproxy-demo
```
結構大きめでした。
```
$ sudo docker images | grep shinyproxy
openanalytics/shinyproxy-demo   latest    a4ad82a764ab   11 months ago   1.35GB
```
### config
以下の公式を参考にしていきました。

https://www.shinyproxy.io/documentation/configuration/

jarでの実行時は、jarと同じフォルダに、`application.yml`を配置します。
```
touch application.yml
```

インストールでの場合は`/etc/shinyproxy/application.yml`になります。

`authentication: simple`だけ修正します。
```yaml:application.yaml
proxy:
  title: Open Analytics Shiny Proxy
  logo-url: https://www.openanalytics.eu/shinyproxy/logo.png
  landing-page: /
  heartbeat-rate: 10000
  heartbeat-timeout: 60000
  port: 8080
  authentication: simple
  admin-groups: scientists
  # Example: 'simple' authentication configuration
  users:
  - name: jack
    password: password
    groups: scientists
  - name: jeff
    password: password
    groups: mathematicians
  # Example: 'ldap' authentication configuration
  ldap:
    url: ldap://ldap.forumsys.com:389/dc=example,dc=com
    user-dn-pattern: uid={0}
    group-search-base:
    group-search-filter: (uniqueMember={0})
    manager-dn: cn=read-only-admin,dc=example,dc=com
    manager-password: password
  # Docker configuration
  docker:
    cert-path: /home/none
    url: http://localhost:2375
    port-range-start: 20000
  specs:
  - id: 01_hello
    display-name: Hello Application
    description: Application which demonstrates the basics of a Shiny app
    container-cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
    container-image: openanalytics/shinyproxy-demo
    access-groups: [scientists, mathematicians]
  - id: 06_tabsets
    container-cmd: ["R", "-e", "shinyproxy::run_06_tabsets()"]
    container-image: openanalytics/shinyproxy-demo
    access-groups: scientists

logging:
  file:
    name: shinyproxy.log
```

再度、ShinyProxyを実行します。
```:jarファイル直接実行の場合
$ java -jar shinyproxy-3.0.1.jar
```
```:インストールの場合
$ sudo systemctl restart shinyproxy
```



プレビューは、以下のボタンを押してブラウザでの表示で行います。内部のプレビューではログイン後にエラーになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/ec203276-7649-0a2a-de91-3fefc77296d6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/c89c20d9-6177-8f2f-5893-e1063b483a31.png)

`application.yaml`で設定したユーザでログインします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/74adfe42-197c-cf4e-438a-86c32a7d71b2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/f692cb5d-067d-53fb-3a70-7b6b4d7837de.png)
起動するまでの待ち画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/d3fc3801-3eec-49ef-1945-9a29001aae7c.png)
起動後は、以下の画面になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/86739e4a-5e98-555f-33de-5e3a248cfe63.png)

アプリの選択前後でコンテナが増えていることがわかります。
```
# アプリを選択する前
$ docker ps --no-trunc
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# 選択した後
$ docker ps --no-trunc
CONTAINER ID                                                       IMAGE                           COMMAND                             CREATED              STATUS              PORTS                     NAMES
a4a01ca81f2b3e0f73e7cfc1bbf4f7269ee4b5c82679e3594540104763801089   openanalytics/shinyproxy-demo   "R -e shinyproxy::run_01_hello()"   About a minute ago   Up About a minute   0.0.0.0:20000->3838/tcp   nervous_moser
```


## Containerizedモード
Containerizedモードは、ShinyProxy自体もコンテナで動かすものになります。
公式の以下の通りにやってみます。

https://github.com/openanalytics/shinyproxy-config-examples/tree/master/02-containerized-docker-engine

新しいディレクトリを作り、そちらで行っていきます。
```
$ mkdir test-containerized && cd test-containerized

# Dockerfileを作成し、上記GitHubの内容をコピーします
$ touch Dockerfile

# application.ymlも同様にコピーします
$ touch application.yml

# Dockerネットワークを作ります
$ docker network create sp-example-net

# 確認
$ docker network ls

# build
$ docker build . -t shinyproxy-example

# run
$ docker run -v /var/run/docker.sock:/var/run/docker.sock:ro --group-add $(getent group docker | cut -d: -f3) --net sp-example-net -p 8080:8080 shinyproxy-example
```

Standaloneの時と同様に、ログインしてアプリが実行できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/0313bc51-5493-3438-bc1b-7a967f6f7f48.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/8c04031e-fa73-b4c0-bb36-9712fdc16efb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/c25e3450-b17a-f6ee-771d-e0104189c556.png)


## 自作のShinyアプリをイメージにして使う方法
今まではShinyのアプリが既にdockerイメージになっていましたが、今度はShinyアプリをdockerイメージにする方法も行ってみました。

以下の2つを参考にしました。


https://github.com/openanalytics/shinyproxy-template

https://www.shinyproxy.io/documentation/deploying-apps/

```
$ mkdir test-apps && cd test-apps

# テンプレートをクローン
$ git clone https://github.com/openanalytics/shinyproxy-template.git

$ cd shinyproxy-template/

# Shinyアプリのイメージを作成
$ docker build -t openanalytics/shinyproxy-template .

$ cd ..

$ touch application.yml
```

最初に作った`application.yml`の、`spec`のみ以下に差しかえます。


```yaml:application.yml(一部)
specs:
  - id: euler
    display-name: Euler's number
    container-cmd: ["R", "-e", "shiny::runApp('/root/euler')"]
    container-image: openanalytics/shinyproxy-template
    access-groups: scientists
```
Shinyproxyを実行します。
```
$ wget https://github.com/openanalytics/shinyproxy/releases/download/v3.0.1/shinyproxy-3.0.1.jar

$ java -jar shinyproxy-3.0.1.jar
```
アクセスすると、デモと同様にログイン画面が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/3a7fd565-f6e5-f57b-8639-30371b756623.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/9228691b-bb8e-531c-532c-63de0c5cafef.png)

自分でbuildしたアプリが動いています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/eeddf169-161a-8b26-13f5-cb9750c417e0.png)

# おわりに
今回は統計解析のWebアプリの運用を楽にできるShinyProxyを紹介しました。
Cloud9上での実行でしたが、EC2でも同様の方法で動くと思われます。

どなたかのお役に立てれば幸いです。