それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

choco でインストールしたものを最新版にアップグレード

アップグレードするには

インストール済みのアプリケーションをUPGRADEをしたいときに、まとめてすべてアップグレードしたいなとおもったら。

choco upgrade all

何も考えず、パッケージ名にAllを指定すればよかった。

https://docs.chocolatey.org/en-us/choco/commands/upgrade

細かい定義は次のようになっている。

choco upgrade <pkg|all> [<pkg2> <pkgN>] [<options/switches>]

all をパッケージ名と同等に扱うのはちょっと盲点でした。オプションじゃないんですね。。。。

all で分かった注意点。

完全に自動化として自動実行するのは、ちょっと厳しい時がある。インストーラーが起動しクリック待ちで停止するアプリケーションがまれにあるので、寝ている間に実行などは控えたほうが良さそうでした。

python の netaddr で ip6( ipv6) アドレスを扱う

前の、ipv6 版です、

ip アドレスを計算を簡便にするライブラリがあったので使ってみることにした。

ライブラリを読み込む

インストールする。

$ pip install netaddr

使う準備をする。

from netaddr import *

v4/ v6 ともに同じライブラリで扱うことが出来ます。

ip6アドレス(ネットマスク含む)を扱う。

サブネットマスク表記を含む場合は IPNetwork を使う。

>>> ip = IPNetwork('fdc2:be69:2aeb:bd6c::1/64')
>>> ip.ip
IPAddress('fdc2:be69:2aeb:bd6c::1')
>>> ip.network
IPAddress('fdc2:be69:2aeb:bd6c::')
>>> ip.netmask
IPAddress('ffff:ffff:ffff:ffff::')

IPアドレスを扱う。

IPアドレスだけを扱うときは、IPAddress を使う。

>>> ip = IPAddress('fdc2:be69:2aeb:bd6c::1')
>>> ip
IPAddress('fdc2:be69:2aeb:bd6c::1')

主に、IPNetworkの戻り値として得られる。

IPアドレスのネットワーク部を扱う。

>>> ip = IPNetwork('fd8f:4f9a:417f:b584::/64')
>>> ip.network
IPAddress('fd8f:4f9a:417f:b584::')

または、ちゃんとネットマスクを適用する。AND演算でネットマスクを掛けてやる。

>>> ip.ip & ip.network
IPAddress('fd8f:4f9a:417f:b584::')

ホスト部を取り出す。

>>> ip
IPNetwork('fd8f:4f9a:417f:b584::1/64')
>>> ip.hostmask
IPAddress('::ffff:ffff:ffff:ffff')
>>> ip.hostmask & ip.ip
IPAddress('::1')

ホスト部とネットワーク部をあわせてIPアドレスを作る。

>>> ip = IPNetwork('fd8f:4f9a:417f:b584::1/64')
>>> ip.hostmask & ip.ip
IPAddress('::1')
>>> ip.netmask & ip.ip
IPAddress('fd8f:4f9a:417f:b584::')
>>> ( ip.hostmask & ip.ip ) + ( ip.netmask & ip.ip )
IPAddress('fd8f:4f9a:417f:b584::1')
>>>

ホスト部を変更

ホスト部 と ネットワーク部を足し合わせると完成。

>>> ip = IPNetwork('fd8f:4f9a:417f:b584::1/64')
>>> ip.ip & ip.netmask
IPAddress('fd8f:4f9a:417f:b584::')
>>> ip.ip & ip.netmask | IPAddress('::2')
IPAddress('fd8f:4f9a:417f:b584::2')
>>>

ネットワーク部を変更する。

>>> ip = IPNetwork('fd8f:4f9a:417f:b584::1/64')
>>> ip2 = IPNetwork('fdab:ab1d:1ad8:75d8::/64')
>>> ip.network
IPAddress('fd8f:4f9a:417f:b584::')
>>>
>>> ip.hostmask & ip.ip
IPAddress('::1')
>>> ip.hostmask & ip.ip | ip2.network
IPAddress('fdab:ab1d:1ad8:75d8::1')
>>>

インターフェースIDからホスト部を生成

v6アドレスのホスト部は、インターフェースIDから生成される。 インターフェースIDは、MACアドレスから生成される。

これを覚えておけば、プレフィックスを変更するだけでIPv6アドレスが手軽に得られるようになるはずだ。

インターフェースID生成しホスト部と、ULAやリンクローカル、グローバルと組み合わせるだけでよいのだから。

EUI-64でホスト・アドレスを生成する。

MACアドレスからインターフェースIDを生成し、インターフェースIDとネットワーク部を併せULAを作る。

MACアドレスはEUI48であり、EUI-48→ EUI-64 に変換してインターフェースIDに使う。 インターフェースIDは、EUI-64へ変換したあと、上位7 ビット目をフラグを反転してあげる。

ビットの反転はXORを使う。XORは0を入れるとそのまま出力され、1を入れると反転する。 なので、該当ビットだけを反転させた値をint として使う。

EUI-48 ( MACアドレス)からEUI-64へ変換。

>>> mac = EUI('94:c6:91:3b:09:7c')
>>> mac.eui64()
EUI('94-C6-91-FF-FE-3B-09-7C')
>>> int(mac.eui64())
10720416491670014332
>>> int(mac.eui64()) ^ 144115188075855872
10864531679745870204
>>> EUI(int(mac.eui64()) ^ 144115188075855872)
EUI('96-C6-91-FF-FE-3B-09-7C')

EUI-64に変換が終われば、7ビット目を反転させる。

出来上がったEUIを v6 のネットワーク部と合わせれば 「v6アドレス」をインターフェースIDから生成が完成である。

>>> ip = IPNetwork('fe80::')
>>> ip.network | EUI('96-C6-91-FF-FE-3B-09-7C')
IPAddress('fe80::96c6:91ff:fe3b:97c')

ここで、ビット反転に使ったINTは次のとおりである。

>>> format(144115188075855872, '064b')
'0000001000000000000000000000000000000000000000000000000000000000'

上記の例でで生成したのはリンクローカルアドレスである。 Ubuntuが自動生成したリンクローカルアドレスと比較しよう。

3: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 94:c6:91:3b:09:7c brd ff:ff:ff:ff:ff:ff
    inet6 fe80::96c6:91ff:fe3b:97c/64 scope link

やったね。一致します。

Uubntu genrated                fe80::96c6:91ff:fe3b:97c/64
python  genrated IPAddress('fe80::96c6:91ff:fe3b:97c')

ULAを生成する

インターフェースIDが生成出来たので、ユニキャスト・リンクローカルアドレスを作りたい。

ランダムなプレフィックスを作る

$ openssl rand -hex 7 | sed -r 's|^(.{2})(.{4})(.{4})(.{4})|fd\1:\2:\3:\4::/64|'
fd8b:eb64:cbf6:b721::/64

このランダムなプレフィックスと、MACアドレスを使って、ネットワーク部と合体させる。

