NanoPi R2SでFreeBSDを動かす

やること

Amazon買ったNanoPi R2Sで、FreeBSDを動かす。 FreeBSDFreeBSD 13.0-RC5。

FreeBSDのダウンロード

SDへの書き込みは時間がかかるので、先にやっておく。ROCK64用のイメージをダウンロードして、いつものように書き込み。 ROCK64なのは、CPUが同じだから。

unxz -c FreeBSD-13.0-RC5-arm64-aarch64-ROCK64.img.xz | sudo dd of=/dev/da0 bs=1m status=progress

書き込んでいる間にu-boot

最新のu-boot-masterの2021.04を使いたかったが、portsnapでは落ちで来なかったのでGitHubから持ってくる。

# git cloneは時間がかかりそうだからZIPでダウンロード。
curl -L -O https://github.com/freebsd/freebsd-ports/archive/refs/heads/main.zip
unzip main.zip
mv freebsd-ports-main /usr/ports

NanoPi R2S用のu-bootのportsはなかったので、自分で作った。これもROCK64用をカスタマイズして作った。

github.com

インストールはmake installするだけ。

cd /usr/ports/sysutils
git clone https://github.com/rixwwd/u-boot-nanopi-r2s.git
cd u-boot-nanopi-r2s
make install

u-bootの書き込み

u-bootのビルド&インストールとFreeBSD用のイメージの書き込みが終わったら、u-bootをSDに書き込む。

dd if=/usr/local/share/u-boot/u-boot-nanopi-r2s/idbloader.img of=/dev/da0 seek=64 bs=512 conv=sync
dd if=/usr/local/share/u-boot/u-boot-nanopi-r2s/u-boot.itb of=/dev/da0 seek=16384 bs=512 conv=sync

起動!

SDカードを差し込んで、しばらく待つと、SSHで接続できるようになる。 ユーザー、パスワードはfreebsdでログインできる。

freebsd@generic:~ % dmesg
---<<BOOT>>---
Copyright (c) 1992-2021 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
    The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 13.0-RC5 #0 releng/13.0-n244727-f8a134d0ef1: Fri Apr  2 06:18:30 UTC 2021
    root@releng1.nyi.freebsd.org:/usr/obj/usr/src/arm64.aarch64/sys/GENERIC arm64
