PostgreSQLをWindows11のWSL（AlmaLinux）で利用する

# この記事は
PostgreSQLをこれから勉強する方向けに、簡単にPostgreSQLの実習環境を用意することを目的とします。
WSLの初期セットアップ部分はWin11固有のところがありますが、WSL起動後はWindowsのバージョンによる差はありません。
* WSL（AlmaLinux 8）のセットアップ
* AlmaLinux on WSLの初期設定
* PostgreSQLのインストールと設定

を解説します。

また、本記事の公開は **2023年1月**です。WSLに関して、直近1年の日付でもすでに実情と異なる情報が書かれた記事が散見されましたので、古いノウハウにご注意ください。そして、本記事の信憑性も徐々に薄れていくものとお考え下さい。


# はじめてのWSL
最近のWindowsでは、Windows Subsystem for Linux（WSL）が利用可能で、各自のPC上で軽快に動作するLinux環境が手に入ります。

業務で使用するRDBMSを学習するのに、本番と違うWindows版の製品で学習するのは違和感があったのですが、WSLによりLinux版の学習環境を、誰でも簡単に自分のWindowsマシン内で完結する形で作れます。データベースに関しては、起動停止やバックアップリカバリなど、OS側のコマンド操作を前提にする作業が多数ありますのでこの学習環境が手に入ることは有益です。

WSL上でのPostgreSQL構築手順を整理し公開することで、これから学習したい方の初動のハードルが少しでも下がればと思っています。


# WSLのセットアップ（AlmaLinux 8）
Windows 11では、以下の3ステップでWSLを利用できました。
* Windows機能の有効化
* WSLのインストール
* AlmaLinux 8のインストール

ちょっとした罠もあったので一つ一つ解説します。

### 1.Windows機能の有効化
スタートメニュー → 設定 → アプリ → オプション機能 → Windowsのその他の機能
と進み、以下の機能を有効化します。
* Linux用Windowsサブシステム
* 仮想マシンプラットフォーム
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89971/1863092b-810d-530f-a547-aabaabc259f0.png" width=50%>

どちらもPCの再起動が必要＆Windows Upadteが走る可能性があります。

**注意：** Surface Pro 9、Windows11では、両機能を同時に有効化するとPC再起動に失敗し、機能が無効化されるという現象を繰り返しました。片方ずつ有効化、再起動、Windows Updateを全部適用した上でもう一つも有効化したら上手くいきました。

### 2.WSLのインストール
Windows 10向けの情報で`Windows Terminal`のインストールや、`wsl --install`のようなコマンドを複数紹介している情報がありますが、Windows 11での準備はかなりシンプルです。
Microsoft Storeで以下2つをインストールします。この順番で、WSLの入手→起動できたらAlmaの入手→起動です。

* Windows Subsystem for Linux（WSL）
* AlmaLinux 8 WSL（ディストリビューション）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89971/cb6cdc1c-93ed-a906-1ef2-a67718077e8b.png" width=70%>

Storeから入手すると、インストール後に「開く」ボタンが押せるのでそれでWSLを初回起動しました。内部処理が走り使える状態になりました。
その後好きなディストリビューションを入手します。私は業務で馴染みのあるRHEL系のAlmaにしました。

**注意：** 実は、この **Microsoft Sotre版のWSLを入手する** というのがこの後のステップで重要になります。
Windows Terminal上で`wsl --install`とやると一連のセットアップ＋Ubuntu環境が出来上がるそうですが、ここで導入されるWSLはバージョンが少し古いようで、Store版でないとサポートしない操作があります。（2022/12時点で確認）

### 3.AlmaLinuxの起動
正常にインストールできるとWindowsのスタートメニューに`AlmaLinux 8`アイコンが追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89971/a56ef5f7-c6a0-ff23-0301-987661d7cc80.png)

これをクリックするとWindows Terminalが立ち上がりLinuxにログインできます。（初回のみログインユーザーの指定をします。任意の名前とパスワードを入力ください。）
Tera TermでLinuxにログインしたかのように、Windows Terminalが起動し、コマンドラインでLinuxの操作ができます。

# AlmaLinux on WSLの初期設定
上記で初回起動したAlmaLinuxは、普通のサーバー環境としては必要なコマンド類がインストールされておらず、最低限のセットアップとしては以下が必要でした。
* 初回起動時のユーザ作成（ここまでの手順で済）
* systemdの設定
* ipコマンドの追加
* パッケージ更新（任意）
* 日本語環境やタイムゾーンの設定

その他、各自が「最小限」と思ってる構成に足りないモジュール等はあるかもしれないので、ここから先は各々でパッケージ追加などお試しください。

