はじめに:なぜこんなことを…
ふと、昔の思い出に浸っていました。
社会人新人時代、メインフレーム開発をやってたな…あの複雑怪奇な JCL、COBOL、PL/1・・・あの独特の世界観。あの時代は、今のような情報も少なくて、ひたすら試行錯誤の日々だった。
「それって、ブログのネタになるんじゃ…?」
ふと、そんなことを考えました。
「もし、現代の技術(Docker、Apple Silicon など)を使って、あの時代のシステムを動かせたら、その過程での試行錯誤や工夫は、技術ブログとしていい記事になるかもしれない。」
調べてみると、TK4-Hercules というプロジェクトがあるではないですか。IBM MVS 3.8j を Docker で実行できる。
「これだ。やってみよう。」
結果?
丸一日、Google先生なしに試行錯誤をすることになりました。
本記事は、そのドタバタの記録です。もし同じ轍を踏む人がいたら、少しでも参考になれば幸いです。
TK4-Herculesとは(そして、なぜ自分はハマったのか)
TK4-Herculesは、Hercules System/370 emulator上でIBM MVS 3.8j(Service Level 8505, from 1981)を動作させるDockerコンテナです。
1981年…43年前のメインフレーム環境を、2025年のMacで動かせる。
(まあ、自分は1997年〜5年間ほどやっていただけですが・・・)
不思議なことに、このプロジェクトを発見した瞬間、思い出がいっぱい蘇ってきました。あのモノクロのターミナル画面、c3270コマンド、JCLスクリプト…あの独特の体験が、Dockerコンテナで再現されているなんて。
「試しにやってみるか」
その一言で、自分の地獄の試行錯誤は始まりました。
情報の砂漠
最初、自分が直面した大きな問題は情報の不足です。
- Apple Silicon Mac上でのクロスプラットフォームビルド? → ほぼ情報がない
- Herculesの起動トラブル? → Stack Overflowにも答えがない
- c3270のポート指定? → ドキュメントをよく読め、と言われるだけ
Google で検索しても、大抵は古い情報か、まったく関係のない話ばかり。そうなると、自分の手で試して、エラーメッセージとにらめっこするしかありません。
それが、実は一番の学習になったのですが。
環境
- Host: Apple Silicon Mac(M1/M2/M3/M4)- 自分の場合はM4
- OS: macOS 26.0+
- Container Runtime: Docker Desktop for Mac
- Guest OS: IBM MVS 3.8j-tk4(1981年のメインフレーム)
- Emulator: Hercules 4.4.1
- Architecture Nightmare: x86_64のバイナリをARM64のMacで動かす → Rosetta 2に祈る
セットアップ:簡単に見える5ステップ(でも実際は…)
ステップ1: Rosetta 2のインストール(5分)
まずはこれ。Apple Silicon では x86_64 バイナリを実行するために Rosetta 2 が必須です。
softwareupdate --install-rosetta
これで完了。簡単です。
完了メッセージ:
Install of Rosetta 2 finished successfully
当時の心情: 「よし、簡単だ。この調子ならすぐできるな」← 後に後悔することになる
ステップ2: Docker Desktopの設定(3分)
Docker Desktop のメモリとCPUを確保します。
- Docker Desktop を開く → Settings
- Resources タブで以下を設定:
- Memory: 2GB以上(推奨: 4GB。けちるな)
- CPUs: 2以上
- Swap: 1GB以上
当時の心情: 「まだ簡単。もしかして、ネットの情報は古いのか?」
ステップ3: プロジェクトのクローン(1分)
git clone https://github.com/skunklabz/tk4-hercules.git
cd tk4-hercules
README を読むと、セットアップ手順が書いてあります。
当時の心情: 「いけるいける。」
ステップ4: Docker イメージのビルド(2分…だと思ってた)
README に従って実行:
make build
…
…30秒待つ…
…1分待つ…
…1分30秒…
ついに完了。TK4- ZIP ファイル(238MB)のダウンロードと展開が含まれていました。
当時の心情: 「あ、思ったより時間かかったな。でも、これで起動するはず…」
実際には、ここまでは非常にスムーズでした。本番はここからです。
ステップ5: コンテナの起動(ここから地獄)
docker compose up -d
起動確認:
docker compose ps
出力:
NAME COMMAND SERVICE STATUS
tk4-hercules-1 "/bin/bash /tk4-/..." tk4-hercules Up 2 minutes
ステータスが Up になった!
ログを確認しようとします:
docker compose logs -f
そこで見た光景:
=== TK4- MVS Startup ===
=== TK4- MVS Startup ===
=== TK4- MVS Startup ===
=== TK4- MVS Startup ===
=== TK4- MVS Startup ===
無限ループ。
当時の心情: 「あ、これ、やばい。」
試行錯誤の記録:5時間の格闘
こここからが、本当の戦いです。以下、実際に経験した4つの課題と、その解決までの苦労の道を記します。
課題1: 無限ループ地獄
最初の症状:
=== TK4- MVS Startup ===
=== TK4- MVS Startup ===
=== TK4- MVS Startup ===
当時の思考プロセス: 1. 「これは何だ?」 2. ネットで検索 → 情報がない 3. ログをもっと読む → 何も出ていない 4. Dockerfile を眺める → 何も問題が見当たらない 5. 「もしかして、設定ファイルの問題?」 6. 昔の知識を思い出す → 「あ、スクリプトが…」
犯人を見つけるまで:
config/mvs.fixed というファイルを発見。中身を見ると:
#!/bin/bash
# ...いろいろ...
exec ./mvs # ← これだ!
「あああああああ」
このスクリプトが自身を呼び出すたびに無限ループが発生していました。
解決策:
config/mvs.fixedを削除するか、オーバーライドをやめる- Dockerfile を修正して、直接 Hercules バイナリを実行
修正後のDockerfile:
export LD_LIBRARY_PATH=/tk4-/hercules/linux/64/lib:$LD_LIBRARY_PATH
exec /tk4-/hercules/linux/64/bin/hercules -f /tk4-/conf/tk4-.cnf
当時の心情: 「あああ…もう二度と嫌や…」
課題2: アーキテクチャの地獄(本当の地獄はここから)
無限ループを修正して、再度 make build を実行。
するとエラーが出ます:
qemu-i386: Could not open '/lib/ld-linux.so.2': No such file or directory
「え、なにこれ?」
何が起きていたのか
- Dockerfile の
FROM ubuntu:22.04は、実行環境のアーキテクチャ(ARM64)を指定していた - でも、ビルド内で x86_64 バイナリを使おうとしている
- そのため、32ビット・64ビットの x86_64 ライブラリが見つからない
試してみたこと(その1):ライブラリをインストール
# Dockerfile に追加してみた
RUN apt-get update && apt-get install -y libc6-i386 libstdc++6:i386
結果:
E: Unable to locate package libc6-i386
当時の思考: 「え、なんで?」
その時点では、ARM64 Ubuntu にはそもそも x86_64 用の 32/64 ビットライブラリが存在しないことに気づいていませんでした。
試してみたこと(その2):GHCR のイメージを使う
公式リポジトリの pre-built image を使ってみようと思いました。
# docker-compose.yml
image: ghcr.io/skunklabz/tk4-hercules:latest
docker compose up -d を実行…
同じエラーが出ました。
この瞬間気づきました。
「これ、ベースイメージのアーキテクチャを指定する問題だ。」
真犯人
Dockerfile を見直します:
FROM ubuntu:22.04 # ← これがARM64指定になっていた!
Docker は、実行環境のアーキテクチャを自動選択します。Mac(ARM64)上では、自動的に ARM64 Ubuntu イメージを選ぶのです。
解決策:明示的にアーキテクチャを指定
FROM --platform=linux/amd64 ubuntu:22.04 AS builder
...
FROM --platform=linux/amd64 ubuntu:22.04
さらに、ビルド時も明示的に指定:
docker buildx build --platform linux/amd64 -t tk4-hercules:latest .
「docker build ではなく docker buildx か…」
その時点では、docker buildx の存在すら知りませんでした。調べて実行。
ビルド時間: 約2分。
結果:成功。
当時の心情: 「…終わった。やっと…」
課題3: c3270 ターミナルの謎のエラー
ようやく Hercules が起動しました。
次は、3270 ターミナルでログインを試みます。
c3270 localhost
エラー:
localhost, port 23: Connection refused
「え?ポート 23?」
その時点では、何が起きているのかわかりませんでした。
試してみたこと(その1):ポートが本当にリッスンしているか確認
netstat -an | grep 3270
出力:
tcp46 0 0 *.3270 *.* LISTEN
ポート 3270 は確かにリッスンしている。では、なぜ connection refused?
試してみたこと(その2):Web コンソールにアクセス
curl http://localhost:8038
結果:成功。HTML が返ってきた。
「あ、Web は動くんだ。だったら c3270 の問題?」
真犯人(その1)
c3270 のマニュアルをよく読んでみると…
c3270 [options] [host[:port]]
ポート指定がないと、デフォルトでポート 23(Telnet)に接続する。
「あ…」
TK4-Hercules は、ポート 3270 でリッスンしています。それなのに、c3270 は勝手にポート 23 を選んでいた。
真犯人(その2)
なぜ Telnet(ポート 23)をデフォルトにしたのか?
歴史的には、System/370 エミュレータは本来、Telnet プロトコル を使うものだったからです。1980年代、3270 ターミナルはネットワーク経由で Telnet で接続していました。
でも、TK4-Hercules は Telnet じゃなくて、raw TCP の 3270 プロトコルでリッスンしているわけです。
解決策:ポート番号を明示的に指定
c3270 localhost:3270
これだけ。
当時の心情: 「…いや、これ、ドキュメントに書いてあったんじゃ…」(怒り)
課題4: Docker Daemon が起動していない(初期段階の問題)
実は、一番最初に遭遇した問題がこれでした:
Cannot connect to the Docker daemon at unix:///Users/username/.docker/run/docker.sock
解決策:
open /Applications/Docker.app
Docker Desktop が完全に起動するまで待つ。
これだけです。
当時の心情: 「あ、普通に Docker 起動してなかった…」
ようやく成功
課題1: コンテナの無限ループ
症状: コンテナが起動すると、ログが無限に繰り返されます:
=== TK4- MVS Startup ===
=== TK4- MVS Startup ===
=== TK4- MVS Startup ===
...(永遠に続く)
原因: プロジェクトの config/mvs.fixed スクリプトが、自身を再帰的に呼び出していました:
# config/mvs.fixed(問題のあるコード)
exec ./mvs # 自身を呼び出す → 無限ループ!
解決方法: 1. config/mvs.fixed を削除またはオーバーライドをやめる 2. TK4-の元々の mvs スクリプトを使用 3. 最終的には、Dockerfileで直接Herculesバイナリを実行するように修正
修正後のDockerfile抜粋:
export LD_LIBRARY_PATH=/tk4-/hercules/linux/64/lib:$LD_LIBRARY_PATH
exec /tk4-/hercules/linux/64/bin/hercules -f /tk4-/conf/tk4-.cnf
Learning Point: スタートアップスクリプトは必ずテストしましょう。特に再帰呼び出しには注意。
課題2: アーキテクチャの不一致エラー
症状: 以下のようなエラーが表示されます:
qemu-i386: Could not open '/lib/ld-linux.so.2': No such file or directory
または:
rosetta error: failed to open elf at /lib64/ld-linux-x86-64.so.2
根本原因: – ARM64ベースのUbuntuイメージ上で、x86_64バイナリを実行しようとした – ARM64環境では、x86_64用の32ビット/64ビットライブラリが利用できない
失敗した試み:
ARM64イメージ上で依存ライブラリをインストールしようとしました:
# ❌ 失敗
apt-get install libc6-i386 libstdc++6:i386
# エラー: パッケージが ARM64 Ubuntu にない
この失敗から学んだこと:環境が異なると、パッケージの利用可能性も異なるということです。
解決方法 ✅:
Dockerfileの FROM ステートメントで明示的にプラットフォームを指定します:
# ✅ 正しい方法
FROM --platform=linux/amd64 ubuntu:22.04 AS builder
...
FROM --platform=linux/amd64 ubuntu:22.04
そして、ビルド時にも明示的にプラットフォームを指定:
docker buildx build --platform linux/amd64 -t tk4-hercules:latest .
Why docker buildx? – docker build: ホストのアーキテクチャ用のイメージのみ構築 – docker buildx build: クロスプラットフォーム対応のビルダーを使用
Learning Point: クロスプラットフォーム開発では、コンテナベースイメージのアーキテクチャ と ビルダーのプラットフォーム指定 の両方が重要です。
課題3: c3270 ターミナルエミュレータの接続エラー
症状: c3270でTK4-Herculesに接続しようとすると、接続拒否エラーが出ます:
$ c3270 localhost
localhost, port 23: Connection refused
なぜこんなことが起こるのか?
c3270はポート指定なしの場合、デフォルトでポート23(Telnetプロトコル) に接続しようとします。しかし、TK4-Herculesはポート3270 でリッスンしています。
イメージ:
ユーザー入力: c3270 localhost
↓
c3270の動作: localhost:23 に接続しようとする ← ❌ ここが間違っている
TK4-Hercules: ポート 3270 でリッスン中
↓
接続拒否エラー
検証:
ポートが本当にリッスンしているか確認:
netstat -an | grep 3270
出力:
tcp46 0 0 *.3270 *.* LISTEN
✅ ポート3270は確かにリッスン中です。
解決方法 ✅:
ポート番号を明示的に指定:
# ✅ 成功
c3270 localhost:3270
これだけです!
Learning Point: デフォルト値が常に正しいとは限りません。特にネットワーク通信では、明示的にポート番号を指定することが重要です。
課題4: Docker Daemon の接続エラー(初期段階)
症状:
Cannot connect to the Docker daemon at unix:///Users/username/.docker/run/docker.sock
原因: Docker Desktop が起動していない
解決方法:
open /Applications/Docker.app
Docker Desktop が完全に起動するまで待ちます(メニューバーにDockerアイコンが表示される)
c3270 localhost:3270
実行するとターミナルが表示されます。
Enter キーを 2 回押す…
ログイン画面が表示されます。
HHCPF003I LOGON REQUIRED
HERC01 USERID ========> [ ]
[PASSWORD]
[ ]
LOGON COMPLETE
ここに入力:
ユーザー名: HERC01
パスワード: CUL8TR
当時の心情: 「…あああ、やった。やっと動いた。」
何を学んだのか
丸一日をかけた試行錯誤から得た教訓:
1. ドキュメントをちゃんと読め
c3270 --help を見れば、ポート指定方法は書いてあった。docker buildx --help を見れば、クロスプラットフォーム対応について書いてある。
でも、実際には、エラーが出てからドキュメントを読みました。
2. デフォルト値は信頼するな
- c3270 はデフォルトでポート 23 を選ぶ
- Docker は実行環境のアーキテクチャを自動選択する
- スクリプトは silent に失敗することがある
デフォルトの背後にある歴史と意図を理解することが重要です。
3. エラーメッセージはあなたの友
「Connection refused」というシンプルなエラーメッセージから、ポート番号の問題を特定できました。エラーメッセージは、問題への手がかりです。
4. 試行錯誤は無駄ではない
正解を教えてもらうのと、自分で試行錯誤するのでは、頭に残るレベルが全く違います。
昔メインフレームを使っていた自分でも、Apple Silicon と Docker の組み合わせは新しい領域。知識がない中での試行錯誤が、一番の学習になりました。
5. 懐かしさって、すごい
この作業中、何度も昔の記憶が蘇りました。
JCL のあの独特の文法、3270 ターミナルのあの画面、COBOL のあの冗長性…
43年前のシステムが、今も動いているし、今も学ぶ価値がある。そして、当時のエンジニアたちが設計した思想や制約が、今なお影響を与えているんだなと。
最後に:なぜこんなことを…
結局、何時間も費やして得たものは何か?
- Apple Silicon Mac での Docker クロスプラットフォーム構築の知見
- 3270 ターミナルエミュレータの使い方
- 1981年のメインフレームが動く環境
そして、何より:
昔触ってた世界が、まだ息づいてるんだな。という実感。
クラウドネイティブ、マイクロサービス、Kubernetes…確かに新しい技術は素晴らしい。でも、世界の金融システムの多くが、いまだに 1981 年のメインフレーム上で動いている。
その事実と、その世界を学ぶ価値を、改めて認識させてくれたプロジェクトでした。
参考:最終的なコマンド集
すべてがうまくいったときのコマンド:
# 1. Rosetta 2 インストール
softwareupdate --install-rosetta
# 2. クローン
git clone https://github.com/skunklabz/tk4-hercules.git
cd tk4-hercules
# 3. ビルド(ここで --platform を指定)
docker buildx build --platform linux/amd64 -t tk4-hercules:latest .
# 4. 起動
docker compose up -d
# 5. ログ確認
docker compose logs -f
# 6. 接続
c3270 localhost:3270
# 7. または Web コンソール
open http://localhost:8038
謝辞
このプロジェクトと資料を提供してくださった TK4-Hercules のメンテナーの皆様に感謝申し上げます。そして、Google なしに試行錯誤をさせてくれた環境に感謝。
続編に向けて
本記事では、TK4-Hercules を Apple Silicon Mac にセットアップするまでのプロセスを記録しました。
しかし、ここからが本番です。
次の記事では:
- 実際にメインフレームにログインして、何ができるのか
- JCL(Job Control Language)の基礎と実践
- TSO(Time Sharing Option)の使い方
- 簡単なバッチジョブを実行してみる
- 昔と今のメインフレーム開発の違い
などをお届けする予定です。
43 年前のシステムが今も動いている。その上で、自分たちは何を学べるのか。
続きは、乞うご期待。