>>> ip  = IPNetwork('fd8b:eb64:cbf6:b721::/64')
>>> ip.network | EUI(int(EUI('94:c6:91:3b:09:7c').eui64()) ^ 144115188075855872)
IPAddress('fd8b:eb64:cbf6:b721:96c6:91ff:fe3b:97c')
>>>IPNetwork(str(ip.network | EUI(int(EUI('94:c6:91:3b:09:7c').eui64()) ^ 144115188075855872))+'/64')
IPNetwork('fd8b:eb64:cbf6:b721:96c6:91ff:fe3b:97c/64')

やった、これでインターフェースIDを用いたULAが生成できるぞ。

グローバルなプレフィックスが来ても大丈夫。自動生成に頼ってるのでいいんだけど、RA・DHCPv6ーPDとか疎通関連 で考えることが多く、設定しても疎通確認が自動生成に頼るのでテストがめんどくさい。

ULAをインターフェースIDでMACアドレスから作成する、コピペ用

コピペ用にまとめておく。

from netaddr import *
ip =  IPNetwork('fd34:5f2d:d3cb:8161::/64')
mac = EUI('00:16:3e:fc:57:d5')
a = IPNetwork(str(ip.network | EUI(int(mac.eui64()) ^ 144115188075855872))+'/64')
print(a)

IPアドレスを進める。

>>> ip.ip
IPAddress('fd8f:4f9a:417f:b584::1')
>>> ip.ip + 1
IPAddress('fd8f:4f9a:417f:b584::2')
>>>

/64 アドレスを/66へさらに分割する。

実際に使うことが出来ないが、計算だけはできる。

>>> for i in ip.subnet(66):
...   print(i)
...
fd8f:4f9a:417f:b584::/66
fd8f:4f9a:417f:b584:4000::/66
fd8f:4f9a:417f:b584:8000::/66
fd8f:4f9a:417f:b584:c000::/66

List comprehension でも表現できる。

演算子で計算がカッコいい

IPv6 でもv4 と同様に演算子(operand) を使ってIPアドレス計算するのがよくわかった。

おまけ

MACアドレス取得

ip link show eth0 | grep -Po '(?<=link/ether ).+'

v6 プレフィックス作成

openssl rand -hex 7 | sed -r 's|^(.{2})(.{4})(.{4})(.{4})|fd\1:\2:\3:\4::/64|'

MACアドレスからv6アドレスを生成

from netaddr import *
ip =  
mac = EUI('00:16:3e:fc:57:d5')
a = IPNetwork(str(IPNetwork('fd34:5f2d:d3cb:8161::/64').network | EUI(int(mac.eui64()) ^ 144115188075855872))+'/64' )
print(a)

これらを併せたワンライナー

python3 -c   "from netaddr import *;\
print(IPNetwork(str(IPNetwork( \
'$(openssl rand -hex 7 | sed -r 's|^(.{2})(.{4})(.{4})(.{4})|fd\1:\2:\3:\4::/64|')').network \
 | EUI(int(EUI('$(ip link show eth0 | grep -Po '(?<=link/ether ).+')').eui64()) \
 ^ 144115188075855872))+'/64' ))"

コマンドとして

ipcalc コマンドとして、自動計算する MACアドレスと、IPv6アドレスを与えて、EUIからユニークなv6アドレスを計算するコマンドをこれからサクッと作れるわけです。

#!/usr/bin/env python3


from netaddr import *
import sys

ip = None

if len(sys.argv)>2 :
  ip = IPNetwork(sys.argv[2])
else:
  ip = IPNetwork('fe80::/64')

if len(sys.argv)>1 :
  mac = EUI(sys.argv[1])
else:
  raise Exception(f'{sys.argv[0]} MAC_ADDR')



a = IPNetwork(str(ip.network | EUI(int(mac.eui64()) ^ 144115188075855872))+'/64' )
print(a)

python の netaddr で ip( ipv4) アドレスを扱う

ip アドレスを計算を簡便にするライブラリがあったので使ってみることにした。

ライブラリを読み込む

インストールする。

$ pip install netaddr

使う準備をする。

from netaddr import *

ip アドレス(ネットマスク含む)を扱う。

サブネットマスク表記を含む場合は IPNetwork を使う。

>>> ip= IPNetwork('10.2.0.1/8')
>>> ip.network
IPAddress('10.0.0.0')
>>> ip.netmask
IPAddress('255.0.0.0')
>>> ip.ip
IPAddress('10.2.0.1')>>>

IPアドレスを扱う。

IPアドレスだけを扱うときは、IPAddress を使う。

>>> ip = IPAddress('192.168.1.1')
>>> ip
IPAddress('192.168.1.1')

主に、IPNetworkの戻り値として得られる。

IPアドレスのネットワーク部を扱う。

>>> ip = IPNetwork('192.168.1.1/24')
>>> ip.network
IPAddress('192.168.1.0')

または、ちゃんとネットマスクを適用する。AND演算でネットマスクを掛けてやる。

>>> ip.ip & ip.netmask
IPAddress('192.168.1.0')

ホスト部を取り出す。

>>> ip.ip
IPAddress('192.168.1.1')
>>> ip.hostmask
IPAddress('0.0.0.255')
>>> ip.hostmask  & ip.ip
IPAddress('0.0.0.1')
>>>

ホスト部とネットワーク部をあわせてIPアドレスを作る。

>>> ip = IPNetwork('192.168.1.1/24')
>>> ip.ip
IPAddress('192.168.1.1')>>> ( ip.hostmask  & ip.ip )
IPAddress('0.0.0.1')
>>> ( ip.netmask & ip.ip )
IPAddress('192.168.1.0')
>>> ( ip.hostmask  & ip.ip ) + ( ip.netmask & ip.ip )
IPAddress('192.168.1.1')
>>>

ホスト部を変更

>>> ip = IPNetwork('192.168.100.1/24')
>>> ip
IPNetwork('192.168.100.1/24')
>>>
>>> ip.ip & ip.netmask
IPAddress('192.168.100.0')
>>> ip.ip & ip.netmask | IPAddress('0.0.0.24')
IPAddress('192.168.100.24')
>>>

IPアドレスを進める。

>>> ip.ip
IPAddress('192.168.1.1')
>>> ip.ip +  1
IPAddress('192.168.1.2')

/24 アドレスを/28へさらに分割する。

>>> for i in ip.subnet(28):
...     print(i)
...
192.168.1.0/28
192.168.1.16/28
192.168.1.32/28
192.168.1.224/28
192.168.1.240/28

List comprehension でも表現できる。

[ x for x in ip.subnet(30)]

演算子で計算がカッコいい

演算子(operand) を使ってIPアドレス計算するのが、良かった。

2進数に落としてビットフラグ計算なんてやってられないけど、原理原則としてビットマスク計算がIPアドレスなので、計算はそのままなのがいい。

ipv6については次回。

ipv4 でnetaddr の使い方が把握できたので、それをv6に置き換えて、インターフェースIDを扱うことにする。

https://takuya-1st.hatenablog.jp/entry/2021/01/28/201047

参考資料

openssl と sed でipv6 のULAプレフィックスを作る(IPv6アドレスのランダム生成)

ULAのPrefixを生成するなら

