企画書より強力な一言、「とりあえず一度見せてください」
公共機関のSI現場で一人で開発を担うことになった私にとって、最大の壁は技術ではなかった。まさに「不確実性」だった。緻密な要件定義書に従って設計が進む理想的な環境などなかった。開発知識が乏しい担当者は、画面を直接見るまで自分が何を望んでいるのかすら分からないことが多かった。
「うーん、絵で見てもよく分からないけど…実際に押してみることはできませんか?」
私は機能を一つ作るたびに、ローカル(自分のPC)で実行し、画面をキャプチャし、赤ペンで注釈を入れた「報告書ファイル(HWP/PPT)」を毎回作成してメールで送っていた。しかし静的な画像だけでは担当者を満足させられなかった。
「あ、さっきの機能のほうが良かったみたい。元に戻してください。」「このボタンを押すとどうなりますか?動画で撮ってください。」
昨日はAがいいと言っていたのに、今日はBを求める。ローカルでコードを修正し、再キャプチャし、報告書を書く無限ループ。開発時間より報告書作成時間のほうが長くなる本末転倒な状況だった。
私は痛切に悟った。「自分のPC画面をキャプチャして送るのではなく、担当者が直接アクセスして思う存分クリックして壊してみることができる遊び場(開発サーバー)が必要だ。」

機会は偶然訪れる:捨てられたサーバーの再発見
ちょうど会社分割の過程で、運良くうちのチームに割り当てられた遊休サーバー(空のPC)が一台できた。スペックは良くなかったが、Linuxがインストールされ、グローバルIPが繋がっている貴重なリソースだった。
「リーダー、この余っているサーバーを使ってもいいですか?担当者の確認用サーバーとして構築したいんです。」
許可は下りた。私はこの空っぽのサーバーに、これまで学んだすべての技術を注ぎ込んで「自分だけの小さなインフラ帝国」を建設し始めた。これは過去数か月の試行錯誤(Works on My Machine & The Pipelineシリーズ)を総まとめする作業だった。
- GitLab(コードリポジトリ): プライベートリポジトリを構築し、コードを安全に管理する。
- Docker Registry(イメージリポジトリ): ビルドしたDockerイメージを保管する、自分たちだけの倉庫をつくる。
- Portainer(コンテナ管理): CLIが怖い私のために、DockerをGUIで管理できるようにする。
- Nginx(Webサーバー): フロントエンドとバックエンドへのリクエストを交通整理してくれる門番を立てる。

解決策:環境の完全な分離(Dev vs Prod)
これで私には二つの舞台(Server)ができた。担当者の気まぐれを受け入れつつ、本番サーバーを守るためデプロイ戦略を分離した。
- 開発サーバー(Development):「自由な実験室」
- 担当者に「あれ、できましたか?」と聞く隙すら与えない。
developブランチにコードが上がると、パイプラインが即座に回って自動デプロイされる。- 担当者はいつでも開発サーバーのURLにアクセスして機能をテストし、フィードバックをくれる。
- 本番サーバー(Production):「検証済みの聖域」
- 担当者が「この機能で最終確定です!」と宣言したときだけデプロイされる。
masterブランチにコードをマージ(Merge)し、私がGitLabで「デプロイ承認ボタン」を押したときだけ(Manual)デプロイされる。
[Code Verification] 条件付きデプロイで秩序をつくる
GitLab CIはブランチごとにデプロイ先を変えて指定できる。この戦略をコードで実装すると次のようになる。
stages:
- build
- deploy
# 1. ビルド(共通)
build_job:
stage: build
script:
- ./gradlew build
- docker build -t my-reg/app:$CI_COMMIT_SHA .
- docker push my-reg/app:$CI_COMMIT_SHA
# 2. 開発サーバーへデプロイ(自動)
# 'develop' ブランチにコードが上がれば、問答無用でデプロイする。
deploy_to_dev:
stage: deploy
script:
- ssh user@dev-server "docker service update --image my-reg/app:$CI_COMMIT_SHA app-dev"
only:
- develop
# 3. 本番サーバーへデプロイ(手動承認)
# 'master' ブランチにコードが上がっても、自分がボタンを押すまではデプロイされない。
deploy_to_prod:
stage: deploy
script:
- ssh user@prod-server "docker service update --image my-reg/app:$CI_COMMIT_SHA app-prod"
only:
- master
when: manual # 重要!「人がボタンを押したときだけ」実行される。
核心ポイント:
only: - develop: 開発ブランチは無条件で自動デプロイ。スピードが命だ。when: manual: 本番ブランチには、人がもう一度確認してから押す安全装置を設ける。
おわりに:ついに完成した「一人で生きる」
これで一人開発者である私にも完璧なシステムが整った。
- ローカル(Local): 自分のPCで機能を開発。
- 開発(Dev):
git push一発で、5分後には開発サーバーに反映。担当者が直接確認する。 - 本番(Prod): OKが出た機能だけを集めて、クリック一つで安全にデプロイ。
入社初期、キャプチャツールを起動してHWPファイルに注釈を入れながら残業していた私はもういない。担当者が「これちょっと変えてください」と言えば、「はい、修正して開発サーバーに上げたので確認してください」と言いながら、ゆったりとコーヒーを飲めるようになった。システムが私の代わりに働いてくれているからだ。
これで長かった[Re: Booting]プロジェクトの幕を閉じる。CSの基礎から始まり、Linux、Docker、そしてCI/CDパイプラインまで。手探りで積み上げてきたこの知識が、今もどこかで一人奮闘しているであろう「生計型フルスタック開発者」たちにとって、小さな灯火となることを願う。


