Docker版プリザンターで運用する方法

本記事は [OSSのノーコード・ローコード開発ツール「プリザンター」のアドベントカレンダー](https://qiita.com/advent-calendar/2023/pleasanter) の14日目の記事です。

## (追記) プリザンターのバージョンについて

本エントリはプリザンター **ver.1.3.50.2** までの内容です。

**ver.1.4.0.0** 以降は [Docker版プリザンターで運用する方法\(1\.4系編\) \- Qiita](https://qiita.com/imp-kawano/items/da84b02b23aa78aa41d8) を参照してください。

## はじめに

公式のDockerイメージで運用する方法を書いてみたいと思います。

- [implem/pleasanter \- Docker Image \| Docker Hub](https://hub.docker.com/r/implem/pleasanter)

本エントリではDocker Composeを用いた手順とします。

- [Docker Compose Overview \| Docker Docs](https://docs.docker.com/compose/) (英語)

## 事前準備

Docker ComposeはDocker Desktopをインストールするか、Compose pluginをインストールする2通りのシナリオがあります。  
詳細はドキュメントを参照して使えるようにしておいてください。

- [Overview of installing Docker Compose \| Docker Docs](https://docs.docker.com/compose/install/)

## 配置イメージ

最終的にこのような配置にしていきます。

```text
.
|-- docker-compose.yml
|
+-- app_data_parameters
|   +-- ExtendedSqls
|   |   +-- Sample.json.txt
|   |  
|   +-- Mail.json
|   +-- Rds.json
|
+-- CodeDefiner
|   +-- Dockerfile
|
+---Pleasanter
    +-- Dockerfile
```

## パラメータファイルの配置

まずはパラメータJSONや拡張SQLなど `App_Data/Parameters` 配下を `app_data_parameters` に置きます。

`app_data_parameters` ディレクトリの注意点です。

1. `App_Data/Parameters` と同じディレクトリ構造にする必要があります
   - [Implem\.Pleasanter/Implem\.Pleasanter/App\_Data/Parameters at main · Implem/Implem\.Pleasanter](https://github.com/Implem/Implem.Pleasanter/tree/main/Implem.Pleasanter/App_Data/Parameters)
1. 変更や追加したファイルだけを配置することを推奨いたします
1. ファイルを編集しただけでは実行イメージに反映されないため必ず `docker compose build` を実行してください

## 環境変数の設定

`ConnectionString` やPostgreSQLの初期化に必要な環境変数を設定します。設定する項目は以下です。

- PostgreSQLのバージョン指定
- PostgreSQL初期化パラメータ
- PostgreSQL用データボリュームのマウント先パス
- プリザンターのバージョン指定
- デーダベース接続文字列(`ConnectionString`)

### PostgreSQLのバージョン指定

- `POSTGRES_VER`: PostgreSQLのバージョン
  - [postgres \- Official Image](https://hub.docker.com/_/postgres)

※Docker Hubで公開されているバージョンを指定してください

### PostgreSQL初期化パラメータ

PostgreSQLの管理ユーザやそのパスワード、DBの指定は環境変数で渡していきます。

- `POSTGRES_USER`
- `POSTGRES_PASSWORD`
- `POSTGRES_DB`
- `POSTGRES_HOST_AUTH_METHOD`
- `POSTGRES_INITDB_ARGS`

`POSTGRES_HOST_AUTH_METHOD` と `POSTGRES_INITDB_ARGS` は認証方式を明示的に指定できます。  
詳細は PostgreSQLの公式イメージのドキュメントを参照してください。

例としてこうなります。

```bash
POSTGRES_HOST_AUTH_METHOD=scram-sha-256
POSTGRES_INITDB_ARGS="--auth-host=scram-sha-256"
```

こちらのブログが参考になります。

- [Postgres公式Dockerイメージのパスワードの扱いについて](https://zenn.dev/praha/articles/6cc31869346a06)

### PostgreSQL用データボリュームのマウント先パス

Dockerの機能でコンテナとは別のデータ保持のための機構で、データベースのデータ領域にこのデータボリュームを使います。

- `PGDATA`

コンテナ内でデータベースの実体ファイルが置かれるディレクトリをフルパスで指定します。  
公式イメージのドキュメントを参照してください。

### プリザンターのバージョン指定

プリザンターのバージョンを指定する環境変数です。

- `PLEASANTER_VER`: Pleasanterのバージョン
  - [implem/pleasanter Tags \| Docker Hub](https://hub.docker.com/r/implem/pleasanter/tags)

重要ポイントです。

1. Docker Hubの公式イメージとして公開されているバージョンを指定してください
1. この環境変数がない場合や有効なバージョンではない場合は `latest` になり、`docker compose build` を実行したタイミングで公開されている最新バージョンになります

### データベース接続文字列(ConnectionString)

いつものデータベース接続文字列ですが、この環境変数名にする必要があります。

- `Implem_Pleasanter_Rds_PostgreSQL_SaConnectionString`
- `Implem_Pleasanter_Rds_PostgreSQL_OwnerConnectionString`
- `Implem_Pleasanter_Rds_PostgreSQL_UserConnectionString`

理由は過去のエントリを参照してください。

- [PleasanterをDockerで動かす \- Qiita](https://qiita.com/imp-kawano/items/3bd23f0139a53957134b#compose%E3%81%AE%E5%AE%9A%E7%BE%A9%E3%82%92%E8%AA%AD%E3%82%80)

データベース接続文字列についてのマニュアルです。

- [パラメータ設定：Rds\.json \| Pleasanter](https://pleasanter.org/manual/rds-json)

PostgreSQLの環境変数の内容と `SaConnectionString` に記述されている内容を合わせる必要があります。

`SaConnectionString` は最初にPostgreSQLにスーパーユーザで接続するための設定が一行で表現されています。それぞれの意味はこうです。

- `Database`: 環境変数の `POSTGRES_DB` と揃える
- `UID`: 環境変数の `POSTGRES_USER` と揃える
- `PWD`: 環境変数の `POSTGRES_PASSWORD` と揃える

いずれもPostgreSQLを初期化する `initdb` で作成されるものとなります。

PostgreSQLのDocker公式イメージはコンテナの初期化時に `initdb` が実行されます。  
その際に `POSTGRES_` ではじまる環境変数のものを使用して初期化するように実装されています。

- [postgres - Official Image | Docker Hub](https://hub.docker.com/_/postgres)

- [docker-library/postgres: Docker Official Image packaging for Postgres](https://github.com/docker-library/postgres)

### 環境変数のサンプル

各パスワード箇所は `********` にマスクしているため適宜修正してください

```bash
PLEASANTER_VER=1.3.xx.y
POSTGRES_VER=15
Implem_Pleasanter_Rds_PostgreSQL_SaConnectionString='Server=db;Database=postgres;UID=postgres;PWD=********'
Implem_Pleasanter_Rds_PostgreSQL_OwnerConnectionString='Server=db;Database=#ServiceName#;UID=#ServiceName#_Owner;PWD=********'
Implem_Pleasanter_Rds_PostgreSQL_UserConnectionString='Server=db;Database=#ServiceName#;UID=#ServiceName#_User;PWD=********'
POSTGRES_USER=postgres
POSTGRES_PASSWORD=********
POSTGRES_DB=postgres
POSTGRES_HOST_AUTH_METHOD=scram-sha-256
POSTGRES_INITDB_ARGS="--auth-host=scram-sha-256 --encoding=UTF-8"
PGDATA=/var/lib/postgresql/data
```

## 各定義ファイルのサンプル

以降にサンプルを載せますのでそれぞれ配置してください。

### docker-compose.yml

```yaml
version: '3.7'

services:
  pleasanter:
    build:
      context: .
      dockerfile: ./Pleasanter/Dockerfile
      args:
        - VERSION=${PLEASANTER_VER}
    container_name: pleasanter_${PLEASANTER_VER}
    environment:
      Implem.Pleasanter_Rds_SaConnectionString: ${Implem_Pleasanter_Rds_PostgreSQL_SaConnectionString}
      Implem.Pleasanter_Rds_OwnerConnectionString: ${Implem_Pleasanter_Rds_PostgreSQL_OwnerConnectionString}
      Implem.Pleasanter_Rds_UserConnectionString: ${Implem_Pleasanter_Rds_PostgreSQL_UserConnectionString}
    depends_on:
      - db
    ports:
      - '8881:80'
    networks:
      - default
  codedefiner:
    build:
      context: .
      dockerfile: ./CodeDefiner/Dockerfile
    container_name: codedefiner
    environment:
      Implem.Pleasanter_Rds_SaConnectionString: ${Implem_Pleasanter_Rds_PostgreSQL_SaConnectionString}
      Implem.Pleasanter_Rds_OwnerConnectionString: ${Implem_Pleasanter_Rds_PostgreSQL_OwnerConnectionString}
      Implem.Pleasanter_Rds_UserConnectionString: ${Implem_Pleasanter_Rds_PostgreSQL_UserConnectionString}
    depends_on:
      - db
    networks:
      - default
    stdin_open: true
  db:
    container_name: postgres${POSTGRES_VER}
    image: postgres:${POSTGRES_VER}
    volumes:
      - type: volume
        source: pg_data
        target: ${PGDATA}
    networks:
      - default
    environment:
      - POSTGRES_USER
      - POSTGRES_PASSWORD
      - POSTGRES_DB
      - POSTGRES_HOST_AUTH_METHOD
      - POSTGRES_INITDB_ARGS
      - PGDATA
    user: postgres
  dbbackup:
    image: ubuntu
    container_name: dbbackup
    networks:
      - default
    volumes:
      - type: volume
        source: pg_data
        target: /pg_data
      - type: bind
        source: .
        target: /backup

volumes:
  pg_data:
    name: ${COMPOSE_PROJECT_NAME:-default}_pg_data_${POSTGRES_VER}

networks:
  default:
    name: pleasanter_prod_network
```

### CodeDefiner/Dockerfile

```dockerfile
FROM implem/pleasanter:codedefiner

COPY app_data_parameters/ /app/Implem.Pleasanter/App_Data/Parameters/
ENTRYPOINT [ "dotnet", "Implem.CodeDefiner.dll" ]
```

### Pleasanter/Dockerfile

```dockerfile
ARG VERSION=latest
FROM implem/pleasanter:${VERSION}

COPY app_data_parameters/ App_Data/Parameters/
ENTRYPOINT [ "dotnet", "Implem.Pleasanter.dll" ]
```

## イメージ構築・DB初期化

実行する前にコンテナイメージのビルド(`build`)をする点を意識してください。(忘れがちです)

各定義ファイルを配置したら実行してみます。

- プリザンターのイメージ構築

  ```bash
  docker compose build
  ```

- DB初期化

  ```bash
  docker compose run --rm codedefiner _rds
  ```

- プリザンターのサービス用のコンテナを構築、作成、実行

  ```bash
  docker compose up -d pleasanter
  ```

ブラウザで <http://localhost:8881/> にアクセスして、起動の確認をしてください。

初回のログインはいつもの通りです。

## プリザンター停止

```bash
docker compose stop pleasanter
```

プリザンターのコンテナは残ったまま停止します。

PostgreSQLのコンテナは実行したままです。

## プリザンター起動

`stop` した場合は、`start` とすることで再度実行することができます。

```bash
docker compose start pleasanter
```

## PostgreSQL停止

PostgreSQLのコンテナを停止します。 コンテナは残ったままです。  
`start` すれば再度実行されます。

```bash
docker compose stop db
```

```bash
docker compose start db
```

## コンテナログ

1. 各サービスのコンテナのログを確認できます。

    ```bash
    docker compose logs [サービス名]
    ```

1. `-f` オプションでログを出力し続けますので起動確認などで利用すると良いです。

    ```bash
    docker compose logs -f [サービス名]
    ```

## コンテナ及びネットワークの削除

`down` すると次のものが依存関係を保ちながらコンテナが削除されます。

```bash
docker compose down
```

```bash
[+] Running 3/3
 ✔ Container pleasanter_1.3.48.0    Removed
 ✔ Container postgres15             Removed
 ✔ Network pleasanter_prod_network  Removed       
 ```

1. プリザンターのコンテナ
2. PostgreSQLのコンテナ
3. ネットワーク

このコマンドを実行してもPostgreSQLのデータが格納されているデータボリュームはそのまま残っています。  

再び実行したい場合は、

```bash
docker compose up -d pleasanter
```

とすると、ネットワーク作成後、PostgreSQLのコンテナとプリザンターのコンテナが作成されて起動します。

```bash
[+] Building 0.0s (0/0)
[+] Running 3/3
 ✔ Network pleasanter_prod_network  Created
 ✔ Container postgres15             Started
 ✔ Container pleasanter_1.3.48.0    Started
 ```

## バージョンアップの仕方

プリザンターのバージョンアップは以下の手順で実施できます。

1. プリザンターの停止
2. 環境変数のバージョンを変更
3. 新バージョンのコンテナイメージを作成
4. CodeDefinerの更新とDBの再定義
5. プリザンターを実行

### プリザンターのコンテナ停止

```bash
docker compose stop pleasanter
```

### 環境変数のバージョンを変更

Docker Hubにてバージョンタグを確認し環境変数の`PLEASANTER_VER`を変更します。

プリザンターのバージョンアップ情報を確認してパラメータの差分があれば反映します。

- [プリザンターの直近のバージョンアップ情報 \| Pleasanter](https://pleasanter.org/manual/release-notes-core)

### 新バージョンのコンテナイメージを作成

```bash
docker compose build
```

### CodeDefinerの更新とDBの再定義

pullしてCodeDefinerのイメージを更新します。

```bash
docker compose pull codedefiner
```

DBの再定義を実施します。

```bash
docker compose run --rm codedefiner _rds
```

### プリザンターを実行

```bash
docker compose up -d pleasanter
```

```bash
[+] Building 0.0s (0/0)
[+] Running 3/3
 ✔ Container postgres15           Running
 ✔ Container pleasanter_1.3.48.0  Recreated
 ✔ Container pleasanter_1.3.49.0  Started
```

停止して残っていた前バージョンのコンテナを再作成して新バージョンのコンテナとして再作成後開始します。

データベースのデータは引き継がれます。

## コンテナ内を確認するには

ここからはコンテナの中身を確認したりする手順や注意点を書いていきます。

1. コンテナイメージがどのようになっているか確認する場合

   ```bash
   docker compose run --rm --entrypoint /bin/bash pleasanter
   ```

1. 動いているpleasanterのコンテナインスタンス内に入る場合

   ```bash
   docker compose exec pleasanter /bin/bash
   ```

   ※動いているコンテナや Compose projects がある状態で有効なコマンドです。以下の条件を満たしている  必要があります。

   - `docker compose ls`: running となっているプロジェクトが存在すること
   - `docker ps`: コンテナ一覧に表示されること

## データボリュームのバックアップをするには

データボリュームとホストのバックアップ先ディレクトリをマウントし `tar` でPostgreSQLのデータディレクトリをアーカイブすることで、バックアップが可能です。

例) `pgdata-backup.tar.gz` として実行時のディレクトリに作成する

```bash
docker compose run --rm dbbackup tar czvf /backup/pgdata-backup.tar.gz -C /pg_data .
```

## コンテナ、ネットワーク、データボリュームの削除

**※注意※** : データボリュームの削除はデータベースのデータディレクトリ(`${PGDATA}`)の削除と同じ意味なので注意してください

```bash
docker compose down -v
```

以上です。