openssl rand -hex 5 | sed -r 's|^(.{2})(.{4})(.{4})|fd\1:\2:\3::/48|'

ローカルアドレスプレフィックスの場合は、

prefix に16のネットワーク・アドレスを付ける。まとめてランダム生成すると。

openssl rand -hex 7 | sed -r 's|^(.{2})(.{4})(.{4})(.{4})|fd\1:\2:\3:\4::/64|'

実行例

root@router01:~# openssl rand -hex 5 | sed -r 's|^(.{2})(.{4})(.{4})|fd\1:\2:\3::/48|'
fd8b:9230:0268::/48
root@router01:~# openssl rand -hex 7 | sed -r 's|^(.{2})(.{4})(.{4})(.{4})|fd\1:\2:\3:\4::/64|'
fd71:c054:8514:c035::/64

あとは、これに ::1 とか書いておけば、実験用なサンプルのv6アドレスをランダムに生成することができる。

たとえば、::1と書いておく。

root@router01:~# openssl rand -hex 7 | sed -r 's|^(.{2})(.{4})(.{4})(.{4})|fd\1:\2:\3:\4::1/64|'
fd8a:c6e2:e280:275d::1/64

フルランダムで、128ビットのすべてを作ってもいいけど、実験用にv6アドレスを作る分には、MACアドレスから生成したりインタフェース名も冗長だし可視性も低下するので、ランダムで/64くらいで、適当な実験をするには十分なのです。

アドレスを追加する例

ユニークローカルユニキャストアドレスを明示する

ADDR=$(openssl rand -hex 7 | sed -r 's|^(.{2})(.{4})(.{4})(.{4})|fd\1:\2:\3:\4::1/64|')
ip addr add $ADDR dev eth1
ip -6 addr show eth1

ユニークローカルユニキャストアドレス

fd00 ってなに?ユニークローカルユニキャストアドレスってfc00 じゃないの?という疑問も出てくると思うが。

fc00::/7 は 先頭7ビットが1111,110である

F C 0 0
1111 1100 0000 0000

先頭7ビット(1111,110 ) が固定で残りの全ては0/1のすべてを含む

1111,1100,000,....0 から 1111,1101,1111,111...1である。

すなわち FC00:00... から FDFF までである。

2023-04-21

実行例を追記

FC00 と fd12 などのプレフィックスについて追記。

ipv6 のリンクローカルアドレスを使う

ipv6 で通信したい

ipv6 を有効にすると、いっぱいアドレスが割り振られて気持ち悪い。

たくさん割り振られるアドレスのなかでも、fe80 から始まるv6アドレスを リンクローカル・アドレスという。英語では link-local と表記されます。

v6リンクローカルアドレスとは。

v6のリンクローカルアドレスは、IPv4 169.254.*.* と同様のアドレスです。

ホスト間で通信を1対1で行う事ができます。 同一リンク内、つまりスイッチングハブを通して通信できる範囲(これをリンクという)で有効です。

ハブで接続されたホスト間で通信が可能になるのが、リンクローカルの役割です。

言い換えれば、リンクローカルアドレスは、経路を持ちえません。 経路表を使った伝送はできません。

v6 リンクローカルアドレス間で通信を行う。

ホストAとホストBのリンクローカルアドレスを確認します。

リンクローカルアドレスとは fe80::/ なアドレスです。

ホストAとホストBはスイッチング・ハブで接続されています。

ホストA

ip -6 addr show br0
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet6 fe80::f86c:d5ff:fe1e:e490/64 scope link
       valid_lft forever preferred_lft forever

ホストB

ip -6 addr show br-lan0
3: br-lan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet6 fe80::e080:bcff:fe7a:ddac/64 scope link
       valid_lft forever preferred_lft forever

ホストA/ホストBのv6アドレスの注目ポイント

ここでの注目ポイントは、NICのデバイス名と、リンクローカルのv6アドレスです。

ホストのNICバイス名とアドレスをまとめるたものが、次表になります。

インタフェース リンクローカル・アドレス
ホストA br0 fe80::f86c:d5ff:fe1e:e490
ホストB br-lan0 fe80::e080:bcff:fe7a:ddac

PINGする。ホストAからホストBへ

リンクローカルは経路がないため、どのインタフェースから送信するか明示する必要がある。

ping - I br0 fe80::e080:bcff:fe7a:ddac 

インタフェースをV6アドレスに含める。

ping コマンドはインタフェース指定に対応しているから良いが、非対応のコマンドだと困ることになる。 そのため、ipv6 のリンクローカルでは、デバイスを明示する仕様が盛り込まれている。これを利用すると、ipv6 のアドレスに送信元インタフェースを含めることができる。

リンクローカルのアドレスに、 fe80::1%eth0 のように、デバイス名をつけて送信元となるデバイス名を明示する。指定したデバイス名が出口となりパケットが送出される。

ping  fe80::e080:bcff:fe7a:ddac%br0

これでリンクローカルを使った通信ができる。

まとめ

  • IPv6にはリンクローカルがある。
  • リンクローカルは fe80 から始まる。
  • リンクローカルは経路を持たない
  • 通信するインタフェースを fe80::1%eth0 のように指定する。

php, mysqlで wordpress のテーブルへ pdo したときに文字化けする。

機種依存文字が化けます。

めっちゃ化けます。とくに、外字的な、ハシゴダカのような文字列を扱えません。PDOまじアレ。

PDOのマニュアルとか検索結果を見ても、ほとんど情報がないんですよね。困りました。

Windowsだと外字に登録するような文字列であっても、UTF-8では扱えるのですが、一部の文字では正しく変換されずにクエスチョンマークになって情報が落ちてしまう。

文字化けといえば、文字化けなのですが、豆腐に近い状態の文字化けなのです。

文字コードを次のようにします。

<?php
$pdo = new \PDO( "mysql:host=${host};dbname=${name};charset=utf8mb4", $user, $pass);

または

<?php

