XREAサーバーに自動デプロイ

gitHubにpushしたら自動でサーバーにデプロイされるようにする

  • サーバー:XREA(無料プラン)

ローカル環境

  • apacheインストール済
$ which apachectl
/usr/local/bin/apachectl
$ vim /usr/local/etc/apache2/2.4/httpd.conf

# ドキュメントルートの設定
DocumentRoot "/usr/local/var/www/htdocs"
#  index.phpを利用できるように設定
DirectoryIndex index.php index.html
  • ブラウザからアクセスできることを確認する

XREAにsshできるようにして公開鍵を置いてくる

管理メニュー→ホスト情報登録→SSH登録
これでローカルPCからsshできるようになる。

# 公開鍵をXREAサーバーに配置する
$ scp ~/.ssh/id_rsa.pub [ユーザー名]@[XREAサーバー名]:.
# 配置されていることを確認
$ ssh [ユーザー名]@[XREAサーバー名]
$ ls -la
id_rsa.pub
# authorized_keysに追加する
-bash-4.2$ mkdir .ssh
-bash-4.2$ chmod 700 .ssh
-bash-4.2$ mv id_rsa.pub ./.ssh/.
-bash-4.2$ cd .ssh/
-bash-4.2$ cat ./id_rsa.pub >> authorized_keys
-bash-4.2$ chmod 600 authorized_keys
-bash-4.2$ exit
# 接続確認
$ ssh [ユーザー名]@[XREAサーバー名]
# サーバー名、ユーザー名、パスワードはXREAの管理メニュー→FTP設定に書いてある

デプロイスクリプト

deploy.php
XREAサーバーに置く

<?php
require_once(dirname ( __FILE__ ).'/../cfg.php');

$LOG_FILE = dirname(__FILE__).'/hook.log';
$SECRET_KEY = $MY_SECRET_KEY;
$POST_DATA = file_get_contents("php://input");
$hmac = hash_hmac('sha1', $POST_DATA, $SECRET_KEY);
$signature = substr($_SERVER['HTTP_X_HUB_SIGNATURE'], 5);
if ( $signature == $hmac  ) {
    $payload = json_decode($POST_DATA, true);
    exec('cd htdocs ; git pull 2>&1');
    file_put_contents($LOG_FILE, date("[Y-m-d H:i:s]")." ".$_SERVER['REMOTE_ADDR']." git pulled: ".$payload['after']." ".$payload['commits'][0]['message']."\n", FILE_APPEND|LOCK_EX);
} else {
    file_put_contents($LOG_FILE, date("[Y-m-d H:i:s]")." invalid access: ".$_SERVER['REMOTE_ADDR']."\n", FILE_APPEND|LOCK_EX);
}

XREAサーバー側であらかじめ対象のリポジトリをgit clone しておく…

gitHubのWebhooksを使う

リポジトリ→Settings→WebhooksからPayload URLとSecretを設定する。

残り作業

ローカルで開発を行っているhtdocsディレクトリをそのままgitHubリポジトリにしていたが、
これをpullするとやはりhtdocsのまま。
XREAはpublic_htmlというディレクトリにアップロードしたものが公開される仕様のため、
XREAサーバーのhtdocs配下にpull してきてからpublic_htmlにmvかcpするスクリプト作る。

Spring解体新書を読んだ

kindle unlimited。入門書として読んだ。
アノテーションをつけていろいろ設定する感じ。

エンジニアの知的生産術を読んだ

何かをを作りたいと思うが、何も思いつかない、といったときに思いつくにもやり方があるのだということ。

エンジニアの知的生産術 ──効率的に学び、整理し、アウトプットする (WEB+DB PRESS plusシリーズ)

エンジニアの知的生産術 ──効率的に学び、整理し、アウトプットする (WEB+DB PRESS plusシリーズ)

コーディングを支える技術を読んだ

何を楽にしたいのか、どんなプログラムを書くのを楽にしたいのか、高速なコードを書きたいのか、読むのが楽なコードを書きたいのか。そんなわけでいろんな言語がある。

コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)

コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)

実践Vimを読んだ

出てくるコマンドを覚えようと線を引きながら読んだ(kindle)が、翻訳のためかまとめづらい。

実践Vim 思考のスピードで編集しよう! (アスキー書籍)

実践Vim 思考のスピードで編集しよう! (アスキー書籍)

大量データ作成SQL

1000万レコードをテーブルにinsertする。