### 1.初回起動時の一般ユーザ作成
初回のみ、Linuxユーザ作成の指示があるので`myname/mypassword`を任意に決めてください。
rootで操作が必要な場合は `sudo su -`でパスワード無しにスイッチできます。この後の初期設定作業はrootで行います。
```bash
sudo su -
```

### 2.systemdの設定（root）
RHEL7の時代にお勉強して、それ以来いつも当たり前に使えると思っていたsystemdによるサービスの起動/停止。WSLではデフォルトでsystemdが使えない状態だったので、ミドルウェア製品の導入前に動作を変更しておく必要があります。

**注意：  これがWSLのバージョン依存（Store版WSLが良い）としていた操作です。**

> ！　Store版をインストールしていない場合この通りに操作できません。
> ！　また、旧バージョン向けの回避策として複雑な技術情報が多数ヒットしますが
> ！　今は以下の方法が圧倒的に簡単です。

やることは簡単で、`/etc/wsl.conf`に該当の記述を追記。というか、ファイルが存在しないので新規作成でこれだけ書けばOKです。
```bash
vi /etc/wsl.conf
```
```
/* 以下を追記 */
[boot]
systemd=true
```
次回起動時にsystemdが有効になるので、WSLを終了してもう一度起動します。
Windows側でコマンドプロンプトを立ち上げ以下を実行します。
```
/*ディストリビューションの停止*/
>wsl --shutdown

/*起動*/
>wsl
```


### 3.ipコマンドの追加（root）
デフォルトだとipコマンドが使えないようなのでパッケージを追加します。
```
/*再起動したのでrootになる*/
sudo su -
```
iprouteのインストール
```
dnf install iproute -y
```
#### ipアドレス確認
ipコマンドが通るようになったので状態確認
```
# ip a
　/* 一部抜粋*/
6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:15:5d:b7:74:15 brd ff:ff:ff:ff:ff:ff
    inet 172.27.249.125/20 brd 172.27.255.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::215:5dff:feb7:7415/64 scope link
       valid_lft forever preferred_lft forever
```
#### Windows側から疎通確認
```
>ping 172.27.249.125

172.27.249.125 に ping を送信しています 32 バイトのデータ:
172.27.249.125 からの応答: バイト数 =32 時間 <1ms TTL=64
172.27.249.125 からの応答: バイト数 =32 時間 <1ms TTL=64
172.27.249.125 からの応答: バイト数 =32 時間 <1ms TTL=64
172.27.249.125 からの応答: バイト数 =32 時間 <1ms TTL=64

172.27.249.125 の ping 統計:
    パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 0ms、最大 = 0ms、平均 = 0ms
```

### 4.パッケージ更新（root）
デフォルトは8.5だったので更新しました。
```
dnf update -y
```
バージョン確認
```
# cat /etc/redhat-release
AlmaLinux release 8.7 (Stone Smilodon)
```
### 5.その他の操作
この辺は各自の違和感のないサーバー設定を踏襲できるとよいと思われる。

#### 日本語対応、タイムゾーンの設定
```
# dnf install -y glibc-langpack-ja
# localectl set-locale LANG=ja_JP.utf8
# localectl set-keymap jp106
# dnf install -y langpacks-ja
# timedatectl set-timezone Asia/Tokyo
```
日本語環境の例
```
# export LANG=C
# date
Tue Jan 17 14:00:51 JST 2023

/* 必要に応じて表示言語を切り替える*/
# export LANG=ja_JP.utf8
# echo $LANG
ja_JP.utf8
# date
2023年  1月 17日 火曜日 14:01:23 JST
```

# ここまでをexportし複製
ここまでは、PostgreSQLは関係しない、WSL利用時のお作法というか、俺俺Linux仮想マシンを準備したぜ！という段階です。この時点を今後も複製できるようにバックアップファイルとして保管しておきます。