FreeBSD clang version 11.0.1 (git@github.com:llvm/llvm-project.git llvmorg-11.0.1-0-g43ff75f2c3fe)
VT: init without driver.
module firmware already present!
real memory  = 1071427584 (1021 MB)
avail memory = 1023131648 (975 MB)
Starting CPU 1 (1)
Starting CPU 2 (2)
Starting CPU 3 (3)
FreeBSD/SMP: Multiprocessor System Detected: 4 CPUs
arc4random: WARNING: initial seeding bypassed the cryptographic random device because it was not yet seeded and the knob 'bypass_before_seeding' was enabled.
random: entropy device external interface
MAP 3cf1f000 mode 2 pages 1
MAP 3cf23000 mode 2 pages 3
MAP 3cf27000 mode 2 pages 4
MAP 3ff40000 mode 2 pages 16
WARNING: Device "openfirm" is Giant locked and may be deleted before FreeBSD 14.0.
WARNING: Device "kbd" is Giant locked and may be deleted before FreeBSD 14.0.
kbd0 at kbdmux0
ofwbus0: <Open Firmware Device Tree>
simplebus0: <Flattened device tree simple bus> on ofwbus0
clk_fixed0: <Fixed clock> on ofwbus0
rk_grf0: <RockChip General Register Files> mem 0xff100000-0xff100fff on ofwbus0
rk3328_cru0: <Rockchip RK3328 Clock and Reset Unit> mem 0xff440000-0xff440fff on ofwbus0
Cannot set frequency for clk: aclk_bus_pre, error: 34
rk3328_cru0: Failed to set aclk_bus_pre to a frequency of 15000000
Cannot set frequency for clk: aclk_peri_pre, error: 34
rk3328_cru0: Failed to set aclk_peri_pre to a frequency of 15000000
clk_fixed1: <Fixed clock> on ofwbus0
regfix0: <Fixed Regulator> on ofwbus0
regfix1: <Fixed Regulator> on ofwbus0
simple_mfd0: <Simple MFD (Multi-Functions Device)> mem 0xff450000-0xff45ffff on ofwbus0
psci0: <ARM Power State Co-ordination Interface Driver> on ofwbus0
gic0: <ARM Generic Interrupt Controller> mem 0xff811000-0xff811fff,0xff812000-0xff813fff,0xff814000-0xff815fff,0xff816000-0xff817fff irq 49 on ofwbus0
gic0: pn 0x2, arch 0x2, rev 0x1, implementer 0x43b irqs 160
rk_pinctrl0: <RockChip Pinctrl controller> on ofwbus0
gpio0: <RockChip GPIO Bank controller> mem 0xff210000-0xff2100ff irq 53 on rk_pinctrl0
gpiobus0: <OFW GPIO bus> on gpio0
gpio1: <RockChip GPIO Bank controller> mem 0xff220000-0xff2200ff irq 54 on rk_pinctrl0
gpiobus1: <OFW GPIO bus> on gpio1
gpio2: <RockChip GPIO Bank controller> mem 0xff230000-0xff2300ff irq 55 on rk_pinctrl0
gpiobus2: <OFW GPIO bus> on gpio2
gpio3: <RockChip GPIO Bank controller> mem 0xff240000-0xff2400ff irq 56 on rk_pinctrl0
gpiobus3: <OFW GPIO bus> on gpio3
rk_i2c0: <RockChip I2C> mem 0xff160000-0xff160fff irq 16 on ofwbus0
iicbus0: <OFW I2C bus> on rk_i2c0
rk805_pmu0: <RockChip RK805 PMIC> at addr 0x30 irq 57 on iicbus0
gpioregulator0: <GPIO controlled regulator> on ofwbus0
generic_timer0: <ARMv8 Generic Timer> irq 4,5,6,7 on ofwbus0
Timecounter "ARM MPCore Timecounter" frequency 24000000 Hz quality 1000
Event timer "ARM MPCore Eventtimer" frequency 24000000 Hz quality 1000
rk_tsadc0: <RockChip temperature sensors> mem 0xff250000-0xff2500ff irq 22 on ofwbus0
cpulist0: <Open Firmware CPU Group> on ofwbus0
cpu0: <Open Firmware CPU> on cpulist0
cpufreq_dt0: <Generic cpufreq driver> on cpu0
cpu1: <Open Firmware CPU> on cpulist0
cpufreq_dt1: <Generic cpufreq driver> on cpu1
cpu2: <Open Firmware CPU> on cpulist0
cpufreq_dt2: <Generic cpufreq driver> on cpu2
cpu3: <Open Firmware CPU> on cpulist0
cpufreq_dt3: <Generic cpufreq driver> on cpu3
pmu0: <Performance Monitoring Unit> irq 0,1,2,3 on ofwbus0
uart0: <16750 or compatible> mem 0xff130000-0xff1300ff irq 14 on ofwbus0
uart0: console (1500000,n,8,1)
iic0: <I2C generic I/O> on iicbus0
rockchip_dwmmc0: <Synopsys DesignWare Mobile Storage Host Controller (RockChip)> mem 0xff500000-0xff503fff irq 41 on ofwbus0
rockchip_dwmmc0: Hardware version ID is 270a
mmc0: <MMC/SD bus> on rockchip_dwmmc0
dwc0: <Rockchip Gigabit Ethernet Controller> mem 0xff540000-0xff54ffff irq 44 on ofwbus0
miibus0: <MII bus> on dwc0
rgephy0: <RTL8169S/8110S/8211 1000BASE-T media interface> PHY 0 on miibus0
rgephy0:  none, 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT, 1000baseT-master, 1000baseT-FDX, 1000baseT-FDX-master, auto
rgephy1: <RTL8169S/8110S/8211 1000BASE-T media interface> PHY 1 on miibus0
rgephy1:  none, 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT, 1000baseT-master, 1000baseT-FDX, 1000baseT-FDX-master, auto
dwc0: Ethernet address: xx:xx:xx:xx:xx:xx
ehci0: <Generic EHCI Controller> mem 0xff5c0000-0xff5cffff irq 46 on ofwbus0
usbus0: EHCI version 1.0
usbus0 on ehci0
ohci0: <Generic OHCI Controller> mem 0xff5d0000-0xff5dffff irq 47 on ofwbus0
usbus1 on ohci0
dwcotg0: <DWC OTG 2.0 integrated USB controller> mem 0xff580000-0xff5bffff irq 48 on ofwbus0
usbus3 on dwcotg0
gpioc0: <GPIO controller> on gpio0
gpioc1: <GPIO controller> on gpio1
gpioc2: <GPIO controller> on gpio2
gpioc3: <GPIO controller> on gpio3
gpioled0: <GPIO LEDs> on ofwbus0
cryptosoft0: <software crypto>
armv8crypto0: <AES-CBC,AES-XTS,AES-GCM>
Timecounters tick every 1.000 msec
usbus0: 480Mbps High Speed USB v2.0
usbus1: 12Mbps Full Speed USB v1.0
usbus3: 480Mbps High Speed USB v2.0
ugen3.1: <DWCOTG OTG Root HUB> at usbus3
uhub0 on usbus3
uhub0: <DWCOTG OTG Root HUB, class 9/0, rev 2.00/1.00, addr 1> on usbus3
ugen1.1: <Generic OHCI root HUB> at usbus1
uhub1 on usbus1
uhub1: <Generic OHCI root HUB, class 9/0, rev 1.00/1.00, addr 1> on usbus1
ugen0.1: <Generic EHCI root HUB> at usbus0
uhub2 on usbus0
uhub2: <Generic EHCI root HUB, class 9/0, rev 2.00/1.00, addr 1> on usbus0
mmcsd0: 16GB <SDHC SD16G 3.0 SN 7CD5F333 MFG 03/2020 by 39 PH> at mmc0 50.0MHz/4bit/1021-block
Release APs...done
CPU  0: ARM Cortex-A53 r0p4 affinity:  0
                   Cache Type = <64 byte D-cacheline,64 byte I-cacheline,VIPT ICache,64 byte ERG,64 byte CWG>