create table ITEM_INFO
(NO varchar(10),
YM varchar(6),
ID varchar(8),
PRDCT varchar(30),
PRICE varchar(32),
OTHER1 varchar(30),
OTHER2 varchar(30),
OTHER3 varchar(30),
OTHER4 varchar(30),
OTHER5 varchar(30),
OTHER6 varchar(30),
OTHER7 varchar(30),
OTHER8 varchar(30),
OTHER9 varchar(30),
OTHER10 varchar(30),
OTHER11 varchar(30),
OTHER12 varchar(30),
OTHER13 varchar(30),
OTHER14 varchar(30),
OTHER15 varchar(30),
OTHER16 varchar(30),
OTHER17 varchar(30),
OTHER18 varchar(30),
OTHER19 varchar(30),
OTHER20 varchar(30),
OTHER21 varchar(30),
OTHER22 varchar(30),
OTHER23 varchar(30),
OTHER24 varchar(30),
OTHER25 varchar(30),
OTHER26 varchar(30),
OTHER27 varchar(30),
OTHER28 varchar(30),
OTHER29 varchar(30),
OTHER30 varchar(30),
OTHER31 varchar(30),
OTHER32 varchar(30),
OTHER33 varchar(30),
OTHER34 varchar(30),
OTHER35 varchar(30),
OTHER36 varchar(30),
OTHER37 varchar(30),
OTHER38 varchar(30),
OTHER39 varchar(30),
OTHER40 varchar(30),
OTHER41 varchar(30),
OTHER42 varchar(30),
OTHER43 varchar(30),
OTHER44 varchar(30),
OTHER45 varchar(30),
OTHER46 varchar(30),
OTHER47 varchar(30),
OTHER48 varchar(30),
OTHER49 varchar(30)
);

--実行時間計測
set timing on

--1000万件登録
insert into ITEM_INFO
--最初のselectにはinsertしたい項目を羅列する
select
    --1000万までの連番
    i + j
    
    --ランダム日付
    ,to_char(
        -- 2016/01から2018/09のランダム月を取得(YYYYMM形式)
        TO_DATE('20160101','YYYYMMDD') + MOD(ABS(DBMS_RANDOM.RANDOM()), TO_DATE('20181001', 'YYYYMMDD') - TO_DATE('20160101', 'YYYYMMDD')) , 'YYYYMM')

    --連番を8桁で右X埋め
    ,rpad(to_char(i + j),8,'X')

    --以降は固定値を入れている
    ,'りんご'
    ,'138'
    ,'OTHER1'
    ,'OTHER2'
    ,'OTHER3'
    ,'OTHER4'
    ,'OTHER5'
    ,'OTHER6'
    ,'OTHER7'
    ,'OTHER8'
    ,'OTHER9'
    ,'OTHER10'
    ,'OTHER11'
    ,'OTHER12'
    ,'OTHER13'
    ,'OTHER14'
    ,'OTHER15'
    ,'OTHER16'
    ,'OTHER17'
    ,'OTHER18'
    ,'OTHER19'
    ,'OTHER20'
    ,'OTHER21'
    ,'OTHER22'
    ,'OTHER23'
    ,'OTHER24'
    ,'OTHER25'
    ,'OTHER26'
    ,'OTHER27'
    ,'OTHER28'
    ,'OTHER29'
    ,'OTHER30'
    ,'OTHER31'
    ,'OTHER32'
    ,'OTHER33'
    ,'OTHER34'
    ,'OTHER35'
    ,'OTHER36'
    ,'OTHER37'
    ,'OTHER38'
    ,'OTHER39'
    ,'OTHER40'
    ,'OTHER41'
    ,'OTHER42'
    ,'OTHER43'
    ,'OTHER44'
    ,'OTHER45'
    ,'OTHER46'
    ,'OTHER47'
    ,'OTHER48'
    ,'OTHER49'
from
  (
    with data2(j) as
    (
      select 0 from dual
      union all
      select j+10000 from data2 where j < 9990000
    )
    select j from data2
  ),
  (
    with data1(i) as
    (
      select 1 from dual
      union all
      select i+1 from data1 where i < 10000
    )
    select i from data1
);
commit;

結果

10,000,000 rows inserted.
Elapsed: 00:03:27.323

3分程。

ボットを作る(hubot + slack + heroku)

開発環境

vmware上のubuntu
macからemacsでファイルを編集する。

  • vmwareのubuntuを起動しておく
  • macのコンソールからの接続:
