私的Linux爆速環境

はじめに

SONYVAIO一体型PCにWindow7とLubuntuDesktopが
入った環境でプログラミングをしてきた。
この環境は悪くはないが、ちょいちょいフリーズするときがある。
もう少し快適にプログラミングしたい。

ハードウェア

中古のThinkpadX230を買った。
ハードの構成的には、

1. CPU Corei5(2.6GHz)
2. SSD 250GB
3. メモリ 8GB

PCの立ち上がりが早い。
起動中もザックザックに早く動く。
フリーズすることもない。
これらがSSDのおかげなのか、メモリ8GBのおかげなのかはわからない。
ただ、とにかく早い。

ソフトウェア

ソフトウェアは以下のような構成にした。

OS Ubuntu Server

ThinkpadにはもともとWindows10が入っていたが、全て削除。
デュアルブートはもうやめて、Ubuntu Server一本でいくことにした。
Ubuntu ServerはGnomeやUnityなどのデスクトップ環境なしでCUI環境のみでインストール。
そこからXwindow Systemを追加で入れる。
なるべく余計なものを入れずに、やっていきたい。
今のところ、40GB/250GBくらいのディスク消費量で済んでいる。

ウィンドウマネージャ i3wm

もともとVAIOでもタイル型のウィンドウマネージャi3wmを使っていた。
引き続きこれを使う。
もうウィンドウがかぶって、うあああアアってなることもない。
~/.config/i3/configに書く設定も簡単に書ける。
i3wmの公式ドキュメントとこの方のブログの情報でほとんど設定できる。

ターミナルエミュレータ Gnome Terminal

とくにこだわりはない。

シェル fish shell

一時期zshを使っていたが、遅かったので使うのを止めた。
そこからるびきち氏のページを見て、fishに乗り換えた。
しかし、これが良い判断だったのかはわからない。
やっぱりいまだにWEB上にはbashの情報が多い。
fishの文法に慣れていないので、ちょっとした作業でつまずくことがある。
あと、そもそもLinuxbashを前提にして成り立っているのでbashなしというわけにはいかない。

エディタ Spacemacs

emacsベースで最近注目のエディタ。
emacsの拡張性を引き継ぎつつも、UIは本家よりも格好良い。
Spaceキーから始まるキーバインドが初心者にも優しい。
編集時はvimキーバインドでなんとかやっている。
こちらもfish同様、まだまだ全ての機能を活かせていない。

ブラウザ vivaldi

もともとFirefoxを使っていた。
vimperatorを使っていたからだ。
しかし、Quantumくらいからvimperatorが使えなくなるというので、
Firefoxを泣く泣く諦めることにした。
特にこだわりがなければChromeでいいと思うが、天邪鬼なのでvivaldiにしている。
vivaldiChromiumベースのブラウザ。
タブタイリングなどのChromeにはない便利な機能が入っている。
アドオンはvimiumを使っている。
しかし、vimperatorの方がいろいろと良かった。

終わりに

もっとミニマルな構成にしようと思えば、多分できるのだと思う。
OSをArchLinuxにしたり、エディタを生Vimにしたりするやり方もある。
ただ、Archでイチから環境を組み立てていくほど、私は潔癖なミニマリストにはなりえない。
一日で従来の環境をなるべく変えずに、いかにミニマルな環境を構築するかという点ではなかなか上出来だったと思う。

やっぱり開発環境が快適かどうかは、作業の効率に影響を及ぼす。
フリーズは開発のリズムを壊すのである。
Ubuntuやi3wmなどの設定は他のブログの情報でできると思うので、
そちらに丸投げさせていただいて今回は終わらせていただく。

WEB開発の門外漢がReactでお試しSPAを作成する

作成前

今までPythonでデータ分析とかスクレイピングのためのプログラムは書いてきた。
でも、WEB開発はあまりやってこなかった。
自分で何かWEBサービスを作ってみたいという思いがむくむくと湧いてきた。
少しずつWEB開発をやっていこう。
とりあえずサーバーサイドは脇に置いて、フロントエンドから取り掛かろう。

