/
カテゴリー

はじめまして!帝塚山大学の松 涼雅です。

ICTトラブルシューティングコンテストの参加は2回目となります。

今回は、HOT STAGE(会場内での準備期間)に入りましたので準備の模様を紹介します。

 

続きを読む

 /
カテゴリー

はじめに

はじめまして。北海道大学の小林巧です。
普段は@chamaharunというアカウントでくだらないことをつぶやいたり、
石狩市にあるデータセンターでサーバー構築のアルバイトをしたりしています。
ICTトラコン、「名前だけは知っている」程度だったのですが、
昨年さくらインターネット新卒の凄腕エンジニア川畑さんよりお声がけいただきまして、

右も左も分からぬまま学生運営スタッフにjoinしました。
僕も問題作成をさせていただいているので、解いていただけると嬉しいです。

 

自宅ラックとは

「自宅ラックとは、ロマンである。」

ニコニコ大百科「自宅ラック」より

とありますが、自宅にデータセンター向け規格の19インチのラックを設置して趣味その他に使用することを言うようです。

自宅ラックとの出会い

自己紹介にも書いたように、データセンターでのアルバイトをしているのですが、

仕事に慣れてくるにつれて、業務で行っているBIOSの設定などの作業だけでなく、
ハードウェア交換といった保守作業やWebやDNSなどのサーバ構築作業を行ってみたくなったのと、
自宅にあったMicroServerで出来ることにスペック的にも拡張性的にも限界を感じていたところに、

昨年11月、幸いにも引越しが決まり、新居にて自宅ラックを始めたのでした。

 

ラックが自宅に届いた時の感動を振り返ってみようと思います。

 

19インチの静音ラックをヤフオクで入手。
ラック内に機器の設置と配線を済ませ、電源を入れてみる。。。
「ファーーーーー」
って音、まるで自宅がDCになったかのようです。。。
さて、ラックの防音効果は如何ほどか、
サイドの蓋を閉め、前面のドアを閉めます。
「ゴオオオオオオオオオ」
全然静音じゃない。まるで轟音ラック。
これからは毎日これと共に寝るのか。
自宅ラック生活がスタートしました。

 

こばやしの自宅ラック

こんな感じです。

1

  •  DELL R415 8コア 8G
  • FUJITSU RX200S5 8コア 32GB
  • HP MicroServer N54L 2コア 16GB
  • HP MicroServer N54L 2コア  8GB
  • DELL PoerConnect 5224
  • HP MicroServer N54L 2コア 8GB

いずれも新品で揃えると150万円前後かかると思いますが、一学生に出せるような金額ではないので、
型落ちで安くなった新品を購入したり、ヤフオクや秋葉原で中古品を手にいいれることで、
10万円前後の支出に抑えました。
XenServerとHyper-Vによる仮想マシンが30-40台程度常時起動していて、

そのほとんどがWebサーバで、Webサービスを開発したり、友人に貸したりしています。

 

工夫していること・苦労していること

ドメインとIPアドレス

複数のWebサーバに外部からアクセスするにあたって、1つ問題があります。
VPSなどのインフラサービスと違って、一つのIPアドレス共有しなければならないので、
HTTPのリクエストも、SSHも直接IPアドレスに対して繋ぎに行くわけには行きません。

そこで、HTTPとSSHにそれぞれ、代理サーバを用意しています。

ルータから特定のポートに来た通信をそれぞれに転送するよう設定します。

nginxでは以下のような設定ファイルを書くことで簡単にリバースプロキシを構築することができます。

 

server {
    listen 80;
    server_name hime.charakoba.com;

    proxy_set_header    X-Real-IP       $remote_addr;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header    Host            $http_host;
    proxy_redirect      off;
    proxy_max_temp_file_size    0;

    location / {
        proxy_pass http://192.168.11.125;
    }
}

 

特に、HTTPのリバースプロキシは設定ファイルの書き換え/再読み込みを頻繁に行うので、