Trying to mount root from ufs:/dev/ufs/rootfs [rw]...
 Instruction Set Attributes 0 = <CRC32,SHA2,SHA1,AES+PMULL>
 Instruction Set Attributes 1 = <>
         Processor Features 0 = <AdvSIMD,FP,EL3 32,EL2 32,EL1 32,EL0 32>
         Processor Features 1 = <>
      Memory Model Features 0 = <TGran4,TGran64,SNSMem,BigEnd,16bit ASID,1TB PA>
      Memory Model Features 1 = <8bit VMID>
      Memory Model Features 2 = <32bit CCIDX,48bit VA>
             Debug Features 0 = <2 CTX BKPTs,4 Watchpoints,6 Breakpoints,PMUv3,Debugv8>
             Debug Features 1 = <>
         Auxiliary Features 0 = <>
         Auxiliary Features 1 = <>
CPU  1: ARM Cortex-A53 r0p4 affinity:  1
CPU  2: ARM Cortex-A53 r0p4 affinity:  2
CPU  3: ARM Cortex-A53 r0p4 affinity:  3
GEOM: mmcsd0: the secondary GPT header is not in the last LBA.
GEOM: diskid/DISK-7CD5F333: the secondary GPT header is not in the last LBA.
Warning: no time-of-day clock registered, system time will not be set accurately
Dual Console: Serial Primary, Video Secondary
uhub1: 1 port with 1 removable, self powered
uhub0: 1 port with 1 removable, self powered
uhub2: 1 port with 1 removable, self powered
random: randomdev_wait_until_seeded unblock wait
random: unblocking device.
dwwdt0: <Synopsys Designware watchdog timer> mem 0xff1a0000-0xff1a00ff irq 20 on ofwbus0
dwwdt0: cannot find clock
device_attach: dwwdt0 attach returned 6
lo0: link state changed to UP
dwc0: link state changed to DOWN
dwc0: link state changed to UP

LANは2個ついているが、WANの方しか認識していない。

まだ対応してないようなので、いかにあるパッチを当ててみると動くかも。 https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=253374

freebsd@generic:~ % ifconfig
dwc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
    options=8000b<RXCSUM,TXCSUM,VLAN_MTU,LINKSTATE>
    ether xx:xx:xx:xx:xx:xx
    inet 192.168.102.18 netmask 0xffffff00 broadcast 192.168.102.255
    media: Ethernet autoselect (100baseTX <full-duplex>)
    status: active
    nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
    options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
    inet6 ::1 prefixlen 128
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
    inet 127.0.0.1 netmask 0xff000000
    groups: lo
    nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>

R2S用のDTSも最近コミットされているので、最新のソースならちゃんと動きそう。

COVID-19のワクチンの接種を予約するアプリを作る

やること

COVID-19のワクチンの接種を予約するアプリを作る

動機