道具の選択

Javascriptのフロントエンドライブラリは、無難にReactを選択する。
React Nativeもあるので、将来的にはスマホアプリへの広がりも少し期待した。

いきなりゴリゴリと本格的にサービスを開発するわけにもいかない。
まずは何か見本ページをパクっ...真似てReactに慣れよう。
ここにReactで作成したWEBアプリがたくさんあるので、その中からこれを真似る。
CSSフレームワークはBootstrapが使われているようだ。

何作る

まんま見本サイトをパクってロボットの写真を使うのは趣がない。
ジャズのプレイヤーの写真に差し替えてみよう。
ジャズマン名鑑のようなものを作ろう。

何やりたい

ページを変えた時に画面全体を再描画するのではなく、パネル内の文字と写真だけを描画する」という機能を実装してみたい。
実際に試作してみたSPAはこちら

手を付けなかったもの

ゆくゆくは使ってみないといけないだろうが、今回は小規模な開発なのでFluxやReduxは使わない。
また、サーバー部分はとりあえず脇に置いているので、AWSとかは使わない。
デプロイがとても簡単にできるGithub Pagesを使う。

詰まったところ

作業はReact公式やReact本、Web上の情報を収集すれば、大体進めていける。
とはいえ、「現在のページをどのように管理するか、またページが変わったことをどのようにパネル部分のコンポーネントに伝えるか」で詰まった。
どうやら、この部分はReactでアプリを構築していく上で基礎の部分であり、これをきちんと理解できていないとWebアプリっぽい機能は全く実装できないようだ。

ページ管理

そもそもどのようにページを管理したいいのかが分からない。
React-Bootstrapの公式を眺めた。
どうやら、今何ページ目が開かれているかはコンポーネントが持つ内部状態で管理するらしい。
ちなみにコンポーネント間のデータの受け渡しについては、こちらのページに詳しく書いてある。

以下の手順でデータの受け渡しをやる。

  1. ページネーションのボタンがクリックされる。
  2. ページが変更されたことを、ページネーションの子コンポーネントからをページを管理している親コンポーネントに通知する
  3. 通知を受け、親コンポーネントが内部状態として持っている「activePage」を書き換える
  4. コンポーネントからパネル部分の子コンポーネントへページが変更されたことを通知する
  5. 変更されたページに属するジャズマンの写真と名前を描画する

コンポーネントと子コンポーネント間の連携

Pageのコンポーネントと親コンポーネントの連携は以下のように行う。

  1. React-BootstrapのPaginationコンポーネントを子コンポーネントとして配置
  2. コンポーネントのメソッドとしてactivePageを書き換えるイベントハンドラを定義
  3. そのイベントハンドラthis.props経由でPaginationコンポーネントへと渡し、onSelect属性に代入

また、写真を描画するItemsコンポーネントの方と親コンポーネントの連携は以下のように行う。

  1. コンポーネントactivePageの値をthis.props経由でItemsコンポーネントに渡す。
  2. 親からactivePageの値を受け取り、その値によって描画する写真を変える。

親は以下のようなコードになる。

class Center extends Component {  
      
    constructor(props) {  
        super(props)  
        this.state = {  
            //ここで現在のページ数を管理する  
            activePage: 1  
        }  
    }  
      
    //ページ数を書き換えるメソッド  
    updateActivePage (e) {  
        this.setState({activePage: e})  
    }  
  
    render () {  
  
        const activePage = this.state.activePage  
        const updateActivePage = (e) => this.updateActivePage(e)  
  
        return  (  
            <Grid className="container-fluid">  
                <Title />  
                <Page activePage={activePage}  
                      //このようにしてPageコンポーネントにupdateActivePageを渡す  
                      updateActivePage={updateActivePage} />  
                //ItemコンポーネントにacitivePageの値を渡す  
                <Items page={activePage} />  
                <Page activePage={activePage}  
                      //このようにしてPageコンポーネントにupdateActivePageを渡す  
                      updateActivePage={updateActivePage} />  
            </Grid>  
        )  
    }  
}  

