1.4K Views
October 24, 25
スライド概要
2025/10/23に開催されたイベント「CI/CD Test Night #8」の登壇スライドです。
イベント概要:https://testnight.connpass.com/event/369890/
「CI/CD Test Night #8」アーカイブ動画:https://youtu.be/lBD1JADqL5k
DeNA が社会の技術向上に貢献するため、業務で得た知見を積極的に外部に発信する、DeNA 公式のアカウントです。DeNA エンジニアの登壇資料をお届けします。
macOSランナーに VNCできるまで 前田 薫 DeNA SWET 1G 2025/10/23 CI/CD Test Night #8 © DeNA Co., Ltd. 1
自己紹介 ● 前田 薫 @mad_p, GitHub: mad-p ○ DeNA 2017年入社 ● HHKB (尊師スタイル) ● 漢字直接入力 (T-Code, MacTcode) ● ルービックキューブ (公式記録) ● Splatoon3 (5000時間) © DeNA Co., Ltd. 2 2
background ● DeNAでは社内向けにActionsセルフホストランナーを提供している ● macOSランナーをベータ提供中 ○ ● uptermを利用したsshログインを提供済み ■ uptermdを社内向けにホスティング ■ owenthereal/action-upterm を改造し、社内uptermdに向けている 「VNCを使いたくなるのではないか?」という指摘があった © DeNA Co., Ltd. 3
why VNC VNC接続に成功したところ ● なぜVNCしたいのか ○ アプリ署名時、keychain ダイアログで止まりがち ● これまではどうしていた? ○ オンプレの物理マシンなので VNCできていた ● なぜrunnerにVNCできないのか ○ マシンは動的に割当て、 固定IPアドレスはない ○ 自分以外のジョブ実行中の runnerにログインできてはいけない © DeNA Co., Ltd. 4
how ● debug-action (次で説明) ○ ● runnerにsshできる機能 uptermを使ってsshログイン できる ○ 認証つきリンク+自分の GitHub用SSH鍵 ● tmuxにつながる © DeNA Co., Ltd. 5
how runner ● debug-actionの仕組み ● OSSを改造して利用している ○ ● tmux job tmux upterm sh sshd tmux attach owenthereal/action-upterm tmuxでセッションを作り、 ssh後にセッションにアタッチ ● ジョブ進行と独立にuptermを起動する 目的でもtmuxを使っている client (your pc) terminal ssh © DeNA Co., Ltd. 6
how ● sshできる環境なら、通常はport forwardingを使ってVNCできるはず ○ ssh -L5901:127.0.0.1:5900 -l account host ○ VNCはTCP 5900を使って接続するので、リモートの5900向けの接続を ローカルの5901からできるようにforwarding ● upterm経由ではport forwardingが未実装、実行コマンドもtmuxに固定 ● 標準入出力を使ってport forwardingできるツールを使えないか? ○ nc (netcat) ○ socat (SOcket CAT) ■ socatで通常のssh経由でVNCトンネルする場合 ■ socat TCP-LISTEN:5901,fork,bind=127.0.0.1 \ "SYSTEM:ssh host 'socat STDIO TCP:127.0.0.1:5900' " © DeNA Co., Ltd. 7
try ● debug-action改造しリモートでsocatを動かす runner tmux job VNC server upterm 5900 command: "socat STDIO TCP:127.0.0.1:5900" ● 手元ではsocatからsshを起動 socat sshd socat \ TCP-LISTEN:5901,fork,bind=127.0.0.1 \ "SYSTEM:ssh -tt \ '~~:~~@actions-uptermd.dena.com' " ● この状態でVNCを起動 open vnc://localhost:5901/ ● client (your pc) VNC client socat ssh 5901 VNC接続できない © DeNA Co., Ltd. 8
investigate ● 通信をWiresharkで見てみる。sshトンネルでVNCできた場合と比較すると debug-action経由 VNCできない場合 sshトンネルでVNCできた場合の リモートからの通信内容 © DeNA Co., Ltd. 9
investigate ● 通信をWiresharkで見てみる。直接VNCする場合と比較すると debug-action経由 VNCできない場合 0a が 0d 0a に 化けている! sshトンネルでVNCできた場合 © DeNA Co., Ltd. 10
understand ● なぜ化けるのか ● uptermの仕組み © DeNA Co., Ltd. ○ https://upterm.dev/ より ○ とくに化けそうな要素はない 11
understand ● なぜ化けるのか ● uptermの仕組み ○ https://upterm.dev/ より ○ とくに化けそうな要素はない host sshd upterm host bash ssh client tunnel tunnel uptermd proxy sshd client ssh client © DeNA Co., Ltd. 12
understand runner ● tmux debug-actionの仕組み再掲 job ● どこで化けるのか tmux upterm sh sshd tmux attach client (your pc) terminal ssh © DeNA Co., Ltd. 13
reason runner ● どこで化けるのか ● ptyが介在している ● pty (一般的にtty)がする仕事 ● ○ 0a を 0d 0a にしてくれる ○ 行編集 ○ エコーバック ○ Control-CをSIGINTに変換 ttyの挙動はsttyコマンドで変えられる ○ © DeNA Co., Ltd. stty -icanon -echo -nlcr -isig tmux job tmux upterm sh pty sshd tmux attach pty client (your pc) terminal ssh pty 14
reason runner ● debug-action改造でsocatを動かす ○ ● ● tmux 使っていないtmuxのために job VNC server upterm uptermの制約でsshにptyが必要 ○ gosshを使ってsshdを自作している ○ ssh -tt ~~@~.dena.com sshd socat pty socat実行直前にstty -icanon -echo -nlcrなど試したがダメ ○ なぜダメだったのかはナゾ pty変換に耐性のあるsocatもどきを client (your pc) VNC client socat ssh 自作すればいいじゃない! © DeNA Co., Ltd. 15
vibe ● ttyで化けそうなバイトをエスケープするトンネル ○ transと命名 ■ ○ github.com/mad-p/trans trans := transparent + transport ● encode/decode ソ ケ ッ ト パ イ プ ● encode decode ssh tty Claude Codeで瞬殺 ○ © DeNA Co., Ltd. プロンプト trans.txt 標 準 入 出 力 encode decode ソ ケ ッ ト 以下のようなプログラムを考えます。 sttyによって cr/lfなどが混 乱する通信路を使って、 byte-transparentなTCPトンネルを提供し ます - 変換 - データのうち特定のバイト値にあるものをエスケープする - 変換方法 1 - uuencode/uudecodeによって変換する - 変換方法 2 - エンコード側 : 0x0d, 0x0a, 0x1c, 0x7f, 0x5cが あったら、 0x5cの後にそのバイトを 16進数 2桁のアスキーコードで 出力する - デコード側 : 0x5cが来たら、その後の 2バイトを 16進ア スキーと見なし、元のバイトを復元する - 送信側 - 指定された TCPポートで listenし、接続があったら acceptす る - TCPポートとの入出力を変換し、標準入出力へつなぐ - 受信側 - 指定された TCPポートへ接続する - TCPポートとの入出力を変換し、標準入出力へつなぐ - TCPポートとの入出力は、 forkによって 2つのプロセスで実装して もよい - 送信 /受信の別、 TCPポート番号、変換方法はコマンド行オプショ ンで指定する このようなプログラムを Cで書いてください。 エンコード /デコード部分は単体テストも書いてください。 ---- systemするオプションを追加してください - ポートに転送する標準入出力を外部コマンドに接続できるよ うにしてください - 外部コマンドは execveするのではなく、 systemのように シェル経由がよいです - 標準エラー出力はそのまま、現在の stderrに出力でよいです - 動作モードのエイリアスとして to、fromを追加してください。 to はconnectする側、 fromがlistenする側です - --hostのデフォルト値を `127.0.0.1` としてください - recvは、ポートに新しい connectionが来るたびに、新しく acceptしたソケットに対してコマンドを起動するように修正してく ださい 16
socket & pipe ● ● ソケットとパイプを使う場合のコツ ○ バッファリングがある ○ 入出力はブロックするかもしれない 4つのfd入出力を監視 めんどう。バグの元 ssh側 VNC側 ソ ケ ッ ト selectでどのfdが準備OKか見て 送信と受信を別プロセスでやるとよい ○ 2回forkする ○ fork後は使わないfdのcloseを 忘れないこと © DeNA Co., Ltd. パ イ プ fork 利用 処理するのは大変 ○ encode decode VNC側 ソ ケ ッ ト ssh側 encode decode パ イ プ 2つのfd、2組 単方向でシンプル 17
struggle ● sshで実験するとつながらない ● 調査のため、16進ダンプログ機能追加 ● ○ ダンプログ比較ツール作成 ○ 8つのストリームは2つずつ一致するはず VNC server 5900 sshd trans pty encode/decodeが逆! ○ ● 開発PC1 プロンプトに方向明示してなかった byte transparentになっていないことが判明 © DeNA Co., Ltd. ○ いったんVNCは忘れて透過性を確保 ○ trans経由でsshできることをゴールに 開発PC2 VNC client trans ssh 5901 18
struggle 開発PC ● いったんVNCは忘れて透過性を確保 ○ ● trans経由でsshできることをゴールに sshd ● ./trans -m from -p 20022 -s "ssh -tt -e none localhost 'stty raw -icanon -echo; \ ./trans -q -m to -p 22 -d 1' " ssh -p 20022 localhost ● PCが1台で開発を進められる ● sshは暗号化するのでバイト値0~255がまんべんなく来そう ○ © DeNA Co., Ltd. trans pty 22 直接ssh trans経由 ssh ssh -p 20022 trans ssh -tt 20022 byte透過でないと復号に失敗し、sshが切れてくれるので検出しやすい 19
trouble shooting
開発PC
1.
○
2.
3.
④
blocking I/O: 短い送信が来ないで止まる
sshd
エスケープシーケンスとバッファ境界で化け
22
リモートのstty設定前にechoされる (右図)
○
ローカルsshは①接続後すぐしゃべる
○
リモートは③でstty設定変更するが、
それ以前に届いた分がechoされちゃう
○
解決: ローカル側transで数秒待つ
○
./trans -m from -p 20022 -d 8
trans
pty
⑤
O_NONBLOCKとpollを利用
直接ssh
trans経由
ssh
ssh
-p 20022
③
trans
①20022
ssh -tt
②
-s "ssh -tt -e none localhost 'stty raw -icanon -echo; ./trans -q -m to -p 22 -d 1' "
sshできた == byte transparent
© DeNA Co., Ltd.
20
VNC protocol VNC client ● やっぱりなんかつながらない ○ VNCはTCP接続を3往復している (右図) ● transでは接続のたびにsshし(8秒待って) トンネルを作っている ○ 接続 パスワード入力画面までは進む ● ● VNC server めんどくさい 解決: transを使ってsshを通し、 そのsshのport forwardを使う セキュリティタイプリスト × 接続 セキュリティタイプリスト × パスワード入力 接続 セキュリティタイプリスト セキュリティタイプ選択 通信開始 © DeNA Co., Ltd. 21
permission ● ローカルPC間ではtrans+sshでVNCできたが、 ランナーでは「画面共有が許可されていません」 ● 設定の「一般 → 共有 → 画面共有」を オンにする必要がある ● CLIでできないか調べたが無理そう ○ ぐぐるとkickstartなどヒットするが、 OSのバージョン更新で使えなくなっている ○ ● なんとかなったとしても後の更新で変わるかも ランナーVM作成時にpackerでGUI操作して設定 © DeNA Co., Ltd. 22
success runner VNC server tmux job upterm+ssh 5900 upterm sshd trans ssh port fw trans pty sshd VNC client (your pc) VNC client ssh 5901 © DeNA Co., Ltd. trans ssh 20022 23
use ● ジョブ内でtransをcloneしてビルド ● - name: SSH Debug uses: gha-runner/debug-action@pr/175 with: command: | chmod 600 ~/.ssh/config stty raw -icanon -echo $HOME/trans -q -m to -p 22 ● ● ● ● make tunnel HOST=<コピーしたssh先> 作ったトンネルを使ってVNCをポートforward ○ make ssh-runner ○ 8秒くらいかかってパスワードを聞かれる make vnc ○ ● 3つのターミナル画面が必要 トンネルを起動 ○ ssh先の部分をコピー © DeNA Co., Ltd. ローカルPCからtransでVNC接続 ○ ジョブのログを開きSSH Command が 表示されるまで待つ ● ● ユーザー名、パスワードを入力して接続 参考: Makefile 24
technology ● stty raw -icanon -echo ● escape/unescape、uuencode/uudecode ● socket listen/connect/accept/shutdown/close ● pipe/dup2、fork/exec、stdin/stdout ● select/poll/fcntl/EAGAIN/EWOULDBLOCK ● Wireshark/protocols © DeNA Co., Ltd. ○ TCP/SYN/ACK/FIN ○ SSH ○ VNC 25
summary ● ● ● macOSランナーにVNCを通したい ○ uptermでsshはできる ○ なぜかssh port forwardingできない ○ なぜかsocatでうまくいかない トンネルツール「trans」を作った ○ うまくいくまでいろいろ調べて対策した ○ 調査では16進ダンプやWiresharkを活用できた 低レイヤは面白いですね! © DeNA Co., Ltd. upterm+ssh trans ssh port fw VNC 26
© DeNA Co., Ltd. 27