図のように、ロードバランサを置いて片方のリバースプロキシがダウンしていても正常にリクエストに答えられうようにしています。

3

SSHの踏み台サーバは、よりセキュリティを意識して構築しています。

rootでのログイン禁止はもちろん、

全ユーザーに対して公開鍵認証を要求しパスワード認証を禁止します。

こばやし家内のサーバにアクセスする場合は、

踏み台サーバに対して一度SSHログインしたのち、対象のサーバにSSHでログインします。

2

 

一般の家庭であるこばやし家には動的IPアドレスが一つ割り当てられています。

変動するIPアドレスにドメインを割り当てる方法として、IPアドレスが変更される度にDNSサーバに通知し更新してもらう、

DDNS(DynamicDNS)というものがありますが、DDNSで設定できるドメインってあまりカッコいいイメージが無かったので、

何か良い方法はないかと調べていたところ、

お名前.comで取得したドメインはDDNSで使えそうということがわかり、

WindowsServerでクライアントを設定し運用しています。

 

 

最後に・こばやしのやぼう

他にも、新規仮想マシンを作成した際にあらゆる設定を自動化するような実験などを行っています。
今後は騒音と電気代の面から自宅ラックを実家に移設し、
VPNを張って遠隔で管理したりしていこうかと考えています。

まだまだこばやし家は発展途中ですがこういった工夫をすることで、
IT企業が普通に行っていることを高価な機器を使わずに実現できたらなぁと考えています。

 /

はじめまして!大阪工業大学の藪野好一です。
ICTトラブルシューティングコンテストは初参加となります。普段は、大学でルーターやスイッチを触ってネットワークの勉強をしています。トラブルシューティングコンテストでは、問題作成の担当をしております。問題は、大会当日の楽しみとして頂いて、今回はWEBアプリケーションについて書きたいと思います。

はじめに

WEBページは、ページを見る人の端末(クライアント側)で処理したページとサーバー側で処理を行った結果を表示するページそしてそれらを組み合わせたページがあります。今回は、クライアント側で動くWEBアプリケーションを例にWEB技術の紹介をしたいと思います。

WEBアプリケーションで使われている技術例としてHTML、CSS、JavaScriptがあります。
HTML、CSS、JavaScriptとは何かをざっくり言うと、

  • HTMLはページの大まかな構成を定義するもの
  • CSSはページのデザインの調整をするもの
  • JavaScriptはページに動きをつけるもの

となります。

例えてみると

ここで、これらを家に例えてみると以下のようなイメージとなると思います。

  • HTMLは、設計図や基礎のようなもの
  • CSSは、壁の材料や家のデザイン
  • JavaScriptは、電化製品や家具のようなもの

これらのクライアント側技術を組み合わせて、クライアント側で動くWEBアプリケーションを作ることが出来ます。WEBアプリケーションは、CSSやJavaScriptに対応したブラウザがあれば、どのような端末からでも使うことが出来るので、大きな可能性のある技術だと私は考えています。指定した日付に変わるまでの時間をカウントダウンするWEBアプリケーションを作成したのでそのソースコードを使って紹介したいと思います。

プログラム例

time-counter-screen

HTML

  
<!DOCTYPE html>
<html lang="ja">
<head>
 <meta http-equiv="Content-type" content="text/html; charset=UTF-8">
 <title>カウントダウン</title>
 <script src="js/jquery-1.11.3.js"></script>
 <link rel="stylesheet" type="text/css" href="css/style.css">
 <script src="js/timecounter.js" type="text/javascript"></script>
 <link rel="shortcut icon" href="favicon.ico" />
</head>
<body>
 <div id="clock"></div>
 <div id="printArea"></div>
 <div id="searchArea"></div>
</body>
</html>

このように、HTMLのヘッダーには、ページに関する情報のほか読み込みたいCSSやJavaScriptの情報を記述します。
bodyには、どこに、どのような要素を置くという情報を記述します。一般的なWEBページにある、タイトルや見出し、リンク、リストといった要素はここに書きます。
今回作成したWEBアプリケケーションは、時計を表示する場所、日数を表示する場所、調べたい日付を入力する場所の3つの場所をHTMLファイルで定義しました。