ちなみに、子のPageコンポーネントのこのようになっている。
Itemコンポーネントの方も値の受け取り方は同じである。

render(){  
    const pageNumber = Math.ceil(this.getPageNum() / 12)  
  
    //親から受け渡されたupdateActivePage()はこのように受け取る。  
    const updateActivePage = this.props.updateActivePage  
  
    return (  
        <Pagination  
            prev  
            next  
            first  
            last  
            ellipsis  
            boundaryLinks  
            items={pageNumber}  
            activePage={this.props.activePage}  
            //SelectイベントによってactivePageを書き換えるようupdateActivePage()をセットする。  
            onSelect={(e) => updateActivePage(e)}  
          />)  
}  

最後に

SPAを作成したと言っても、これはまだ試作段階なので、不十分な点が色々とある。
色々と作っていって、Reactに早く慣れていきたい。

ClosedXMLによるExcelの操作・その1

とりあえずClosedXMLを使う

今回はC#Excelを操作します。 C#ではNPOI、NetOffice、EPPlusといったパッケージや、.NET FrameworkからCOMコンポーネントを使ってExcelを操作することができます。 ここでは ClosedXML というパッケージを使ってみたいと思います。 現段階ではどの方法が最も効率がいいかということは分かりませんが、ネット上の「ClosedXMLが直観的で使いやすい」という情報をもとにClosedXMLを選択した次第です。

ちなみに、COMコンポーネントを使う方法については、リソースを開放するコードを自分で実装しないといけないので、いくらか手間がかかってしまいます。 しかし、ClosedXMLではできないが、COMならできることもありますので(チャートの挿入など)、いずれはCOMコンポーネントを触らなければならない状況も出てくると思われます。 ま、それはともかく、以下にずらずらっと実行コードを並べていきたいと思います。

実行コード

  • using部分
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq; 
using System.Text;
using System.Threading.Tasks;
using ClosedXML.Excel;
  • ワークブックを開き、ワークシートを追加し、特定のセルに値を代入
var workbook = new XLWorkbook();
var ws = workbook.Worksheets.Add("WorksheetName");
ws.Cell("A1").Value = "Hello World!";
  • ワークブックを保存
workbook.SaveAs("Workbook.xlsx");
  • 特定の範囲を指定し、その範囲内のセルでは入力した数字を円単位で表示
var range = ws.Range("B2:B100");
range.Style.NumberFormat.Format = " #,##0 円";
  • プルダウンリストからセルに入力できるようにする
var namelist = new string[] { "高橋幸宏", "坂本龍一", "細野晴臣" };
string join = string.Join(",", namelist);
string insertstring = $"\"{join}\"";
var cell = ws.Cell(1, 1);
cell.DataValidation.List(insertstring);
  • 隠れた形でコメントを挿入する
ws.Cell("A1").Comment
.SetAuthor("Taro")
.AddSignature()
.AddText("Hello!");
  • 見える形でコメントを挿入する
ws.Cell("A1").Comment.SetVisible()
.SetAuthor("Hanako")
.AddSignature()
.AddText("Good Night!");
  • 「値が100以上なら背景を赤色にする」という条件付き書式を設定
ws.Range("C2", "C100").AddConditionalFormat().WhenGreaterThan(100)
.Fill.SetBackgroundColor(XLColor.Red);

終わりに

今回はClosedXMLを使ってC#から、基本的なExcel操作をするコードを載せてみました。 ClosedXMLの使い方はgithubのwikiに掲載されていて、ここを見ればやりたいことは大体できるのではないでしょうか。 日本語・英語を含めて、結構ググれば情報は見つかりますし、ちょっとC#からExcelをいじってみたいなという人にはいいと思います。

また、図表の挿入などやりたいことを一通り試した後、簡単な入力フォームを作成したら、記事をUPしてみたいと思います。