$pdo = new \PDO( "mysql:host=${host};dbname=${name}", $user, $pass, [\PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"] );

wordpressMySQLの場合、文字コードがutf8mb4になっています。

そのため文字コードutf8mb4 で指定しなくては、ある種の文字が化けます。

wordpress で 直接SQLを発行する場合

<?php

function getPDO (): \PDO {
  [$host, $name, $user, $pass] = [DB_HOST, DB_NAME, DB_USER, DB_PASSWORD];
  $pdo = new \PDO( "mysql:host=${host};dbname=${name};charset=utf8mb4", $user, $pass,
     [\PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"] );
  //
  $pdo->setAttribute( \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION );
  //
  return $pdo;
}
function getMySQLi(){
  $mcli = new \mysqli(DB_HOST,DB_USER, DB_PASSWORD, DB_NAME);
  $mcli->set_charset('utf8mb4');
  return $mcli;
}

wsl環境のターミナルで pbcopy/pbpaste でクリップボードにコマンドの結果を入れる。

pbcopy/pbpaste を使いたい

macOSならターミナルとCocoaクリップボードをpbcopy でやり取りできるのですが、WindowsのWSLDebian/Ubuntuでも同じようにコピー・ペーストのクリップボードをターミナルから使いたかった。

調べたら見つかったのでメモ

使い方

openssl -rand -base64 123 | pbcopy
pbpast | cat - 

コマンド pbcopy を作ればいい。

Linuxのときもそうだったけど、ないならなんとかAliasやシェルを組み合わせて実現したらいい。

調べたら、もうすでにあった。

# ~/.bin/pbcopy

#!/bin/bash
# pbcopy for wsl


wsl=/mnt/c/Windows/System32/wsl.exe
clip=$( $wsl wslpath C:/Windows/System32/clip.exe)
ps=$( $wsl wslpath C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe )

##
tee <&0 | $clip
exit 0

# ~/.bin/pbpaste

#!/bin/bash
# pbcopy for wsl


wsl=/mnt/c/Windows/System32/wsl.exe
clip=$( $wsl wslpath C:/Windows/System32/clip.exe)
ps=$( $wsl wslpath C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe )

##
$ps Get-Clipboard | sed 's/\r$//' | sed -z '$ s/\n$//'
exit 0

# PATH に追加。

つくった、コマンドをいつでも使えるようにPATHに追加する。

export PATH=$HOME/.bin:$PATH >> ~/.bashrc
source ~/.bashrc

使っている wsl コマンドについて。

Windows の cmd.exe / ps から wsl を起動するコマンド wsl は、オプションで wslpath を指定すると、windowsのパスを wsl のパスに変換できる。

takuya@DESKTOP-2AO3 C:\Users\takuya > wsl wslpath  C:/Users/takuya/Desktop/
/mnt/c/Users/takuya/Desktop/

つかっている clip コマンドについて

CLIPは「クリップボードへコマンド結果を流し込む」事ができる。昔からあるコマンドです。ただしペーストはできません。

C:\Users\takuya>clip /?

CLIP

Description:
    Redirects output of command line tools to the Windows clipboard.
    This text output can then be pasted into other programs.

Parameter List:
    /?                  Displays this help message.

Examples:
    DIR | CLIP          Places a copy of the current directory
                        listing into the Windows clipboard.

    CLIP < README.TXT   Places a copy of the text from readme.txt
                        on to the Windows clipboard.

ペースト(貼り付け)の実現

ペーストについては、PowerShell(PS)を利用する。

ps Get-Clipboard

これを、WSLのPATH内部からWindowsのコマンドを実行することで実現する。

私の実行環境は

実行環境は、WSL v1 です。WSL2 は暗号化ドライブを一旦解除して、インストールしなおしになるので面倒なので WSL2にバージョンアップしていません・・・

参考資料

https://www.techtronic.us/pbcopy-pbpaste-for-wsl/

VSCode で PlantUML をプレビューする

準備

vscode のインストール

Windows の場合

choco install vscode 

Macの場合

brew install --cask visual-studio-code

プラグインのインストール

f:id:takuya_1st:20210117030149p:plain

PlantUML のインストール

choco install plantuml

インストールするとOpenJDKも一緒にインストールされる。

## java と plantuml.jar のパスを確認。

インストールされた場所の確認する。

choco でインストールすると普段と違う場所になったりするので、 実際の場所 を cmd.exeで確認。

# javaの場所

C:\Users\takuya>where java
C:\Program Files\AdoptOpenJDK\jre-15.0.1.9-hotspot\bin\java.exe

# plantuml の場所

plantuml.jar がほしいのだけれど、 plantuml.jar を探すのは手間なので、先に plantuml.exe を探す。

C:\Users\takuya>where plantuml

C:\ProgramData\chocolatey\bin\plantuml.exe

これで、 plantuml がインストールされた場所がわかった。

choco でインストールすると、choco のは以下に作られるのが面白いですね。

java の場所

where java

確認したら次のようになっていました。

C:\Users\takuya>where java
C:\Program Files\AdoptOpenJDK\jre-16.0.1.9-hotspot\bin\java.exe
C:\Program Files\AdoptOpenJDK\jre-15.0.2.7-hotspot\bin\java.exe

java.exe の場所はアップデートで頻繁に変わるので困ります。 バージョン番号なしでアクセスできるようにしてほしい・・・

エクスプローラーで開いて確認

plantuml がインストールされた場所がわかったので、このフォルダを開いて plantuml.jar を探す。

インストールした箇所をエクスプローラーで確認します。見つけました。

f:id:takuya_1st:20210117030153p:plain

plantuml.jarjava.exeのパスを設定へ

先程探した、これらのPATHを、PlantUMLのプラグイン設定に追加。

f:id:takuya_1st:20210117030146p:plain

拡張子 PU のファイルを作る

@startuml test

class PlantUml

@enduml

このファイルをVS Codeで確認

f:id:takuya_1st:20210117030156p:plain

ALT-D を押してプレビュー

f:id:takuya_1st:20210117030159p:plain

もしプレビューがどうしても使えないとき

そして、どうしてもUMLの作成を急ぐときは、オンライン変換を使う。 http://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000

マニュアルについて

日本語マニュアルもあるので大丈夫だよ。 https://plantuml.com/ja/download

2021-07-09

PlantUMLでマッチなかったので、記述を見直し

lsof でIPを指定する /v4 or v6 / ポート使ってるプロセスを見る

lsof でIPを指定する

lsof で探すときに、指定したIPでリッスンしているものを見たいときにどうするのか、複数のIPがあると明示的に指定したいですね。

ポートを使ってるプロセスを見る

たとえば、22番を使ってるプロセスを探す。

lsof -i :22 -n

実例

$lsof -i :22 -n
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
dropbear  3272 root    3u  IPv4    618      0t0  TCP 192.168.1.1:ssh (LISTEN)
dropbear 18793 root    0u  IPv4 853114      0t0  TCP 192.168.1.1:ssh->172.16.4.3:54401 (ESTABLISHED)

ip を@マークで指定する。

lsof では @マークで ip アドレスを指定することができる。

アドレス指定

lsof -i @192.168.1.201

アドレス・ポート指定

lsof -i @192.168.1.201:10000

IPv6の場合

いい感じに囲む必要がある。

ls of -i @[2001::::97c]:22

また、v6のIPすべてでリッスンしている場合は、次のようにv4/v6ともに具体的なIPなく表示される。

$sudo lsof -i :22
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd     946   root    5u  IPv4  23026      0t0  TCP *:ssh (LISTEN)
sshd     946   root    6u  IPv6  23028      0t0  TCP *:ssh (LISTEN)

実際にやってみた例。

アドレス・ポート指定でどのアプリがリッスンしているか見ることができた。

root@jitsi:~# lsof -i @10.185.93.136:3479
COMMAND  PID      USER  FD  TYPE  DEVICE SIZE/OFF NODE NAME
turnserve 569 turnserver  36u  IPv4 17368603      0t0  UDP jitsi.lxd:3479
turnserve 569 turnserver  37u  IPv4 17368604      0t0  UDP jitsi.lxd:3479
turnserve 569 turnserver  38u  IPv4 17368605      0t0  UDP jitsi.lxd:3479
turnserve 569 turnserver  39u  IPv4 17368606      0t0  UDP jitsi.lxd:3479
root@jitsi:~# lsof -i @10.185.93.136:10000
COMMAND  PID USER  FD  TYPE  DEVICE SIZE/OFF NODE NAME
java    1341  jvb  155u  IPv6 17592832      0t0  UDP jitsi.lxd:10000

ss コマンドとの違い

lsof だと「プロセス」を探すので、wireguardのようなカネールモジュールのリッスンは見えない。

該当プロセスが見つからないとき、正確にポートをリッスンしているかどうかをみたいなら ss -nlu(udp) ss -nlt (tcp)を使ってもいいと思う。

2023-04-19 追記

IPv6の場合について追記。

2023-05-16 追記

ポートのみの場合と、ssとの違いについて言及

docker exec で root になる。/ docker exec を指定したユーザーで実行する

docker exec しても root になるとは限らない。

dockerのインスタンスによっては、Dockerfile の記述によっては、docker exec がユーザー root で実行できないことがある。

docker exec を強制的に root にする

uid をオプションに付けたら、強制的にrootユーザ で実行することができる。 -u UIDでUIDを指定することができる。

docker exec -u 0 -it XXXXXX bash 

docker exec で user を指定する。

指定したユーザで起動するには。まずUIDを調べる。UIDがわからないと指定できないし、Dockerのコンテナ内部でどのユーザーがどの番号で存在してるかわからないですね。

たとえば、psqlpostgresql で起動するとする。

# docker exec -it 6a7e5eca6505 getent passwd | grep post
postgres:x:999:999::/var/lib/postgresql:/bin/bash

そのUIDで起動する。

docker exec -it -u 999 6a7e5eca6505 psql

こうすれば、postgresユーザーをdocker exec で直接指定できる。 これで別のユーザーに成り代わってシェルを使えたりする。

apt が使えない docker インスタンスとかで使える

通常通り exec しても apt が使えないときとか。sudo が使えないときとか。

ps がないのでインストールしたいときとかに使える。

docker のイメージファイルはあれこれ省略されているので、ちょっとしたトラブルがあると困るのですが、権限がない程度で Dockerfile から書いて build するのはめんどくさすぎるので。ユーザーを指定されているDockerイメージを扱うためには、ちょっとしたコツがいる。

参考資料

https://stackoverflow.com/questions/59376888/become-root-in-a-docker-container

2021-05-27

表記ゆれ更新

ssh/config で ホストを踏み台にして、直接 lxc のコンテナにログインする。

LXCにssh コマンドでログインしたい。

lxcのコンテナに にいちいちSSHインストールしたりパスワード決めたり、公開鍵を設定するのがめんどくさい。

通常であれば次のようにログインする。

いったん、SSHでログインして、その後にlxc コマンドで shell を起動する。

takuya@local $ ssh lxc-host
takuya@lxc-host$
takuya@lxc-host$ lxc shell lxc-container-01

頻繁に実行しているとめんどくさいです。そこで ssh_config でconfig ファイルを設定してなんとかできないか考えました。

SSH経由でログインを自動化したい。

~/.ssh/configのファイルに記載します。

  Host lxc-container01
    Hostname lxc-host
    RequestTTY force
    RemoteCommand lxc exec --force-interactive  lxc-container-01 bash

ssh でlxc-hostにログインする設定をかき、ログイン後に実行されるRemoteCommandで lxc shell コマンドを実行するわけです。

SSH踏み台経由と組み合わせる。

踏み台を使う場合は次のように書きます。

  Host lxc-host
    Hostname lxc-host
    ProxyCommand ssh -W %h:%p ssh-GW

踏み台を使う場合は、ProxyCommandを書きますよね。 ProxyCommand はローカルで実行され、接続に使用されます。

これを、RemoteCommandと組み合わせてれば、良い訳です。これでGWを経由しつつ、LXCホストを踏み台にし、LXCコンテナのbashに1発でアクセスできるわけです。

組み合わせると次のようになります。

  Host lxc-container01
    Hostname lxc-host
    RequestTTY force
    ProxyCommand ssh -W %h:%p ssh-GW
    RemoteCommand lxc exec --force-interactive  lxc-container-01 bash

この設定では RequestTTY forcelxc exec --force-interactive を使って tty をAllocateしています。こうしないと制御文字(EOF/CTRL-Dなど)がうまく渡せません。

まとめ

  • RemoteCommand でSSHログイン後にリモートで実行するコマンドを指定
  • lxc exec --force-interactive でTTYを確保
  • RequestTTY force でローカルからリモートまでTTYでつなぐ

その他の応用方法

肝になる設定はRemoteCommandなので、踏み台に設置する authorized_keys に書くことで、鍵で識別して接続を振り分けてしまうことができる。

今回は、lxc だが。 docker exec -it でも同じようにすることで、ちょくせつDockerのインスタンスに入れる。

sshの公開鍵authorized_keys ファイルの制限機能について調べてみたら楽しかった. - それマグで!

Snap でインストールしたApp/コマンドの man を見る。

snap でインストールしたコマンドの man が見つからない。

たとえばLDX をインストールしている場合でも、man はない。

takuya@m75q-1:~$ man -k lxc
lxc: nothing appropriate.

LXDのman を見たいんだ。

MANPATH をなんとかすれば見れそうだが

通常であれば、MANPATH をなんとかすれば見れます。

export MANPATH=":/snap/$APP/current/share/man"

LXC/LXDの場合は。manpageそのものがない。

でもLXDの場合は、manpage が存在しないのでインストールされていない。

そもそもmanがないので、MANPATHで解決しない。

調べた結果 manはなかった。

manがないんですよ。man はオワコンなんです?

--help を使えって言われた。

takuya@:~$ lxc shell --help
Description:
  Execute commands in instances

  The command is executed directly using exec, so there is no shell and
  shell patterns (variables, file redirects, ...) won't be understood.
  If you need a shell environment you need to execute the shell
  executable, passing the shell commands as arguments, for example:

    lxc exec <instance> -- sh -c "cd /tmp && pwd"

  Mode defaults to non-interactive, interactive mode is selected if both stdin AND stdout are terminals (stderr is ignored).

Usage:
  lxc exec [<remote>:]<instance> [flags] [--] <command line>

Flags:
      --cwd                    Directory to run the command in (default /root)
  -n, --disable-stdin          Disable stdin (reads from /dev/null)
      --env                    Environment variable to set (e.g. HOME=/home/foo)
  -t, --force-interactive      Force pseudo-terminal allocation
  -T, --force-noninteractive   Disable pseudo-terminal allocation
      --group                  Group ID to run the command as (default 0)
      --mode                   Override the terminal mode (auto, interactive or non-interactive) (default "auto")
      --user                   User ID to run the command as (default 0)

Global Flags:
      --debug            Show all debug messages
      --force-local      Force using the local unix socket
  -h, --help             Print help
      --project string   Override the source project
  -q, --quiet            Don't show progress information
  -v, --verbose          Show all information messages
      --version          Print version number

参考資料

https://discuss.linuxcontainers.org/t/how-can-i-make-use-of-man-pages-with-the-snap-package/2572/2

https://stackoverflow.com/questions/34445796/how-do-i-configure-ssh-proxycommand-correctly-to-run-docker-exec

ubuntu で kvm qemu インストール

ubuntuqemu kvm を入れて仮想マシンを作る準備をする。

kvm + qemulibvirt 一式をぱぱっと入れる。

kvm が使えるか調べる。

sudo apt install cpu-checker

KVMが使えるか調べる

takuya@ubuntu01:~$ kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

qemu kvm と libvirtd をインストールする。

sudo apt -y install qemu-kvm libvirt-daemon-system \
libvirt-daemon virtinst bridge-utils libguestfs-tools virt-top

インストールの確認

takuya@ubuntu01:~$ systemctl status libvirtd
● libvirtd.service - Virtualization daemon
     Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2020-11-30 13:02:12 UTC; 2s ago
TriggeredBy: ● libvirtd-admin.socket
             ● libvirtd-ro.socket
             ● libvirtd.socket
       Docs: man:libvirtd(8)
             https://libvirt.org
   Main PID: 3232 (libvirtd)
      Tasks: 17 (limit: 32768)
     Memory: 5.9M
     CGroup: /system.slice/libvirtd.service
             └─3232 /usr/sbin/libvirtd

Nov 30 13:02:12 ubuntu01 systemd[1]: Starting Virtualization daemon...
Nov 30 13:02:12 ubuntu01 systemd[1]: Started Virtualization daemon.
Nov 30 13:02:12 ubuntu01 libvirtd[3232]: libvirt version: 6.0.0, package: 0ubuntu8.5 (Christian Ehrhardt <christian.ehrhardt@canonical.com> Thu, 08 Oct 2020 07:36:06 +0200)
Nov 30 13:02:12 ubuntu01 libvirtd[3232]: hostname: ubuntu01

いつもググるのでメモを残します。

windows で multipass を動かす

multipass を windows にインストール

windowsubuntu の実行環境を手軽に使いたかった。

choco install multipass

UAC のPSから使う。

multipass は UAC 昇格後のPSから使うように設計されている。

基本的な使い方は以下の通り。

新しくインスタンスを起動する

multipass  launch --name sample01

メモリ・ディスク容量・CPU数を指定して、新しいインスタンスを作る。

multipass launch --name sample01 --disk 20G --cpus 8  -m 8G

シェルに入る。

multipass  shell sample01

シェルに入る(別の方法)

## docker exec  / lxc exec 的な方法
multipass  exec sample01 bash 

インスタンスを削除する(データは残る。)

multipass  delete sample01

削除済みのインスタンスを完全に消去する。

multipass  purge 

wsl から使う。

私は WSL1 を使っているので直接EXEを叩けば使える。

alias を設定しておくと便利。

alias multipass=/mnt/c/ProgramData/chocolatey/bin/multipass.exe

標準はHyper-Vが使われる。

multipassはデフォルト設定では、Hyper-V を使うので、Hyper-Vの管理画面から、インスタンスを制御できる。

もしトラブったらそこを見ればいい。

UACなしだと、delete && purge ができない。

Admin権限のユーザーであればUAC昇格 なしでも launch や shell は動くのですが、delete purge がうまく動かずHyper-Vインスタンスが消されずに残ってしまう。

もし、Hyper-Vを使っているのであれば、次のフォルダのアクセス権限を取得しておけば、削除される。(はず)

C:\Windows\System32\config\systemprofile\AppData\Roaming\multipassd

virtualbox をバックエンドに使用する。

purge がHyper-Vでうまく行かないのであれば、 Virtualboxを利用する。

hyper-Vの代わりにVirtualBoxを使うように設定する。

choco install virtualbox
multipass set local.driver=virtualbox

わたしの場合、フォルダのアクセス権限を取得しておいて、virtualbox で起動することにした。

virtualbox を使うと、ファイルは次にの場所に設置される。

仮想ハードディスクなどは次の場所に設置された。

C:\Windows\System32\config\systemprofile\AppData\Roaming\multipassd\virtualbox

万が一の場合は、ここのフォルダを全消ししたら良さそう。

multipass の Virtualbox を表示する。

https://multipass.run/docs/using-virtualbox-in-multipass-windows

hyper-v みたいに、仮想マシンの管理画面でMultipassのゲストを確認するには、次のようなコマンドで pstoolsを使って起動する。

choco install pstools
PsExec.exe -s -i $env:VBOX_MSI_INSTALL_PATH\VirtualBox.exe

hyper-v に戻すには

multipass set local.driver=hyperv

multipass 便利ですね。

カーネルビルドとかやってると完全仮想化のマシンが欲しくなる。削除・作成・起動ができる環境が手に入るのはとても嬉しい。

multipass の bash-completion とかも

wsl で multipass 使うなら bash-completion もあれば便利 ubuntu から持ってきた bash-completion を bashrc に追記しておく

#export PATH="${PATH}:/mnt/c/ProgramData/chocolatey/bin/multipass.exe"
alias multipass=/mnt/c/ProgramData/chocolatey/bin/multipass.exe
# Copyright © 2017-2019 Canonical Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

_multipass_complete()
{
    _multipass_instances()
    {
        local state=$1

        local cmd="multipass list --format=csv"
        [ -n "$state" ] && cmd="$cmd | \grep -E '$state'"

        local instances=$( \eval $cmd | \grep -Ev '(\+--|Name)' | \cut -d',' -f 1 )

        local found

        _get_comp_words_by_ref -n := -w WORDS -i CWORD cur prev
        for instance in $instances; do
            found=0
            for ((i=2; i<CWORD; i++)); do
                if [[ "${WORDS[i]}" == ${instance} ]]; then
                    found=1
                    break
                fi
            done
            if [ ${found} == 0 ]; then
                opts="${opts} ${instance}"
            fi
        done
    }

    local cur cmd opts prev prev_opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    cmd="${COMP_WORDS[1]}"
    prev_opts=false
    multipass_cmds="transfer delete exec find help info launch list mount purge \
                    recover shell start stop suspend restart umount version get set"

    opts="--help --verbose"
    case "${cmd}" in
        "info")
            opts="${opts} --all --format"
        ;;
        "list"|"ls")
            opts="${opts} --format"
        ;;
        "delete")
            opts="${opts} --all --purge"
        ;;
        "launch")
            opts="${opts} --cpus --disk --mem --name --cloud-init"
        ;;
        "mount")
            opts="${opts} --gid-map --uid-map"
        ;;
        "recover"|"start"|"suspend"|"restart")
            opts="${opts} --all"
        ;;
        "stop")
            opts="${opts} --all --cancel --time"
        ;;
        "find")
            opts="${opts} --show-unsupported --format"
        ;;
    esac

    if [[ ${prev} == -* ]]; then
        case "${prev}" in
            "--format"|"-f")
                opts="table json csv yaml"
                prev_opts=true
            ;;
            "--cloud-init")
                _filedir
                return
            ;;
        esac
    fi

    if [[ "$prev_opts" = false ]]; then
        case "${cmd}" in
            "exec"|"stop"|"suspend"|"restart")
                _multipass_instances "Running"
            ;;
            "connect"|"sh"|"shell")
                _multipass_instances "Running"
                _multipass_instances "Stopped"
                _multipass_instances "Suspended"
            ;;
            "start")
                _multipass_instances "Stopped"
                _multipass_instances "Suspended"
            ;;
            "delete"|"info"|"umount"|"unmount")
                _multipass_instances
            ;;
            "recover")
                _multipass_instances "Deleted"
            ;;
            "mount")
                local source_set=0
                local prev
                _get_comp_words_by_ref -n := -w WORDS -i CWORD cur prev
                # Scan through the current command line to detect if the source
                # positional arg has been set.
                for ((i=2; i<CWORD; i++)); do
                    if [[ "${WORDS[i]}" != -* ]] && \
                       ([[ "${WORDS[i-1]}" != -* ]] || [[ "${WORDS[i-1]}" == *=* ]]); then
                            source_set=1
                            break
                    fi
                done

                if [ ${source_set} == 0 ] ; then
                    if [[ ${prev} != -* ]] || ([[ ${prev} == -* ]] && [[ ${prev} == *=* ]]); then
                        _filedir -d
                        return
                    fi
                elif [ ${source_set} == 1 ] && [[ ${prev} != -* ]]; then
                    _multipass_instances "Running"
                    _multipass_instances "Stopped"
                    _multipass_instances "Suspended"
                fi
            ;;
            "transfer"|"copy-files")
                _multipass_instances "Running"

                COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
                if [[ "${#COMPREPLY[@]}" == "0" ]]; then
                    _filedir
                    return
                fi
            ;;
            "help")
                opts=$multipass_cmds
            ;;
        esac
    fi

    if [[ ${COMP_CWORD} -eq 1 ]]; then
        opts="${opts} ${multipass_cmds}"
    fi

    if [[ -n "${opts}" ]]; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
    fi

    return 0
}
complete -F _multipass_complete multipass