アプリケーション開発の練習のため。 ワクチンの接種という身近な物をテーマにすることで仕組みを考えやすくする。 また、難易度的にちょうどいいと思った。

今週の成果

Githubにコミットして、Herokuにデプロイできるように設定した。

github.com

MAP-EでL2TP/IPSecが使えないからWireGuardでAWSを経由させる

やること

自宅はIPoEでMAP-Eな環境になっている。そのため、4500/udpとかESPは通過できない。 そのため、AWS(Lightsail)を構築させることで、制限のないグローバルIPアドレスを入手し、そこからIPSecを使用する。 その構築にあたり、FreeBSDでWireGuardなVPNを構築した記録。

仕組み

特定のアドレスへの通信は、WireGuardを使用して、Lightsailへ転送し、Lightsailから接続する。

IPSecのクライアントになるPC→WireGuardの入り口→WireGuardの出口(Lightsail)→IPSecの接続先

Lightsailは3.5ドル/月で、1TBまでデータ転送できるため、用途的には十分。

方法

FreeBSDにWeireGuardをインストールして、特定アドレスはそれを経由するようにしただけ。

AWS

LightsailでFreeBSDインスタンスを作る。もちろん一番安い3.5ドルのプランで。

タイムゾーンUTCだったので、JSTにしておく。

bsdconfig timezone

WireGuard

WireGuardはpkgでインストール。

pkg install wireguard

接続時の認証に使用する鍵をつくる。

# privateはAWSに設定、publicは自宅に設定
wg genkey | tee aws-private.txt | wg pubkey > aws-public.txt

# privateは自宅に設定、publicはAWSに設定
wg genkey | tee local-private.txt | wg pubkey > local-public.txt

生成した鍵と、IPアドレスを書いた設定ファイルを作る。 10.01.0/2はVPNのネットワークアドレス。192.168.1.0/24は自宅のネットワークアドレス。 ポートの5555は、自分で使えるポートにする。MAP-Eは使えるポートに制限がある。

cat << 'EOF' > /usr/local/etc/wireguard/wg0.conf
[Interface]
Address = 10.0.1.1/32
ListenPort = 5555
PrivateKey = WKEaYCv+VOmSY/m/n82+IXNIapij8c8KqMW4e8cPKXE=

[Peer]
PublicKey = VSjhCn9WTEJWjSQW7tWmzKB0G/RE/z5t2AUaa58RrQU=
AllowedIPs = 10.0.1.2/32, 192.168.1.0/24
'EOF'

pf

pfでNATする。

cat << 'EOF' > /etc/pf.conf
ext_if=xn0
wg_if=wg0

home=172.16.0.1
home_net="192.168.1.0/24"

wireguard_port=5555


set block-policy drop
set skip on lo0

nat on $ext_if inet proto udp from $home_net port 500 to any -> $ext_if port 500
nat on $ext_if inet proto udp from $home_net port 4500 to any -> $ext_if port 4500

nat on $ext_if inet from $home_net to any -> $ext_if

block in quick proto udp from ! $home to self port $wireguard_port

pass all
'EOF'

インスタンスは使い捨てなので、rc.confには書かない。(書いてもいいけど)

kldload pf
service pf onestart

パケットを転送する設定も忘れずに。

sysctl net.inet.ip.forwarding=1

起動する。

wg-quick up wg0

自宅側

AWSと同様に設定する。(インストール、ルーティングなどは面倒なので省略。) 172.17.0.1はIPSecの接続先のつもり。

WireGuardの設定はこんな感じで。

cat << 'EOF' > /usr/local/etc/wireguard/wg0.conf
[Interface]
Address=10.0.1.2/32
PrivateKey=+M2zyuI9IAnG6QxVMAg0nEf69rs3FeOTUsmQZVSKgFA=

[Peer]
Endpoint=AWSのアドレス:5555
PublicKey= U/OONLU/6LoDIo5j1hkKX2WH3gdh8KbhxlFRL/E6BUI=
AllowedIPs=10.0.1.1/32, 172.17.0.1
PersistentKeepalive=25
'EOF'

起動する。

wg-quick up wg0

WireGuardの設定ファイルのAllowedIPsに書いてあるアドレス宛の場合は、wg0に流れるようになる。

まとめ

WireGuardは、接続早いし、設定は簡単。(証明書とか作らなくていいし。) AWSも3.5ドルでほぼ固定なので、外出先のWifiを使うときに、AWSまでWireGuardにして、通信の暗号化にもいいかもしれない。(スマートフォン用のアプリもあるし。)

