AWS x OpenVPNでP2P接続できる環境を作る

目的

遠隔地の端末XにNATを挟まずに接続したい!

端末Xの既存環境はいじりたくない!

(ついでに、クラウドと連携できると夢が広がるね!)


上記実現のために、

  1. VPN接続、かつルーティングのみで構成する
  2. 端末Xが接続するルーター(ex.ラズパイ等)に、VPNクライアント環境を構築する
  3. AWSパブリックサブネット上にVPNサーバーを構築する

想定するネットワークは以下の通り

image

赤、青、黒色のIPアドレスはそれぞれのサブネット内で割り振られたもので、紫色のIPアドレスはVPNネットワーク上で割り振られるアドレスとする

ここで、赤のVPNクライアント(10.8.0.6)から、青のVPNクライアントサブネット上の端末X(192.168.20.5)に、プライベートアドレス指定でアクセス可能な環境を構築する

具体的にやること

上記環境を構築するために、以下の手順で作業を行う

  1. AWSパブリックインスタンスにOpenVPNを導入する
  2. OpenVPN接続用の証明書を発行する
  3. サーバーの準備をする
  4. クライアントの準備をする
    1. mac編
    2. ubuntu編
  5. 各サブネットに接続確認を行う

なお、VPNクライアントすべてに対して、OpenVPN環境は未導入、VPNクライアント兼ルーターにはRaspberryPiを使用し、すでにルーターとして利用可能な状態であるとする

また、赤のVPNクライアントのOSはmacとする

1. AWSにOpenVPNを導入する

前提条件

AWS上のVPC、及びその内部のパブリックサブネットとプライベートサブネットは作成済みであるものとし、作成方法などの解説は行わない

以下に最低限必要な設定を示す

AWSパブリックサブネット上でVPNサーバーとして利用するインスタンスのOSには、Amazon Linux AMI 2016.09.1(HVM)を使用する

ボリュームサイズや処理性能は特に指定しないが、セキュリティグループ設定の際に、ssh及びVPN接続用に以下のポートを空けておく

  • ssh接続用ポート

    • タイプ:SSH
    • プロトコル:TCP
    • ポート範囲:22
    • 送信元:任意
  • VPN接続用ポート
    • タイプ:カスタムUDPルール
    • プロトコル:UDP
    • ポート範囲:1194
    • 送信元:任意

VPN接続用のポート設定は以降で利用する

他、必要に応じてソフトウェアの更新などを行っておく

合わせて、接続確認用にプライベートサブネット上にインスタンス(10.0.1.228)を立ち上げておく

パブリックサブネット上のインスタンスをOpenVPNサーバーとして動かすに当たり、導入が必要なものは以下の二つである

1. OpenVPN(v2.3.12)
2. easy-rsa(証明書方式の場合)(v3.0.0)

まずはsshでインスタンスに接続し、これらを導入する

OpenVPNのインストール

OpenVPNはyumでインストールできる

$ sudo yum install -y openvpn
...
完了しました!

基本的に、自動で自動起動に登録される

easy-rsaのインストール

拡張性、安全性、そして複数のクライアントを管理するVPNを構成するために、easy-rsaを利用する

easy-rsaはバイナリを取得、解凍して導入する

また、以降の作業は/usr/local/EasyRSA/ディレクトリ下で行うので移動しておく

$ wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.0-rc2/EasyRSA-3.0.0-rc2.tgz
...
2017-03-28 02:22:13 (107 KB/s) - `EasyRSA-3.0.0-rc2.tgz' へ保存完了 [34886/34886]
$ tar -xvzf EasyRSA-3.0.0-rc2.tgz
...
EasyRSA-3.0.0-rc2/easyrsa
$ sudo mv EasyRSA-3.0.0-rc2 /usr/local/EasyRSA
$ cd /usr/local/EasyRSA/

2. OpenVPN接続用の証明書を発行する

easy-rsaの初期設定

easy-rsaを導入した際には、以下のコマンドで認証情報を生成するための初期設定を行う必要がある

  1. init-pki
  2. build-ca
  3. gen-dh

init-pki

init-pkiを実行し、初期化を行う

$ ./easyrsa init-pki
init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /usr/local/EasyRSA/pki

ここで生成された/usr/local/EasyRSA/pki/ディレクトリに、以降の手順で生成する認証用ファイルが配置される

build-ca

build-caで認証局を作成する

$ ./easyrsa build-ca
Generating a 2048 bit RSA private key
.+++
..+++
writing new private key to '/usr/local/EasyRSA/pki/private/ca.key'
Enter PEM pass phrase:<パスフレーズ>
Verifying - Enter PEM pass phrase:<パスフレーズ(確認)>
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:<ホスト名等>
CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/usr/local/EasyRSA/pki/ca.crt
  • <パスフレーズ>:任意のパスワード

    • 証明書の発行の際に必要、覚えておくこと
  • <ホスト名等>:認証局を識別するための名称
    • 本気で運用するならばつけるべき
    • 今回はVPN接続目的のみのため適当な名称 or デフォルトで可

gen-dh

gen-dhでDHパラメータを生成する

  • DH:Diffie-Hellman

    • 公開鍵暗号方式の具体的な方法の一つ
    • DHは公開鍵暗号方式の概念を初めて公開した人たちの名前
$  ./easyrsa gen-dh
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
...

DH parameters of size 2048 created at /usr/local/EasyRSA/pki/dh.pem

以上で、証明書の発行準備は完了である

次の手順から、実際に使用するサーバー/クライアント向けの認証ファイルの生成を行っていく

サーバー用秘密鍵・証明書の生成

build-server-fullでサーバー用秘密鍵と証明書の作成、及び署名を行う

$ ./easyrsa build-server-full server nopass
Generating a 2048 bit RSA private key
..........................+++
..................................+++
writing new private key to '/usr/local/EasyRSA/pki/private/server.key'
-----
Using configuration from /usr/local/EasyRSA/openssl-1.0.cnf
Enter pass phrase for /usr/local/EasyRSA/pki/private/ca.key:<登録したパスフレーズ>
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'server'
Certificate is to be certified until Mar 26 02:26:31 2027 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
  • 証明書読み込み時にパスフレーズ不要とする場合はnopassオプションを使用する

    • オプションを使用しない場合、VPN接続時に毎回、パスフレーズの入力が求められる
  • 途中でCA証明書生成時に設定したパスフレーズの入力を求められるので入力する

クライアント用秘密鍵・証明書の生成

build-client-fullでクライアント用秘密鍵と証明書の作成、及び署名を行う

以下に、ファイルを生成するコマンドの例を示す

$  ./easyrsa build-client-full client1 nopass

Generating a 2048 bit RSA private key
.....................................................................+++
.........+++
writing new private key to '/usr/local/EasyRSA/pki/private/client1.key'
-----
Using configuration from /usr/local/EasyRSA/openssl-1.0.cnf
Enter pass phrase for /usr/local/EasyRSA/pki/private/ca.key:<登録したパスフレーズ>
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'client1'
Certificate is to be certified until Mar  8 07:31:37 2025 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
  • client1には任意のクライアント名を指定する

    • ex, client1,client2,client3,and more…
    • ex, alpha,beta,and more…
  • パスフレーズ不要とする場合はnopassオプションを使用する

同様に、必要なだけクライアント用の秘密鍵、証明書の生成を行う

今回はclient1に加え、ルーター兼用クライアント向けにclient2も作成しておく

その際のコマンドは以下のようになる

$  ./easyrsa build-client-full client2 nopass

以上で、認証に必要なファイルの生成は終了である

次に、これらのファイルを配置し、VPN接続を行うための設定を行っていく

3. サーバーの準備をする

これまでに生成したファイルのうち、以下のファイルを/etc/openvpn/に移動する

  • ca証明書:ca.crt
  • サーバー用証明書:server.crt
  • サーバー用秘密鍵:server.key
  • DHパラメータ:dh2048.pem
$ sudo cp pki/ca.crt /etc/openvpn/
$ sudo cp pki/issued/server.crt /etc/openvpn/
$ sudo cp pki/private/server.key /etc/openvpn/
$ sudo cp pki/dh.pem /etc/openvpn/dh2048.pem

VPNサーバー設定ファイルのサンプルをコピーし、それをもとに実際にサーバーとして動かす際の設定を行う

サンプルの置かれているディレクトリは以下の通りである

/usr/share/doc/openvpn-2.3.12/sample/sample-config-files/server.conf

このサーバー設定ファイルも/etc/openvpn/に配置する

$ sudo cp /usr/share/doc/openvpn-2.3.12/sample/sample-config-files/server.conf /etc/openvpn/server.conf

サーバー設定ファイルを環境に合わせて修正する

好みのエディタで開き、編集する

$ sudo vi /etc/openvpn/server.conf

以下に編集例(抜粋)を示す

port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 10.0.0.0 255.255.0.0"
push "route 192.168.20.0 255.255.255.0"
client-config-dir ccd
route 192.168.20.0 255.255.255.0
client-to-client
keepalive 10 120
comp-lzo
persist-key
persist-tun
status openvpn-status.log
log-append  openvpn.log
verb 3
  • portprototunはそれぞれ接続ポート番号、接続方式(udp/tcp)、インターフェイス形式(tap/tun)を指定する

    • 本環境では、UDP1194ポートをVPN接続用として開放しているので、これを指定する
    • この設定は、後述のクライアント設定ファイルでも使用する
  • cacertkeydhは、各々のサーバー用ファイルの場所を、/etc/openvpn/ディレクトリを基準とした相対パスで入力する
  • serverには、サーバーサブネットアドレス範囲を指定する
  • push "route ..."には、クライアントへ通知する、クライアントからアクセス可能なサブネットを指定する

    • 実際の動作としては、クライアントのルーティングテーブルに、指定したサブネットへアクセスする場合に、VPNサーバーへとルーティングするような設定が追加される
  • client-config-dir ccdオプションは、クライアントサブネットへアクセスする必要がある場合など、クライアントに関する設定が必要な際に有効化する

    • 有効化した際には/etc/openvpn/ccd/ディレクトリを作成しないと、openvpnそのものが正常に起動しなくなるので注意する(次の手順で作成)
    • ディレクトリ名称ccdは任意のディレクトリを指定可能
    • 合わせて、route ...により、クライアントサブネットとして192.168.20.0/24サブネットを、サーバーのルーティングテーブルに追加している
  • client-to-clientオプションは、クライアント間の通信、及びクライアントサブネット間の通信を許可する場合に有効化する
  • 設定項目については以下も参照

上記設定では、サーバー側からVPNクライアントに通知するルーティング設定として、以下の二つのサブネットにアクセスする際に、サーバーへとルーティングするような設定を加えている

  • 192.168.20.0/24
  • 10.0.0.0/16

前者のサブネットは、青のVPNクライアント兼ルーターの属するクライアントサブネットを示す

後者のサブネットは、AWSのVPC上のサブネット10.0.0.0/24(サーバーの立っているパブリックサブネット)と10.0.1.0/24(プライベートサブネット)を内包する

クライアントサブネットへの接続設定

VPNサーバーに、アクセス可能なVPNクライアントサブネットへのルートを登録する

サーバー設定ファイル上で追加したVPNクライアントサブネット192.168.20.0/24への通信をclient2へルーティングするよう設定を加える

まず、/etc/openvpn/ccd/ディレクトリを作成する

$ sudo mkdir /etc/openvpn/ccd

ディレクトリは、サーバー設定ファイル上で行った指定に従う

次に、ccdディレクトリ中にclient2という名称のファイルを生成し、iroute ...にサブネットを指定する

$sudo vi /etc/openvpn/ccd/client2

iroute 192.168.20.0 255.255.255.0

このiroute ...の設定は、OpenVPNサーバーに対し、192.168.20.0/24サブネット(上記設定の場合)への通信を、client2にルートさせるためのものである

サーバーをルーターとして使用可能にする

VPNサーバーにルーターとしての機能を持たせるためには、IPフォワーディングを許可する必要がある

以下のファイルを編集し、net.ipv4.ip_forwardを1に変更する

$ sudo vi /etc/sysctl.conf

net.ipv4.ip_forward = 1

以上で、インスタンス内で実施する必要のある設定は終了である

次に、AWS上で、ルーティング設定の修正を行う

AWS上の設定

AWS上のサブネットとデータの送受信を行うために、以下の設定を行う必要がある

  1. サブネットのルートテーブルへ、VPNネットワークのアドレスを登録
  2. VPNサーバーのインスタンスの送信元/送信先の変更チェックの無効化

ルートテーブルの修正

VPNクライアントからサーバー側サブネットにアクセスするため、サーバー側サブネットのルートテーブルにVPNサブネット(10.8.0.0/24)を登録する

VPNクライアントからサーバー側サブネットに接続するための設定はサーバー側設定ファイル上のpush "route ..."で実施済みであるが、サーバー側サブネットからVPNクライアントに接続するための情報は与えられていない

よって、AWSサブネットに紐づけられたルートテーブルの設定を修正する

  • AWS>[VPC]>[ルートテーブル]>サブネットに関連付けているルートテーブルを選択
    * [ルート]タブ>[編集]>[別ルートの追加]

    • 送信先:10.8.0.0/24(VPNサブネットを指定)
    • ターゲット:OpenVPNインスタンス(のネットワークインターフェイス)を指定

サーバー側サブネットからVPNクライアントサブネットにアクセスする場合には、同様の手順(送信先のみ変更)でルートテーブルに追加する

今回は、サーバー側サブネット-クライアントサブネット間のアクセスはないものと想定し、設定しない

送信元/送信先の変更チェックの無効化

AWSのEC2インスタンスは通常、自身のIPアドレス以外を指定した通信を無視する設定となっている

この状態では、クライアントサブネット間の通信のように、自インスタンス以外に向かう通信をルーティングすることができない

よって、この設定を無効化し、通信を受け取ることができるようにする必要がある

以下の設定を行う

  • AWS>[EC2]>VPNサーバーのインスタンスを選択

    • [アクション]>[ネットワーキング]>[送信元/送信先の変更チェック]
    • ダイアログにて、有効である場合には無効化を行う

02.png

ここまでの設定が終了したならば、念のためインスタンスを再起動させておく

4.1. クライアントの準備をする:mac編

以下の環境を想定し、クライアント側の準備を行う
(先述の想定環境中の赤のVPNクライアントを想定する)

  • OS:mac(macbook pro)
  • VPNクライアント:TunnelBlick(GUI)

クライアントへ必要なファイルを移動

SCPコマンド等を使用し、以下のファイルをクライアントへ移動する

  • ca証明書:ca.crt
  • クライアント用秘密鍵:client1.key等
  • クライアント証明書:client1.crt等

SCPコマンドを使用して、ファイルをダウンロードする際の例を以下に示す

  • 以下はssh接続用のキーが存在する場合の例

    • pemファイル名:xxx.pem
    • ダウンロード元アカウント名:ec2-user(AWSデフォルトの場合)
    • ダウンロード元グローバルIP:xxx.xxx.xxx.xxx(VPNサーバーグローバルIP)
    • ダウンロード元ファイル:/usr/local/EasyRSA/pki/private/ca.key等
    • ダウンロード先ディレクトリ:/etc/openvpn/
  • 接続先のポート番号を指定する場合は、scp -P xxxx -i ...
  • 接続先のパスは絶対パスで指定する
$ sudo scp -i ~/.ssh/xxx.pem ec2-user@xxx.xxx.xxx.xxx:/usr/local/EasyRSA/pki/private/ca.key /etc/openvpn
$ sudo scp -i ~/.ssh/xxx.pem ec2-user@xxx.xxx.xxx.xxx:/usr/local/EasyRSA/pki/issued/client1.crt /etc/openvpn
$ sudo scp -i ~/.ssh/xxx.pem ec2-user@xxx.xxx.xxx.xxx:/usr/local/EasyRSA/pki/private/client1.key /etc/openvpn

取得したファイルは/etc/openvpn/に配置する

クライアント設定ファイルの修正

必要があれば、クライアント設定ファイルのサンプルも、クライアントにコピーし使用する

あるいは、OpenVPNのサイトより、コピーして使用することもできる

ファイル名は任意であるが、ここではclient.confとする

以下にクライアント設定ファイルの設定例(抜粋)を示す

client
dev tun
proto udp
remote <サーバーグローバルIP> 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client1.crt
key client1.key
comp-lzo
verb 3
  • clientは、この設定ファイルを読んだ端末がクライアント側であることを示す
  • devprotoの指定はサーバー設定ファイル(前述)に従う
  • remoteには、<サーバーグローバルIP>とサーバーポート番号をスペース区切りで記述する

    • <サーバーグローバルIP>にはグローバルIPでなくとも、クライアントからサーバーにアクセスできるIPアドレス、あるいはホスト名を指定する
    • サーバーポート番号の指定はサーバー設定ファイルに従う
  • cacertkeyには、max x tunnelblick環境では、/etc/openvpn/ディレクトリを基準としたパスを指定する

    • 今回は/etc/openvpn/直下のためディレクトリ指定は行う必要はない

Tunnelblickへの登録

作成したclient.confを、Tunnelblickで開く

  • エラーが出た場合は修正する

    • どこが間違っているかは教えてくれる
    • tls設定がサンプル時点で有効になっている場合があるので確認が必要
  • 特に、ca証明書のディレクトリ指定などに注意する

問題なく登録が終わったならば、”接続”できるはずである

4.2. クライアントの準備をする:ubuntu編

インストール手法などは異なるものの、linux系統でOpenVPNをクライアントとして導入する手順は同一である
(今回は、具体的にRaspberryPiにOpenVPNを導入する場合を想定する)

ここで、クライアントが所属するサブネットワークへのアクセスを許可する場合、VPNクライアント側で直接設定をする必要は基本的には存在しない

サブネットへのルーティング設定は、VPNサーバー側の設定のみで良い

ただし、ルーター上でサブネットの設定を行う必要はあるが、すでにルーターとして使用可能な状態であり、設定済みであるとして、今回は説明しない

ここでは以下の環境を想定し、クライアント側の準備を行う

  • OS:ubuntu(macbook pro上でrefind使用)
  • VPNクライアント:OpenVPN(CUI)

OpenVPNのインストール

以下のコマンドでOpenVPNをインストールする

$ sudo apt-get install openvpn

クライアントへ必要なファイルを移動

SCPコマンド等を使用し、以下のファイルをクライアントへ移動する

  • ca証明書:ca.crt
  • クライアント用秘密鍵:client1.key等
  • クライアント証明書:client1.crt等

取得したファイルは/etc/openvpn/に配置する

クライアント設定ファイルの修正

VPNクライアント設定ファイルのサンプルをコピーし、それをもとに実際の設定を行う

サンプルの置かれているディレクトリは以下の通りである

/usr/share/doc/openvpn-2.3.12/sample/sample-config-files/client.conf

サーバー設定ファイルが置かれていたディレクトリと同一である

このクライアント設定ファイルも/etc/openvpn/に配置する

$ sudo cp /usr/share/doc/openvpn-2.3.12/sample/sample-config-files/client.conf /etc/openvpn/client.conf

サーバー設定ファイルを環境に合わせて修正する

好みのエディタで開き、編集する

$ sudo vi /etc/openvpn/client.conf

以下に編集例(抜粋)を示す

client
dev tun
proto udp
remote <サーバーグローバルIP> 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca /etc/openvpn/ca.crt
cert /etc/openvpn/client1.crt
key /etc/openvpn/client1.key
comp-lzo
verb 3
  • 一番上のclientは、このファイルを読んだ端末がクライアント側であることを示す
  • cacertkeyには絶対パスを指定する

なお、上記編集例はサーバー設定ファイルの内容に対応する

VPNサーバーへの接続

VPNのクライアントとして起動させるには、起動の際にクライアント設定ファイルを指定する必要がある

以下のコマンドで、クライアントようコンフィグファイルを指定し、クライアントとしてVPNサーバーへ接続する

$ sudo /usr/sbin/openvpn /etc/openvpn/client.conf
...
... Initialization Sequence Completed

※コンソールを一つ占有することに注意する

5. 各サブネットに接続確認を行う

ここでは、以下のような環境で、クライアントからVPNサーバーを経由し、サーバー側サブネットへtracerouteを行う

ここまでの手順通りに行っていれば、問題なく接続できるはずである

netstatコマンドなどで、対応するルーティングが行われているか確認する

VPNクライアントからping、あるいは以下のようなtracerouteコマンドが通れば、正常に設定できている

$ traceroute 10.0.1.228
traceroute to 10.0.1.228 (10.0.1.228), 64 hops max, 52 byte packets
1 10.8.0.1 (10.8.0.1) xxx ms xxx ms xxx ms
2 10.0.1.228 (10.0.1.228) xxx ms xxx ms xxx ms
$ traceroute 10.8.0.10
traceroute to 10.8.0.10 (10.8.0.10), 64 hops max, 52 byte packets
1 10.8.0.10 (10.8.0.10) xxx ms xxx ms xxx ms
$ traceroute 192.168.20.5
traceroute to 192.168.20.5 (192.168.20.5), 64 hops max, 52 byte packets
1 10.8.0.10 (10.8.0.10) xxx ms xxx ms xxx ms
2 192.168.20.5 (192.168.20.5) xxx ms xxx ms xxx ms

以上

続きを読む

Amazon Elasticsearch ServiceにTwitterの情報を集めてみよう EC2 + AWS ES

何をしているか

Twitterの情報楽に集めて色々出来ないかと思い試してみました。
割りとメジャーなネタなのか結構資料あって楽でした。
logstash + Elasticserchの勉強が出来て良かったです。

前提

  • Elasticserch Serviceの構築が完了し、AWSesに対してデータの投入や削除が出来るようにポリシーの設定まで完了している
  • コンソール上のKibanaエンドポイントからKibanaのコンソールが見れるようになっている

今回省略しましたが、需要あるなら書こうかな・・・?

手順

1.EC2インスタンスの作成

Ec2を一台作成します。

  • SSHが出来るようにしておく

EC2の準備

yum をアップデートしておきます

コマンド
sudo su
yum update -y

Javaのインストール

AmazonLinuxには1.7が入っていた(2017/04 現在)のでjava1.8系を導入

まず確認

コマンド
java -version
結果
java version "1.7.0_131"
OpenJDK Runtime Environment (amzn-2.6.9.0.71.amzn1-x86_64 u131-b00)
OpenJDK 64-Bit Server VM (build 24.131-b00, mixed mode)

インストール

コマンド
yum -y install java-1.8.0-openjdk-devel
alternatives --config java

alternativesコマンドで1.8を指定する

コマンド
java -version
結果
openjdk version "1.8.0_121"
OpenJDK Runtime Environment (build 1.8.0_121-b13)
OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)
コマンド
javac -version
結果
javac 1.8.0_121

javacのほうが1.7だったら

alternatives --config javac で1.8を指定する

参考: Amazon LinuxでJava8/Tomcat8の環境を構築する| Developers.IO

logstashをインストールする

yumから最新版をインストール出来るようにします
参考: 公式リファレンス

鍵のインストールし、レポジトリを登録します

コマンド
rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
戻り値
なし
コマンド
ls /etc/yum.repos.d/
結果
amzn-main.repo  amzn-nosrc.repo  amzn-preview.repo  amzn-updates.repo  epel.repo  epel-testing.repo

では登録

コマンド
cat << _FIN_ > /etc/yum.repos.d/logstash.repo
[logstash-5.x]
name=Elastic repository for 5.x packages
baseurl=https://artifacts.elastic.co/packages/5.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
_FIN_
確認
cat /etc/yum.repos.d/logstash.repo
結果
[logstash-5.x]
name=Elastic repository for 5.x packages
baseurl=https://artifacts.elastic.co/packages/5.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

インストール

コマンド
yum install logstash -y

インストール出来たか確認

コマンド
/usr/share/logstash/bin/logstash --version
結果
logstash 5.3.1

logstash-output-amazon_esプラグインのインストール

参考:logstash-output-amazon_esを使ってAmazon Elasticsearch Serviceにデータを投入する | Developers.IO
記事で書かれているものと、logstashのバージョンがだいぶ違うのでパスが異なります。注意してください

コマンド
/usr/share/logstash/bin/logstash-plugin install logstash-output-amazon_es

ちょっと時間かかります。待ちましょう

戻り値
Validating logstash-output-amazon_es
Installing logstash-output-amazon_es
Installation successful

上記以外でエラーが出たら恐らくJava関係だと思うので戻って確認しましょう。

vi  /etc/logstas/logstash.yml

confファイルの設定
Twitterの方は以前書いたこれを参考に
Twitter Developer登録

変数指定
TWI_KEY=記事を参考に
TWI_KYE_SEC=記事を参考に
TWI_TOKEN=記事を参考に
TWI_TOKEN_SEC=記事を参考に
ES_EDP=ESのエンドポイントを記載(******.es.amazonaws.com)
ES_REG=ESを立てたリージョンを記載

コマンド
cat << _FIN_ > /etc/logstash/conf.d/twitter.conf
input {
  twitter {
    consumer_key => "$TWI_KEY"
    consumer_secret => "$TWI_KYE_SEC"
    oauth_token => "$TWI_TOKEN"
    oauth_token_secret => "$TWI_TOKEN_SEC"
    keywords => ["引っ掛けたいキーワード"]
    full_tweet => true
  }
}
output { 
    amazon_es {
        hosts => ["$ES_EDP"]
        region => "$ES_REG"
        index => "twitter"
        document_type => "stream"
    }
    stdout { } 
}
_FIN_
コマンド
cat /etc/logstash/conf.d/twitter.conf

これで指定したとおりに結果が帰ってくれば大丈夫です。

実行

コマンド
/usr/share/logstash/bin/logstash --path.settings /etc/logstash -f /etc/logstash/conf.d/twitter.conf

しばらく待つとスタートします。

2017-04-26T09:50:06.000Z %{host} %{message}

こんな感じで標準出力が出てくればOKです。
引っかかりが弱いツイートだとゆっくり出てきますが、ものすごい早いやつかませるととんでもなく大量に出てきます。

https://www.elastic.co/guide/en/logstash/current/plugins-inputs-twitter.html
ここに書いてある通りですが、ストリーミング全部喰って、読み込み制限かかったら5分待機してもう一回読み込む様になってます。

Kibanaで確認すれば情報の確認ができると思います。

Kibanaの調教はまた別途溜まったら書きます。

続きを読む

Elastic Beanstalkトラブルシューティング集

公式のトラブルシューティングに載ってないものをまとめてみました。
いろいろハマった気もしますが、覚えているやつだけ記載しています。

と、その前に

基本的なデバッグ方法としては以下の通りです。

  1. eb create をするときに –debug をつける
  2. eb ssh して直接インスタンスの中を確認する
  3. eb logs する

インスタンスが生成できていなければ 1. 、インスタンスが生成できていれば 2. 、pingで疎通できれば 3. で探っていく感じになります。

Q1. Application Load Balancer を選択するとエラーになる

eb create するときに Select a load balancer type で application を選択すると、こんな感じのエラーが出る。

eb : Configuration validation exception: Invalid option value: 'null' (Namespace: 'aws:ec2:vpc', OptionName: 'Subnets'): Specify the subnets for the VPC for load balancer type application.

A1. コマンドオプションで指定する

VPC が複数ある環境の場合、Elastic Beanstalk がどの VPC を選んだらいいか判断できないようで、このエラーが発生するみたいです。
なので、 eb create のコマンドオプションで VPC 関連の情報を指定すれば OK です。

eb create xxxxxxxx \
    --elb-type application \
    --vpc.id vpc-xxxxxxxx \
    --vpc.elbsubnets subnet-xxxxxxxx,subnet-xxxxxxxx \
    --vpc.ec2subnets subnet-xxxxxxxx,subnet-xxxxxxxx \
    --vpc.elbpublic \
    --vpc.publicip

Q2. リソースが作成できない

以下のようなエラーが出てリソースの作成に失敗する。

Stack named 'awseb-e-xxxxxxxxxx-stack' aborted operation. Current state: 'CREATE_FAILED' Reason: The following resource(s) failed to create: [ALB, AWSEBV2LoadBalancerTargetGroup, AWSEBBeanstalkMetadata, AWSEBLoadBalancerSecurityGroup].

A2. 権限を付与する

実行ユーザーに AWSElasticBeanstalkFullAccess というポリシーをアタッチすれば OK です。
ここでいう実行ユーザーとは ~/.aws/config で指定している IAM ユーザーのことです。

Q3. composer / bundler などで落ちる

hooks/appdeploy/pre にある shell を実行するタイミングで落ちる。
例えばこんなエラーです。

/var/log/eb-activity.log を見てもだいたい解決しないのはお約束です。

ERROR: [Instance: i-xxxxxxxx] Command failed on instance. Return code: 1 Output: [CMD-AppDeploy/AppDeployStage0/AppDeployPreHook/10_composer_install.sh] command failed with error code 1: /opt/elasticbeanstalk/hooks/appdeploy/pre/10_composer_install.sh
++ /opt/elasticbeanstalk/bin/get-config container -k app_staging_dir
+ EB_APP_STAGING_DIR=/var/app/ondeck
+ cd /var/app/ondeck
+ '[' -f composer.json ']'
+ export COMPOSER_HOME=/root
+ COMPOSER_HOME=/root
+ '[' -d vendor ']'
++ /opt/elasticbeanstalk/bin/get-config optionsettings -n aws:elasticbeanstalk:container:php:phpini -o composer_options
+ PHP_COMPOSER_OPTIONS=--no-dev
+ echo 'Found composer.json file. Attempting to install vendors.'
Found composer.json file. Attempting to install vendors.
+ composer.phar install --no-ansi --no-interaction --no-dev

なんとかかんとか

Hook //opt/elasticbeanstalk/hooks/appdeploy/pre/10_composer_install.sh failed. For more detail, check /var/log/eb-activity.log using console or EB CLI.

この場合は出ているエラーのうち、なんとかかんとかの部分で判断できます。

A3-1. Cannot allocate memory

Cannot allocate memory と出ているなら composer の実行時にメモリが足りていない可能性が高いので、.ebextensions でメモリを増やす設定を追加します。

.ebextensions
option_settings:
  aws:elasticbeanstalk:container:php:phpini:
    memory_limit: 1024M

インスタンスを大きくするとかできるなら楽ちんです。
(swap ファイル作るでも解決できるはずだが調べてない)

A3-2. ErrorException

[ErrorException] Undefined index: hash

ERROR: bundle install failed!
の場合、lock ファイルおかしい可能性があります。

eb ssh をしてみて、lock ファイルを消してライブラリをインストールすると分かったりします。

# ruby なら
cd /var/app/ondeck/
sudo rm Gemfile.lock
bundle install

# php なら
cd /var/app/ondeck/
sudo rm composer.lock
composer.phar install

僕の場合は composer 自体のバージョンがローカル環境とあっていないためにエラーになっていました。
なので、.ebextensions でバージョンを指定して対応しました。

.ebextensions
commands:
  01updateComposer:
    command: export HOME=/root && /usr/bin/composer.phar self-update 1.5-dev

Q4. DB に繋がらない

エラーログをみると DB に繋げないっていうのです。

A4. ローカル IP からのアクセスを変更する

原因としては Application Load Balancer を選択したせいで subnet の IPv4 CIDR が複数のブロックになった可能性が疑われます。

なので、MySQL にログインして該当のブロックアドレスに GRANT してあげれば OK です。

use mysql;
SELECT Host, User, Password, Select_priv, Insert_priv,Update_priv, Delete_priv FROM user; -- 権限を調べてみる

GRANT ALL PRIVILEGES ON database.* to hoge@"ブロックアドレス%" IDENTIFIED BY 'password' WITH GRANT OPTION;

Q5. 環境を削除しても消えない

Elastic Beanstalk のイベントでこんな感じになって環境が消せないという症状です。

The environment termination step failed because at least one of the environment termination workflows failed.

A5. 問い合わせたら消してくれるっぽい

まあ影響ないし置いといたらいいんじゃないかな。。。

続きを読む

Poweshellでsshチックなことをする

経緯

aws で、最近 iam role の付け替えが出来るようになりました。
早速 windows の iam role を起動したまま切り替えたのですが、その際に ssm が connection timeout になってしまいました。
Restart-Service Ec2ConfigOnline になるのですが、対象サーバがそれなりにあったので、もう少し楽にできないかと思い、 powershell を使うことにしました。

方法

winrm を使用すれば、 powershell でリモート接続しコマンドを叩ける。
ざっくりと二通りあったのでメモしておきます。

wirm でリモート接続するためには、 Enable-PSRemoting で有効化する必要があるので、詳しくは参考 URL を見ていただければと。。。

方法其ノ一

セッションをはる

New-PSSession -ComputerName <Public DNS or Private DNS>
※ __Public DNS__ , __Private DNS__ どちらでも行けました。検証済み

下記でリモート接続しているサーバに対してコマンドを叩く

Invoke-Command -Session $sess -ScriptBlock {ls;}

添付画像のように、変数でうけるのがベターっぽいです。

jump.png

補足

New-PSSession を使用すると、サインアウトしても session は残るので、 Remove-Session してあげましょう。

方法其ノ弐

New-PSSession だけではなく、 Enter-PSSession でも出来るようです。

Enter-PSSession -ComputerName <Public DNS or Private DNS>

jump 2.png

ほぼ見えてませんが、下記のようになってます。
多段sshしている気分になります

[Public DNS]: PS C:¥Users¥hoge¥Documents>

まとめ
RDP したくないから、ssm使ってるのになんでやねん!ってなりました。
ただ、一つ知見が増えて良かったです。

参考

http://hensa40.cutegirl.jp/archives/677

続きを読む

GolangのWebアプリケーションをECSにデプロイするCI環境をCodeCommit、CodeBuild、CodePipelineでつくる【cloudpack大阪ブログ】

cloudpack大阪の佐々木です。
内部で開発しているGolangのWebアプリをECSで稼働させるように、CI環境をつくってみました。
パブリックのgithubとかであれば、CircleCIとかでもう少しいい感じにできるとおもうのですが、ローカルのGitリポジトリで開発しているため、パブリックアクセスできないCodeCommitを使う形にしました。

概要

動作イメージは下記のような感じです。

Kobito.HvgCcI.png

  1. CodeCommitにプッシュ
  2. CodePipelineでコミットを検知し、CodeBuildを起動
  3. CodeBuildでコンパイルし、実行ファイルをビルド、S3に保存
  4. S3に保存後、ECSのサービスの既存タスクを停止
  5. サービスが新しいタスクを起動
  6. 新しいコンテナがS3から実行ファイルをダウンロードし、実行

環境

アプリケーション

もとのアプリケーションのファイルは下記のような感じです。

.
├── app
│   ├── model
│   ├── util
│   └── view
├── bindata.go
├── glide.yaml
├── server.go
└── static
    └── js

リージョン

CodeCommitが東京リージョン未対応のため、すべてus-east-1で作成します。

設定

CodeCommitリポジトリの作成

リポジトリの作成

リポジトリ名をgotestにします。
Kobito.WZjQG3.png

CodeCommitリポジトリにアクセスするユーザを作成

IAMでユーザを作成します。
AccessKeyを使ったHTTPSでのアクセスも可能ですが、SSH接続でやってみます。
ユーザを作成したら、認証情報のタブを開いて、AWS CodeCommitのSSHキーSSH 公開キーのアップロード をクリックし、SSH公開鍵を貼り付けます。
Kobito.zYMfwr.png

アップロードすると、SSHキーIDが発行されます。
Kobito.7LDjWt.png

SSHのconfigに情報を追加します。

~/.ssh/config
Host git-codecommit.*.amazonaws.com
    User `SSH キー ID`
    IdentityFile ~/.ssh/秘密鍵

コードをpushしておきます。

$ git push origin master                                                          
Counting objects: 41, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (34/34), done.
Writing objects: 100% (41/41), 73.27 KiB | 0 bytes/s, done.
Total 41 (delta 3), reused 0 (delta 0)
To ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/gotest
 * [new branch]      master -> master

Buildしたファイル保存用のS3バケットを作成

保存用S3バケットを作成します。

Kobito.hjTh2t.png

CodeBuildプロジェクトを作成

下記のようなプロジェクトを作成します。

Kobito.KHdvNj.png

環境イメージはあらかじめ用意されているGolangのものを使用しました。
当初、自分でコンテナを作成し、ビルド+Dockerコンテナ作成+ECRにプッシュという感じでやりたかったのですが、独自コンテナでDocker on Docker はできない(下記参照)、DockerイメージにGolangをインストールするとビルドのたびに時間がかかりすぎるということで、独自コンテナはあきらめました。
https://forums.aws.amazon.com/thread.jspa?messageID=761184

ロールには自動で生成されるPolicyに、ECSのタスクをコントロールするためにAmazonEC2ContainerServiceFullAccessを追加しています。

CodeBuild用のファイルを作成

下記の2つのファイルを作成します。

buildspec.yml
version: 0.1

phases:
  install:
    commands:
      - go get github.com/Masterminds/glide
      - go get -u github.com/jteeuwen/go-bindata/...    
  build:
    commands:
      - ./build.sh
  post_build:
    commands:
      - aws s3 cp /go/src/git.local/sasaki/gotest/server s3://gotest-pkg/server
      - aws ecs stop-task --task `aws ecs list-tasks --cluster $ECS_CLUSTER_NAME --service-name $ECS_SERVICE_NAME --region $AWS_DEFAULT_REGION --query taskArns --output text` --cluster $ECS_CLUSTER_NAME --region $AWS_DEFAULT_REGION
build.sh
mkdir -p $GOPATH/src/git.local/sasaki/gotest
cp -r app $GOPATH/src/git.local/sasaki/gotest
cp -r static $GOPATH/src/git.local/sasaki/gotest
cp server.go $GOPATH/src/git.local/sasaki/gotest
cp bindata.go $GOPATH/src/git.local/sasaki/gotest
cp glide.yaml $GOPATH/src/git.local/sasaki/gotest
cd $GOPATH/src/git.local/sasaki/gotest
glide up
go-bindata app/view
GOOS=linux GOARCH=amd64 go build server.go bindata.go

buildspec.yml がCodeBuildの設定ファイルになります。
CodeBuildeでGolang用のコンテナを起動しますので、goコマンドは使える状態になっています。
まずinstallフェーズでgolangのglidego-bindataをインストールします。

次にbuildフェーズでbuild.shを実行します。
開発時はローカルにあるGitリポジトリを使っているので、glide up でエラーになることを回避するために、ローカル環境と同じパスにソースをコピーしています。
そのあと、go build でコンパイルしています。

post_buildフェーズでは、S3に実行ファイルをアップロードし、ECSの現在のタスクを停止しています。
artifactでもアップロードはできるのですが、post_buildのECSタスク停止後にアップロードされ、タスクに新しいファイルが反映されないため、このようにしています。

ECRにDockerイメージを作成

下記のDockerfileでDockerイメージを作成し、ECRにプッシュしておきます。

Dockerfile
FROM ubuntu:16.04
RUN apt-get -y update
RUN apt-get install -y python-pip
RUN yes | pip install --upgrade awscli
RUN apt-get remove -y python-pip
ADD start_gotest.sh /
ENTRYPOINT ./start_gotest.sh
start_gotest.sh
aws s3 cp s3://gotest-pkg/server ./
chmod +x server
./server

UbuntuにS3でビルドしたファイルをダウンロードし、実行するだけです。
Alpineでやると、 ./server がどういうわけか、not foundになるので、断念・・・

ECS設定

ECRに保存したイメージを常時稼働するように、タスク定義、サービスの設定します。

CodePipeline

CodePipelineを作成します。

ソースの場所 は作成したCodeCommitリポジトリを指定します。
Kobito.H6ZYi8.png

ビルド は作成したCodeBuildを指定します。
Kobito.xAGCCv.png

デプロイはCodeDeploy等は使用しないので、デプロイなしを選択します。
Kobito.ppkLhz.png

実行

作成したリポジトリに、buildspec.yml と、build.shを追加し、プッシュすると、CodePipelineが反応し、ECSのタスクが再起動されるまで自動実行されます。

Kobito.NZkYFB.png

イケてないところ

  • CodeBuildで使うコンテナが融通がきかない

    • 独自コンテナではDocker on Dockerができないとか
    • Docker + Go等 みたいなコンテナがないとか
    • 本来はビルドプロセスでコンテナイメージつくってECRにプッシュするまでやりたい
  • Artifactが使えてない
    • そもそもあんまりよくわかってない・・・
  • ECRに保存しているアプリケーションを動かすだけのコンテナのサイズがデカすぎ
    • S3からダウンロードするためにubuntuにpipインストールして、aws-cliをpipインストールしただけで、こんなに・・・
ubuntu              16.04               117 MB
gotest-image        latest              462 MB

続きを読む

TensorFlow with GPU on Docker を AWS で起動する

構成

https://github.com/NVIDIA/nvidia-docker にある以下の図が分かりやすい。

図

今回、Server は AWS の p2 インスタンス (GPU インスタンス)。
Host OS は Ubuntu 16.04 を利用する。

手動でインストールが必要なものは以下の通り。

  • CUDA Toolkit / CUDA Driver

    • NVIDIA GPU をコントロールするために必要
    • 2つ同時にインストールされる
  • Docker Engine
  • nvidia-docker
    • Docker コンテナ内から CUDA Toolkit 経由で GPU を触るために必要

1. AWS インスタンス起動

GPU インスタンスの p2 系を起動する。

AMI
Ubuntu Server 16.04 LTS (HVM), SSD Volume Type
備考
ディスクサイズは 100 GB に変更する (デフォルトは 8 GB、足りない)

2. CUDA のインストール

公式ドキュメント 通りに進める。
ただ、ドキュメントが長いので読まない方が良い。ハマると果てしなくハマって辛い。

実際に必要なのは3箇所のみ。

  • “2. Pre-installation Actions” > “2.6. Download the NVIDIA CUDA Toolkit”
  • “3. Package Manager Installation” > “3.6. Ubuntu”
  • “6. Post-installation Actions” > “6.1.1. Environment Setup”

実際のコマンドは以下の通り。

## 2.6 Pre-installation Actions (Download the NVIDIA CUDA Toolkit)
$ wget https://developer.nvidia.com/compute/cuda/8.0/Prod2/local_installers/cuda-repo-ubuntu1604-8-0-local-ga2_8.0.61-1_amd64-deb

## 3.6 Package Manager Installation (Ubuntu)
$ sudo dpkg -i cuda-repo-ubuntu1604-8-0-local-ga2_8.0.61-1_amd64-deb
$ sudo apt-get update
$ sudo apt-get install cuda

## 6.1.1 Post-installation Actions (Environment Setup)
$ echo 'export PATH=/usr/local/cuda-8.0/bin${PATH:+:${PATH}}' >> ~/.bashrc
$ source ~/.bashrc

nvcc が入れば成功。

$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2016 NVIDIA Corporation
Built on Tue_Jan_10_13:22:03_CST_2017
Cuda compilation tools, release 8.0, V8.0.61

3. Docker のインストール

公式ドキュメント (Install using the repository) 通りに、Docker CE をインストールする。

インストール完了したら、sudo 無しで動作するよう ubuntu ユーザを docker グループに追加して、SSH ログインし直す。

$ sudo usermod -aG docker ubuntu

hello-world が動けば完了。

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
78445dd45222: Pull complete
Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

4. nvidia-docker のインストール

公式ドキュメント 通りに進める。

“Quick start” > “ubuntu distributions” のコマンドを実行すればOK。

$ wget -P /tmp https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.1/nvidia-docker_1.0.1-1_amd64.deb
$ sudo dpkg -i /tmp/nvidia-docker*.deb && rm /tmp/nvidia-docker*.deb

以下のコマンドで Docker コンテナがホスト (p2 インスタンス) の GPU を認識していることが確認できる。

$ nvidia-docker run --rm nvidia/cuda nvidia-smi
Sun Apr 23 06:10:55 2017
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.39                 Driver Version: 375.39                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           Off  | 0000:00:1E.0     Off |                    0 |
| N/A   47C    P8    28W / 149W |      0MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

TensorFlow

あとは TensorFlow でもなんでもコンテナ内から GPU が触れる。

https://hub.docker.com/r/tensorflow/tensorflow/

$ nvidia-docker run -it -p 8888:8888 tensorflow/tensorflow:latest-gpu

続きを読む

Amazon EC2上のRed Hat Enterprise Linuxにリモートデスクトップ接続してElixir ReportをGUIインストールする手順

クラウド環境のLinuxインスタンスに、帳票ツールのElixir Reportをインストールする手順をまとめています。

参考までに、以前の記事はこちら。
Amazon EC2上にRed Hatインスタンスを作成してElixir Reportをコンソールインストールする手順
Amazon EC2上のRed Hat Enterprise LinuxにX11転送でElixir ReportをGUIインストールする手順

今回は、Amazon EC2上のRed Hatインスタンスに、デスクトップ環境VNCサーバーをインストールして、WindowsからVNCクライアントを使って接続し、Elixir ReportのレポートサーバーをGUIインストールする手順を試してみたいと思います。

環境

Windows 8.1
Elixir Report 8.7J
UltraVNC 1_2_12 64bit
Amazon EC2 Red hat Enterprise Linux 7.3
tigervnc-server

Red Hatインスタンスを作成して、パスワード認証を許可する

  1. Amazon EC2上に、デフォルトの構成でRed Hatインスタンスを作成します。以前まとめた、Amazon EC2上にRed Hatインスタンスを作成してElixir Reportをコンソールインストールする手順[Red Hatインスタンスの作成と準備]を参考にしてください。

    セキュリティ設定のポートの開放では、レポートサーバーが使用するポート7001と、サンプルのTomcatで使用するポート9090だけでなく、VNCが使用するポート5901も追加する必要があるので、注意してください。

  2. Windowsから作成したインスタンスにSSH接続します。この記事ではTera Termを使用します。Tera Termのインストール手順については、こちらも以前の記事[SSH接続用にWindowsにTera Termをインストールする]を参考にしてください。

  3. Tera Termでインスタンスに接続したら、パスワード認証(PasswordAuthentication)を許可するように変更します。sshd_configは念のためバックアップを取っておいてください。変更後のsshd_configは次のようになります。

    $ cat /etc/ssh/sshd_config|grep Pass
    PasswordAuthentication yes
    #PermitEmptyPasswords no
    #PasswordAuthentication no
    #KerberosOrLocalPasswd yes
    
  4. sshdサービスを再起動します。

    $ sudo systemctl restart sshd.service
    
  5. ec2-userのパスワードを設定します。

    $ sudo –i
    $ passwd ec2-user
    パスワード入力
    
  6. Tera Termを新しく起動して、パスワードでログインできるか試してみます。

Red Hatに、デスクトップ環境とVNCサーバーをインストールする

  1. Tera TermでRed Hatインスタンスに接続して、パッケージのグループServer with GUIをインストールします。

    $ sudo yum grouplist
    $ sudo yum -y groupinstall 'Server with GUI'
    
  2. 次にVNCサーバーをインストールします。

    $ sudo yum –y install tigervnc-server
    
  3. VNCサーバーのパスワードを設定します。

    $ vncpasswd
    Password:
    Verify:
    
  4. VNCサーバーのユニットファイルをコピーします。

    cp -a /lib/systemd/system/vncserver@.service /etc/systemd/system /vncserver@:1.service
    
  5. コピーしたユニットファイルを編集して、<USER>の部分をログインユーザー名ec2-userで置き換えます。

    $ vi /etc/systemd/system/vncserver@:1.service
    ExecStart=/usr/sbin/runuser -l ec2-user -c "/usr/bin/vncserver %i"
    PIDFile=/home/ec2-user/.vnc/%H%i.pid
    
  6. ファイアウォールの設定にVNCサーバーを追加します。また、レポートサーバーが使用するポート7001も許可しておきます。

    $ firewall-cmd --permanent --zone=public --add-service=vnc-server
    $ firewall-cmd --zone=public --add-port=7001/tcp --permanent
    $ firewall-cmd --reload
    $ firewall-cmd --list-all
    
  7. rootでVNCのサービスを起動します。

    $ sudo su –
    # systemctl start vncserver@:1
    
  8. Windowsに、VNCクライアントとしてUltraVNCをインストールします。筆者は以下のサイトからダウンロードしてインストールしました。

    窓の杜 UltraVNCUltraVNC_1_2_12_X64_Setup.exe

  9. UltraVNC Viewer を起動して、VNC Serverの入力箇所にRed HatインスタンスのIP::ポート(またはIP:ポート)と入力して、Red Hatインスタンスのデスクトップに接続できることを確認します。
    1vnc接続成功.png
    接続できました。

Red HatへVNC接続してレポートサーバーのインストーラを実行する

  1. UltraVNC ViewerでRed Hatインスタンスに接続します。

  2. レポートサーバーのインストーラをTera TermからSCPで転送し、実行権限の設定を行います。この手順の詳細は、以前の記事、Amazon EC2上にRed Hatインスタンスを作成してElixir Reportをコンソールインストールする手順[レポートサーバーのインストーラをRed Hatに転送する]を参照してください。

  3. Tera TermまたはRed Hatインスタンスのコンソールを開き、必要なライブラリをインストールします。このライブラリインストールはコマンドインストール、X11転送でのGUIインストールでも行います。

    $ sudo yum -y install libc.so.6
    
  4. レポートサーバーのインストーラを次のコマンドで起動します。

    $ ./elixirreport87_linux64.bin
    

    2VNC_GUIインストーラ00.png

  5. その後の手順の詳細は、以前の記事、Amazon EC2上のRed Hat Enterprise LinuxにX11転送でレポートサーバーをGUIインストールする手順[GUIインストールを実行する]を参考に完了させてください。

インストールしたレポートサーバーを起動する

  1. レポートサーバーを起動するユーザーのLANG環境変数を日本語ロケールへ変更します。

    $ export LANG=ja_JP.UTF-8
    
  2. レポートサーバーをインストールしたディレクトリ以下の/binに移動します。筆者の環境では、/home/ec2-user/ElixirReport87J/bin/になります。

    $ cd /home/ec2-user/ElixirReport87J/bin
    
  3. レポートサーバーの起動シェルスクリプトを実行します。

    $ ./reportserver-start.sh
    

    ※”&”を付加することでバックグラウンド実行にします。

  4. 起動に成功すると、コンソール上に次のようにCopyrightが表示されます。

    INFO  [main] com.elixirtech.ers2.Main - Copyright 2016 Elixir Technology Pte Ltd
    INFO  [Thread-19] com.elixirtech.ers2.EnsureServerStarted - Checking server status
    
  5. Windows上のブラウザからレポートサーバーのWebインターフェースにログインしてみます。

    http://<パブリックIP>:7001
    

    3WebインターフェースURL.png

    【注意】ログイン画面が表示されないときは、以下のような原因が考えられます。
    ・レポートサーバーの起動に失敗している
    ・Red Hatインスタンスのセキュリティグループの設定で、ポート7001を追加していない
    ・Red Hatインスタンスのファイアウォール設定でポート7001を許可していない

  6. ログイン画面が表示されたら、デフォルトで用意されている次の管理者ユーザーでログインします。

    ユーザー名: admin
    パスワード: sa
    
  7. [リポジトリ]以下のサンプルテンプレートを実行してみます。[samples]‐[demo]-[sales2]-[sales2.rml]を選択して、出力形式に”PDF”を選んで[OK]をクリックすると、レポートが生成されます。
    4ロケールを日本語にして、PDFもできます.png

以上で完了です。

続きを読む

[AWS] Terraform で EFS 作って、EC2 起動時にマウントさせておく

Terraform を使うと、EFS を作成して EC2 にマウントさせておくなんてことが簡単にできます。
Autoscaling 環境で Web ドキュメントルートを共有したい時とかに便利なんで、みんな使えばいいと思うよ。
なお、この記事の想定読者は AWS はダッシュボードからポチポチしてインスタンス立てたりしてるけど、そろそろインフラをコードで管理したいな。Terraform とか便利そうだねー使ってみたいねーって人です。
てわけで、単純に EC2 立ち上げても面白くないので EFS をマウントさせてみました。

そもそも、Terraform ってなんだ?って人は、以下のページとか参考になると思います。
Terraform簡易チュートリアル on AWS

実際の設定

Terraform は、特定のディレクトリ下にある拡張子が .tf なファイルを全部読み込んでいい感じにリソースを起動してくれます。なので、機能別に .tf 作成していってみましょう。

メイン設定

まず、メインの設定を作成。
プロバイダーとか、設定ファイル内で使用する変数とか設定していってみましょうか。

main.tf
# 今回のプロジェクト名
variable "project" {}
variable "domain" {}

# AWS リソースを起動するリージョンとかの情報
variable "region" { default = "us-west-2" }
variable "azs" {
    default {
        "a" = "us-west-2a"
        "b" = "us-west-2b"
        "c" = "us-west-2c"
    }
}

# AMI ID (Amazon Linux)
variable "ami" { 
    default {
        "us-west-2" = "ami-8ca83fec"
    }
}

# EC2 接続用の SSH 鍵の公開鍵
variable "ssh_public_key" {}

provider "aws" {
    region = "${var.region}"
}

variable で設定した値は tf ファイル内で ${var.region} のようにして参照可能です。
また、terraform の各種コマンドを実行する際に以下のようにパラメータとして変数を渡して上書きすることもできます。

$ terraform plan \
  -var 'project=example' \
  -var 'domain=example.com'

同じディレクトリ内に terraform.tfvars というファイルがあれば、それを読み込んで値が上書きされたりします。この辺の詳細は以下を参照してください。
Input Variables – Terraform by HashiCorp

provider "aws" は、aws を使いますよって宣言です。
以下のように アクセスキーを書いておくこともできますが、それやるとうっかり github とかに公開した時とかに切ない目にあうのでやめたほうが吉でしょう。

provider "aws" {
    access_key = "__ACCESS_KEY__"
    secret_key = "__SECRET_KEY__"
    region = "us-west-2"
}

環境変数 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY を読み込んでいい感じでやってくれるので、僕は direnv 使って作業ディレクトリ内で環境変数を変更することで対応してます。
(もちろん、この場合でも .gitignore.envrc を含めておいて間違って公開しないようにしないと切ない目にあうので注意)

VPC の作成

こんな感じの .tf ファイルで VPC と subnet が作成できます。

vpc.tf
## VPC
resource "aws_vpc" "app" {
    cidr_block           = "172.31.0.0/16"
    enable_dns_hostnames = true
    enable_dns_support   = true
    instance_tenancy     = "default"

    tags {
        "Name" = "${var.project}"
    }
}

## Subnet
resource "aws_subnet" "a" {
    vpc_id                  = "${aws_vpc.app.id}"
    cidr_block              = "172.31.0.0/20"
    availability_zone       = "${lookup(var.azs,"a")}"
    map_public_ip_on_launch = true

    tags {
        "Name" = "${var.project}-subnet-a"
    }
}

resource "aws_subnet" "b" {
    vpc_id                  = "${aws_vpc.app.id}"
    cidr_block              = "172.31.16.0/20"
    availability_zone       = "${lookup(var.azs,"b")}"
    map_public_ip_on_launch = true

    tags {
        "Name" = "${var.project}-subnet-b"
    }
}

resource "aws_subnet" "c" {
    vpc_id                  = "${aws_vpc.app.id}"
    cidr_block              = "172.31.32.0/20"
    availability_zone       = "${lookup(var.azs,"c")}"
    map_public_ip_on_launch = true

    tags {
        "Name" = "${var.project}-subnet-c"
    }
}

resource "aws_subnet" の中に ${aws_vpc.app.id} ってのが出てきましたね。
Terraform の中では、管理下にあるリソースの情報を他のリソースの設定でも参照することが可能です。
各リソースで使用できる値が異なってくるので、その辺は公式ドキュメント読みましょう。
例えば aws_vpc で使用できる値は aws_vpc を参照すればわかります。

また、${lookup(var.azs,"a")} ってのも出てきましたね。
これは Terraform の組み込み関数です、lookup は配列の中からキーをもとに値を探す関数です。
詳しくは Built-in Functions を読んでください。

ついでに Internet Gateway と Route Table も設定しておきましょう。

route-table.tf
## Internet Gateway
resource "aws_internet_gateway" "igw" {
    vpc_id = "${aws_vpc.app.id}"
}

## Route Table
resource "aws_route_table" "rtb" {
    vpc_id     = "${aws_vpc.app.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.igw.id}"
    }
}

resource "aws_route_table_association" "route_a" {
    subnet_id = "${aws_subnet.a.id}"
    route_table_id = "${aws_route_table.rtb.id}"
}

resource "aws_route_table_association" "route_b" {
    subnet_id = "${aws_subnet.b.id}"
    route_table_id = "${aws_route_table.rtb.id}"
}

resource "aws_route_table_association" "route_c" {
    subnet_id = "${aws_subnet.c.id}"
    route_table_id = "${aws_route_table.rtb.id}"
}

IAM ロールの作成

次に EC2 に割り当てるための IAM ロールを作ってみましょう。
ポリシーは、AWS が用意している AmazonEC2RoleforDataPipelineRole と、EC2 から CloudwatchLogs にログを送信するためのカスタムポリシーを作ってアタッチしてみます。

iam-role.tf
## For EC2 instance Role
resource "aws_iam_role" "instance_role" {
    name               = "instance_role"
    path               = "/"
    assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
POLICY
}

## AmazonEC2RoleforDataPipelineRole
resource "aws_iam_role_policy_attachment" "data-pipeline" {
    role       = "${aws_iam_role.instance_role.name}"
    policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforDataPipelineRole"
}

## PutCloudwatchLogs
resource "aws_iam_policy" "put-cloudwatch-logs" {
    name        = "AmazonEC2PutCloudwatchLogs"
    description = ""
    policy      = <<POLICY
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "put-cloudwatch-logs" {
    role       = "${aws_iam_role.instance_role.name}"
    policy_arn = "${aws_iam_policy.put-cloudwatch-logs.arn}"
}

aws_iam_roleassume_role_policy のところと、aws_iam_policypolicy のところでヒアドキュメントが出てきましたね。
こんな風に複数行にわたるインラインポリシーはヒアドキュメントで記述することが可能です。
また、以下のように別ファイルにしておいて読み込ませることも可能です。
管理しやすい方でやってください。

iam-role.tf
resource "aws_iam_role" "instance_role" {
    name               = "instance_role"
    path               = "/"
    assume_role_policy = "${file("data/instance_role_assume_policy.json")}"
}
data/instance_role_assume_policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

セキュリティグループの作成

EC2 から EFS へのアクセスは 2049 番ポートを介して行われるので、EFS が所属するセキュリティグループに穴を開けないといけません。
EC2 は 80, 443, 22 を解放してみます。

security-group.tf
## For EC2
resource "aws_security_group" "ec2" {
    name        = "${var.project}-EC2"
    description = "for ${var.project} EC2"
    vpc_id      = "${aws_vpc.app.id}"

    ingress = [
        {
            from_port       = 80
            to_port         = 80
            protocol        = "tcp"
            cidr_blocks     = ["0.0.0.0/0"]
        },
        {
            from_port       = 443
            to_port         = 443
            protocol        = "tcp"
            cidr_blocks     = ["0.0.0.0/0"]
        },
        {
            from_port       = 22
            to_port         = 22
            protocol        = "tcp"
            cidr_blocks     = ["0.0.0.0/0"]
        }
    ]

    egress {
        from_port       = 0
        to_port         = 0
        protocol        = "-1"
        cidr_blocks     = ["0.0.0.0/0"]
    }
}

## For EFS
resource "aws_security_group" "efs" {
    name        = "${var.project}-EFS"
    description = "for ${var.project} EFS"
    vpc_id      = "${aws_vpc.app.id}"

    ingress {
        from_port       = 2049
        to_port         = 2049
        protocol        = "tcp"
        security_groups = ["${aws_security_group.ec2.id}"]
    }

    egress {
        from_port       = 0
        to_port         = 0
        protocol        = "-1"
        cidr_blocks     = ["0.0.0.0/0"]
    }
}

EFS の作成

こんな感じで EFS が作成できます。
各サブネットごとにマウントターゲットを作成して、そいつをセキュリティグループに所属させる形ですね。

efs.tf
resource "aws_efs_file_system" "app" {
  tags {
        "Name" = "${var.domain}"
  }
}

resource "aws_efs_mount_target" "app-a" {
  file_system_id  = "${aws_efs_file_system.app.id}"
  subnet_id       = "${aws_subnet.a.id}"
  security_groups = ["${aws_security_group.efs.id}"]
}

resource "aws_efs_mount_target" "app-b" {
  file_system_id = "${aws_efs_file_system.app.id}"
  subnet_id      = "${aws_subnet.b.id}"
  security_groups = ["${aws_security_group.efs.id}"]
}

resource "aws_efs_mount_target" "app-c" {
  file_system_id = "${aws_efs_file_system.app.id}"
  subnet_id      = "${aws_subnet.c.id}"
  security_groups = ["${aws_security_group.efs.id}"]
}

EC2 の作成

さて、いよいよ EC2 です。
ここでは、user-data を使って、初回ローンチ時に EFS をマウントさせてしまいます。
さらにマウントした EFS 内に html/ ってディレクトリを作成して、そいつを /var/www/html にシンボリックリンクしてみましょうか。
と言っても、こんな感じで大丈夫です。

ec2.tf
## IAM Instance Profile
resource "aws_iam_instance_profile" "instance_role" {
    name = "instance_role"
    role = "${aws_iam_role.instance_role.name}"
}

## SSH Key
resource "aws_key_pair" "deployer" {
  key_name   = "${var.project}"
  public_key = "${var.ssh_public_key}"
}

## EC2
resource "aws_instance" "app" {
    ami                         = "${lookup(var.ami,var.region)}"
    availability_zone           = "${aws_subnet.a.availability_zone}"
    ebs_optimized               = false
    instance_type               = "t2.micro"
    monitoring                  = true
    key_name                    = "${aws_key_pair.deployer.key_name}"
    subnet_id                   = "${aws_subnet.a.id}"
    vpc_security_group_ids      = ["${aws_security_group.ec2.id}"]
    associate_public_ip_address = true
    source_dest_check           = true
    iam_instance_profile        = "${aws_iam_instance_profile.instance_role.id}"
    disable_api_termination     = false

    user_data                   = <<USERDATA
#!/bin/bash
az="${aws_subnet.a.availability_zone}"
efs_region="${var.region}"
efs_id="${aws_efs_file_system.app.id}"
efs_mount_target="${aws_efs_mount_target.app-a.dns_name}:/"
efs_mount_point="/mnt/efs/$${efs_id}/$${az}"
web_doc_root="/var/www/html"

# EFS Mount
/usr/bin/yum -y install nfs-utils || /usr/bin/yum -y update nfs-utils
if [ ! -d $${efs_mount_point} ]; then
  mkdir -p $${efs_mount_point}
fi
cp -pi /etc/fstab /etc/fstab.$(date "+%Y%m%d")
echo "$${efs_mount_target}    $${efs_mount_point}   nfs4    defaults" | tee -a /etc/fstab
mount $${efs_mount_point}

# create Web document root
if [ -d $${web_doc_root} ]; then
  rm -rf $${web_doc_root}
fi
if [ ! -d $${efs_mount_point}/html ]; then
  mkdir $${efs_mount_point}/html
  chown ec2-user:ec2-user $${efs_mount_point}/html
fi
ln -s $${efs_mount_point}/html $${web_doc_root}
chown -h ec2-user:ec2-user $${web_doc_root}
USERDATA

    root_block_device {
        volume_type           = "gp2"
        volume_size           = 10
        delete_on_termination = true
    }

    tags {
        "Name"          = "${var.domain}"
    }
}

user_data は長めのシェルスクリプトなので、可読性が悪いから ${file("data/user_data.sh")} とかってやって別ファイルで管理したいですよね。
でも待ってください、ヒアドキュメントでやってるのは理由があるのです。

ヒアドキュメントで書くと、user_data 用のシェルスクリプトの中で Terraform の変数が使えます。
マウントするには EFS の ID とか、マウントターゲットの dns_name とか必要になってきますが、それを作成前に知らなくてもこのように書いておけるのです。便利ですね。
その代わり、user_data 用のシェルスクリプト内でローカルな環境変数を使いたい場合は $${efs_mount_point} のように書いてあげてくださいね。

ざっと、こんな感じです。
慣れちゃえば、tf ファイルを使い回しできるので便利ですよ。
また、すでに作成済みの AWS リソースを Terraform 管理下に置きたい場合は

$ terraform import aws_instance.app ${instance_id}

のようにして管理下に置くことができます。
管理されているリソースは terraform.tfstate というファイルに書き込まれます。
さらに別プロダクトになるのですが Terraforming と言うツールを使用すると、既存の AWS リソースから Terraform 用の tf ファイルを作成したり、terraform.tfstate を作成したりもできるので便利です。
Terraforming については、Terraforming で既存のインフラを Terraform 管理下におく を参考にしてください。

実際にリソース作成してみる

tf ファイル書いたら

$ terraform plan

で、設定ファイルに誤りがないか?既存のリソースへの影響はどの程度あるのかが確認できます。
実際に反映させたい時は

$ terraform apply

で、おっけ。

では、良い Terraform を!

続きを読む

Amazon EC2上のRed Hat Enterprise LinuxにX11転送でElixir ReportをGUIインストールする手順

この記事はクラウド環境のLinuxインスタンスに、帳票ツールのElixir ReportをGUIインストールする手順についてまとめたものです。

以前の記事、Amazon EC2上にRed Hatインスタンスを作成してElixir Reportをコンソールインストールする手順では、デスクトップ環境のないLinuxインスタンスにコンソールインストールする手順を試してみました。

今回は、SSHのX11転送(X11フォワーディング)機能を使って、デスクトップ環境の入っていないAmazon EC2上のRed Hat Enterprise LinuxのインスタンスでElixir Reportのレポートサーバーのインストーラを実行し、GUIインストーラをWindows側に表示してインストールしてみたいと思います。

環境

Windows 8.1
Elixir Report 8.7J
Amazon EC2 Red hat Enterprise Linux 7.3

WindowsにTera Termをインストールする

この記事では、Linux OSへのSSH接続にTera Termを使用します。Tera TermのWindowsへのインストールは、以前の記事[SSH接続用にWindowsにTera Termをインストールする]を参考にしてください。

WindowsにXサーバーをインストールする

Linux上のGUIアプリケーションをWindows側で操作するには、WindowsのリモートデスクトップやVNC経由でLinuxのデスクトップに接続することもできますが、この記事では、Linux上で動作しているアプリケーションのGUIをWindows側に表示する方法としてX11転送を利用します。

この方法ではWindows側にXサーバーがインストールされている必要があるので、今回はXmingというフリーのWindows用Xサーバーを使用します。こちらの記事を参考にしました。

【参考記事】フリーのWindows用Xサーバー「Xming」のインストールと基本設定、使い方

  1. Xmingインストーラをダウンロードサイトからダウンロードします。本記事の作成時(2016年11月)で最新のXming(Xming-6-9-0-31-setup.exe)と、Xming-fonts(Xming-fonts-7-7-0-10-setup.exe)をダウンロードします。1ダウンロードファイル選択.png  

  2. Xmingのインストーラをダブルクリックで起動します。選択項目は基本的にデフォルト設定を受け入れてインストールします。[Next]で進みます。
    2install01.png

  3. インストール先を指定して次に進みます。

  4. コンポーネントの選択画面では、デフォルト設定を受け入れて進みます。3install03.png

  5. アイコンやタスクの選択ステップも同様に、デフォルトのまま進みます。4install05.png

  6. インストール前の確認項目をチェックして進み、インストールを完了します。5install07.png

  7. インストールの完了画面で[Launch Xming]にチェックを入れて終了すると、Xmingが起動してタスクトレイにアイコンが表示されます。
    6icon.png

    [注意]Xming起動時に、Windowsファイアウォールの警告が表示されることがあります。その場合は、アクセスを許可します。

  8. 次にXming-fontsをインストールします。Xming-fontsのインストーラを起動し、コンポーネントの選択でデフォルトを受け入れます。
    7fontinstall01.png

  9. インストールの内容を確認して進めると、インストールが完了します。8fontinstall03.png

Amazon EC2 Red Hatインスタンスの作成と準備

Amazon EC2上に、デフォルトの構成でRed Hatインスタンスを作成します。以前の記事[Red Hatインスタンスの作成と準備]セクションを参考にしてください。

インスタンスの作成と、Windows上のTera TermからRed Hatインスタンスへ接続するまでの手順が完了します。

X11転送の設定をする

X11転送に関する、Red Hat側およびWindows側の設定と確認を行います。

Linux側の設定

  1. Red Hatインスタンスで、X11転送が有効化されているか確認します。/etc/ssh/sshd_config内で、X11Forwardingyesになっていれば問題ありません。

    $ sudo cat /etc/ssh/sshd_config |grep X11
    X11Forwarding yes
    #X11DisplayOffset 10
    #X11UseLocalhost yes
    #       X11Forwarding no
    
  2. 手順1で、X11Forwardingnoになっている場合は、/etc/ssh/sshd_configをバックアップした上で設定をyesに変更し、sshdを次のコマンドに従って再起動します。

    $ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config_org
    $ sudo vi /etc/ssh/sshd_config
    $ sudo service sshd restart
    Redirecting to /bin/systemctl restart  sshd.service
    
  3. XアプリケーションをX11転送によりWindows上に表示できるか確認するため、今回はxeyesというXアプリケーションをRed Hatインスタンスにインストールしておきます。

    $ sudo yum –y install xeyes
    

Windows側の設定とテスト

  1. Windows側でXmingが起動していることを確認します。

  2. Tera Termの設定で、リモートのXアプリケーションをローカルに表示する設定を行います。Tera Termの[設定]-[SSH転送]をクリックします。
    9TeraTerm_SSH転送設定.png

  3. [リモートの(X)アプリケーションをローカルのXサーバに表示する]にチェックを入れて、[OK]をクリックします。
    10TeraTerm_SSH転送設定01.png

  4. 一旦Tera Termからログアウトして、再度ログインし直します。

  5. DISPLAY変数が設定されているかコマンドで確認します。

    $ echo $DISPLAY
    
  6. 前の手順で何も返ってこなかった場合は、先ほどインストールしたxeyesを実行しても次のようなエラーになってしまいます。

    $ sudo xeyes
    Error: Can't open display:
    

    Red Hatインスタンス側にxauthと、x11のライブラリが不足しているようなので、必要なライブラリを次のコマンドでインストールしました。

    $ sudo yum –y install xorg-x11-xauth.x86_64 xorg-x11-server-utils.x86_64
    
  7. 一旦Tera Termでログアウトします。

    $ exit
    
  8. 再度Tera TermでRed Hatインスタンスにログインして、次のコマンドでDISPLAY変数を確認します。筆者の環境では自動でlocalhost:10.0が設定されていました。

    $ echo $DISPLAY
    localhost:10.0
    
  9. xeyesを実行してみます。無事Windows側にxeyesアプリケーションが表示されました。

    $ xeyes
    

    11xeyes.png

    [注意]次のようなX転送のエラーが出るときは、XmingがWindows側で起動していない可能性があります。起動していることを確認してください。
    12TTSSHエラー.png

レポートサーバーのインストーラをRed Hatに転送する

Tera Termを利用して、Windows側にあるElixir ReportのレポートサーバーのLinux OS用インストーラ(elixirreport87_linux64.bin)と、ライセンスファイル(*.license)をRed Hatインスタンスに転送します。

この手順については、以前の記事[レポートサーバーのインストーラをRed Hatに転送する]を参照してください。

ファイルの転送が完了したら、次の準備を行っておきます。

  1. インストールは現在ログインしているec2-userで行います。ec2-userのLANG環境変数が英語になっている場合は、日本語(ja_JP.UTF-8)に変更しておきます。

    $ echo $LANG
    en_US.UTF-8
    $ export LANG=ja_JP.UTF-8
    $ echo $LANG
    ja_JP.UTF-8
    
  2. 転送したインストーラに実行権限を与えます。

    $ chmod +x ./elixirreport87_linux64.bin
    $ ls -la
    -rwxr-xr-x. 1 ec2-user ec2-user 279506476 Sep 29 00:00  elixirreport87_linux64.bin
    

GUIインストーラの実行とエラーの発生

いよいよインストーラを実行してみます。しかし、エラーでインストーラが終了してしまいました。必要なライブラリがRed Hat側に不足しているようです。

$ ./elixirreport87_linux64.bin
Preparing to install...
Extracting the JRE from the installer archive...
Unpacking the JRE...
Extracting the installation resources from the installer archive...
Configuring the installer for this system's environment...
strings: '/lib/libc.so.6': No such file

Launching installer...

Invocation of this Java Application has caused an InvocationTargetException. This application will now exit. (LAX)

Stack Trace:
java.lang.NoClassDefFoundError: Could not initialize class java.awt.Toolkit
        at java.awt.Component.<clinit>(Component.java:593)
        at com.zerog.ia.installer.LifeCycleManager.g(DashoA8113)
        at com.zerog.ia.installer.LifeCycleManager.h(DashoA8113)
        at com.zerog.ia.installer.LifeCycleManager.a(DashoA8113)
        at com.zerog.ia.installer.Main.main(DashoA8113)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at com.zerog.lax.LAX.launch(DashoA8113)
        at com.zerog.lax.LAX.main(DashoA8113)
This Application has Unexpectedly Quit: Invocation of this Java Application has caused an InvocationTargetException. This application will now exit. (LAX)

必要なライブラリをインストールして実行時エラーを解消する

  1. 上記のエラーを最初から確認すると、まずlibc.so.6ファイルが見つからないという内容のエラーが出力されているので、次のコマンドでlibc.so.6ライブラリをインストールします。

    $ sudo yum -y install libc.so.6
    
  2. 次に発生しているInvocationTargetExceptionは、X11のライブラリが不足していることが原因のようです。必要なライブラリをインストールします。

    $ sudo yum –y install libXtst
    

起動したGUIインストーラの日本語が□に…フォントをインストールする

  1. 再度インストーラを実行してみます。

    $ ./elixirreport87_linux64.bin
    
  2. インストーラのGUIが起動しましたが、日本語が□表示になっています。Linux側に日本語フォントがインストールされていないことが原因でしょう。左下のキャンセルボタンをクリックしてインストールを中止します。
    13GUIトーフになる.png

    14終了02.png

  3. 日本語フォントをインストールします。VLゴシック、IPA明朝、IPAゴシックをインストールしました。

    $ sudo yum -y install vlgothic-fonts ipa-mincho-fonts ipa-gothic-fonts 
    

GUIインストールを実行する

  1. 再度インストーラを起動します。今度は日本語も表示されるようになりました。
    15GUI_01.png

  2. [次へ]で進み、[使用許諾契約の条項に同意する]にチェックして、進みます。
    16GUI_02.png

  3. [ライセンスキーファイルの登録]をクリックして、登録するライセンスファイルを選択します。
    17GUI_03.png

  4. インストールするモジュールにチェックが入っていることを確認して、次に進みます。この画面では、先ほどの手順で追加したライセンスでインストールできるモジュールだけが表示されます。18GUI_04.png

  5. レポートサーバーで使用するポート(今回はデフォルトの7001)、ログレベルを確認します。デフォルトのまま進みます。
    19GUI_ポート設定.png

  6. インストール先ディレクトリは、ec2-userにアクセス権のある場所を選択します。今回はユーザーディレクトリの下にします。
    20GUI_インストール先.png

    [注意]ec2-userに書き込み権限のない場所を指定すると、エラーが表示されます。

  7. 確認画面で内容を確認したら、[インストール]をクリックします。
    21GUI_確認.png

  8. 次の画面が表示されれば完了です。
    22GUI完了.png

ヘッドレスモードの設定とレポートサーバーの起動

インストールはX11転送でGUIを利用しましたが、今後、レポートサーバーの実行時にX Window Systemに接続できない場合は、Javaのヘッドレスモードを有効にする必要があります。

  1. レポートサーバーのインストール先/binディレクトリに移動します。筆者の環境では/home/ec2-user/ElixirReport87J/bin/になります。

    $ cd /home/ec2-user/ElixirReport87J/bin
    
  2. レポートサーバーの起動シェルスクリプトをバックアップした後、編集します。

    $ cp reportserver-start.sh reportserver-start.sh_org
    $ vi reportserver-start.sh
    

    ※5行目のheadless設定を追加して、保存します。

    #!/bin/sh
    JAVACMD="../jre/bin/java"
    
    $JAVACMD -mx512M 
            -Djava.awt.headless=true 
            -Duser.home=../license 
     (以下省略)
    
  3. レポートサーバーの起動シェルスクリプトを実行します。

    $ ./reportserver-start.sh &
    

    ※”&”を付加してバックグラウンド実行にします。

    【注意】起動ユーザーのLANG環境変数が英語の場合、レポートサーバーが英語ロケールで起動され、Webインターフェースのメニューなどが英語表示になってしまいます。日本語ロケールへ変更して起動してください。

  4. 起動に成功すると、コンソール上に次のようにCopyrightが表示されます。

    INFO  [main] com.elixirtech.ers2.Main - Copyright 2016 Elixir Technology Pte Ltd
    INFO  [Thread-19] com.elixirtech.ers2.EnsureServerStarted - Checking server     status
    
  5. Windows上のブラウザからレポートサーバーのWebインターフェースにログインしてみます。

    http://<パブリックIP>:7001
    

    23WebインターフェースURL.png

    【注意】ログイン画面が表示されないときは、以下のような原因が考えられます。
    ・レポートサーバーの起動に失敗している
    ・Red Hatインスタンスのセキュリティグループの設定で、ポート”7001”を追加していない

  6. ログイン画面が表示されたら、デフォルトで用意されている次の管理者ユーザーでログインします。

    ユーザー名: admin
    パスワード: sa
    
  7. [リポジトリ]以下のサンプルテンプレートを実行してみます。
    [samples]‐[demo]-[sales2]-[sales2.rml]を選択して、出力形式に”PDF”を選んで[OK]をクリックします。
    24レポート生成PDF選択.png

  8. PDF形式のレポートが生成できました。
    25フォントインストール後の結果.png

以上で完了です。

参考情報

Q1. No X11 DISPLAY variable was setエラーでインストールが終了する

X11などの設定を何も行っていない状態でGUIインストールを実行すると、X11のエラーでインストーラが終了してしまいます。この記事の[X11転送の設定をする]の項目を確認してみてください。

[参考情報]エラー出力の例
$ ./elixirreport87_linux64.bin
Preparing to install...
Extracting the JRE from the installer archive...
Unpacking the JRE...
Extracting the installation resources from the installer archive...
Configuring the installer for this system's environment...
strings: '/lib/libc.so.6': No such file

Launching installer...

Invocation of this Java Application has caused an InvocationTargetException. This application will now exit. (LAX)

Stack Trace:
java.awt.HeadlessException:
No X11 DISPLAY variable was set, but this program performed an operation which requires it.
        at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:207)
        at java.awt.Window.<init>(Window.java:536)
        at java.awt.Frame.<init>(Frame.java:420)
        at java.awt.Frame.<init>(Frame.java:385)
        at javax.swing.JFrame.<init>(JFrame.java:189)
        at com.zerog.ia.installer.LifeCycleManager.g(DashoA8113)
        at com.zerog.ia.installer.LifeCycleManager.h(DashoA8113)
        at com.zerog.ia.installer.LifeCycleManager.a(DashoA8113)
        at com.zerog.ia.installer.Main.main(DashoA8113)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at com.zerog.lax.LAX.launch(DashoA8113)
        at com.zerog.lax.LAX.main(DashoA8113)
This Application has Unexpectedly Quit: Invocation of this Java Application has caused an InvocationTargetException. This application will now exit. (LAX)

Q2. フォントをインストールしても、日本語が□のままになる

fc-listコマンドがRed Hatインスタンスで実行できるか確認してください。コマンドが入っていない場合は、フォントの管理に使用されるfontconfigパッケージを次のコマンドでインストールして、fc-listコマンドが使用できるようになるか確認した上で、再度インストールを試してみてください。

$ sudo yum –y install fontconfig

※この記事では、X11転送の確認用にxeyesアプリケーションをインストールしています。このインストール中、依存関係によりfontconfigが一緒にインストールされるため、日本語の表示には問題ありませんでした。xeyesをインストールしなかった場合は、別途fontconfigをインストールする必要があります。

Q3. Xアプリケーションを起動したが、Windows側にX転送エラーが表示される

次のようなX転送のエラーが出るときは、XmingがWindows側で起動していることを確認してください。
12TTSSHエラー.png

Q4. レポートサーバー起動時にWindows側にX転送エラーが表示され、レポートサーバーが起動できない

Q3と同様のエラーが表示され、レポートサーバーの起動中に次のようなjava.awt.AWTErrorが出力される場合は、ヘッドレスモードの設定が正しく行われていない可能性があります。この記事の[ヘッドレスモードの設定とレポートサーバーの起動]の項目を参考に、起動シェルスクリプトの編集を行ってみてください。

Exception in thread "main" java.awt.AWTError: Can't connect to X11 window server using 'localhost:10.0' as the value of the DISPLAY variable.
        at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)
        at sun.awt.X11GraphicsEnvironment.access$200(X11GraphicsEnvironment.java:65)
(以下省略)

続きを読む

個人的mastodonの出来事(技術編)

何の話か

結果的に中規模インスタンス(一応某リストで上位100以内にはいっているから現状間違ってないはず)を4台立てることになったので、その経緯とかそこで知ったこととか書きます。

得られた知見

総括として、

  • 100-300人程度であればDBあたりはまだネックにならずメモリが真っ先に悲鳴をあげた(1GBしかない場合)
  • 100人超えると何もいじってないt2.microだときつい
  • 300人超えたくらいでもt2.smallでとりあえずスペック的には動く

ただし、金銭的な都合でRDSやElastiCache、複数EC2による冗長構成などをとっていないために、インスタンスサイズを変更する時など絶対にサービスが止まるので、そこは今回妥協しています。
また、CloudFrontやS3を使うこともできるのですがこちらも金銭的事情と今の所なんとかなっているので使ってないです。

環境としては

  • mailにmailgun
  • SSL証明書にLet’s Encrypt
  • サーバーはだいたいAWS
  • 最低限のメトリクス監視はmackerel

です。

mastodonをはじめたところ

4/12に多分Twitterでみかけてmastodonを始めた。現mstdn.jpインスタンスでアカウントを作りました。
しばらく楽しくやってたのですが、どんどん人が増えるのでコンセンプト的には分散させたほうがいいよなーという思いとか、mastodonで知り合った人にボドゲインスタンスほしいって言われたとか、この勢いなら人くるんじゃね?という企みとかそういうのがあって立てようかなと考え始めました。
結果、4/12は見送ったものの、4/13にmstdn.jpが不安定なこともあり分散する流れになるだろうと判断してそれなら急ごうとその夜から構築を開始することにしました。

1台目 tablegame.mstdn.cloud

どうせAWSとか使うと金銭的に維持できないと思い、家にあったサーバーを流用することに。
帰りにLANカードとバカHUBを買って帰宅。
マシン構成としては

  • ubuntu 14.04 LTS
  • CPU: Sempron 145
  • RAM: 4GB

と非常に貧弱ながらも、ジャンルがニッチなのでこれで試そうと突っ込みました。
ちなみに、Dockerは使っておらず、理由としてはDockerにそこまで明るくないので死活監視とかDB周りをいじる必要が出た時にうまく弄れる自信がなかったためです。

構築で苦労したことは、LANとFletsのPPPoE直の物理インタフェース2本構成になったので、そのroutingとかiptablesわすれたとかその辺です。
また、設定を間違えたままresorceをbuildしたところ、アプリの設定など以外の動的に変わる部分(メインのタイムラインですね)が何も表示されない事態に陥り、そこで困ったりしました。
消してrebuildしたら治りましたが。
あとは、ubuntu 14.04なのでデフォルトのdaemon化する設定が使えず、現状nohupで動かしています。streamのnodeがよく落ちるのでそこだけpythonで監視して落ちてれば再起動するスクリプトをcronで回すという手荒い対応です。

結果として現在300人弱ですが、快適に動いています。

2台目 socialgame.mstdn.cloud

思ったよりうまく動いて、昼休みに先輩と喋っていた勢いで2台目を作りました。
こちらはジャンル的に人が集まる可能性もあったので、AWSを使って、でもまずは最小構成でということでt2.microにすべて載せる構成で作りました。

こちらはUbuntu 16.04なので公式ドキュメント通りに構築しました。(ただしこちらも非Dockerで)

ちゃんと動いたのは良かったものの、その日の夜にメモリを使いきりswapし始めた途端にアクセスさえ困難な状況に。
この時、sshで入れない状況だったのですが公式ドキュメント通りに作っていたのが功をなし、AWSコンソールから直接停止、インスタンスサイズアップで難を逃れました。

結果t2.small一台で現状300人超えたくらいですが、快適に動いています。

3台目, 4台目

2台目を参考に構築しました。4台目のR18可能なソシャゲインスタンス構築の話についてはできれば別の記事で書きます。

技術的タスク

  • バージョンアップが早いのでバージョンアップをどう実施していくか。
  • SSL証明書の更新やLet’s Encryptについてもっと知る
  • mailgunが一部制限かかっているのでそれの対応

最後に

タスク整理とかもあったので書いてみたんですが、これ、得られる情報ありますかね。。。
とりあえずお一人様や100人未満のインスタンスなら多分t2.microで動くと思うので無料枠でお試しとかするといいですよ、くらいかもしれないです。

続きを読む