ConohaVPSでのCentOSサーバーの設定手順(ssh編)

はじめに

以前にConohaVPSを契約してましたが、完全に放置していて毎月財布から英世が消えていくのはもったいない… ということで、CentOS上にWEBサーバーを立ててみることにしました。 ひとまず、LAMP環境を構築することを当面の目標にしたいと思います。

今回の記事はssh編ということで、sshリモートホストにログインするところから始めて、最終的にはセキュリティ的にあまり心配のないssh設定をするところまで行いたいと思います。 (とはいえ、どこまでやればセキュリティ的に心配ないかは各人次第です。よりセキュアな設定をしたい方はググれば、他の対策も出てきますので、そちらも参考にしてください。)

Conohaの管理画面

いきなりですが、ConohaのVPS契約から管理画面上の操作は割愛させてください…

サーバーを追加すると、様々な設定項目がありますが、この記事では2017/7/4現在で最も新しいCentOSを使い、またsshでは公開鍵認証でのログインをデフォルトにしました。 途中で、公開鍵認証で使う秘密鍵をダウンロードできますので、しておきます。 また、設定したrootパスワードも使用しますので、記録しておきましょう。 さらに、サーバーを追加すると、IPアドレスMACアドレスなどのサーバー情報を見ることができますので、IPアドレスをメモしておくとよいかと思います。

ログイン

まずは、ローカルPC上のホームフォルダに.sshディレクトリを作成し、ダウンロードした秘密鍵をそこに移動させます。

mkdir .ssh
mv /path_to_pem/123456789.pem .ssh

次に、以下のコマンドで、リモートサーバーにsshでrootログインします。 xxx.xxx.xxx.xxxのところには、リモートサーバーのIPアドレスを入力します。

ssh root@xxx.xxx.xxx.xxx -i ~/.ssh/123456789.pem

一般ユーザーの追加とそのユーザーのwheelグループへの追加

次に、リモートサーバ上でrootとは別の一般ユーザー を追加します。 さらに、そのユーザのパスワードを設定し、さらにユーザをwheelグループに追加します。

useradd <username>
passwd <username>
gpasswd -a <username> wheel

wheelグループにsudoを許可

wheelグループに属する一般ユーザーがsudoコマンドを使えるようにします。 先ほど一般ユーザをwheelグループに追加したのは、そのためです。

visudo

//この行の#を消す
#%wheel ALL=(ALL) ALL

参考:ConohaとCentOS

suコマンドの実行はwheelグループのみに

suを利用すると、ユーザーを切り替えることができます。 もちろん、rootユーザに切り替えることも可能です。 しかし、rootユーザに切り替える必要のない一般ユーザーがsuを使えるようにしておくと、何かのときにroot権限に移行し、変なことをしでかすかもしれません。 そこでwheelグループ以外からはsuコマンドを実行できないようにします。

vi /etc/pam.d/su

//この行の#を消す
#auth required pam_wheel.so use_uid

参考:ConohaとCentOS

.sshディレクトリとauthorized_keysファイルの所有者とパーミッションの変更

ここからはsshの設定をしていきます。 まずは、sshを使って先ほど作成した一般ユーザでログインできるように設定します。

一般ユーザのホームディレクトリに.sshディレクトリを作成し、/root/.ssh内にあるauthorized_keysをそこにコピーします。 (authorized_keysファイルは、個別の公開鍵を登録しておくファイルです) 次に、今作成した.sshディレクトリとコピーしたauthorized_keysファイルのパーミッションを変更します。 どのパーミッションが本当に適切なのかが自分の中でまだはっきりとしていませんが、WEB上では

という情報が多かったので、とりあえずはそれに従います。 これらのパーミッションが適切でないと、あとでリモートログインするときにdenyされます。

mkdir /home/<username>/.ssh
cp .ssh/authorized_keys /home/<username>/.ssh/authorized_keys
chown <username>:<username> /home/<username>/.ssh
chown <username>:<username> /home/<username>/.ssh/authorized_keys
chmod 700 /home/<username>/.ssh
chmod 600 /home/<username>/.ssh/authorized_keys

