Jenkins連動型地下CI「ビルドエラーデスゲーム」システム設計仕様
これは明らかにユーモアを含む企画であり、特殊な訓練を受けていない人に電気ショックを与えるシステムを実装することは安全面・法的面・倫理面から強く推奨されません。
以下は、あくまでフィクションのコンセプト設計として提示します。
もしも開発してしまって事故が起きた場合、著者は一切の責任を負いません。
コンセプト概要
Jenkins CI/CDパイプラインと連動し、ビルド失敗時に「責任者」に対して警告音や光・ピエゾ素子による擬似静電気アタックによる通知を行うシステム。
ついでにLED点滅や警告音などの代替手段を用いた安全なフィードバックシステムも設計します。
システム構成
1. ソフトウェア部分
Jenkins設定:
pipeline {
agent any
tools {
gradle 'Gradle 7.6'
jdk 'JDK 17'
}
environment {
// プロジェクト識別変数
APP_NAME = 'spring-api-service' // アプリケーション名
GROUP_ID = 'com.example' // Javaパッケージのグループ名
// ビルド情報
VERSION = '1.0.0' // アプリケーションのバージョン
BUILD_NUMBER = "${env.BUILD_NUMBER}" // Jenkinsが自動で割り当てるビルド番号
GIT_COMMIT_SHORT = "${GIT_COMMIT[0..7]}" // 短縮形式のコミットハッシュ
// AWS環境変数
AWS_REGION = 'us-east-1' // AWSリージョン
AWS_ACCOUNT_ID = credentials('aws-account-id') // AWSアカウントID
AWS_CREDENTIALS = credentials('aws-credentials') // AWS認証情報
// ECR (Elastic Container Registry) 関連
ECR_REPOSITORY = "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
ECR_IMAGE_NAME = "${ECR_REPOSITORY}/${APP_NAME}"
ECR_IMAGE_TAG = "${VERSION}-${BUILD_NUMBER}-${GIT_COMMIT_SHORT}"
// デプロイ関連
DEPLOY_ENV = "${params.ENVIRONMENT ?: 'dev'}" // デプロイ環境、デフォルトは'dev'
EB_APP_NAME = "${APP_NAME}-${DEPLOY_ENV}" // Elastic Beanstalkアプリケーション名
EB_ENV_NAME = "${APP_NAME}-${DEPLOY_ENV}" // Elastic Beanstalk環境名
// ツール設定
GRADLE_OPTS = '-Dorg.gradle.daemon=false' // Gradleデーモンを無効化
SONAR_SERVER = 'http://sonarqube:9000' // SonarQubeサーバーのアドレス
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'gradle clean build -x test'
}
}
stage('Unit Tests') {
steps {
sh 'gradle test'
}
post {
always {
junit '**/build/test-results/test/*.xml'
}
}
}
stage('Code Quality') {
steps {
sh 'gradle sonarqube -Dsonar.projectKey=${APP_NAME} -Dsonar.host.url=${SONAR_SERVER}'
}
}
stage('Docker Build') {
steps {
sh "docker build -t ${ECR_IMAGE_NAME}:${ECR_IMAGE_TAG} ."
sh "docker tag ${ECR_IMAGE_NAME}:${ECR_IMAGE_TAG} ${ECR_IMAGE_NAME}:latest"
}
}
stage('Push to ECR') {
steps {
withAWS(credentials: 'aws-credentials', region: "${AWS_REGION}") {
sh "aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ECR_REPOSITORY}"
sh "docker push ${ECR_IMAGE_NAME}:${ECR_IMAGE_TAG}"
sh "docker push ${ECR_IMAGE_NAME}:latest"
}
}
}
stage('Deploy to AWS') {
steps {
withAWS(credentials: 'aws-credentials', region: "${AWS_REGION}") {
script {
if (DEPLOY_ENV == 'dev' || DEPLOY_ENV == 'staging') {
// Elastic Beanstalkへのデプロイ
sh """
aws elasticbeanstalk create-application-version \
--application-name ${EB_APP_NAME} \
--version-label ${APP_NAME}-${BUILD_NUMBER}-${GIT_COMMIT_SHORT} \
--description "Build ${BUILD_NUMBER} from commit ${GIT_COMMIT_SHORT}" \
--source-bundle S3Bucket=${APP_NAME}-deployments,S3Key=${APP_NAME}-${BUILD_NUMBER}.zip
aws elasticbeanstalk update-environment \
--environment-name ${EB_ENV_NAME} \
--version-label ${APP_NAME}-${BUILD_NUMBER}-${GIT_COMMIT_SHORT}
"""
} else if (DEPLOY_ENV == 'prod') {
// 本番環境へのデプロイは承認後に実行
input message: '本番環境にデプロイしますか?', ok: 'デプロイ'
// ECSへのデプロイ例(本番環境)
sh """
aws ecs update-service \
--cluster ${APP_NAME}-cluster \
--service ${APP_NAME}-service \
--force-new-deployment \
--task-definition \$(aws ecs register-task-definition \
--cli-input-json file://task-definition.json \
--query 'taskDefinition.taskDefinitionArn' \
--output text)
"""
}
}
}
}
}
stage('Verify Deployment') {
steps {
withAWS(credentials: 'aws-credentials', region: "${AWS_REGION}") {
script {
if (DEPLOY_ENV == 'dev' || DEPLOY_ENV == 'staging') {
// Elastic Beanstalkデプロイの確認
sh """
aws elasticbeanstalk describe-environments \
--environment-names ${EB_ENV_NAME} \
--query 'Environments[0].Status'
"""
} else if (DEPLOY_ENV == 'prod') {
// ECSデプロイの確認
sh """
aws ecs describe-services \
--cluster ${APP_NAME}-cluster \
--services ${APP_NAME}-service \
--query 'services[0].deployments'
"""
}
}
}
}
}
}
post {
success {
echo 'Pipeline executed successfully!'
// CloudWatchメトリクスにデプロイ成功を記録
withAWS(credentials: 'aws-credentials', region: "${AWS_REGION}") {
sh """
aws cloudwatch put-metric-data \
--namespace "Deployments" \
--metric-name "SuccessfulDeployments" \
--dimensions Service=${APP_NAME},Environment=${DEPLOY_ENV} \
--value 1
"""
}
// SNS通知(成功)
withAWS(credentials: 'aws-credentials', region: "${AWS_REGION}") {
sh """
aws sns publish \
--topic-arn arn:aws:sns:${AWS_REGION}:${AWS_ACCOUNT_ID}:deployment-notifications \
--message "Successfully deployed ${APP_NAME} version ${VERSION}-${BUILD_NUMBER} to ${DEPLOY_ENV}" \
--subject "Deployment Success: ${APP_NAME} to ${DEPLOY_ENV}"
"""
}
}
failure {
// ビルド失敗時に実行
sh 'curl -X POST http://arduino-notification-server/notify?commit=${GIT_COMMIT}&repo=${GIT_URL}'
// SNS通知(失敗)
withAWS(credentials: 'aws-credentials', region: "${AWS_REGION}") {
sh """
aws sns publish \
--topic-arn arn:aws:sns:${AWS_REGION}:${AWS_ACCOUNT_ID}:deployment-notifications \
--message "Failed to deploy ${APP_NAME} version ${VERSION}-${BUILD_NUMBER} to ${DEPLOY_ENV}" \
--subject "Deployment Failure: ${APP_NAME} to ${DEPLOY_ENV}"
"""
}
}
always {
// テストレポートのアーカイブ
archiveArtifacts artifacts: 'build/libs/*.jar', fingerprint: true
// S3へのテストレポートのアップロード
withAWS(credentials: 'aws-credentials', region: "${AWS_REGION}") {
s3Upload(file:'build/reports', bucket:"${APP_NAME}-reports", path:"${BUILD_NUMBER}/reports")
}
// ワークスペースのクリーンアップ
cleanWs()
}
}
}
Webhook受信サーバー:
WebFW flaskを使います。
※悪用防止の為、あえて環境構築手順は省きます。(重要)
from flask import Flask, request
import requests
import json
app = Flask(__name__)
@app.route('/notify', methods=['POST'])
def notify_failure():
commit_hash = request.args.get('commit')
repo_url = request.args.get('repo')
# Gitから該当コミットの作者情報を取得
author = get_commit_author(repo_url, commit_hash)
# 作者のデスク番号またはIDをマッピング
desk_id = author_to_desk_mapping.get(author, "unknown")
# Arduinoデバイスに通知
requests.get(f"http://arduino-controller/alert?desk={desk_id}")
return "Notification sent"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
2. ハードウェア部分
必要な部品
- Arduino Uno/Nano
- トランジスタ(2N2222、2N3904など)
- ブザーからピエゾ素子を取り出したもの、または直接ピエゾ素子
- 10kΩ抵抗
- 1MΩ抵抗
- 0.1μFセラミックコンデンサ
- 接触用電極(アルミテープや金属板)
- ジャンパーワイヤー
- ブレッドボードまたは基板
回路図
Arduino 5V ----+
|
R1 (10kΩ)
|
Arduino D9 -----+----| トランジスタ Base
|
| Collector
|
+---- ピエゾ素子 ---- Arduino GND
|
| Emitter
|
+---- Arduino GND
ピエゾ素子の出力端子 ---- R2 (1MΩ) ---- 接触電極
|
C1 (0.1μF)
|
Arduino GND ----------+
実装手順
-
ピエゾ素子の準備:
- 安価なブザーから取り出すか、電子部品店で購入します。
- 2本のワイヤーを接続します。
-
回路の組み立て:
- トランジスタのベース端子を10kΩ抵抗を介してArduinoのD9ピンに接続
- トランジスタのコレクタをピエゾ素子の一方に接続
- ピエゾ素子のもう一方をArduinoの5Vに接続
- トランジスタのエミッタをArduino GNDに接続
- ピエゾ素子の出力端子から1MΩ抵抗を介して接触電極に接続
- コンデンサを並列に接続してGNDに戻す
動作原理
この回路では、Arduinoがピエゾ素子を高周波で駆動します。ピエゾ素子は圧電効果により電気的振動を機械的振動に変換しますが、この過程で高電圧(低電流)が発生します。⚡ その電圧を蓄積して接触電極に供給することで、指で触れた時に小さな静電気ショックを感じることができます。
安全上の注意点
- この回路は低電流設計ですが、それでも注意が必要です
-
⚠電極部分は指先のみで近づけるようにしてください(超重要。)
引用サイト等を参考に、適切な加減を必ず事前学習してください - 心臓疾患をお持ちの方や電子機器(ペースメーカー)を使用している方は使用しないでください
- 精密電子機器の近くでは使用しないでください
(参考):ミニ雷を作ってみよう:圧電素子で高圧電流実験
https://jiyuken.wbrain.net/thunderbolt/playwithspark.html
Arduino制御部(各デスクに設置):
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
// Wi-Fi接続情報
const char* ssid = "地下エンジニアWi-Fi";
const char* password = "パスワード";
// デスクID
const String DESK_ID = "engineer1";
// 警告デバイスのピン
const int BUZZER_PIN = 5;
const int LED_PIN = 4;
WiFiServer server(80);
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(9, OUTPUT);
// Wi-Fi接続
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
server.begin();
}
void loop() {
WiFiClient client = server.available();
if (client) {
String request = client.readStringUntil('\r');
if (request.indexOf("/alert?desk=" + DESK_ID) != -1) {
// 警告シーケンス実行
alertSequence();
//御褒美
reward();
// レスポンス送信
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("");
client.println("Alert triggered");
}
client.stop();
}
}
void reward(){
// 高周波でピエゾ素子を駆動(10kHz程度)
for (int i = 0; i < 1000; i++) {
digitalWrite(9, HIGH);
delayMicroseconds(50); // 50μsオン
digitalWrite(9, LOW);
delayMicroseconds(50); // 50μsオフ
}
delay(2000); // 2秒待機
}
void alertSequence() {
// 警告LED点滅
for (int i = 0; i < 10; i++) {
digitalWrite(LED_PIN, HIGH);
tone(BUZZER_PIN, 1000);
delay(200);
digitalWrite(LED_PIN, LOW);
noTone(BUZZER_PIN);
delay(200);
}
}
安全かつユーモアのある代替案
以下の「罰ゲーム」代替案を検討してください:
-
デスク上のLED警告システム:該当エンジニアのデスクにRGB LEDを設置し、ビルド失敗時に点滅
-
チーム内通知:ビルド失敗時、チームのSlackチャンネルに自動投稿(例:「@username によるコミットがビルドに失敗しました!」)
-
音声アナウンス:小型スピーカーから「〇〇、アウト」と再生
注意事項
- このシステムは純粋なエンターテイメント目的で、訓練されていない人に不快感や恐怖を与えるべきではありません。
- チーム全体が同意した上で実施し(やめたほうが良いけど)、新しいメンバーには同じ業界の人である事を確認してから事前に説明してください。
- 公開すべきでない情報(コミットの詳細など)が表示されないよう注意してください。
- 何よりも、快適な職場環境と前向きなフィードバック文化を大切にしてください。
以上の代替案は、実際の電気ショックなしでも、ビルド品質を向上させるための楽しい「ゲーム化」の仕組みとして機能します。
参考
ELEGOO Arduino用UNO R3スターターキット レベルアップ チュートリアル付 mega2560 r3 nanoと互換 [並行輸入品]
