発売当時くらいに買ったRaspberry pi 2を一通り遊んだ後、放置して使っていなかったので、またちょっと遊んでみる。
ゴール 
Raspberry piが手元に7台あるので、Load Balancer、 Reverse Proxy、Application Server、DB Serverで冗長構成を作成してみる。
Raspberry pi 2はメインメモリが2GB、CPUも32bitと今の基準からすると非力なので、なるべく軽い構成にする。Kubernetesとか使いたかったが、スペック的に無理だった。
Load Balancer : NginxReverse Proxy : Nginx ※無くても良いApplication Server : Apache Tomcat 10 (Java 21)DB Server : MariaDB
Ubuntu 22のインストール 
Raspberry Pi Imager を使ってUbuntuをSDカードにインストールする。
OSでOther general-purpose OS > Ubuntu > Ubuntu Server 22.04.4 LTS (32bit)を選択する。
初期設定 
適当に選んだRaspberry Piで起動し、共通の設定を行ってから、SDカードのイメージを取り、他のSDカードにコピーしていく。
sudo   apt   update  
sudo   apt   upgrade  
sudo   apt   install   net-tools  
 ローカルで使うだけなので、SSH接続でパスワード認証出来るようにしてしまう。
sudo   vi   /etc/ssh/sshd_config.d/60-cloudimg-settings.conf  
下記の通り修正  
 
PasswordAuthentication   yes  
 静的なIPを割り当てる。 イメージを他の機器にコピーするときはIPを変更する。
sudo   vi   /etc/netplan/50-cloud-init.yaml  
下記の通り修正  
 
network:  
     ethernets:  
         eth0:  
             dhcp4:   false  
             dhcp6:   false  
             addresses:  [ローカルIP/24]  #設定したIPは機器ごとに後で変更すること  
             routes:  
                 -   to:   default  
                   via:   ゲートウェイIP   #無いならroutesの設定いらない  
             nameservers:  
                 addresses:  [8.8.8.8,  8.8 .4.4]  
     version:   2  
 ホスト名を変更可能にする。
sudo   netplan   try  
sudo   vi   /etc/cloud/cloud.cfg  
下記の通り修正  
 
preserve_hostname:   true  
 ホスト名を設定する。 イメージを他の機器にコピーするときはホスト名を変更する。
sudo   hostnamectl   set-hostname   rp1   #設定したホスト名は機器ごとに後で変更すること  
Load Balancer 
初期設定したイメージから作業を始める。
nginx をインストールする。
sudo   apt   install   nginx  
sudo   systemctl   start   nginx  
sudo   systemctl   enable   nginx  
sudo   vi   /etc/nginx/nginx.conf  
下記の通り修正  
 
worker_connections   16 ;  
 Web Serverとしては使用しないのでdefaultの設定は読み込まないようにし、Load Balancer用の設定ファイルを作成する。
sudo   rm   /etc/nginx/sites-enabled/default  
sudo   vi   /etc/nginx/conf.d/loadbalancer.conf  
下記の通り新規作成  
 
upstream   backend   {  
     #least_conn;  
     #ip_hash; #設定しても良いが、ラウンドロビンされていることを直ぐに確認したいので今回はなし  
     server   Reverse   Proxy   Server   No.1のIP:80 ;  
     server   Reverse   Proxy   Server   No.2のIP:80 ;  
}  
 
server   {  
     listen   80   default_server ;  
     server_name   _ ;  
 
     location   /   {  
         proxy_pass   http://backend ;  
    }  
}  
 
 設定ファイルに誤りがないことを確認し、nginxを再起動する。
sudo   nginx   -t  
sudo   systemctl   restart   nginx  
Reverse Proxy 
初期設定したイメージから作業を始める。 Reverse Proxy Serverは2台作成する。
nginx をインストールする。
sudo   apt   install   nginx  
sudo   systemctl   start   nginx  
sudo   systemctl   enable   nginx  
sudo   vi   /etc/nginx/nginx.conf  
下記の通り修正  
 
worker_connections   16 ;  
 Web Serverとしては使用しないのでdefaultの設定は読み込まれないようにし、Reverse Proxy用の設定ファイルを作成する。