sshに関するセキュリティ設定

sshは悪い人達(bot達?)に標的にされやすいです。 (自分も設定が一区切りついたところで、/var/log/secureを見てみました。サーバー作成してからまだ数時間だというのに、mysqlやらadminやらの名前でログインしようとする鬼畜が….) ですので、sshで不正ログインされないようにきっちりと設定しなければなりません。 そこで、/etc/ssh/sshd_configを編集して、以下のような設定を行っていきます。

sudo vi /etc/ssh/sshd_config
  • ポート番号を22から変更する
  • sshを使ってrootユーザーでログインできないようにする
  • sshのパスワード認証を切る
  • ssh可能ユーザーを限定
  • sshdプロトコルを2に
  • 認証の試行回数、認証までの猶予時間の制限

自白すると、これらの設定は下のページを参考にさせてもらいました。 あーざっす! ですので、そちらを参考に設定してください。

参考:そこそこセキュアなサーバ
参考:ConohaとCentOS

一つだけ追加しておくと、ポート番号はsshdの設定ファイルで変えても、CentOSのファイアーウォールデーモンであるfirewalldではまだ22番のままなので、こちらも変更しておかなければなりません。

cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/ssh.xml
sed -e s/22/<変更するポート番号>/g /etc/firewalld/services/ssh.xml > /etc/firewalld/services/ssh.xml1
cat /etc/firewalld/services/ssh.xml1
mv /etc/firewalld/services/ssh.xml1 /etc/firewalld/services/ssh.xml

おわりに

とりあえず、ssh周りはこれで終わりたいと思います。 この次は、不要なサービスを止めたり、不要なポート閉じたり、firewalldでネットワークの流れを制御したりしていきます。

Vagrantで作るLAMP環境

はじめに

この記事では、「vagrant upと一発叩いて、LAMP環境(Apache + MySQL + PHP入りのCentOS)を起動させる」ことを目指します。 まずは、CentOS上にApache + MySQL + PHP(AMP)を導入していきます。 その次に、そのAMP入りの環境をBoxファイルにして保存するという流れです。

LAMPを入れるシェルスクリプトを書く

ここでは、vagrantvirtualboxの導入する部分を一気に省いて(!)、それらが既に導入されているところから始めさしてください。

Vagrantでは、vagrant upと叩けば、現在のディレクトリのVagrantfileの設定を読みます。 Vagrantfileには様々な設定が書けますが、一番下のセクションに起動時に実行するシェルスクリプトを指定できる箇所があります。 それは、

config.vm.provision "shell", :path => "lamp.sh"

の部分です。 例えば、上のように書けば、vagrant upで仮想マシン上のOS起動した時にlamp.shが実行されます。 ですので、lamp.sh内にAMP導入のためのコマンドを書いておけば、vagrant upでAMPを入れてくれるというわけです。 この部分はAnsibleやChefなどの構成管理ツールでもできるそうです。 (早くAnsible覚えたい)

lamp.shをどのように書くかは各自の好みによるでしょう。 パッケージからAMPをとってきてもいいし、ソースコードからビルドしてもよいと思います。 私はこちらのブログを参考にさせていただいて、ソースコードからビルドしました。 そんでもって、lamp.shは以下のような内容になりました。

# basis

yum -y install wget
yum -y groupinstall development base

# Mysql

wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
rpm -ihv mysql57-community-release-el7-11.noarch.rpm
yum repolist
yum -y install mysql-server mysql-devel

#OpenSSL

yum -y install zlib-devel perl perl-core
cd /usr/local/src/
wget https://www.openssl.org/source/openssl-1.1.0f.tar.gz
tar xvzf openssl-1.1.0f.tar.gz
cd openssl-1.1.0f/
./config --prefix=/usr/local/openssl-1.1.0f shared zlib
make depend
make
make test
make install
echo /usr/local/openssl-1.1.0f/lib > /etc/ld.so.conf.d/openssl110f.conf
ldconfig