~ $ ssh  ユーザー名@サーバー名
  • macのemacsからの接続:
C-x C-f /ssh:ユーザー名@サーバー名:/home/ubuntu/workspace/

node.jsのインストール

  • まずはnode.jsのバージョン管理ツールnodebrew を導入する

ubuntuに接続しコンソールから

curl -L git.io/nodebrew | perl - setup
  • パスを通す
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.profile
  • .profileを読み込む
source ~/.profile
  • 確認
nodebrew
  • バージョンや使い方が表示されること。
  • nodebrewでnode.jsをインストールする
nodebrew install-binary v6.11.1
nodebrew use v6.11.1
  • コンソールからnpmをアップデート
npm update -g npm

必要なモジュールのグローバルインストールとボットの作成

  • モジュールのインストール
npm install -g yo@1.8.5 --ひな形作成ツール (ジェネレーター) 
npm install -g generator-hubot --Yeoman を利用した Hubot のジェネレーター。Hubotはボットを作成するためのフレームワーク
npm install -g coffee-script@1.12.4 
  • ボットを作成するコマンドを実行する
cd ~/workspace
mkdir myownhubot
cd myownhubot
yo hubot

基本的にYでOK。アダプターだけslackにしてEnter。

? Bot adapter (campfire) slack

ボットでの処理をJavascriptで書くためにコンソールからファイル作成

touch scripts/hello.js
  • hello.jsを書く
'use strict';
//robotという引数を持つ無名関数をモジュールとしている。 
module.exports = (robot) => {
    //HubotのAPIの利用方法が以下。
    ///hello>/iは正規表現。マッチしたら次に渡す無名関数を実行するという形式。
    //msgオブジェクトからユーザーの名前を受け取り、「hello,ユーザー名」と発言する。
    robot.hear(/hello>/i, (msg) => {
    const username = msg.message.user.name;
    msg.send('hello, ' + username);
    });
};
  • 書いたらボットをslackのアダプターなしで動かしてみる

コンソールから

cd ../
chmod a+x bin/hubot
bin/hubot

とりあえず以下のような感じになる。ユーザーがShellになっている。