sudo   rm   /etc/nginx/sites-enabled/default  
sudo   vi   /etc/nginx/conf.d/proxy.conf  
下記の通り新規作成  
 
server   {  
     listen   80   default_server ;  
     server_name   _ ;  
 
     location   /   {  
         proxy_pass   http://Application   Server1のIP:8080 ;  
    }  
}  
 もう1台のReverse Proxy Serverも同様に設定する。
Application Serverも2台構成にする予定のため、 proxy_pass http://Application Server1のIP:8080;のIPはそれぞれ別のIPになる。
設定ファイルに誤りがないことを確認し、nginxを再起動する。
sudo   nginx   -t  
sudo   systemctl   restart   nginx  
Application Server 
Java 21のインストールTomcat 10 のインストール
Tomcat 10はインストールパッケージがなかったため、Apache Tomcatのページからダウンロードして解凍する。実行ユーザー、シンボリックリンクも作っておく。
sudo   apt   install   openjdk-21-jdk  
 
cd   /opt  
sudo   tar   xvfz   /mnt/nfs/apache-tomcat-10.1.20.tar.gz  
sudo   ln   -s   /opt/apache-tomcat-10.1.20   tomcat  
sudo   useradd   -m   -U   -d   /opt/tomcat   -s   /bin/ false   tomcat  
sudo   chown   -R   tomcat:   /opt/apache-tomcat-10.1.20  
 起動用のスクリプトを作成する。
sudo   vi   /usr/lib/systemd/system/tomcat.service  
下記の通り新規作成  
 
#  
# Systemd unit file for Apache Tomcat  
#  
[ Unit ]  
Description = Apache   Tomcat   10   Web   Application   Server  
After = network.target  
[ Service ]  
# Configuration  
Environment = " JAVA_OPTS=-Djava.awt.headless=true "  
Environment = " CATALINA_BASE=/opt/tomcat "  
Environment = " CATALINA_HOME=/opt/tomcat "  
Environment = " CATALINA_OPTS=-Xmx1024m -server "  
Environment = " CATALINA_PID=/opt/tomcat/temp/tomcat.pid "  
# Lifecycle  
Type = forking  
ExecStart = /opt/tomcat/bin/startup.sh  
ExecStop = /opt/tomcat/bin/shutdown.sh  
Restart = always  
PIDFile = /opt/tomcat/temp/tomcat.pid  
# Logging  
SyslogIdentifier = tomcat  
# Security  
User = tomcat  
Group = tomcat  
[ Install ]  
WantedBy = multi-user.target  
 自動起動は設定しない。
sudo   systemctl   daemon-reload  
sudo   systemctl   start   tomcat  
 もう1台のApplication Serverも同様に設定する。
起動確認が終わったら一度Tomcatを停止して、レプリケーションの設定をserver.xmlに追記する。
今回は簡単に確認するため、SimpleTcpClusterを使用している。別の機会にSpring Sessionを使用した方法を試してみたい。
<Cluster   className = " org.apache.catalina.ha.tcp.SimpleTcpCluster "  
          channelSendOptions = " 6 " >  
   <Manager   className = " org.apache.catalina.ha.session.BackupManager "  
            expireSessionsOnShutdown = " false "  
            notifyListenersOnReplication = " true "  
            mapSendOptions = " 6 " />  
   <Channel   className = " org.apache.catalina.tribes.group.GroupChannel " >  
     <Membership   className = " org.apache.catalina.tribes.membership.McastService "  
                 address = " 228.0.0.4 "  
                 port = " 45564 "  
                 frequency = " 500 "  
                 dropTime = " 3000 " />  
     <Receiver   className = " org.apache.catalina.tribes.transport.nio.NioReceiver "  
               address = " auto "  
               port = " 5000 "  
               selectorTimeout = " 100 "  
               maxThreads = " 6 " />  
 
     <Sender   className = " org.apache.catalina.tribes.transport.ReplicationTransmitter " >  
       <Transport   className = " org.apache.catalina.tribes.transport.nio.PooledParallelSender " />  
     </Sender>  
     <Interceptor   className = " org.apache.catalina.tribes.group.interceptors.TcpFailureDetector " />  
     <Interceptor   className = " org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor " />  
     <Interceptor   className = " org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor " />  
   </Channel>  
 
   <Valve   className = " org.apache.catalina.ha.tcp.ReplicationValve "   filter = "" />  
 
   <ClusterListener   className = " org.apache.catalina.ha.session.ClusterSessionListener " />  