[参考サイト1：WSL2でAlmaLinuxサーバー3台用意](https://qiita.com/mingchun_zhao/items/41fe87ef5787e5616f35)
[参考サイト2：標準機能だけでWSLを好きな場所にインストールする](https://qiita.com/yamada6667/items/9e73193b0167cba2351d)

### 1.状態確認
Windowsのコマンドプロンプト側で実行
```
>wsl -l -v
  NAME           STATE           VERSION
* AlmaLinux-8    Running         2
```
### 2.エクスポート
`C:\path\to\export`の部分は好きなフォルダ位置を指定してください。
このフォルダに俺俺テンプレートが配置されることになりますので長期保管するつもりの命名にしておくと良いと思います。
```
>wsl --export AlmaLinux-8 C:\path\to\export\MyAlmaLinux8.tar
エクスポートが進行中です。これには数分かかる場合があります。
この操作を正しく終了しました。
```
### 3.インポート
`C:\path\to\study`の部分は好きなフォルダ位置を指定してください。
実際にPostgreSQLをインストールしたりするのはココで作成する`MyStudy`のマシンです。例えばPostgreSQLの勉強用であれば、お勉強プロジェクトのstudyフォルダを一個作って、そこに配置すると良いでしょう。今後、勉強の中で使うであろうスクリプトとかも一緒に配置する想定です。
```
>wsl --import MyStudy C:\path\to\study\MyStudy C:\path\to\export\MyAlmaLinux8.tar
インポート中です。この処理には数分かかることがあります。
この操作を正しく終了しました。
```
結果
```
>wsl -l -v
  NAME            STATE           VERSION
* AlmaLinux-8     Stopped         2
  MyStudy         Stopped         2
  /*エクスポートすると元の仮想マシンも停止します*/
```
### 4. 複製したマシンの起動
これで複数ディストリビューションを使い分けられるようになりました。
WindowsのスタートメニューからAlmaLinuxアイコンで起動すると、デフォルトの仮想マシンが起動してしまいますので、プロジェクトで使用するものはコマンドで起動します。

```
>wsl -d MyStudy -u myname
```
`-d`でディストリビューション名を指定します。
`-u`でLinux側のユーザ名を指定します。

Linuxにログインすると、こんな感じで、Windowsのユーザフォルダがカレントディレクトリになるので、`cd ~`でホームディレクトリに移動すると良いでしょう。
```
>wsl -d MyStudy -u myname
[myname@PC:/mnt/c/Users/myname]$
[myname@PC:/mnt/c/Users/myname]$ cd
[myname@PC:~]$
[myname@PC:~]$ pwd
/home/myname
```

# PostgreSQLのインストールと初期設定
さて、これでOSの準備が整ったので、PostgreSQLをインストールします。
ここではパッケージの依存関係など少なく、なるべくシンプルな形でオフラインインストールできる手順を紹介します。

### 1.パッケージの入手
日本PostgreSQLユーザ会のページから「[ダウンロード](https://www.postgresql.jp/download)」タブ→「Linux（rpm）」のリンクを進むと、グローバルのPostgreSQL開発グループが配布している[RPM置き場](https://yum.postgresql.org/rpmchart/)があります。

PostgreSQLのバージョンとOSディストリビューション別にリンクがあるので、2023年1月時点で最新の正式リリース版である [PostgreSQL15、RHEL / Rocky Linux 8 - x86_64](https://yum.postgresql.org/15/redhat/rhel-8-x86_64/) を選択し、以下のrpmをダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89971/34040c29-f40f-3cea-153d-4510431be744.png)


* postgresql15-15.1-1PGDG.rhel8.x86_64.rpm
* postgresql15-contrib-15.1-1PGDG.rhel8.x86_64.rpm
* postgresql15-libs-15.1-1PGDG.rhel8.x86_64.rpm
* postgresql15-server-15.1-1PGDG.rhel8.x86_64.rpm

※<15.1>の部分は、マイナーVer<15.x>の桁が進んでいれば最新を選びましょう。
※この4つは学習用に必須です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89971/c3c78b9f-595e-af77-9d54-f9594ad74ffa.png" width=70%>

業務サーバーではllvmjitやdevelも必要なケースがありますが、単にデータ格納してSQLで取り出す分には困りません。llvmjitはデータ分析系では役に立つかも。データ量や繰り返し同じ計算を行うときに少し性能が良くなる可能性があります。しかし依存パッケージが増えるので初めての勉強用には無くてもいいかな、という感じ。

ダウンロードしたファイルは、Windows側で、OSイメージを配置したお勉強プロジェクトフォルダに置きましょう。今回はstudy配下にmodulesフォルダを作ってそこに入れました。

### 2. LinuxにPostgreSQLをインストール
インストール作業はrootユーザで行います。
```
/* rootユーザにスイッチ */
sudo su -
```

WSLの仮想マシンでは、`/mnt/Windows上のパス`でWindows上のファイルにアクセスできます。入手したRPMを配置したプロジェクトフォルダに移動します。
```
# cd /mnt/c/path/to/study/modules
# ls -l
total 8768
-rwxrwxrwx 1 root root 1700920 Jan 17 03:14 postgresql15-15.1-1PGDG.rhel8.x86_64.rpm
-rwxrwxrwx 1 root root  766744 Jan 17 03:14 postgresql15-contrib-15.1-1PGDG.rhel8.x86_64.rpm
-rwxrwxrwx 1 root root  299056 Jan 17 03:14 postgresql15-libs-15.1-1PGDG.rhel8.x86_64.rpm
-rwxrwxrwx 1 root root 6198364 Jan 17 03:14 postgresql15-server-15.1-1PGDG.rhel8.x86_64.rpm
```
このフォルダでdnfコマンドを実行してインストール
```
# dnf install -y \
> postgresql15-15.1-1PGDG.rhel8.x86_64.rpm \
> postgresql15-contrib-15.1-1PGDG.rhel8.x86_64.rpm \
> postgresql15-libs-15.1-1PGDG.rhel8.x86_64.rpm \
> postgresql15-server-15.1-1PGDG.rhel8.x86_64.rpm
```

成功すると、以下の状態になります。
* OSユーザpostgresが作成されている
* /usr/pgsql-15ディレクトリ配下に製品がインストールされている

```
# su - postgres
Last login: 火  1月 17 05:42:21 JST 2023 on pts/0
$ id
uid=26(postgres) gid=26(postgres) groups=26(postgres)
```
インストールされたモジュール群
```
$ cd /usr/pgsql-15
$ ll
total 16
drwxr-xr-x 2 root root 4096 Jan 17 03:34 bin
drwxr-xr-x 3 root root 4096 Jan 17 03:34 doc
drwxr-xr-x 3 root root 4096 Jan 17 03:34 lib
drwxr-xr-x 7 root root 4096 Jan 17 03:34 share
```

**補足：** 依存パッケージ少なくと思っていたが、WSLのAlmaには不足パッケージがまあまああったようです。仕方がない。。。依存性で自動入手したパッケージをメモっておくので、完全オフラインで済ませたい人はこれらを事前入手してください。全部modulesフォルダに配置して、dnf install時に指定すればすんなりいくはず。
```
groff-base-1.22.3-18.el8.x86_64
libicu-60.3-2.el8_1.x86_64
libxslt-1.1.32-6.el8.x86_64
lz4-1.8.3-3.el8_4.x86_64
perl-Carp-1.42-396.el8.noarch
perl-Data-Dumper-2.167-399.el8.x86_64
perl-Digest-1.17-395.el8.noarch
perl-Digest-MD5-2.55-396.el8.x86_64
perl-Encode-4:2.97-3.el8.x86_64
perl-Errno-1.28-421.el8.x86_64
perl-Exporter-5.72-396.el8.noarch
perl-File-Path-2.15-2.el8.noarch
perl-File-Temp-0.230.600-1.el8.noarch
perl-Getopt-Long-1:2.50-4.el8.noarch
perl-HTTP-Tiny-0.074-1.el8.noarch
perl-IO-1.38-421.el8.x86_64
perl-IO-Socket-IP-0.39-5.el8.noarch
perl-IO-Socket-SSL-2.066-4.module_el8.6.0+2811+fe6c84b0.noarch
perl-MIME-Base64-3.15-396.el8.x86_64
perl-Mozilla-CA-20160104-7.module_el8.5.0+2812+ed912d05.noarch
perl-Net-SSLeay-1.88-2.module_el8.6.0+2811+fe6c84b0.x86_64
perl-PathTools-3.74-1.el8.x86_64
perl-Pod-Escapes-1:1.07-395.el8.noarch
perl-Pod-Perldoc-3.28-396.el8.noarch
perl-Pod-Simple-1:3.35-395.el8.noarch
perl-Pod-Usage-4:1.69-395.el8.noarch
perl-Scalar-List-Utils-3:1.49-2.el8.x86_64
perl-Socket-4:2.027-3.el8.x86_64
perl-Storable-1:3.11-3.el8.x86_64
perl-Term-ANSIColor-4.06-396.el8.noarch
perl-Term-Cap-1.17-395.el8.noarch
perl-Text-ParseWords-3.30-395.el8.noarch
perl-Text-Tabs+Wrap-2013.0523-395.el8.noarch
perl-Time-Local-1:1.280-1.el8.noarch
perl-URI-1.73-3.el8.noarch
perl-Unicode-Normalize-1.25-396.el8.x86_64
perl-constant-1.33-396.el8.noarch
perl-interpreter-4:5.26.3-421.el8.x86_64
perl-libnet-3.11-3.el8.noarch
perl-libs-4:5.26.3-421.el8.x86_64
perl-macros-4:5.26.3-421.el8.x86_64
perl-parent-1:0.237-1.el8.noarch
perl-podlators-4.11-1.el8.noarch
perl-threads-1:2.21-2.el8.x86_64
perl-threads-shared-1.58-2.el8.x86_64
```


### 3.データベースクラスタを作成
ここからはPostgreSQLのコマンドです。

PostgreSQL的には基本であり、学習の状況によってはインストール先を変えてみたり、WALを別ディスクに置いてみたりすることもあるかもしれませんが、初級者はこのまま作ってみてください。rpmインストールしたrootユーザのまま実行でOKです。

```
# export PGSETUP_INITDB_OPTIONS='--no-locale -E utf8'
# postgresql-15-setup initdb
Initializing database ... OK
```
何をしているかというと、データベースクラスタを作成する`initdb`という操作です。

initdbは通常、一般ユーザでの実行を想定したpostgresのコマンドです。
しかし、初期セットアップにおいてはinitdbとあわせてsystemdサービスや権限などrootを必要とする操作ができたほうが望ましく、それを1コマンドでやってくれるものです。
環境変数`PGSETUP_INITDB_OPTIONS`は、この場限りでinitdbコマンドに渡す引数リストです。構築に使うコマンドや引数の意味はOSS-DB Silverなどの範囲になりますが、初学者はまずはこの通りに指定してみてください。

### 4.PostgreSQLの起動
起動はrootユーザで、systemctlで行います。
停止はstop、再起動はrestartが使えます。
デフォルトのサービス名`postgresql-15.service`を指定します。
```
systemctl start postgresql-15.service
```

起動後の状態確認です。
起動後は一般ユーザ（PostgreSQL運用管理に用いるOSユーザ）として作成されたpostgresユーザで操作します。
```
# su - postgres
Last login: 火  1月 17 05:39:09 JST 2023 on pts/0
$ ps x
    PID TTY      STAT   TIME COMMAND
    453 ?        Ss     0:00 /usr/pgsql-15/bin/postmaster -D /var/lib/pgsql/15/data/
    454 ?        Ss     0:00 postgres: logger
    455 ?        Ss     0:00 postgres: checkpointer
    456 ?        Ss     0:00 postgres: background writer
    458 ?        Ss     0:00 postgres: walwriter
    459 ?        Ss     0:00 postgres: autovacuum launcher
    460 ?        Ss     0:00 postgres: logical replication launcher
    462 pts/0    S      0:00 -bash
    510 pts/0    R+     0:00 ps x
```
データベースにアクセスするにはコマンドラインツールpsqlを使用します。
psqlを終了するときは`exit`または`\q`です。
```
$ psql
psql (15.1)
Type "help" for help.

postgres=# \l
                                            List of databases
   Name    |  Owner   | Encoding | Collate | Ctype | ICU Locale | Locale Provider |   Access privileges
-----------+----------+----------+---------+-------+------------+-----------------+-----------------------
 postgres  | postgres | UTF8     | C       | C     |            | libc            |
 template0 | postgres | UTF8     | C       | C     |            | libc            | =c/postgres          +
           |          |          |         |       |            |                 | postgres=CTc/postgres
 template1 | postgres | UTF8     | C       | C     |            | libc            | =c/postgres          +
           |          |          |         |       |            |                 | postgres=CTc/postgres
(3 rows)

postgres=# exit
```

### 5.PostgreSQLの自動起動設定
systemdのサービス自動起動設定を用いて、OS起動時にPostgreSQLが起動するようにします。この操作はrootで実行します。
```
# systemctl list-unit-files | grep postgres
postgresql-15.service                  disabled

# systemctl enable postgresql-15.service
Created symlink /etc/systemd/system/multi-user.target.wants/postgresql-15.service → /usr/lib/systemd/system/postgresql-15.service.

# systemctl list-unit-files | grep postgres
postgresql-15.service                  enabled
```
この状態で、もう一度本記事に記載した「WSL仮想マシンのエクスポート」をしておけば、まっさらなPostgreSQL環境にいつでも戻れるので、障害系のお茶目な検証もやり放題ですね！


# まとめ
PostgreSQLをこれから勉強する方向けに、Windows環境で誰でも使えるPostgreSQL実習環境の準備について整理しました。

* WSL（AlmaLinux 8）のセットアップ
* AlmaLinux on WSLの初期設定

ここまではPostgreSQLに限らず、Linux初学者にとって、または他のミドルウェア製品の学習や開発環境にもおすすめの環境になると思います。

* PostgreSQLのインストールと設定

空のデータベースクラスタを作成し、systemctlで起動停止、OS起動時に自動起動できるようにしました。