LifeWrite

気が向いたら書きます

株を始めました。

1週間前に、ドリコムが確実に上がると思ったので始めました。

口座開くのに時間かかってその間に株価200円も上がったのが悔やまれる。

 

現物のみ、50万からスタート。中期目的です。

 

保有

ドリコム 保300 → +47,100円

 

きららファンタジア期待です。

ソーシャルゲームを運営してる身としては、どういうゲームがユーザーさんに人気が出るか大体わかっているつもりなので頑張ります。マギアレコードよりは売れます。ただキャラが多いのでユーザーさんにとっての価値は分散しそう。

 

株を始めてこの1週間色々なゲーム銘柄(ゲーセク等)見ましたが、他に面白そうなゲームだそうとしてる所はあまりないですね。

サイバーステップも上げてますが中国のゲームが個人的に材料に見えない...

でも株価が上がるって事はそれも株って事なんですかね。

方針としてはゲームの場合は株価やそれまでの会社の業績ではなく、期待出来るかで見ていきます。決算がよくても材料がなければ買いません。

ゲーム以外だとそれまでの業績も気にしますが・・・。

ニトリってすごいなぁと思ったり。

 

気になる銘柄

カヤック (何かやってくれそう、でも材料がないのでまだ下げそう。 1336

クックパッド (今が底値の気がする、でも材料なし。 776

ブロッコリー(底値な気がするが、材料なし、そもそも買えない 627

 

 

株式会社INDETAILを退職します。

※ネガティブな記事を期待している人はごめんなさい

この記事は大手企業の退職エントリーが多い中、中小企業でも沢山いい会社はあるという事を伝えたい。

その中でINDETAIL(https://www.indetail.co.jp/)がどういう風な会社だったかを伝える記事です。

INDETAILでは1年間ソーシャルゲームの運営エンジニアとして勤務していました。

INDETAILが何をやっている会社か

1.マイネットと業務提携を行いソーシャルゲームの運営を行うの部署
2.ブロックチェーン等の新しい技術への取り組みを行うの部署
3.案件を提案し受託開発を行う部署

やってることは上記の3つに分かれています。

私はソーシャルゲーム運営の部署なので、そこについて書いていきます。

ゲーム運営って地味そうじゃない?

「ゲーム運営」と聞くと、開発と違い同じ事をやり続けるみたいなイメージでつまらなそうと言う人が多いと思います。

開発は1からサービス自体を作れるという利点があります。

確かに運営にはそれはありません、しかし開発にはない運営の一番いい点は

ユーザーの反応を直ぐにダイレクトに受け取れるということです。

開発は大抵年単位で行いますが、運営の場合は新規イベント等を追加するサイクルが短いので、自分が作ったものが直ぐにユーザーに届けられ、その反応を直ぐに確かめることが出来ます。

業務について

プロジェクトの技術的には下記の感じです。

クライアントサイド

coffee script

backborn.js

サーバーサイド

fuelphp

等言語的には古めですね。

あとはjenkinsで自動化したりですね。

プロジェクト自体は小規模でしたので新規イベントの作成や 定期的にあるゲーム内のイベント(グラブルで言えば古戦場等)の実施、 ユーザーさんからのメールの調査や不具合対応、AWSのコスト削減などをやってました。

また、プロジェクトに入る前はオンプレのサーバーで、ちょうどAWSに移管するというタイミングでjoinできたので AWSの知識や、移管するためにゲーム全体のインフラやフロントサイド、自動化の仕組み等を見ることが出来てすごくいい経験になりました。

やめた理由

・自分の知識、経験を積むに当り、より規模が大きい場合のインフラ周りの知識を得たいという思い

・もっと情報をキャッチアップできる環境に身を置きたい

・とにかく知らないことをもっと知りたい

多分エンジニアとしてよくある欲求だと思います。

INDETAILのススメ

上記の様に書きましたが、人間環境などや職場環境は大変恵まれていました。

たった1年しか勤務してませんでしたが、やめる際もいつでも戻って来ていいよ等と声をかけていただいたり、お菓子をもらったり・・・ありがとうございます! f:id:abot_s:20170922193816j:plain 山岡家部のみなさまは活動がんばってください。

こういうブログを書くことによって札幌にもこういうベンチャー企業があるんだという事を知ってもらいたいです。

INDETAILという会社に少しでも興味を持って頂いて(見る人は少ないと思いますが・・・)会社が今後も発展してくれれば幸いです。

・会社の雰囲気

人がとにかくいいです。相談したり出来る雰囲気がちゃんと作られていて(雑談等も)すごい話しやすいです。

エンジニアの交流会やりたいっていったらちゃんと開催してくれます。(食事等会社が出してくれます)

1on1とかが定期的にあり、個々のやりたい事等を上司が吸い上げてくれちゃんと反映されます。

・こんな人おすすめ

ゲーム業界に興味があるけどそんな業務の経験ないという方

北海道みたいなの落ち着いたところで働きたい、けど東京で仕事するみたいに新しいことにも取り組みたい方(ブロックチェーン等)

そんなエンジニアの方はINDETAILがオススメですよ!(宣伝

興味ある方はいくらでも教えますので、ご連絡ください。

今後

DeNA Games Tokyoに入社予定です(http://denagames-tokyo.jp/

単純に規模が大きくなるので、今まで得られなかった知見等得られるのが今から楽しみです。

そうして経験したこと等を、私自身もっと発信していけるようにしていきたい。

AutoScaleを設定し、lambdaでAMIとAutoScaleの設定を自動更新する

今回はAuto Scaleの設定のまとめです。

概要

負荷分散のためにAutoScaleを検討することはよくあることです。

ゲームのイベントなどでは負荷がかかる時間帯が決まっているので、常時起動しているサーバーを減らしAutoScaleのスケージュールで設定することで費用を抑えることが出来ます。

※AutoScaleは起動に時間がかかるので、スケーリングポリシーでは突発的な負荷に対応できないのでスケジュールを使っています。

問題点

AutoScaleを設定した場合、設定しているAMIのassetやsourceが起動中のインスタンスと違うといった事が起こります。

そういった場合にAMIを更新し、自動的AutoScaleに割り当てる設定を行います。

AutoScaleグループの作成

今回の設定は元々あるAutoScaleグループの設定を置き換えるので先にAutoScaleグループを作成しておきます。

AWSコンソールの[AUTO SCALING]→[起動設定]→[起動の作成]

f:id:abot_s:20170731164200p:plain

※ここの起動設定は最終的に使わないので適当でOKです

AWSコンソールの[AUTO SCALING]→[AUTO SCALINGグループ]→[AUTO SCALINGグループの作成]

f:id:abot_s:20170731164457p:plain

上記の起動設定を選択、下記を設定

・ネットワーク

・グループ名

・ロードバランシング

※今回はスケジュールなのでスケーリングポリシーは設定しない ※通知を使用するとauto scaleの情報をlambda等に引き渡して色々出来ます。 ※タグを使いauto scaleで作成されたインスタンスに適用できます。

※ここで作成したAUTO SCALINGグループの名前を控えておきます。

lambdaを設定

f:id:abot_s:20170731170036p:plain ・[Blank Function]→リストから[CloudWatch Events]を選択 ・ルール:新規のルール ・ルール名:任意 ・ルール説明:任意 ・ルールタイプ:スケジュール ・スケジュール式:cron(0 * * * ? *) ※cronの設定と同じ、上記は1時間毎 ・トリガーの有効化にチェック f:id:abot_s:20170731170404p:plain

・名前:任意 ・説明:任意 ・ランタイム:python f:id:abot_s:20170731170915p:plain

・ロール:[カスタムロールの作成]を選択、IAMに下記をアタッチし作成、再度[既存のロールを選択]で作成したIAMを選択

f:id:abot_s:20170731171308p:plain

・コード:下記を貼り付けて***の部分を自分の環境に置き換える

import boto3
import time
from botocore.client import ClientError
from datetime import datetime, timedelta, tzinfo
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)

ec2 = boto3.client('ec2')
autoscaling = boto3.client('autoscaling')

instance = "***" #コピー元のec2インスタンスID(例:i-22a9edc2ted27d2a1)
device_name = "***" #コピー元のec2のブロックデバイス(例:/dev/sda1)
image_prefix = "***" #amiの名前の識別子(任意※他のAMIで使っていない文字)
launch_prefix = "***" #auto scaleの起動設定の名前の識別子(任意※他の起動設定で使っていない文字)
ec2_volume_size = *** #ebsのボリュームサイズ(単位:GB)
ec2_volume_type = "***" #ebsのボリュームタイプ(例:gp2)
secrity_group = [***] #ec2インスタンスのセキュリティグループ
ec2_instance_type = "***", #ec2インスタンスタイプ(例:c4.2xlarge)
ec2_key_name = "***", #ec2インスタンスのキーペア名
auto_scaling_group_name ="***",#作成したAutoScaleGroup名


def lambda_handler(event, context):
    try:
        dstr = datetime.now().strftime('_%Y-%m-%d-%H-%M-%S_') + instance
        logger.warning("create ami:%s" % (dstr))
        new_ami = ec2.create_image(Name=image_prefix + dstr ,InstanceId=instance,NoReboot=True,DryRun=False)
        recv = ec2.describe_images(Owners=['self'])
        list=[]
        target = image_prefix
        for img in recv['Images']:
            if target in img['ImageLocation']:
                list.append(img)
        s_list = sorted(list,key=lambda h: h['CreationDate'])
        if len(s_list) > 0:
            del_target = s_list[0]
            logger.info("delete ami:%s" % (del_target['Name']))
            ec2.deregister_image(ImageId=del_target['ImageId'],DryRun= False)
        dstr = datetime.now().strftime('_%Y-%m-%d-%H-%M-%S')
        logger.info("create auto scale launch config:%s" % (dstr))
        device = {}
        device['DeviceName'] = device_name
        ebs = {}
        ebs['VolumeSize'] = ec2_volume_size
        ebs['VolumeType'] = ec2_volume_type
        ebs['DeleteOnTermination'] = True
        device['Ebs'] = ebs
        device_mapping = [device]
        launch_name = launch_prefix + dstr
        
        res = autoscaling.create_launch_configuration(
            LaunchConfigurationName = launch_name,
            ImageId = new_ami['ImageId'],
            InstanceType = ec2_instance_type,
            SecurityGroups = secrity_group, 
            KeyName = ec2_key_name,
            BlockDeviceMappings = device_mapping,
            AssociatePublicIpAddress = True
        );
        logger.info("update auto scale group name:%s" % (launch_name))
        res = autoscaling.update_auto_scaling_group(
            AutoScalingGroupName=auto_scaling_group_name 
            LaunchConfigurationName = launch_name
        );  
        target = launch_prefix
        recv = autoscaling.describe_launch_configurations()
        list=[]
        for launch in recv['LaunchConfigurations']:
            if target in launch['LaunchConfigurationName']:
                list.append(launch)
        s_list = sorted(list,key=lambda h: h['CreatedTime'])
        if len(s_list) > 2:
            del_target = s_list[0]
            logger.info("delete launch config:%s" % (del_target['LaunchConfigurationName']))
            autoscaling.delete_launch_configuration(
                LaunchConfigurationName=del_target['LaunchConfigurationName'],
            )
        logger.info("end ami update")
        
    except ClientError as e:
        logger.error( e )
    return 'end'

auto scaleのスケジュールを登録する

f:id:abot_s:20170731172333p:plain

以上

注意事項

※最初はelbのhealthチェックだけじゃなくwebサーバーのログやawsコンソールで正常な起動を確認すること

※デプロイがAMIの更新と被らないようにすること

githubのTrendingになっているchromelessをWindowsで試す

windowsでchromelessのexsampleを試すまで

github.com

下記を参考にnodistをインストール http://qiita.com/satoyan419/items/56e0b5f35912b9374305

nodist + v8.0.0 //node v 6.0.0とかだとasync functionが使えないのでv7.0.0以上にすること
nodist v8.0.0
node -v //確認
npm install chromeless
cd C:\Users\ryo-sato\AppData\Local\Google\Chrome SxS\Application //chromeのパス
chrome.exe --romote-debugging-port=9222  --disable-gpu --headless

・C:直下にtmpフォルダを作る //スクリーンショット用 ・C:\nodeのフォルダを作る //スクリプトを置く場所 ・C:\node\testにexsampleスクリプト記載

cd C:\node
node test

これでC:\tmpに下記の感じでchromeスクリーンショットが保存される。

gyazo.com

追記 なんていうことだ・・・、本家がpuppeteerなるものを・・・

ソシャゲのボックスガチャの当たるまでにかかる金額の期待値をプログラム化してみた

ソシャゲのボックスガチャでどれくらいお金賭けたら出るんだろうという興味でやってみました

期待値

期待値 - Wikipedia

参考サイト

【パワプロアプリ】BOXガチャのリセットタイミング:ぽて子のゲーム研究所 - ブロマガ

gyazo.com

上記をプログラム化する

function math(){
  var lottery_count = 100; //ボックス内全体数
  var lottery_once_bet_amount = 300; //1回に掛かる金額
  var lottery_hit_count = 2; //当たり数
  var c = 0;
  var k = t(lottery_count,lottery_hit_count);
  for(var x = 1; x <= (lottery_count-(lottery_hit_count-1)); x++){
    c += (1/k)*(x)*(t(lottery_count-x,lottery_hit_count-1));
  }
  var ev = c * lottery_once_bet_amount; //当たるまでいくらかければいいかの期待値
}
function t(n,c){
  var l = 1;
  var m = 1;
  for(var x = 0 ; x < c; x++){
    l = l*(n-x);
    m = m*(x+1);
  }
  return l/m;
}

100個ある中で3個のあたりを狙い1回300円かかる場合=25.25300=7575円という期待値 100個ある中で1個のあたりを狙い1回300円かかる場合=50.5300=15150円という期待値

cronでdocker-composeが動かなかった件

問題

/var/www/dockerにdocker-compose.ymlが存在していてコンソール上でそのままのdocker-compose startは動くがcrontabでは動かない

例えば

cd /var/www/docker && docker-compose start

とか

cd /var/www/docker; docker-compose stop

cd /var/www/docker; docker-compose start

で試してもcronのlogには出てくるのだが走ってる様子がない

解決策

直接にdocker-composeの/usr/local/bin/docker-composeスクリプトを指定する

cd /var/www/docker; /usr/local/bin/docker-compose start

参照:

Crontab can’t execute docker-compose commands · Issue #2293 · docker/compose · GitHub

外部から社内のパソコンへWake on lanを実装したときのまとめ(サーバー側)

外部からリモートデスクトップするためのwake on lanを実装したときのサーバー側のまとめ

前提資料

http://www.atmarkit.co.jp/ait/articles/0602/25/news014_2.html

必要事項

・外部から見れるサイトを社内にサーバーを立てれること
※Web UIとかログイン認証、sslは別途でやってね

概要

前提として下記の設定が必要になります。(マシンによって異なる)

8e70e928d849800df74cd206b0d90d74.png

今回はphpWake on lanを実施する部分のみ

wakeonlanにはMAC Addressが必要だが、Ip Addressしかわからない人がいるのでコマンドを使って探す処理を実装

//ip address → mac address
if(isset($ip_address && $ip_address != ""){
    $mac = "";
    $pcs = shell_exec("nmap -sP {$ip_address} ");
    $pcs = shell_exec("arp -a");
    $pcss = explode("\n",$pcs);

    foreach($pcss as $value){
        if(strripos($value,$ip_address !== false){
            if(preg_match("/([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}/",$value,$match) === 1){
                $mac = $match[0];
                break;
            }
        }
    }
    if($mac != ""){
        $ping = " {$ip_address} → MAC address {$mac}";
    }else{
        $ping = "get faild";
    }
}

その逆

//mac address → ip address 
if(isset($mac_address) && $mac_address != ""){
    $ip = "";
    #Need to change *.*.*. (192.168 or 172.16 or ....)
    $pcs = shell_exec("nmap -sP 192.168.6.* ");
    $pcs = shell_exec("arp -a");
    $pcss = explode("\n",$pcs);

    foreach($pcss as $value){
        if(strripos($value,$mac_address) !== false){
            if(preg_match("/\(([a-zA-Z0-9.]+)\)/",$value,$match) === 1){
                $ip = substr(substr($match[0],1),0,-1);
                break;
            }
        }
    }
    if($ip != ""){
        $ping = "MAC address {$mac_address} → IP address {$ip}";
    }else{
        $ping = "get failed";
    }
}

また上記で参照できないことがあるので下記をcronで走らせる *.*.*.は192.168.1や192.168.2、172.16.3等に環境に応じて変える

for a in `seq 1 254`; do ping -c 1 -w 0.5 *.*.*.$a > /dev/null && arp -a *.*.*.$a | grep ether; done

MAC Addressがわかったら下記でバッチに引き数を渡す

※batchの実行ユーザーに気を付ける事、この場合はapacheのユーザーを使用して実行

#run user apache
shell_exec("wakeonlan.sh ".$mac_address);
#!/bin/sh
echo 'apache' | sudo -S ether-wake $1
echo "$1 start"

その後の起動確認は下記で実装

$res = shell_exec("ping -c 4 -W 5 ".$ip_address);
$array = explode("\n",$res);
if(strripos($res,'0 received') === false){
    $ping = "boot success";
}else{
    $ping = "boot failed";
}

github:https://github.com/abotkugyu/wakeonlan