</Cluster>  
 もう1台のApplication Serverも同様に設定する。
DB Server 
まずは3台に対してMariaDBをインストールして初期設定を実行する。
sudo   apt   install   mariadb-server  
sudo   systemctl   stop   mariadb  
sudo   mkdir   /mnt/ssd/mariadb  
 データの保存先を変更し、リモートアクセス可能にする。
sudo   vi   /etc/mysql/mariadb.conf.d/50-server.cnf  
下記の通り修正  
 
datadir                   =   /mnt/ssd/mariadb  
#bind-address            = 127.0.0.1  
 MariaDBが外部フォルダにアクセス出来るようにApplication Armorのセキュリティ設定を変更する。
sudo   vi   /etc/apparmor.d/tunables/alias  
下記の通り修正  
 
alias   /var/lib/mysql/  - >   /mnt/ssd/mariadb/,  
 Application Armorを再起動し、MariaDBのデータフォルダをコピーする。
sudo   systemctl   restart   apparmor  
sudo   rsync   -avuz   /var/lib/mysql/   /mnt/ssd/mariadb  
 MariaDBを起動し、初期設定する。
sudo   systemctl   start   mariadb  
sudo   mysql_secure_installation  
Enter   current   password   for   root  (enter  for   none ):  
Switch   to   unix_socket   authentication  [Y/n] n  
Change   the   root   password?  [Y/n]   
New   password:  
Re-enter   new   password:  
Remove   anonymous   users?  [Y/n] y  
Disallow   root   login   remotely?  [Y/n] n  
Remove   test   database   and   access   to   it?  [Y/n] y  
Reload   privilege   tables   now?  [Y/n] y  
 
mysql   -u   root   -p  
grant   all   privileges   on   * . *   to   root@ " % "   identified   by   ' password '   with   grant   option ;  
exit ;  
 
sudo   systemctl   restart   mariadb  
 接続確認を行ったら、一度停止する。
MariaDBをインストールすると自動的にGalera Clusterがインストールされているはず。
自動起動を無効にし、バイナリロギングを有効にする。
sudo   systemctl   disable   mariadb  
sudo   mkdir   -p   /mnt/ssd/log/mariadb  
sudo   chown   -R   mysql:   /mnt/ssd/log/mariadb  
sudo   vi   /etc/mysql/mariadb.conf.d/50-server.cnf  
下記の通り修正  
 
server-id                 =   1   # サーバー毎に変更  
log_bin                   =   /mnt/ssd/log/mariadb/mariadb-bin.log  
 Galera Clusterの設定を行う。
sudo   vi   /etc/mysql/mariadb.conf.d/60-galera.cnf  
下記の通り修正  
 
[ galera ]  
# Mandatory settings  
wsrep_on                   =   ON  
wsrep_cluster_name         =   " MariaDB Galera Cluster "  
wsrep_cluster_address      =   gcomm://サーバーIP1,サーバーIP2,サーバーIP3  
binlog_format              =   row  
default_storage_engine     =   InnoDB  
innodb_autoinc_lock_mode   =   2  
wsrep_provider             =   /usr/lib/galera/libgalera_smm.so  
 
# Allow server to accept connections on all interfaces.  
bind-address   =   0.0 .0.0  
 最初の1台は下記コマンドで実行する。以降は通常の起動コマンドで起動する。
※再起動時の注意 
データが保存されているフォルダにgrastate.datというファイルがあるので、safe_to_bootstrap: 1となっているサーバーからgalera_new_clusterで起動する。
sudo   less   /mnt/ssd/mariadb/grastate.dat  
 
# GALERA saved state  
version:   2.1  
uuid:      xxx  
seqno:     -1  
safe_to_bootstrap:   1  
 それ以外だと、エラー(WSREP: It may not be safe to bootstrap the cluster from this node. It was not the last one to leave the cluster and may not contain all the updates. To force cluster bootstrap with this node, edit the grastate.dat)となって起動できない。
動作確認 
Javaアプリを作りクラスタリングされているか確認する。