参考資料

2020年、良いなと思えたオンプレ(self-hosted)可能ソフトウェア

目次

今年インストールしてオンプレ(self-hosted)可能なソフトウェア

2020 年も終わりを迎えるの。今年インストールして、良かったソフトウェアを上げていきたいと思う。

今年のテーマは脱Googleで、できる限りクラウドのサービスに頼らずに、自前でサーバーにインストールしてデータを扱っていきたいと思う。クラウドサービスの積み上がる請求額に怯える暮らしから脱却したいです。Take Back my own data and Control.

ここに挙げた以外にもたくさんインストールしたり試しているのですが、今年インストールして使い始めて良かったものをまとめておきます。

getoutline

https://www.getoutline.com/

このメモを書いているツール

マークダウンを使ってノートを保存するツールは色々あるが、サーバーにインストールして使えるもの、複数人が使えるもの、権限設定ができるものは限られている。

テーブル(表組み)を手軽に作れるのもポイントが高い。

キーボードショートカットに対応していてリンク挿入や装飾などが手軽なのがいい。

マークダウンで記述できるが、クリック操作でマークダウンをソースを取り出せないのがちょっと悲しい。

今年ようやく日本語IMEに対応して、使い始めた。ずっと進化しているるので、今後が楽しみ。

Qiita よりも書きやすく、Nota ScrapBokほどではない感じ。でもデータを個人で管理できる強みがある。