k3s

Raspberry Pikubernetesクラスタを作っている人もいるくらいなので、そろそろkubernetesを初めてみようと思う。 まずは、簡単そうなk3sをやってみる。

準備

Ubuntu Server 18.04 LTSを普通にインストール。

k3sのインストール

ドキュメントに書いてある通りに、以下を実行する。

curl -sfL https://get.k3s.io | sh -

インストールは終わり。

構築する構成

シンプル?に Ingress(http/tcp) -> Service(http/tcp) -> Pod(http/tcp)の構成にしようと思う。

Pod

Podというかdeploymentを作る。そうするとイメージが Podとしてデプロイされる。 とりあえずnginxをデプロイ。

# 作ったら
sudo kubectl create deployment webserver --image nginx

# できたのを確認
sudo kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
webserver-d698d7bd6-rjht6   1/1     Running   0          14m

Service

Podを束ねる?サービスをPodから作る。

# 作ったら
sudo kubectl expose pod webserver-d698d7bd6-rjht6 --port=80 --target-port=80 --name=webserver

# できたのを確認
sudo kubectl get service
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.43.0.1     <none>        443/TCP   9m15s
webserver    ClusterIP   10.43.69.55   <none>        80/TCP    3s

Ingress

k3sの外から入ってくる部分を作る。外部からのアクセスをServiceに渡す感じ。 これはコマンドではできないっぽい。

Ingressのファイルを作る。

cat <<'EOF' > ingress.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: webserver-ingress
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: webserver
          servicePort: 80
EOF
# 定義を読み込ませる
sudo kubectl apply -f ingress.yml

# できたのを確認
sudo kubectl describe ingress webserver-ingress
Name:             webserver-ingress
Namespace:        default
Address:          192.168.1.16
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host  Path  Backends
  ----  ----  --------
  *     
        /   webserver:80 (10.42.0.8:80)

動作確認

curlでアクセスするとNginxの最初から入っているHTMLが返ってくるはず。

curl 192.168.1.16

Xubuntuをインストールした後にSSDを暗号化したくなった

やること

Xubuntuをインストールして使っていたけど、後からディスク(SSD)全体を暗号化したくなったときにやること。 同じSSDを使って暗号化するため、一度データは全部消す。システムを動かしたまま暗号化はできない。

この手順は、実機でやる前にKVM上のXubuntu 19.10でやった。

暗号化後に必要なものを、暗号化前のシステムでインストールしておく

sudo apt install lvm2 cryptsetup-initramfs

バックアップとパーティション作成

これは、USBからXubuntuを起動して行う。

まずは、バックアップ

sudo mkdir /backup
sudo mount -t ext4 /dev/vdb1 /backup
sudo mount -t ext4 -o ro /dev/vda2 /mnt
sudo apt install dump
sudo dump -0 -z -f /backup/root.dump /mnt
sudo umount /mnt
sudo umount /backup

次にパーティションを作成する。

sudo cgdisk /dev/vda

ここまで終わったら、システムを再起動する。 再起動しないで進めたら、cryptsetupの時にパーティションの容量が何故か少なくなった。 cgdiskの終了時にも警告が出るが、多分、カーネルが古いパーティションテーブルをキャッシュしているからだと思う。

暗号化パーティション作成

再起動が終わったら、パーティションを暗号化する。

sudo cryptsetup luksFormat /dev/vda3
sudo cryptsetup open /dev/vda3 vda3_crypt
sudo cryptsetup status vda3_crypt

暗号化したパーティション状にLVMのボリュームを作る。

sudo pvcreate /dev/mapper/vda3_crypt
sudo pvdisplay
sudo vgcreate vgxubuntu /dev/mapper/vda3_crypt
sudo vgdisplay
sudo lvcreate --size 1024m vgxubuntu -n swap
sudo lvcreate -l 100%FREE vgxubuntu -n root
sudo lvdisplay

作ったら、ext4でフォーマットする。

sudo mkfs -t ext4 -L boot /dev/vda2
sudo mkfs -t ext4 -L root /dev/mapper/vgxubuntu-root

swapも。

sudo mkswap /dev/mapper/vgxubuntu-swap

リストア

バックアップを元に戻す。

