RaspberryPi2のLXDコンテナ環境でプリザンターを動かしてみた。

# はじめに

プリザンター が .NET Core版 に統合されたらしいので、RaspberryPiで動くか試してみた。

[【重要】プリザンター .NET Framework版と.NET Core版の統合について](https://pleasanter.org/archives/net5_integration?fbclid=IwAR2Fel-2dhJrVHGbg_7AdYX9it1TpUjf73r9c0c_5UudqkivaWw440GSKbg)

# 参考文献

- プリザンターをUbuntuにインストールする
  https://pleasanter.org/manual/getting-started-pleasanter-ubuntu  

- Raspberry Pi に .NET アプリを展開する
  https://docs.microsoft.com/ja-jp/dotnet/iot/deployment

- RaspberryPiに.net5をインストールする。
  https://qiita.com/kokimu/items/37728091c9f33c1f61ab

# 環境

- LXD基盤
  - Raspberry Pi 2 Model B V1.1
  - Raspberry Pi OS Lite(2021-05-07-raspios-buster-armhf-lite.img)
  - LXD 4.19

- コンテナ環境
  - Ubuntu 20.04
  - .NET SDK 5.0.401
  - PostgreSQL 12
  - Pleasanter 1.2.x


# インストール

## 1. コンテナを作って初期設定をする

ここは LXDホスト での作業です。

```shell
root@lxd-host:~#
root@lxd-host:~# lxc launch images:ubuntu/20.04 pleasanter
root@lxd-host:~#
root@lxd-host:~# lxc exec pleasanter -- /bin/bash
root@pleasanter:~#
root@pleasanter:~#
```

## 2. .NET 5 をインストール

ここから pleasanter コンテナ での作業です。

ダウンロードサイト：
https://dotnet.microsoft.com/download/dotnet/5.0

```shell

root@pleasanter:~#
root@pleasanter:~# cd /var/tmp/
root@pleasanter:/var/tmp#
root@pleasanter:/var/tmp# curl -LO https://download.visualstudio.microsoft.com/download/pr/ce3cef63-ade6-4209-80f0-ac2815c5b282/e4a8b52aacf74d2a7d6d1cf5b9dca438/dotnet-sdk-5.0.401-linux-arm.tar.gz
root@pleasanter:/var/tmp#
root@pleasanter:/var/tmp# mkdir -p /opt/dotnet
root@pleasanter:/var/tmp#
root@pleasanter:/var/tmp# cd /opt/dotnet
root@pleasanter:/opt/dotnet#
root@pleasanter:/opt/dotnet# tar zxf /var/tmp/dotnet-sdk-5.0.401-linux-arm.tar.gz
root@pleasanter:/opt/dotnet#
root@pleasanter:/opt/dotnet# chown -R root. /opt/dotnet
root@pleasanter:/opt/dotnet#
root@pleasanter:/opt/dotnet# ls -al
合計 144
drwxr-xr-x 7 root root  4096  8月 25 09:28 .
drwxr-xr-x 3 root root  4096 10月 12 23:09 ..
-rw-r--r-- 1 root root  1116  8月 13 07:30 LICENSE.txt
-rw-r--r-- 1 root root 60108  8月 13 07:30 ThirdPartyNotices.txt
-rwxr-xr-x 1 root root 51056  8月 13 07:34 dotnet
drwxr-xr-x 3 root root  4096  8月 13 07:36 host
drwxr-xr-x 6 root root  4096  8月 25 09:28 packs
drwxr-xr-x 3 root root  4096  8月 25 09:28 sdk
drwxr-xr-x 4 root root  4096  8月 11 13:22 shared
drwxr-xr-x 3 root root  4096  8月 25 09:28 templates
root@pleasanter:/opt/dotnet#
root@pleasanter:/opt/dotnet# vi /etc/bash.bashrc
 :
<追記>
# dotnet
export DOTNET_ROOT=/opt/dotnet
export PATH=$PATH:/opt/dotnet

root@pleasanter:/opt/dotnet#
root@pleasanter:/opt/dotnet#
root@pleasanter:/opt/dotnet# source /etc/bash.bashrc
root@pleasanter:/opt/dotnet#
root@pleasanter:/opt/dotnet# echo $DOTNET_ROOT
/opt/dotnet
root@pleasanter:/opt/dotnet#
root@pleasanter:/opt/dotnet# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/dotnet
root@pleasanter:/opt/dotnet#
root@pleasanter:/opt/dotnet# dotnet --version
5.0.401
root@pleasanter:/opt/dotnet#
```

## 4. GDI+のインストール

```shell
root@pleasanter:~#
root@pleasanter:~# apt install -y libgdiplus
root@pleasanter:~#
```

## 3. PostgreSQL12 をインストールする

### 3-1. インストール
[プリザンターの公式ドキュメント](https://pleasanter.org/manual/getting-started-pleasanter-ubuntu)では`PostgreSQL-13`となっているが、公式ドキュメント記載の方法だと`armhf`に対応していないようなので、ここでは標準リポジトリからインストールできる`PostgreSQL-12`で進めます。

```shell
root@pleasanter:~#
root@pleasanter:~# apt install -y postgresql-12 postgresql-client-12
root@pleasanter:~#

```

### 3-2. 設定

`/etc/postgresql/12/main/pg_hba.conf` と `/etc/postgresql/12/main/postgresql.conf` を編集する。

```shell
root@pleasanter:~# 
root@pleasanter:~# vi /etc/postgresql/12/main/pg_hba.conf
　：
# Database administrative login by Unix domain socket
local   all             postgres                                peer
　　　　　　　　　　　　　　↓
local   all             all                                     peer
　：
root@pleasanter:~# 
root@pleasanter:~# vi /etc/postgresql/12/main/postgresql.conf
　：
#------------------------------------------------------------------------------
# REPORTING AND LOGGING
#------------------------------------------------------------------------------
　：
#log_destination = 'stderr'              # Valid values are combinations of
　　↓
log_destination = 'stderr'              # Valid values are combinations of
　：
#logging_collector = off          # Enable capturing of stderr and csvlog
　　↓
logging_collector = on           # Enable capturing of stderr and csvlog
　：
log_line_prefix = '%m [%p] %q%u@%d '           # special values:
　　　　　　　　　　　　　　↓
log_line_prefix = '[%t]%u %d %p[%l]'           # special values:
　：

root@pleasanter:~# 
```

### 3-3. 起動とサービス有効化

```shell
root@pleasanter:~#
root@pleasanter:~# systemctl restart postgresql
root@pleasanter:~# systemctl status postgresql
● postgresql.service - PostgreSQL RDBMS
     Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor preset: enabled)
    Drop-In: /run/systemd/system/service.d
             mqzzz-lxc-service.conf
     Active: active (exited) since Wed 2021-10-13 00:05:17 JST; 15s ago
    Process: 15551 ExecStart=/bin/true (code=exited, status=0/SUCCESS)
   Main PID: 15551 (code=exited, status=0/SUCCESS)

10月 13 00:05:17 pleasanter systemd[1]: Starting PostgreSQL RDBMS...
10月 13 00:05:17 pleasanter systemd[1]: Finished PostgreSQL RDBMS.
root@pleasanter:~#
root@pleasanter:~# ss -antl | grep 5432
LISTEN   0        244            127.0.0.1:5432          0.0.0.0:*
root@pleasanter:~#
root@pleasanter:~# systemctl enable postgresql
Synchronizing state of postgresql.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable postgresql
root@pleasanter:~#
root@pleasanter:~# systemctl is-enabled postgresql
enabled
root@pleasanter:~#
```

### 3-4. データベースの準備

```shell
root@pleasanter:~#
root@pleasanter:~# su - postgres
postgres@pleasanter:~$
postgres@pleasanter:~$ psql
psql (12.8 (Ubuntu 12.8-0ubuntu0.20.04.1))
Type "help" for help.

postgres=#
postgres=# alter role postgres with password 'SetSaPWD';
ALTER ROLE
postgres=#
postgres=# create database "Implem.Pleasanter";
CREATE DATABASE
postgres=#
postgres=# \l
                                      List of databases
       Name        |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges
-------------------+----------+----------+-------------+-------------+-----------------------
 Implem.Pleasanter | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 |
 postgres          | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 |
 template0         | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres          +
                   |          |          |             |             | postgres=CTc/postgres
 template1         | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres          +
                   |          |          |             |             | postgres=CTc/postgres
(4 rows)

postgres=#
postgres=# \c "Implem.Pleasanter"
You are now connected to database "Implem.Pleasanter" as user "postgres".
Implem.Pleasanter=# create extension pg_trgm;
CREATE EXTENSION
Implem.Pleasanter=#
Implem.Pleasanter=# \q
postgres@pleasanter:~$
postgres@pleasanter:~$ exit
root@pleasanter:~#
```

## 4. プリザンターのインストール

### 4-1. プリザンターのダウンロードと展開

```shell
root@pleasanter:~#
root@pleasanter:~# cd /var/tmp/
root@pleasanter:/var/tmp#
root@pleasanter:/var/tmp# curl -LO https://github.com/Implem/Implem.Pleasanter.NetCore/releases/download/Pleasante_1.2.11.0/Pleasante_1.2.11.0.zip
root@pleasanter:/var/tmp# 
root@pleasanter:/var/tmp# mkdir -p /var/www/html
root@pleasanter:/var/tmp# 
root@pleasanter:/var/tmp# cd /var/www/html
root@pleasanter:/var/www/html#
root@pleasanter:/var/www/html# unzip -q /var/tmp/Pleasante_1.2.11.0.zip
root@pleasanter:/var/www/html# ls -lA
合計 8
-rw-r--r-- 1 root root  674  7月 21 22:59 Readme.txt
drwxr-xr-x 5 root root 4096 10月 13 00:21 pleasanter
root@pleasanter:/var/www/html#
root@pleasanter:/var/www/html#

```

### 4-2. 設定

`/var/www/html/pleasanter/Implem.Pleasanter/App_Data/Parameters/Rds.json` の `SaConnectionString` をセットアップした PostgreSQL 12 に合わせて編集する。

```shell
root@pleasanter:/var/www/html#
root@pleasanter:/var/www/html# vi /var/www/html/pleasanter/Implem.Pleasanter/App_Data/Parameters/Rds.json
root@pleasanter:/var/www/html#
{
    "Dbms": "PostgreSQL",
    "Provider": "Local",
    "TimeZoneInfo": "Asia/Tokyo",
 ★ "SaConnectionString": "Server=localhost;Port=5432;Database=postgres;UID=postgres;PWD=[設定したパスワード]",
    "OwnerConnectionString": "Server=localhost;Database=#ServiceName#;UID=#ServiceName#_Owner;PWD=SetAdminsPWD",
    "UserConnectionString": "Server=localhost;Database=#ServiceName#;UID=#ServiceName#_User;PWD=SetUsersPWD",
    "SqlCommandTimeOut": 0,
    "MinimumTime": 3,
    "DeadlockRetryCount": 4,
    "DeadlockRetryInterval": 1000,
    "DisableIndexChangeDetection": false
}
```

### 4-3. CodeDefinerの実行

```shell

root@pleasanter:/var/www/html#
root@pleasanter:/var/www/html# cd /var/www/html/pleasanter/Implem.CodeDefiner
root@pleasanter:/var/www/html/pleasanter/Implem.CodeDefiner#
root@pleasanter:/var/www/html/pleasanter/Implem.CodeDefiner# dotnet Implem.CodeDefiner.NetCore.dll _rds
<INFO> UsersConfigurator.Execute: Implem.Pleasanter_Owner
<INFO> UsersConfigurator.Execute: Implem.Pleasanter_User
　：
<INFO> PrivilegeConfigurator.Execute: Implem.Pleasanter_User
<SUCCESS> Starter.ConfigureDatabase: Database configuration has been completed.
<SUCCESS> Starter.Main: All of the processes have been completed.
root@pleasanter:/var/www/html/pleasanter/Implem.CodeDefiner#
```

### 4-4. プリザンターの起動確認

本環境では、IPv6を無効化しているので `warn:` が出てしまうがそのまま作業を続けます。 

```shell
root@pleasanter:/var/www/html/pleasanter/Implem.CodeDefiner#
root@pleasanter:/var/www/html/pleasanter/Implem.CodeDefiner# cd /var/www/html/pleasanter/Implem.Pleasanter
root@pleasanter:/var/www/html/pleasanter/Implem.Pleasanter#
root@pleasanter:/var/www/html/pleasanter/Implem.Pleasanter# dotnet Implem.Pleasanter.NetCore.dll
root@pleasanter:/var/www/html/pleasanter/Implem.Pleasanter# dotnet Implem.Pleasanter.NetCore.dll
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {a92f7d7b-0001-486e-a9c3-f043783afc64} may be persisted to storage in unencrypted form.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to bind to http://localhost:5000 on the IPv6 loopback interface: 'Cannot assign requested address'.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to bind to https://localhost:5001 on the IPv6 loopback interface: 'Cannot assign requested address'.

～別ターミナルでの接続が確認できたら Ctrl + C で終了する～
root@pleasanter:/var/www/html/pleasanter/Implem.Pleasanter#
```

別ターミナルを開いて、下記のような表示が出ればOK

```shell
root@pleasanter:~#
root@pleasanter:~# ss -antl
State              Recv-Q              Send-Q                           Local Address:Port                           Peer Address:Port             Process
LISTEN             0                   512                                  127.0.0.1:5000                                0.0.0.0:*
LISTEN             0                   512                                  127.0.0.1:5001                                0.0.0.0:*
　：
root@pleasanter:~#
root@pleasanter:~# curl -v http://localhost:5000/
*   Trying 127.0.0.1:5000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Date: Tue, 12 Oct 2021 15:53:17 GMT
< Server: Kestrel
< Content-Length: 0
< Location: http://localhost:5000/users/login?ReturnUrl=%2F
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
<
* Connection #0 to host localhost left intact
root@pleasanter:~#
```


### 4-5. プリザンターのサービス登録

```shell
root@pleasanter:/var/www/html/pleasanter/Implem.Pleasanter# 
root@pleasanter:/var/www/html/pleasanter/Implem.Pleasanter# cd ~
root@pleasanter:~#
root@pleasanter:~# vi /etc/systemd/system/pleasanter.service
[Unit]
Description = Pleasanter
Documentation =
Wants=network.target
After=network.target

[Service]
ExecStart = /opt/dotnet/dotnet Implem.Pleasanter.NetCore.dll
WorkingDirectory = /var/www/html/pleasanter/Implem.Pleasanter
Restart = always
RestartSec = 10
KillSignal=SIGINT
SyslogIdentifier=dotnet-pleasanter
User = root
Group = root
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy = multi-user.target
root@pleasanter:~#
root@pleasanter:~# systemctl daemon-reload
root@pleasanter:~#
root@pleasanter:~# systemctl enable pleasanter
root@pleasanter:~#
root@pleasanter:~# systemctl start pleasanter
root@pleasanter:~#
root@pleasanter:~# systemctl status pleasanter
● pleasanter.service - Pleasanter
     Loaded: loaded (/etc/systemd/system/pleasanter.service; enabled; vendor preset: enabled)
    Drop-In: /run/systemd/system/service.d
             mqzzz-lxc-service.conf
     Active: active (running) since Wed 2021-10-13 01:00:00 JST; 59s ago
   Main PID: 16411 (dotnet)
      Tasks: 19 (limit: 2059)
     CGroup: /system.slice/pleasanter.service
             mq16411 /opt/dotnet/dotnet Implem.Pleasanter.NetCore.dll

10月 13 01:00:00 pleasanter systemd[1]: Started Pleasanter.
10月 13 01:00:48 pleasanter dotnet-pleasanter[16411]: warn: Microsoft.AspNetCore.Server.Kestrel[0]
10月 13 01:00:48 pleasanter dotnet-pleasanter[16411]:       Unable to bind to http://localhost:5000 on the IPv6 loopback interface: 'Cannot assign requested address'.
10月 13 01:00:49 pleasanter dotnet-pleasanter[16411]: warn: Microsoft.AspNetCore.Server.Kestrel[0]
10月 13 01:00:49 pleasanter dotnet-pleasanter[16411]:       Unable to bind to https://localhost:5001 on the IPv6 loopback interface: 'Cannot assign requested address'.
root@pleasanter:~#
root@pleasanter:~# ss -antl | grep 5000
LISTEN   0        512            127.0.0.1:5000          0.0.0.0:*
root@pleasanter:~#
root@pleasanter:~#
root@pleasanter:~# curl -v http://localhost:5000/
*   Trying 127.0.0.1:5000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Date: Tue, 12 Oct 2021 16:02:13 GMT
< Server: Kestrel
< Content-Length: 0
< Location: http://localhost:5000/users/login?ReturnUrl=%2F
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
<
* Connection #0 to host localhost left intact
root@pleasanter:~#
```

## 5. リバースプロキシ(Nginx)のインストールと設定

本環境では HTTP(80) の設定をしていますが、HTTPS(443)に対応するなら Nginx で HTTPS化 する設定をすればよいです。
グローバルアドレスを持っていれば[cert-bot](https://certbot.eff.org/)を使って無料でSSL証明書が入手できます。


### 5-1. Nginxのインストール

```shell
root@pleasanter:~#
root@pleasanter:~# apt install -y nginx
root@pleasanter:~#
```

### 5-2. Nginxの設定

`/etc/nginx/conf.d/pleasanter.conf`を下記内容で新規作成する。

```shell
root@pleasanter:~#
root@pleasanter:~# vi /etc/nginx/conf.d/pleasanter.conf
server {
    listen  80;
    server_name 192.168.x.x;
    client_max_body_size 100M;
    location / {
       proxy_pass         http://localhost:5000;
       proxy_http_version 1.1;
       proxy_set_header   Upgrade $http_upgrade;
       proxy_set_header   Connection keep-alive;
       proxy_set_header   Host $host;
       proxy_cache_bypass $http_upgrade;
       proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header   X-Forwarded-Proto $scheme;
    }
}
root@pleasanter:~#
root@pleasanter:~# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
root@pleasanter:~#
```

### 5-2. Nginxの起動とサービス有効化

```shell
root@pleasanter:~#
root@pleasanter:~# systemctl restart nginx
root@pleasanter:~#
root@pleasanter:~# systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
    Drop-In: /run/systemd/system/service.d
             mqzzz-lxc-service.conf
     Active: active (running) since Wed 2021-10-13 01:05:21 JST; 4min 10s ago
       Docs: man:nginx(8)
   Main PID: 16864 (nginx)
      Tasks: 4 (limit: 2059)
     CGroup: /system.slice/nginx.service
             tq16864 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
             tq16865 nginx: worker process
             tq16866 nginx: worker process
             tq16867 nginx: worker process
             mq16868 nginx: worker process

10月 13 01:05:21 pleasanter systemd[1]: Starting A high performance web server and a reverse proxy server...
10月 13 01:05:21 pleasanter systemd[1]: Started A high performance web server and a reverse proxy server.
root@pleasanter:~#
root@pleasanter:~# ss -antl | grep 80
LISTEN   0        511              0.0.0.0:80            0.0.0.0:*
LISTEN   0        511                 [::]:80               [::]:*
root@pleasanter:~#
root@pleasanter:~# systemctl enable nginx
root@pleasanter:~#
root@pleasanter:~# systemctl is-enabled nginx
enabled
root@pleasanter:~#
```

### 5-3. ブラウザから確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108371/c21356a6-47ac-a3f0-20a3-63a9aac98a9b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108371/a0d5c960-c8e9-a9be-17f4-4f54c43b261c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108371/f2e0ed64-2610-3dc7-4fba-4ff2c05c67f6.png)


## 無事インストールができました

今回は手元に余っていた Raspberry Pi 2 で試してみましたが、ハードウェアスペックが低いせいかモッサリ感があって実用には向かず検証機としての利用がメインになりそうです。
最新の Raspberry Pi 4 ならスペックも向上しているので、設置場所を選ばずにプリザンターが使えるかもしれません。

プリザンター、PostgreSQL、Nginx 起動前

```shell
root@pleasanter:~#
root@pleasanter:~# free -h
              total        used        free      shared  buff/cache   available
Mem:          923Mi        92Mi       296Mi       1.0Mi       534Mi       769Mi
Swap:          99Mi        38Mi        61Mi
root@pleasanter:~#
```

PostgreSQL 起動

```shell
root@pleasanter:~#
root@pleasanter:~# systemctl start postgresql
root@pleasanter:~#
root@pleasanter:~# free -h
              total        used        free      shared  buff/cache   available
Mem:          923Mi        96Mi       281Mi        11Mi       545Mi       755Mi
Swap:          99Mi        38Mi        61Mi
root@pleasanter:~#
```


PostgreSQL + プリザンター 起動

```shell
root@pleasanter:~#
root@pleasanter:~# systemctl start pleasanter
root@pleasanter:~#
root@pleasanter:~# free -h
              total        used        free      shared  buff/cache   available
Mem:          923Mi       104Mi       272Mi        11Mi       545Mi       747Mi
Swap:          99Mi        38Mi        61Mi
root@pleasanter:~#
```


PostgreSQL + プリザンター + Nginx 起動

```shell
root@pleasanter:~#
root@pleasanter:~# systemctl start nginx
root@pleasanter:~#
root@pleasanter:~# free -h
              total        used        free      shared  buff/cache   available
Mem:          923Mi       138Mi       238Mi        11Mi       546Mi       713Mi
Swap:          99Mi        38Mi        61Mi
root@pleasanter:~#
```

# あとがき

今回構築したプリザンターはコンテナなので、コンテナごとコピーしたり、他のLXDホストに移動したりもできます。
PostgreSQLを別コンテナにして、プリザンター部分を複数稼働させるということもできそうですね。

また、RaspberryPi4ならUSB接続したSSDから起動することもできるみたいなので、高速化や大容量化といったカスタマイズにも対応できそうです。