Bitwarden

https://bitwarden.com/

まだパスワードを「記憶している」の?

パスワード管理はソフトウェアに任せる。自動生成・自動保存・自動入力までやってしまうのは当たり前の時代です。記憶よりも器械です。

パスワードをGoogle Chromeに記憶させるのも怖い。多くの人が使うソフトウェアはそれだけ狙われやすい。Chromeを狙うマルウェアは後をたたない。また何よりもGoogleにすべてを依存するのも恐ろしい話だ。GoogleがアカウントをBANまたはシステムダウンさせたらと考えると少し怖い。(実際に今年起こった)。パスワードくらいは自分で管理したい。Google Chromeのパスワード管理はとても安全で、もしパスワード自動保存してない人は今すぐまずChorme自動保存から使い始めるべきと個人的には思うのですが、Google Chromeに保存したパスワードをiOS(iPhone)から更新・保存のwrite管理が不便すぎて不満でした。

パスワード管理ソフトウェアを導入するにしても 1password にロックインされるくらいならiCloud keyChains 使いたいと思う。いろいろソフトウェアを検討した結果、Bitwardenに行き着いた。自分で管理できるものでソースコードGPL公開されていて誰でも手軽に安全に、自動入力・自動保存・自動生成ができ、OS環境問わず使えるもの、これを満たしてくれるのがBitwardenだった。