npm WARN hubot-help@0.2.2 requires a peer of coffee-script@^1.12.6 but none was installed.
npm WARN hubot-slack@4.5.3 requires a peer of hubot@^2.0.0 but none was installed.
body-parser deprecated undefined extended: provide extended option node_modules/hubot/src/robot.js:445:21
No history available
myownhubot> [Mon Aug 06 2018 13:31:24 GMT+0900 (JST)] INFO /home/ubuntu/workspace/myownhubot/scripts/hello.js is using deprecated documentation syntax
[Mon Aug 06 2018 13:31:24 GMT+0900 (JST)] WARNING Loading scripts from hubot-scripts.json is deprecated and will be removed in 3.0 (https://github.com/github/hubot-scripts/issues/1113) in favor of packages for each script.

Your hubot-scripts.json is empty, so you just need to remove it.
[Mon Aug 06 2018 13:31:24 GMT+0900 (JST)] ERROR hubot-heroku-keepalive included, but missing HUBOT_HEROKU_KEEPALIVE_URL. `heroku config:set HUBOT_HEROKU_KEEPALIVE_URL=$(heroku apps:info -s | grep web.url | cut -d= -f2)`
[Mon Aug 06 2018 13:31:24 GMT+0900 (JST)] INFO hubot-redis-brain: Using default redis on localhost:6379
hello>
myownhubot> hello, Shell
  • 次にslack でhubotを動かす
  • slackで開発用のworkspaceを作成する
  • https://slack.com/からメールアドレスを入力しGetStarted、新しいworkspaceを作成する
  • 諸々入力する
  • メールが来たらslackにログインする
  • チャンネルの横のマーククリックしてチャンネルを作成する

slackの設定を行う

https://slack.com/services/new
  • 上記から検索欄にhubotと入力する。出てきたhubotをクリックすると設定ページが表示されるのでinstallをクリックする。
  • ユーザー名を適当に入力。
  • APIトークンを控えておく(パスワードみたいなものなので公開しないように注意)
HUBOT_SLACK_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • インテグレーションの保存をクリックする。
  • 次にこのボットを反応させたいチャンネルに参加させる。
  • 先程のチャンネルに参加させる。作成したslackのチャンネルに入る。歯車ボタンから「新しいユーザーを招待する。」を選択。

先ほど作成したボットの名前を入力しinvite.設定は以上。

ボットを起動する

コンソールから

env HUBOT_SLACK_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx bin/hubot --adapter slack

これで起動した状態になる。
slackのbotチャンネルでhello>と入力して動作確認。

ボットを常時起動させておくことができるようにHerokuを使う

https://www.heroku.com/
  • アカウントを作成する。
  • コンソールからHeroku CLIをインストールする(herokuコマンドが使えるようになる)
wget -O- https://cli-assets.heroku.com/install-ubuntu.sh | sh
  • 確認
heroku --version
heroku-cli/6.15.13-3dce47c (linux-x64) node-v9.3.0
  • Heroku CLI から Heroku にログインする。
  • コンソールから
heroku login
  • 下記のように表示されればログイン完了
Logged in as メールアドレス

githubに新しくリポジトリを作成する。

https://github.com/new

必要な項目を入力して「Create repository」ボタンをクリック
…or create a new repository on the command lineをコンソールにコピペして実行

  • 他のファイルもpushする
  • herokuで動かすための設定ファイルProcfileを作成する。
  • Procfile
web: bin/hubot --adapter slack
  • ProcfileはHeroku がアプリケーションを動作させる際に「どのようなコマンドを実行するか」を認識するための設定ファイル。
  • サーバーの用意をする。これをやるのは一回だけ。
$ heroku create

デプロイ

git push heroku master
  • トークンはherokuのコマンドで登録する。ダブルクォートで囲う。
heroku config:set HUBOT_SLACK_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  • 確認
heroku config:get HUBOT_SLACK_TOKEN

動作確認

slackのチャンネルからhello>と発言してみる

  • なにか変更したらgit push heroku masterする
  • herokuの再起動はコンソールからheroku restart アプリ名

SeleniumとPhantomJSの環境構築

Docker上にUbuntuの構築

$ docker pull ubuntu:16.04
$ docker run -it ubuntu:16.04

Python3とSeleniumのインストール

 apt-get update
 apt-get install -y python3 python3-pip
 pip3 install selenium
 pip3 install beautifulsoup4

PhantomJSのインストール

apt-get install -y wget libfontconfig
mkdir -p /home/root/src && cd $_
wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
tar jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2
cd phantomjs-2.1.1-linux-x86_64/bin/
cp phantomjs /usr/local/bin/

日本語フォントが表示されるようにする

apt-get install -y fonts-migmix
cat <<EOF > /etc/fonts/local.conf
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
	<match target="pattern">
		<test qual="any" name="family">
			<string>serif</string>
		</test>
		<edit name="family" mode="assign" binding="strong">
			<string>MigMix 2P</string>
		</edit>
	</match>
</fontconfig>
EOF

Dockerをコミットしておく

exit
docker ps -a
docker commit (コンテナID) ubuntu-phantomjs

コンテナ起動

$ docker run -it -v $HOME(ホストのパス):$HOME(コンテナのパス) \
> -e LANG=ja_JP.UTF-8 \
> -e PYTHONIOENCODING=utf_8 \
> ubuntu-phantomjs /bin/bash

動作確認

seleniumu-capture.py

from selenium import webdriver

url = "http://www.aozora.gr.jp/cards/000081/files/46268_23911.html"

#PhantomJSのドライバを得る
browser = webdriver.PhantomJS()
#暗黙的な待機を最大3秒行う
browser.implicitly_wait(3)
#URLを読み込む
browser.get(url)
#画面をキャプチャしてファイルに保存
browser.save_screenshot("Website.png")
#ブラウザを終了
browser.quit()
cd $HOME(コンテナのパス)
python3 selenium-capture.py 

実行結果

Website.pngが出来上がる

pythonとかdocker

作業の覚書

python

  • emacsでpythonが自動補完できるように設定
$ sudo easy_install pip
$ sudo pip install virtualenv
    • init.el追記
(require 'python-mode)
(setq auto-mode-alist (cons '("\\.py\\'" . python-mode) auto-mode-alist))

(require 'jedi)
(add-hook 'python-mode-hook 'jedi:setup)
(setq jedi:complete-on-dot t)
  • macにdockerをインストール
  • dockerにPython3とanacondaの環境を整備
$ docker pull continuumio/miniconda3
$ docker run -i -t continuumio/miniconda3 /bin/bash
$ docker ps -a
$ docker commit ef08836ef1b2 mlearn:init
$ docker images
$ docker run -i -t mlearn:init /bin/bash
$ docker run -i -t -v {ホストOSのカレントディレクトリ}:/home mlearn:init /bin/bash

サーバーサイド(node.js)

  • Expressのhelmetモジュールの動作確認

Expressのセキュリティ設定

helmetモジュールでHTTPに於ける脆弱性となるヘッダを取り除く

対応前の確認

  • プロジェクトの生成とExpressに必要なnpmパッケージのインストール
$ express express-helmet
$ cd express-helmet/
$ npm install
  • サーバーの起動
$ DEBUG=express-hlmet:* PORT=8000 npm start

デベロッパーツール→Network→再読込み→localhost選択→Headersタブを見ると、
X-Powered-By:Expressと書かれており、このWebサービスがExpressで開発されていることが分かってしまう。
もしExpressに脆弱性があるとわかったときに攻撃対象にされる危険性がある。
このためX-Powered-Byというヘッダは送信しないほうが安全。

helmetのインストール

$ npm install helmet --save

app.jsの修正

  • モジュールの読み込みとappオブジェクトのuse関数でhelmetを使うようにする
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
+var helmet = require('helmet');

var index = require('./routes/index');
+var users = require('./routes/users');

対応後の確認

  • サーバー起動
$ DEBUG=express-hlmet:* PORT=8000 npm start

デベロッパーツール→Network→再読込み→localhost選択→Headersタブ
X-Powered-By:Expressが消える

まとめ

フレームワークによって自分で実装しなくて済む

node.jsのフレームワークを導入する

ジェネレーターのインストール&必要なファイルの作成

$ npm install -g express-generator
/home/ubuntu/.nodebrew/node/v4.7.0/bin/express -> /home/ubuntu/.nodebrew/node/v4.7.0/lib/node_modules/express-generator/bin/express-cli.js
+ express-generator@4.15.5
added 6 packages in 0.99s
$ cd workspace/$ express express-study

  warning: the default view engine will not be jade in future releases
  warning: use `--view=jade' or `--help' for additional options


   create : express-study
   create : express-study/package.json
   create : express-study/app.js
   create : express-study/public
   create : express-study/routes
   create : express-study/routes/index.js
   create : express-study/routes/users.js
   create : express-study/views
   create : express-study/views/index.jade
   create : express-study/views/layout.jade
   create : express-study/views/error.jade
   create : express-study/bin
   create : express-study/bin/www
   create : express-study/public/javascripts
   create : express-study/public/images
   create : express-study/public/stylesheets
   create : express-study/public/stylesheets/style.css

   install dependencies:
     $ cd express-study && npm install

   run the app:
     $ DEBUG=express-study:* npm start

npmモジュールのインストール

cd express-study
npm install

起動

$ DEBUG=express-study:* PORT=8000 npm start

> express-study@0.0.0 start /home/ubuntu/workspace/express-study
> node ./bin/www

  express-study:server Listening on port 8000 +0ms
  • 「npm スクリプト名」 というコマンドでpackage.jsonで設定されたコマンドが実行される。package.jsonにはこんな箇所がある。
"scripts": {
    "start": "node ./bin/www"
  },

アクセスしてみると雛形ページが表示される

http://localhost:8000/

f:id:sattamassagana:20180204201655p:plain

試しにExpressのdebugモジュールの機能を使ってみる

  • app.jsの先頭に追加する
'use strict';

const debug = require('debug');//debugモジュールを読み込む
const debugInfo = debug('app:info');//module:infoという設定のロガーdebugInfoを用意
setInterval(() => {//1000msごとに関数を実行する
    debugInfo('some information');
}, 1000);

const debugError = debug('app:error');//別の設定のロガーdebugErrorを用意
setInterval(() => {
    debugError('error!');
}, 2000);
  • 実行(複数ログ出力するにはカンマで繋げてコマンドを実行する)
$ DEBUG=express-study:*,app:* PORT=8000 npm start

> express-study@0.0.0 start /home/ubuntu/workspace/express-study
> node ./bin/www

  express-study:server Listening on port 8000 +0ms
  app:info some information +907ms
  app:error error! +997ms
  app:info some information +9ms
  app:info some information +1s
  app:error error! +990ms
  app:info some information +13ms
  app:info some information +1s
  app:error error! +987ms
  app:info some information +14ms
  app:info some information +1s
  app:error error! +985ms
  app:info some information +17ms
  app:info some information +1s
  app:error error! +982ms
  app:info some information +23ms
  app:info some information +1s
  app:error error! +978ms
  app:info some information +25ms