ファビコン(favicon.ico)は、ブラウザでページを表示した際にタイトルの横に出てくるアイコンのことです。画像からファビコンを作成することが出来るサイトもあります。

CSS(style.css)

@charset "utf-8";

table {
	border-collapse: separate;
	border-spacing: 15px 5px;
	margin: 0 auto;
}

th{
	background-color:#00A0E9;
	color: #FFF;
	margin: 10px;
	padding:5px;
	border-top-left-radius: 10px;
	border-top-right-radius: 10px;
	-webkit-border-top-left-radius: 10px;
	-webkit-border-top-right-radius: 10px;
	-moz-border-radius-topleft: 10px;
	-moz-border-radius-topright: 10px;
	font-size: 1.7em;
}
td{
	text-align:center;
	background-color:#EEEEEE;
	border-bottom-left-radius: 10px;
	border-bottom-right-radius: 10px;
	-webkit-border-bottom-left-radius: 10px;
	-webkit-border-bottom-right-radius: 10px;
	-moz-border-radius-bottomleft: 10px;
	-moz-border-radius-bottomright: 10px;
	font-size: 1.8em;
}

#clock{
	font-size:4em;
	width:1080px;
	margin: 0 auto;
	padding : 10px;
}
#printArea {
	font-size:4em;
}
.printClock{
	width:200px;
	float:left;
	height:60px;
	background:#123456;
	color:#FFF;
	text-align:center;
	vertical-align: middle;
	border-radius: 10px;
	-moz-border-radius: 10px;
	-webkit-border-radius: 10px;
	margin: 15px auto;
}
.clockSpace{
	width:15px;
	height:40px;
	vertical-align: middle;
	float:left;
	padding:0 5px;
}
.clearArea{
	clear:both;
	vertical-align: middle;
}

#searchArea{
	text-align : center ;
	padding:15px;
}

button {
	margin: 0 0 0 20px;
	font-size: 1.4em;
	font-weight: bold;
	padding: 10px 30px;
	color: #fff;
	border-style: none;
	border-radius: 5px;
	-moz-border-radius: 5px;
	-webkit-border-radius: 5px;
	background:#064583;
	transition: all 1s;
}

button:hover {
	opacity: 0.8;
}

input{
	width:300px;
	height:60px;
	font-size:2em;
}

#searchArea{
	font-size:1.4em;
}

body{
	animation: bg-color 60s infinite;
}