bitwarden のパスワード管理以外の便利機能。

メモ機能が個人的に気に入ってる。

メモを機能でセキュアなメモを残せる。メモ機能で、パスワードではないが、重要な記録を残せる。写真にとって保存できる。

パスワード記録ににドメイン名・ID・パスワード以外に、メモを残せる。複垢だったり、同一ベースドメインで複数サーブビスが動いているとき、メモを残せるので、このアカウントがどの契約だったかすぐわかる。さくらインターネットの管理画面ログインなど、複数契約で複数アカウントを持っているときに重宝する。

すべてをbitwarden に

1月にインストール後に使い始め、4月にはすべてのパスワードをBitwardenに移動する決断に至った。約1年が経過し、今では生活必需品になった。iOS版、Windows版、Chrome拡張、コマンドラインツールと生活に必要な一式がすべて提供されているのもポイントが高い。5年先くらいまでは戦えそう。

OpenProject

https://www.openproject.org/

プロジェクト管理ツールはあまたあるけど、どれも帯に短し襷に長しになっている。ソフトウェアの設計者のプロジェクト管理思想が具現化しているので、汎用に使えそうなものはなかなかない。

openproject は、ガントチャート、プロジェクト親子関係、タスクの親子関係、進捗入力、プロジェクト作成のテンプレ化、進捗入力のテンプレ化ができるので、入力項目も選択肢一覧をカスタムフィールドとして自分で定義することができる。ソフトウェア開発以外の、どんなプロジェクトにも対応可能だ。顧客ごとに管理する部署や受発注でも使えそうなので面白い。

カンバンの管理ソフトはあまたあるので、うまく連携設定してあげたい。

git連携が不得意なので、gogs や bare repo などとうまく設定連携していてあげたい。

Gogs

Gogs: A painless self-hosted Git service

古き良き(?)、昔のGithubのウェブ画面を実現している。機能が少ない。が、むしろ分かりやすい。

Git初心者に良い。スッキリしててわかりやすい。

Gogsはシンプルにcommits/ Issue / pull req/ wiki の機能で構成されている。分かりやすい。

gitweb ほど無味乾燥でなく、gitlab/githubほどゴチャゴチャしてない。

ここ数年のgithub は多機能とプロジェクト管理機能が増え、チケット管理とIssue管理ソフトウェアになった。pull/push するシンプルな使い方には増えすぎかもしれない。コミットログをブランチごとに見るだけでもgithubのプロジェクト画面を右往左往することがある。