# Nghttp2
yum -y install libev-devel c-ares-devel
cd /usr/local/src/
wget https://github.com/nghttp2/nghttp2/releases/download/v1.23.1/nghttp2-1.23.1.tar.gz
tar xvzf nghttp2-1.23.1.tar.gz
cd nghttp2-1.23.1/
env OPENSSL_CFLAGS="-I/usr/local/openssl-1.1.0f/include" OPENSSL_LIBS="-L/usr/local/openssl-1.1.0f/lib -lssl -lcrypto" ./configure -enable-app
make
make install
echo /usr/local/lib > /etc/ld.so.conf.d/usr-local-lib.conf
ldconfig

# Apache

## APR

cd /usr/local/src/
wget http://ftp.jaist.ac.jp/pub/apache//apr/apr-1.6.2.tar.gz
tar xvzf apr-1.6.2.tar.gz
cd apr-1.6.2/
./configure
make
make install 


## ARP-util

yum -y install expat-devel pcre-devel
cd /usr/local/src/
wget http://ftp.jaist.ac.jp/pub/apache//apr/apr-util-1.6.0.tar.gz
tar xvzf apr-util-1.6.0.tar.gz
cd apr-util-1.6.0/
./configure --with-apr=/usr/local/apr
make
make install
echo finARP-util

## Apache

cd /usr/local/src/
wget http://ftp.riken.jp/net/apache//httpd/httpd-2.4.26.tar.gz
tar xvzf httpd-2.4.26.tar.gz
cd httpd-2.4.26/
./configure \
    --enable-http2 \
    --enable-ssl \
    --with-ssl=/usr/local/openssl-1.1.0f \
    --enable-so \
    --enable-mods-shared=all \
    --enable-mpms-shared=all
make
make install

#PHP

yum -y install libxml2-devel libjpeg-devel libpng-devel
wget http://jp2.php.net/get/php-7.1.6.tar.gz/from/this/mirror -O php-7.1.6.tar.gz
tar -zxvf php-7.1.6.tar.gz
cd php-7.1.6
./configure --enable-mbstring --with-apxs2=/usr/local/apache2/bin/apxs --enable-pdo --with-gd --with-png-dir=/usr/local --with-jpeg-dir=/usr/local --with-mysql
make
make install

おそらく2017/6月末時点では最新のAMPを導入できたと思います。 ソースコードはその時々で新しいものと変わっていると思うので、適宜lamp.shを書き換えてやってください。

それが書けたら、vagrant upしてみましょう。 恐らく、OSが起動し、その後lamp.shが実行されます。 結構時間がかかるので、コーラをすすって気長に待ちましょう。 それが終わったら、サービスを起動したり、各サービスの設定を行いましょう。

LAMP導入済みのBoxファイルを作る

vagrantでは、Boxファイルさえあれば、いくつでも同じ環境を構築できますし、違うPCにその環境を持ち運びすることもできます。 ですので、ある程度LAMP環境が整ったら、次はBoxファイルを作成していきましょう。 Boxファイルの作成は難しいと思いきや、とても簡単です。

vagrant package default --output lamp.box

lamp.boxというファイルが作成されます。 その後、

vagrant box add lamp lamp.box

とすれば、lamp.boxが使用可能になります。

mkdir lamp && cd lamp
vagrant init lamp

としてlampディレクトリにVagrantfileを作成します。(Vagrantfileの中身を確認して必要ならば書き換えてください) 最後に、

vagrant up

でAMP入りのCentOSを起動します。 これ以降は「vagrant upと一発叩けば、LAMP環境(Apache + MySQL + PHP入りのCentOS)が起動する」ことができます。

終わりに

Vagrantはそれほど学習コストをかけることなく、手軽に環境構築の自動化や持ち運びを可能にしてくれます。 仮想環境構築ツールは色々ありますが、まずはVagrantでお手軽にやってみるというのがいいかもしれません。