sudo mount -t ext4 -o noatime /dev/mapper/vgxubuntu-root /mnt
Sudo mkdir /backup
sudo mount -t ext4 -o ro /dev/vdb1 /backup
cd /mnt
sudo mkdir boot
sudo mount -t ext4 -o noatime /dev/vda2 /mnt/boot
sudo apt install dump
sudo restore -v -r -f /backup/root.dump
cd
sudo umount /backup /mnt/boot /mnt

crypttab, fstab, grub

起動できるように設定する。 マウントしてから設定する。

sudo mount -t ext4 -o noatime /dev/mapper/vgxubuntu-root /mnt
sudo mount -t ext4 -o noatime /dev/vda2 /mnt/boot
sudo mount -t vfat -o noatime /dev/vda1 /mnt/boot/efi

マウントしたら、crypttab, fstabを書き換える。 crypttabにはvda3をマウントするように設定しておく、 fstabは/に/dev/mapper/vgxubuntu-rootをマウントするようにする。 そのほか、swapなども忘れずに設定する。

最後に、grubとinitramfs。

sudo mount --bind /dev /mnt/dev
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys
sudo mkdir /mnt/run/udev
sudo mount --bind /run/udev /mnt/run/udev

sudo chroot /mnt grub-install --efi-directory=/boot/efi --boot-directory=/boot --target=x86_64-efi --removable --recheck
sudo chroot /mnt update-initramfs -k all -u
sudo chroot /mnt update-grub 

これで終わり。

sudo umount /mnt/dev /mnt/proc /mnt/sys /mnt/run/udev /mnt/boot/efi /mnt/boot /mnt

再起動して、パスワードを入力すると、起動できる。

Spring BootでJSR-352 Batch Applications for the Java Platform

やること

Spring Batchのリファレンスに記載の方法で起動すると、@Serviceなどのコンポーネントを参照してくれない。

JobOperator jobOperator = BatchRuntime.getJobOperator();
long jobExecutionId = jobOperator.start("myJob", new Properties());

batch.xmlに以下のように記載しておくことで、DIできるが、Spring Bootらしくない。

<bean id="myService" class="com.example.batch.MyService" />

なんとかして、Spring Bootらしくバッチを書く。

調査

BatchRuntime.getJobOperatorすると、JsrJobOperatorのデフォルトコンストラクターが実行される。 このコンストラクターの長で、BaseContextHolderが呼ばれ、GenericXmlApplicationContextがjsrBaseContext.xmlを読み込んでいた。 JobOperator#startで、META-INF/batch.xml、META-INF/batch-jobs/*.xmlを読み込んでいる。 このため、XMLに定義したBeanは使える。

解決案

JsrJobOperatorは以下のようなコンストラクターも持っているため、そちらを使うようにする。

public JsrJobOperator(JobExplorer jobExplorer, JobRepository jobRepository, JobParametersConverter jobParametersConverter, PlatformTransactionManager transactionManager)

Spring Boot + JSR-352

FreeBSDでRubyをビルドする

やること

FreeBSDRubyを自分でビルドしてインストールする。

Jail作成

インストール先のJailを作成する。

cd
mkdir /var/jail/rubybuild
bsdinstall jail /var/jail/rubybuild
cat << 'EOF' > jail-rubybuild.conf
rubybuild {
  path = "/var/jail/rubybuild";
  host.hostname = "rubybuild";
  # とりあえずIPアドレスはホストと同じものにしておく。
  ip4.addr = "172.26.11.142";
  persist;
}
EOF
jail -c -f jail-rubybuild.conf

パッケージのインストール

#/dev/nullなどをつかうコマンドのために/devを用意する。
mount -t devfs -o ruleset=2 devfs /var/jail/rubybuild/dev
pkg -j rubybuild update
pkg -j rubybuild install libedit libyaml bison libffi

Rubyソースコードダウンロード&コンパイル

configureで--with-*-dirで/usr/localを指定するのがポイント。

jexec rubybuild /bin/tcsh
cd ~/
fetch --no-verify-peer https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.4.tar.gz
sha256 ruby-2.6.4.tar.gz
tar xf ruby-2.6.4.tar.gz && cd ruby-2.6.4
./configure --prefix=/opt/ruby-2.6.4 --enable-libedit --with-libedit-dir=/usr/local --with-libyaml-dir=/usr/local --with-libffi-dir=/usr/local --without-gdbm --disable-install-doc
make
make install

動作確認

# /opt/ruby-2.6.4/bin/ruby --version
ruby 2.6.4p104 (2019-08-28 revision 67798) [x86_64-freebsd12.0]