gitlab/github は多機能でとても使いやすいが、多機能ゆえに、非プログラマの人たち(デザイナ・文書作成)にはまだ敷居が高が高いらしく。データをやり取りするのにGithubはUIが難しすぎる。

GitLabも多機能であるが、シンプルに左バーにまとまっているので素敵だが、gitlab-ci.yml をつかってCI/CDをオンプレで回したい以外の用途でインストールは躊躇する。

Git初学者や初心者、多機能がいらないひとたちとgitのやり取りするのに本当におすすめ。インストールも楽ちん。

Jitsi

https://jitsi.org/

オンライン会議ツール。jitsi の発音は、ジッチィ・ジッツィの発音に近い

Google MeetやZoomに代替にとても良い。

Mattermostから連携させると、Slack・Discord・Teamsの代替としてとてもいい。

通話品質は設定次第なので、評価は分かれると思う。使用感として、会議中に複数人が同時に発言した際、音声が途切れない印象。Meetsは発言が被ると消える印象があるので好対照だった。またDiscordほどノイズキャンセルが強力でもなためキーボード音は入りノイズ判定で警告が出たりも多かったがDiscordのようにノイズ判定でマイク入力をカットしない印象だった。

インストール後にSTUNやSSLP2Pのe2e設定がわかりにくい。ユーザー認証周りがめんどくさい。それを除けば最高に使いやすい。

他と違う変わった機能としてyoutube 動画を一緒に閲覧したり、youtube Liveにデータを流したり、youtube関係がある。OBS使わずにブラウザのタブ1枚で、youtubeを扱えるのは便利。

jitsi単体で使うより、Mattermostに追加する感じで使っている。なぜならmattermostに通話関係の機能がなく、MattermostからJitsiへの連携がありこれが使いやすい。

Slackはああなってしまったので、Slack離れをするためMattermostを使うことになったが通話機能にJitsiを使うことでとても使いやすいコラボ環境が入手できる。

iOSアプリも用意されており、日常使いや会議開催また授業で大活躍できる。

Google Meetにおすすめのソフトウェアだと思います。

n8n.io

https://n8n.io/

Workflowを作り上げるWebUIデザインとタスク作成のわかりやすさが良かった。

Zapier や IFTTや Node-REDが比較対象になると思いますが、Node-REDよりはZapierに近い感じ。

どこをどこをつなぐなど、視覚的に取り扱えるので、流行りのノーコード・プログラミングっぽいRTAごっこができます。でも実際にはJSONだとかHTTP GET/POSTを知らないと使えないですけど。「プログラミングを知らなくても作れる」と、「知ってる人が手軽に書けるGUI」はまた別物なのですが、世間ではごっちゃにされている印象は少なからず受けますよね。

n8nは必要なリクエストログはしっかり残るし、コピーして作成するようなこともできる。ただし、Webhookで受け取ったJSONデータから必要箇所を抜き出して、次のWebhookを起動するようなパス廻しまで手軽にできるかというと、そこまででもない。

PreBill

https://github.com/shoynoi/prebill

年間契約のサービスや、月額サービスの更新日をリマインドしてくれる。

半年残して解約はもったいないなぁ。などとケチってると、更新日に解約を忘れ、更に一年継続しちゃうミスを防げるかもしない。クラウドサービスや携帯電話の料金が高くなりがちなのは、月額サービスの更新月を忘れて解約ミスが発生しすることも一因だとおもうし、年間いくら掛けているのか可視化することもとても重要。

年間でいくら払っているのかを可視化しつつ、契約満期直前にサクッと解約できるようにしておくためにリマンドがとても重要。

年間総額の計算と閲覧、リマインド・メールを送信してくれる。

リマインドは通常であれば、カレンダー経由で行うのでカレンダーに忘れずに登録しておけば良いのですが、カレンダーの登録だと、自分がいつどこでいったい全部で何件の何円契約してるかが一覧の視認性が悪くなるので、このように手軽に管理できるものはいいなと思います。クラウド貧乏を避けたい。

できれば、iOSカレンダーやGoogle カレンダーにiCal エキスポートとか欲しかった。

でも、ないものは作ればいいんだってのが、ソースコードが公開されてる良さですね。

OPNSense

https://opnsense.org/

ルータ用OSの代表的存在

今年始めに、家庭内のネットワークをx86 ルータに変更したのですが、その時からOpenWrtを使っているのですが、予備回線の方はwrtではなく、OPNSenseを使っています。

両者を1年使ってて、単なるルーターとして動作させるのであればOPNSenseのほうが扱いやすいなと思ったので挙げておきます。

特に良かった点が、次の3点。

自動的にアップデートされるのがいい。
WEB画面だけでほとんどできる。
バックアップと復元が使いやすい 。

ルータとして十分な機能を備えていて、なおかつWEB-UIで設定できるのでスマホから操作できる。PPPoEとIPoEつないで、ファイアウォールを設定してOpenVPNDDNSを設定するなら、このOPNSenseを入れておけば十分。使い方もそんなに難しくない。x86のNUCやArm ボードが格安なので、自由に設定できるルーターをおいておくには良い。ルーターと無線APを一緒にしていると、無線APを増設が手間になったり、買い替え後に設定をメーカー提供の画面でチマチマやっていくのは苦痛すぎるので、一家に一台設置してもいいと思う。Wifi機能は進化が早いのでルーター機能とわけて管理しておくほうが5年程度運用するとトータルコストでお得になるかもしれない。

ただベースがBSDなので、SSH経由で使うには、Linuxとコマンドと体系が異なるので、iproute2 や systemd もないしファイル・システムもext4でもZFSもなくUHSなのでLinuxしか使ってない人にはちょっととっつきにくいかもしれない。

ただ無線LANサポートが微妙、BSDなのでドライバが少なく動作するUSB-Wifiも少ない。そのためWiFiSoftbank AirをAPを使うことに。11ac 1300 のAPになれる、契約終了後のSoftbank Air4が捨てられてるので養子にすることに。Wifi扱うならOpenWRTの方がドライバサポートが多くてが良いですね。

LXC container

https://linuxcontainers.org/lxc/introduction/

docker や k8s をみんながやってる中、私がコツコツと使っていたのが、 LXC/LXD と multipass 。

LXCで作るコンテナは、Dockerとは違い、仮想マシンしてるので、systemd があったりカーネルをいじれたり、手軽に実験環境を作成・削除するのが便利だった。

virtualbox や libviet qemu+kvmでもいいのだけれどLXCとして使い方と管理が共通化されているので、ここまで紹介したソフトウェアを試験的に動かしたりインストール手順を確認するのに活躍してくれた。

最後に。

今年は粛々と脱Google依存とクラウド貧乏を防止を目指している感じでした。

来季は、暗号化ストレージまわりや、LDAP認証周りNAS周りをめんどくさいが対応していきたいなと思ったり、お仕事を含めOpenLayersOSM周をやるので、Mapでも脱Googleを目指して頑張れればなと思います。脱Googleをしても、最後に残るGmailだけはどうしても依存してしまう。