@keyframes bg-color {
	0% { background-color: #B3E5FC; }
	10% { background-color: #B2DFDB; }
	20% { background-color: #C8E6C9; }
	30% { background-color: #F0F4C3; }
	40% { background-color: #FFF9C4; }
	50% { background-color: #FFECB3; }
	60% { background-color: #ffcdd2; }
	70% { background-color: #F8BBD0; }
	80% { background-color: #E1BEE7; }
	90% { background-color: #C5CAE9; }
	100% { background-color: #B3E5FC; }
}

CSSはデザインの定義を行うために書きます。タグやid、classを指定することが出来ます。

  • タグは、タグ名
  • idは、#id名
  • classは、.class名

で指定を行います。また、これらを組み合わせて、指定することも出来ます。

HTMLは入れ子で定義出来ます。

#idname .classname{
/*指定したい内容*/
}

と書くとid名がidnameの要素の中にある、class名がclassnameという要素を指定することになります。

ただし

#idname, .classname{
/*指定したい内容*/
}

と書くとid名がidnameの要素と、class名がclassnameという要素の両方を同時に指定することになるのでこれらの書き間違いには注意が必要です。

ところで、CSS3対応のブラウザなら、JavaScriptを使うことなく、アニメーションを実現することが可能なのでいろいろ調べてみると面白いかと思います。例えば、102行目から119行目では背景色を60秒の間に指定した10色で順番に色を変えるという指定をしています。とても簡単に指定することが出来るのでいろいろ試してみてください。

JavaScript(timecounter.js)

JavaScriptを用いることで、動きのあるページを作ることが出来ます。今回作成したページは、jQueryというJavaScriptのライブラリを使っています。jQueryを使用することにより簡単にプログラムを実装することが出来るため、多くのWEBサイトやWEBアプリケーションで利用されています。

https://jquery.com/

 

timecounter.jsは、大きく分けて指定した日までの残り時間を表示する関数と時計を表示する関数の2つの関数が宣言されています。それらを定期的に実行することで時間とともに表示が変化します。
main関数は、jQueryを使っているため、functionの前に$が付いています。「$」は、「jQuery」の省略記号です。

//main関数
$(function() {
		init();

		setInterval(function(){

		var now_date = new Date();
		var now_year = now_date.getFullYear();
		var now_month = now_date.getMonth()+1;
		var now_day = now_date.getDate();

		var date = $(":input[name='search_date']").val();
		target_year = parseInt(date.substring(0,4));
		target_month = parseInt(date.substring(5,7));
		target_day= parseInt(date.substring(8,10));

		var remain_day = remainCount(now_year, now_month, now_day, target_year, target_month, target_day);

		$("#printArea").empty();
		var table = $('<table>');

		var th = $('<tr>')
			.append('<th colspan="4">' + target_year +"年" + target_month + "月"+ target_day +"日まで"+'</th>');

		table.append($('<thead>').append(th));

		var tbody = $('<tbody>');
		table.append(tbody);

		if(remain_day > 0){
			var td = $('<tr>')
				.append('<td>' + (remain_day-1) + '日' + '</td>')
				.append('<td>' + sToh(todayRemainSecond()) + '時間' + '</td>')
				.append('<td>' + sTom(todayRemainSecond()) + '分' + '</td>')
				.append('<td>' + sTos(todayRemainSecond()) +'秒</td>');
			}else{
				td = $('<tr>')
					.append('<td>エラー</td>')
					.append('<td></td>')
					.append('<td>計算</td>')
					.append('<td>出来ません</td>');
			}

		table.append(td);
		$("#printArea").append(table);
	  },1000);

		$(function() {
			$("#searchArea").on("click","#notPrint",function(){
				$("#searchArea").css("display","none");
			});
		});
		$('#printArea').hover(function(){
			var date = $(":input[name='search_date']").val();

			var p = $('<p>')
				.append('<input type="date" name="search_date" size="4" value="' + date + '">')
				.append('<button id="notPrint">閉じる</button>');
			$('#searchArea').empty();
			$('#searchArea').append(p);
			$("#searchArea").css("display","block");

		});
});

//初期設定(フォームに次の日の日付をセットする)
function init(){
	$(function(){

		var tomorrow = findTomorrow();

		var p = $('<p>')
				.append('<input type="date" name="search_date" size="4" value="' + tomorrow + '">')
				.append('<button id="notPrint">閉じる</button>');
		$('#searchArea').append(p);
	});
}

//うるう年かどうかを判定
function isLeapYear(year){
	if(year % 4 == 0){
		if(year % 100 == 0 && year % 400 != 0){
			return false;
		}else{
			return true;
		}
	}else{
		return false;
	}
}

//指定した月の日付を求める
function monthDay(month, year){
	if(month == 2){
		if(isLeapYear(year)){
			return 29;
		}else{
			return 28;
		}
	}else if(month == 4 || month == 6 || month == 9 || month == 11){
		return 30;
	}else{
		return 31;
	}
}

//n_yearの次の年の1月1日からt_yearの前の年の12/31までの日数を返却
function addYearDay(n_year, t_year){
	var i = n_year + 1;
	var total = 0;

	//指定した年までの年数分365を足す
	while(i<t_year){
		if(isLeapYear(i)){
			total++;
		}
		total += 365;
		i++
	}
	return total;
}

//指定した日までの日数をカウント(年をまたぐ指定は出来ない)
function counter(year,n_month,n_day,t_month,t_day){
	var count= 0;
	var i = n_month + 1;
	while(i< t_month){
		count += monthDay(i,year);
		i++;
	}
	if(n_month == t_month){
		count -= monthDay(n_month,year);
	}
	count = count + remainDay(n_day, monthDay(n_month, year)) + t_day;
	return count;
}

//指定した日から指定した日までの日数を数える 過去を指定した場合は-1を返す
function remainCount(now_year, now_month, now_day, target_year, target_month, target_day) {
	if(!dec(now_year, now_month, now_day, target_year, target_month, target_day)){
		return -1;
	}
	var count = 0;
	count += addYearDay(now_year, target_year);
	var diff = target_year - now_year;

	if(diff == 0){
		count = counter(now_year, now_month, now_day, target_month, target_day);
	}else{
		//今年の残り日数と指定した年の指定した日までの日数をカウントする
		count += counter(now_year, now_month, now_day, 12, 31);
		count += counter(target_year, 1, 1, target_month, target_day);
	}
	count--;

	return count;
}

//過去かどうか判定
function dec(now_year, now_month, now_day, target_year, target_month, target_day){
	if((now_year * 10000 + now_month * 100 + now_day) > (target_year * 10000 + target_month * 100 + target_day)){
		return false;
	}else{
		return true;
	}
}

//指定した日までの日数を求める。年や月をまたぐ場合使用できない
function remainDay(n_day, t_day){
	var rem =  t_day - n_day + 1;
	return rem;
}

//1から9の一桁の数字を0X形式に変換
function toTime(int_num) {
    var ret;
    if (int_num < 10) {
        ret = "0" + int_num;
    }else {
        ret = int_num;
    }
    return ret;
}
//指定された日数と今日の残り時間を秒に変換して返却
function secondCount(today_remain_second, remain_day){
	var oneday = 86400;//60*60*24
	return today_remain_second + (remain_day -1) * oneday;
}

//今日の残り時間を秒で返却
function todayRemainSecond(){
	var date = new Date();
	var n_hour = date.getHours();
	var n_minute = date.getMinutes();
	var n_second = date.getSeconds();

	var oneday = 86400;//60*60*24

	var pass_time = n_hour * 3600 + n_minute * 60 + n_second;
	return oneday - pass_time;
}

//秒を時間に変換(分と秒を切り捨て)、
function sToh(second){
	return toTime(Math.floor(second/3600));
}

//秒を時間に変換したあまりの時間を分に変換(秒を切り捨て)、
function sTom(second){
		return toTime(Math.floor(second % 3600 / 60));
}

//分を時間に変換したあまりの時間を秒に変換、
function sTos(second){
	return toTime(Math.floor(second % 3600 % 60));
}

//明日の日付をXXXX-YY-ZZ形式で返却
function findTomorrow(){
	var date = new Date();
	var year = date.getFullYear();
	var month = date.getMonth()+1;
	var day = date.getDate();

	return findNextDay(year, month, day);
}

//指定された次の日をXXXX-YY-ZZ形式で返却
function findNextDay(year, month, day){
	//dayを1日増やし、その月の最終日をXXXX-YY-ZZ形式で返却
	if(++day > monthDay(month, year)){
			month++;
			day = 1;
			if(month == 13){
				year++;
				month = 1;
			}
	}
	return "" + year +  "-" +toTime(month) + "-" + toTime(day);
}

//時計を表示
function clock() {
    var t_date = new Date();
    var month = t_date.getMonth()+1;
    var day = t_date.getDate();
    var year = t_date.getFullYear();

    var n_hour = t_date.getHours();
    var n_minute = t_date.getMinutes();
    var n_second = t_date.getSeconds();
    var n_day = t_date.getDay();
    var week = ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"];

   var p_date = "<div class ='printClock'>"
		+ year + "年</div>"
		+ "<div class='clockSpace'></div>"
		+ "<div class ='printClock'>"
		+ toTime(month) + "月</div><div class='clockSpace'> </div>"
		+ "<div class ='printClock'>"
		+ toTime(day) +"日</div><div class ='clearArea'></div>";

    var time = "<div class ='printClock'>"
		+ toTime(n_hour) + "時</div>"
		+ " <div class='clockSpace'> </div> "
		+ "<div class ='printClock'>"
		+ toTime(n_minute) + "分</div>"
		+ "<div class='clockSpace'> </div>"
		+ "<div class ='printClock'>"
		+ toTime(n_second) + " 秒</div><div class='clockSpace'> </div>"
		+ "<div class ='printClock'>"+ week[n_day]
		+"</div><div class ='clearArea'></div>";
    document.getElementById("clock").innerHTML = p_date + time;


}
setInterval('clock()', 1000);

今回のカウントダウンプログラムは、

  • 何年先かをカウント
  • 1年より先なら年数分数値を足す
  • 今年の残りの日付を計算
  • 指定された年の指定した日までの日付を計算
  • これらを合計する
  • 求めた値を整えて表示

という処理手順で実行します。

その処理をsetInterval関数で1000ミリ秒に一度実行することより自動的にカウントダウンが行われるようにしています。1ミリ秒とは0.001秒のことです。従って、1000ミリ秒は1秒となります。

//関数名:kansu 実行間隔1000ミリ秒
setInterval('kansu()', 1000);

jQueryの場合は、関数を引数に取るので次のように書きます。
function()は、名前のない関数で無名関数と呼ばれています。

//jQueryの場合
$(function(){
	setInterval(function(){
        	//ここに処理を書く
	},1000);
});

jQueryはcssの操作も簡単に出来ます。作成したプログラムでも、jQueryを使ってCSSを操作し、検索ボックスの表示、非表示を切り替えています。以下のように指定することにより実装出来ます。なお、セレクタはCSS同様にHTMLタグやHTMLで定義したID名やクラス名で指定します。

	$("セレクタ").css("display","none");
	//セレクタで指定した部分を非表示にする。

	$("セレクタ").css("display","block");
	//セレクタで指定した部分を表示にする

jQueryのマウスイベント

マウスのクリックや、マウスがある要素の上に乗ったことをきっかけとして処理を行うことをマウスイベントと言います。今回マウスクリックの例を紹介したいと思います。

	//クリックしたときに関数を実行
	$(function() {
		$("セレクタ").click(function(){
			//実行する処理
		});
	});

のように書けば、セレクタ名で指定した場所がクリックされれば関数が実行されます。しかし、JavaScriptでHTMLのソースを作って要素の追加を行った場合、この方法では上手く動作しません。そこで、次のように記述します。

	$(function() {
		//セレクタ1 HTMLコードを追加したセレクタ
		//セレクタ2 クリックを認識してほしいセレクタ
		$("セレクタ1").on("click","セレクタ2",function(){			
			//実行する処理
		});
	});

この方法なら、動的に追加された要素であっても正しく動作すると思います。

サンプルプログラムの使い方

HTMLヘッダーのようにファイルを配置すれば、プログラムを使って頂けるかと思います。
jQueryに関しては以下のページからダウンロードするか、ヘッダーでjQueryを読み込んでいる部分を

	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>

に書き換えて実行してみてください。

 

http://jquery.com/download/

 

画像のファイル配置と同じ配置にすれば動くはずです。

filepath

syntaxhighlighter

syntaxhighlighterとは、プログラムのソースコードをWEBページ上でテキストエディターのようにきれいに表示してくれるプラグインのことです。
このブログや、解説サイトで使われているのでご存知の方もいらっしゃるかもしれませんが紹介だけしたいと思います。
簡単に導入でき、ソースコードが読みやすくなるので是非導入してみてください!

http://alexgorbatchev.com/SyntaxHighlighter/

 

最後に

JavaScriptのプログラムは急いで作成したのでバグが含まれている可能性があります。バグを発見したり、もっとコードをきれいに書く方法があれば、教えて頂けると嬉しいです。それでは、大会本番でお会いしましょう!

最近のコメント