Rancher2.0 Tech Preview2 ~Create a RKE Cluster~

Rancher2.0 Tech Preview2の主要機能として追加された「Create a RKE Cluster」は、RKE(Rancher Kubernetes Engine)を利用して、AWS、Azure、DigitalOcean、Packet、vSphereに対してKubernetesクラスタを作成することができます。(※2018年2月現在)

Rancher2.0 Tech Preview2からAWS上にKubernetesクラスタを作成してみましょう。

Tech Preview2のインストールはRancher2.0 Tech Preview2についての「Get Started with Rancher 2.0」を参考にしてください。

Rancher2.0 Tech Preview2でAWS上にKubernetesクラスタを作成

1.Rancher2.0 Tech Preview2 Serverにログイン後に、「Add Cluster」ボタンをクリックします。

image.png

2.「Create a RKE Cluster」の「Select」ボタンをクリックします。

image.png

3.nameに任意名を入力(今回はaws-k8s-clusterとします。)して、「Add a new cluster」をクリックします。

image.png

4.「Configure」をクリックします。

image.png

5.「Amazon EC2」を選択し、nameに任意名を入力(今回はaws-k8s-clusterとします。)し、Countは「3」、Regionは「ap-northeast-1」、Access keyとSecret keyはAWSのIMA Management Consoleでグループとユーザを作成し、そのユーザーのものを入力します。そして、「Next:Authenticate & select a network」ボタンをクリックします。

image.png

6.vpcを選択して、「Next:Select a Security Group」ボタンをクリックします。

image.png

7.「Next:Set Instance options」ボタンをクリックします。

image.png

8.「Create」ボタンをクリックします。

image.png

9.kubernetesの構成を作成します。最後に「Create」ボタンをクリックします。

image.png

10.しばらくするとkubernetesクラスタ構築が完了します。

screencapture-35-198-222-0-g-clusters-1517843931311.png

クラスタ名をクリックすると全体のリソース状況が可視化されます。

screencapture-35-198-222-0-c-cluster-8p8bq-1517844232326.png

11.上部メニュー「Nodes」を選択します。

AWS上に構築されたkubernetesクラスタの状況を確認できます。各クラスタ名をクリックするとリソース状況が可視化されます。

image.png

12.「KubeConfig File」ボタンをクリックします。

image.png

kubectlコマンドのconfigファイルをクリップボードにコピーできます。

image.png

kubectlコマンドを実行できるクライアントをローカルまたはサーバで構築します。今回はGCP上にGCEのインスタンス(Ubuntu 16.04 LTS)を1台用意します。

コマンド
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl

$ chmod +x ./kubectl

$ sudo mv ./kubectl /usr/local/bin/kubectl

$ mkdir .kube

$ vim .kube/config
#クリップボードにコピーした内容をペーストして保存します。
:wq

$ kubectl get nodes
NAME               STATUS    ROLES         AGE       VERSION
aws-k8s-cluster1   Ready     etcd,master   26m       v1.8.5-rancher1
aws-k8s-cluster2   Ready     worker        23m       v1.8.5-rancher1
aws-k8s-cluster3   Ready     worker        25m       v1.8.5-rancher1

これで、kubectlコマンドでアプリケーションをデプロイすることが可能となります。

13.AWSのコンソールを確認します。

インスタンスが3台で来ていることが確認できます。

image.png

以上となりますが、AWS以外のAzure、DigitalOcean、Packet、vSphereも同様にRKEでkubernetesクラスタを構築できると思います。

参考資料

RKE(Rancher Kubernetes Engine)

続きを読む

sitas – 1つのターミナルで複数のサーバーを同時に操作する

https://github.com/jiangwenyuan/sitas

image.png

結構前(10年前?)作ったもので、2、3年前古いパソコンを整理した時Githubに置いたきり、すっかり忘れました。今の時代はあまりいらないな気がしますけどね。

いいところはtmuxのように1つのターミナルで実行して、Single/Multipleモード間切り替えられ、そしてX環境もいらない、VIMのようなアプリもサポートします。後は交互的です。

コマンドは1つのターミナルで実行しているように見えますが、実際は複数のサーバーで同時に実行している。

とりあえずシェアします。

続きを読む

keystoneJSをnginxでデプロイしてaws上で動かす。

wordpressが使いたくなく、python大好きマンなのでmezzanineを使おうと思ったのですが、デプロイで頓挫したのでnodeJSでやろう。keystoneJSでやろうという次第です。

DDNSにはno-IPを利用しました。

keystoneJS official

前提

  • awsにインスタンスを作成済み
  • 上記インスタンスの3000番ポートを開けておく
  • 上記のインスタンスにssh接続出来る

諸々のインストール

sudo yum update -y

nodeJS


curl -L git.io/nodebrew | perl - setup
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
ebisennet$ source ~/.bash_profile

nodebrew install-binary v9.4.0

mongoDB

こちらの記事を参考にさせて頂きました。

sudo vim /etc/yum.repos.d/mongodb-org-3.2.repo

[mongodb-org-3.2]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.2/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.2.asc

sudo yum install -y mongodb-org

sudo service mongod start

sudo chkconfig mongod on

Yoeman

sudo npm install --global yo

keystoneJS

sudo npm install -g generator-keystone

no-IP

sudo yum-config-manager --enable epel
sudo yum install -y noip

nginx

sudo yum install nginx

forever

npm install -g forever

keystoneJSの実行

公式ページの通りに進めます。
htmlはpug,cssはsassがオススメです。

mkdir my-test-project
cd my-test-project
yo keystone

node keystone

この時点で[myIP]の3000ポートにアクセスするとページが見れるはずです。
example : http://x.x.x.x:3000

no-IPの設定

awsのドキュメントを参考に進めます。

sudo noip2 -C
sudo chkconfig noip on
sudo service noip start

nginxでデプロイ

sudo vi /etc/nginx/nginx.conf
nginx.conf
    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf; #この一行だけ加える
    ...
sudo vi /etc/nginx/conf.d/keystone.conf
keystone.conf
upstream node-sampleapp1 {
    server localhost:3000;
}

server {
    listen       80;
    server_name  http://DNSNAME/;
    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
    location / {
        proxy_pass http://node-sampleapp/;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
    root   /usr/share/nginx/html;
    }
}

foreverでデーモン化

forever start keystone.js

デバックモードを切る

vi my-test-project/.env

NODE_ENV=productionとする。

あとは、templatesやpublic,routesなどを編集して自分好みのスタイルに変更する。
また、記事の投稿はhttp://DNSNAME/keystone/signin より行う。

オチ

markdownのプラグインとか欲しいのでwordpressを始めようと思いました。

続きを読む

Amazon Linux 2 LTSの綺麗なVagrant boxを作ってみた

はじめに

Amazon Linux 2 LTSのVagrant box作る方法、2018/1/16時点の各種情報ではそのままではいくつかハマってうまくいかなかった。
でもちゃんと公式読んだら出来た。公式読まなかった俺が悪い。

備忘録としてAmazon Linux 2 LTSの綺麗なVagrant boxを作成する方法を残しておく。

大まかな手順
1. Amazon Linux 2のダウンロード
2. cloud init用データの作成
3. VMの作成とAmazon Linux 2の起動
4. Guest Additionsのインストール
5. クリーンアップとboxの作成

Amazon Linux 2の公式は次のURL

https://aws.amazon.com/jp/amazon-linux-2/

2018年1月16日時点のVirtualBoxイメージは次のものが最新

https://cdn.amazonlinux.com/os-images/2017.12.0.20171212.2/virtualbox/amzn2-virtualbox-2017.12.0.20171212.2-x86_64.xfs.gpt.vdi

さぁ、はじめよう。

準備

VirtualBoxイメージのダウンロード

curl -LO https://cdn.amazonlinux.com/os-images/2017.12.0.20171212.2/virtualbox/amzn2-virtualbox-2017.12.0.20171212.2-x86_64.xfs.gpt.vdi

cloud init用データの作成

mkdir seed
echo "local-hostname: localhost.localdomain" > seed/meta-data

cat << __EOF__ > seed/user-data
#cloud-config
# vim:syntax=yaml
users:
# A user by the name ec2-user is created in the image by default.
  - default
  - name: vagrant
    groups: wheel
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    plain_text_passwd: vagrant
    ssh-authorized-keys:
      - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key
    lock_passwd: false

chpasswd:
  list:
    root:vagrant
  expire: False
__EOF__

# ISOイメージの作成
hdiutil makehybrid -iso -joliet -o seed.iso seed -joliet-volume-name cidata

VMの起動

コマンドラインで実行する。

# VMの作成とAmazon Linux 2の起動
VM=vagrant-amznlinux2
VDI=amzn2-virtualbox-2017.12.0.20171212.2-x86_64.xfs.gpt.vdi
VGA=/Applications/VirtualBox.app/Contents/MacOS/VBoxGuestAdditions.iso
VBoxManage createvm --name "$VM" --ostype "RedHat_64" --register
VBoxManage storagectl "$VM" --name "SATA Controller" --add "sata" --controller "IntelAHCI"
VBoxManage storagectl "$VM" --name "IDE Controller" --add "ide"
VBoxManage storageattach "$VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium $VDI
VBoxManage storageattach "$VM" --storagectl "IDE Controller" --port 0 --device 0 --type dvddrive --medium seed.iso
VBoxManage modifyvm "$VM" --natpf1 "ssh,tcp,127.0.0.1,2222,,22" --memory 1024 --vram 8 --audio none --usb off
VBoxManage startvm "$VM" --type headless

VMにログイン

# Vagrant insecure private keyのダウンロード
curl -sL https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant -o vagrant.pem
chmod 600 vagrant.pem

# ログイン
ssh -p 2222 vagrant@localhost -i vagrant.pem

VBoxGuestAdditionsのインストール準備

kernelを入れない手順が多くアップされているが、kernelを入れないとVBoxGuestAdditionsで失敗する。

# VBoxGuestAdditions依存パッケージのダウンロード
sudo yum install -y kernel kernel-devel perl gcc

# 再起動
sudo shutdown -r now

VBoxGuestAdditionsのインストール

# VBoxGuestAdditionsイメージをアタッチ
VBoxManage storageattach "$VM" --storagectl "IDE Controller" --port 0 --device 0 --type dvddrive --medium $VGA --forceunmount

# ログイン
ssh -p 2222 vagrant@localhost -i vagrant.pem

# VagrantにRHELと認識させるおまじない
sudo ln -s /etc/system-release /etc/redhat-release

# OSからマウント
sudo mount -r /dev/cdrom /media

# VBoxGuestAdditionsのインストール
sudo /media/VBoxLinuxAdditions.run --nox11

# アンマウント
sudo umount /media

クリーンアップ

ボックス化した時にサイズを小さくするための作業

# クリーンアップ
rm $HOME/.bash_history
sudo rm -rf /var/cache/yum
sudo dd if=/dev/zero of=/0 bs=4k
sudo rm -f /0
history -c

# シャットダウン
sudo shutdown -h now

Vagrant boxの作成と登録

vagrant package --base "$VM"
vagrant box add --name "amzn2-2017.12.0.20171212.2-x86_64" package.box

お試し起動

mkdir amznlinux2
cd amznlinux2
vagrant init amzn2-2017.12.0.20171212.2-x86_64
vagrant up

お試しログイン

$ vagrant ssh
Last login: Tue Jan 16 08:24:53 2018 from gateway

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|___|___|

https://aws.amazon.com/amazon-linux-2/
No packages needed for security; 5 packages available
Run "sudo yum update" to apply all updates.

続きを読む

AWSのEC2を使ってJupyterをブラウザから使えるようにする方法

イントロ

初心者のため、いろんなサイトを見ながらやっているうちにつまったことがあったのでメモ。

AWSのアカウントを作成からEC2インスタンスの作成

下のページを参考にさせていただきました。
https://qiita.com/Arashi/items/629aaed33401b8f2265c
ちなみにpemファイルは接続する位置に置いておく必要があります。
もし、WindowsでC:Usersuserから接続するときにはuserフォルダの中にpemファイルを置いてください。

Anacondaのインストール

下のページを参考にさせていただきました。
https://qiita.com/Salinger/items/c7b87d7000e48be6ebe2
https://qiita.com/cafedrip/items/f944f72016ced4ff4361
現時点での最新バージョンは
https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.shのようなので、
wget https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh
で取得して実行するといいのかと思われます。

ちなみに~/.jupyter/jupyter_notebook_config.pyの設定をするときはLinuxの黒い画面テキストエディタで編集します。vimが使えない人は下記ページを参考にしてみてください。
http://www.sejuku.net/blog/5570
基本的には、そのままの状態だと書き込めないので「i」を押してINSERTモードにして編集したあとに「Esc」を押して「:wq」(write quitの略だと思ってます)で保存できます。
INSERTモードじゃないときに「/」を押して検索したい語句を打ち込むと検索もできるので便利です。

AWSのEC2インスタンスへの外部からのアクセスを許可する

下記ページを参考にさせていただきました。
https://www.ipentec.com/document/document.aspx?page=amazon-ec2-add-rule-to-security-group
EC2インスタンスの初期設定では、Jupyterが起動するポート8888(もしくはjupyter_notebook_config.pyc.NotebookApp.port = XXXXで指定したポート番号)は外部からのアクセスができないようになっているようなので、外部からのアクセスを許可する設定に変更します。

Jupyterを起動する

$ jupyter notebook &
で起動して
http://[サーバのホスト名 or IP]:8888/
でブラウザからアクセスできます。
この時、前に起動に失敗したりしていると8888がすでに使用されていて8889等で起動してうまくいかない場合があります。
その場合、
https://hydrocul.github.io/wiki/commands/netstat.html
で使用しているプロセスを特定し、停止しても問題なさそうであればkill -9 プロセス番号で8888を開放して再度Jupyterを起動してみてください。

初心者メモ

①LinuxはDebian系(Ubuntuとか)とRedhat系(CentOSとか)でコマンドが違うらしい。
最近はapt-getではなくaptが推奨されているという話。
http://sig9.hatenablog.com/entry/2015/06/21/081407
https://qiita.com/pocket8137/items/e8370697927220d3fc3c
②Linuxで書いてある手順通りにやってできない場合のよくあるエラー
-Pathが通っていない
-インストールするものが足りていない(もともと使用している環境が違うから)
-パッケージをupdateとかupgradeしていない
-なぜか再インストールしたらうまくいくこともある
-なぜか再起動したらなおることもある

続きを読む

Amazon LinuxでSeleniumを最短で使えるようにする

この記事は、ケーシーエスキャロット Advent Calendar 2017の25日目の記事です。

本日はついにクリスマスですね。皆様いかがお過ごしでしょうか。
私はクリスマスイブに一人でラーメンを食べに行きました。おいしかったです。
今日の予定は職場と自宅の往復です。よろしくお願いします。

概要

Seleniumを使って色々してみたくなったので、Amazon LinuxのEC2に
ChromeDriverとGoogle Chromeを入れようとしたが、依存関係やら何やらで一向に動く状態にならない。
ようやく最小の手順が分かったのでメモ。以下は全てrootで実施したものです。

手順

Google Chrome のインストール
GConf2 のインストール
ChromeDriver のインストール
Google Noto Fonts のインストール
Selenium のインストール

Google Chromeのインストール

yum install google-chrome-stableでやると依存関係で死にます。
以下を実行しましょう。

curl https://intoli.com/install-google-chrome.sh | bash

最新のGoogle Chromeがうまく入るはずです。

GConf2のインストール

ChromeDriverを実行する時にこれがないと動きません。
yum install GConf2をやっても No package GConf2 available. となるので、
リポジトリを追加します。
vim /etc/yum.repos.d/centos.repoで以下を記載。

centos.repo
[CentOS-base]
name=CentOS-6 - Base
mirrorlist=http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=os
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6

#released updates
[CentOS-updates]
name=CentOS-6 - Updates
mirrorlist=http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=updates
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6

#additional packages that may be useful
[CentOS-extras]
name=CentOS-6 - Extras
mirrorlist=http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=extras
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6

GPG keyをインポートします。

rpm --import http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6 

これでGConf2がインストール出来るようになります。

yum -y install GConf2

ChromeDriverのインストール

現時点でインストールしたGoogle Chromeが63なので、それに対応する2.34を取得します。
Google Chromeのバージョンはgoogle-chrome-stable -versionで確認できます。

wget https://chromedriver.storage.googleapis.com/2.34/chromedriver_linux64.zip
unzip chromedriver_linux64.zip
mv chromedriver /usr/local/bin/

Google Noto Fontsのインストール

このままだとSeleniumで画面のスクリーンショットを撮った際に
日本語が文字化けしてしまうのでフォントをインストールします。
https://www.google.com/get/noto/

cd ~/Downloads   # どこか適当な場所で
wget https://noto-website-2.storage.googleapis.com/pkgs/Noto-hinted.zip
unzip Noto-hinted.zip
mkdir -p /usr/share/fonts/opentype/noto
cp *otf *ttf /usr/share/fonts/opentype/noto
fc-cache -f -v # optional

Seleniumのインストール

シンプルにいきましょう。

pip install selenium

インストールするものは以上になります。

Seleniumを使ってみよう

googleのトップページのスクリーンショットを撮る簡単なテストコードを作成して
実行してみましょう。

test.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-gpu')
options.add_argument('--window-size=1280,1024')
driver = webdriver.Chrome(chrome_options=options)
driver.get('https://www.google.co.jp/')
driver.save_screenshot('test.png')

実行ディレクトリにtest.pngが作成されます。

ちなみにoptionsに追加している引数ですが、
・–headlessでヘッドレスモード
 (これで実行しないと動きません)
・–no-sandboxはgoogle-chrome-stableが動くために必要
 (google-chrome-stableを実行すると分かるはず)
・–disable-gpuで描画周りが安定するらしい
 (これ無しで実行したら作られたpngファイルが真っ黒だった)
・–window-sizeはそのままウィンドウサイズの指定
となります。

最後に

作成されたtest.pngは以下のようになっていました。文字化けしていませんね。
test.png

僕のサンタさんはどこにいるのでしょうか?
Googleマップで探しても見つかりませんでした。
来年は来るといいなぁ…

続きを読む

GoでZabbixを爆速にしたかった

はじめに

こんにちは。
CYBIRDエンジニア Advent Calender 2017の22日目は@gucchonさんのゲーム開発をWebViewからUnityに乗り換えて、苦労したこと、良かったことでした。

本日の記事のあらすじ・動機

  • タイトルからもお察しかと思いますが, 失敗談になります。
  • 弊社ではサーバの監視にZabbixを使用しております。(一部はmackerelを使用させていただいております。)
  • Zabbixを容易に拡張する手段として”UserParameter”と”外部スクリプト”が存在します。
    • しかし, これらはメトリクスの取得の度にプロセスをforkするので負荷がかかります。
    • 外部スクリプトの過度の使用によってパフォーマンスが劣化することはZabbixのドキュメントに明記されております。
    • 弊社(のAWSを使用した案件)では外部スクリプトに頼った監視になっており, 監視サーバのインスタンスタイプが本番環境のWebサーバのインスタンスタイプを超えているケースがあったりします。
  • Zabbixサーバの負荷をなんとか抑えたいということが今回の動機になります。
  • Zabbixモジュールを使用することで, ネイティブ実装と同じパフォーマンスを得ることができる。
    • PHPのCGIモードとmoduleモードでパフォーマンスが異なる理由と同じになります。
    • UserParameter・外部スクリプトを使用するときのようなオーバーヘッド(fork)が削減されます。
    • ネイティブ実装と同じパフォーマンスを得ることができる。
    • Zabbixサーバのインスタンスタイプを落とすことが出来るかもしれない。
    • しかしZabbixモジュールを実装するためには基本的にはCで実装する必要があります。
  • そこでGolangで気軽にZabbixモジュールを作成して使用してみました。
    • しかし後述する, “ZabbixとGoランタイムの相容れないアーキテクチャ”によって失敗するという話になります…
  • 着想・実装にあたっては, @ike_daiさんの記事Golangを使ってZabbixを拡張大いに参考にさせていただいております。

実際にやってみた結果…

実装

  • 変数等のネーミングセンスがない件については, ご容赦ください。

    • AWSのCredentialを.envファイルから読み込んでおります。
    • github.com/cavaliercoder/g2zを使用させていただいております。
    • 既に作者様が行ったパフォーマンスのテストの結果がperformance.mdに記載されております。
mod_zabbix_go.go
package main

import (
    "C"
    "errors"
    "log"
    "strings"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/ec2"
    "github.com/joho/godotenv"
    g2z "gopkg.in/cavaliercoder/g2z.v3"
)

// main ... 共有ライブラリなので通常は実行されない
func main() {
    panic("THIS_SHOULD_NEVER_HAPPEN")
}

// env_load ... pathに存在する.envを読み込み環境変数にマッピング
func env_load(path string) {
    err := godotenv.Load(path)
    if err != nil {
        log.Fatalf("Error loading .env file in %v.n", path)
    }
}

// init ... 共有ライブラリ読み込み時に実行される
func init() {
    env_load("/etc/zabbix/aws.env") // AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYの値を参照
    g2z.RegisterStringItem("go.echo", "Hello World", Echo)
    g2z.RegisterStringItem("go.ec2_name2id", "error", Ec2Name2Id)
}

// Echo ... 引数の値を全て連結して返す
func Echo(req *g2z.AgentRequest) (string, error) {
    return strings.Join(req.Params, " "), nil
}

// Ec2Name2Id ... EC2インスタンスのタグ名からインスタンスIDを取得
func Ec2Name2Id(req *g2z.AgentRequest) (string, error) {
    if len(req.Params) != 1 {
        return "", errors.New("can use only 1 argument(s).")
    }

    sess, err := session.NewSession(&aws.Config{
        Credentials: credentials.NewEnvCredentials(),
    })
    if err != nil {
        return "error", err
    }

    svc := ec2.New(
        sess,
        aws.NewConfig().
            WithRegion("ap-northeast-1").
                WithLogLevel(
                    aws.LogDebugWithRequestRetries |
                    aws.LogDebugWithRequestErrors  |
                    aws.LogDebugWithHTTPBody,
                ),
    )

    params := &ec2.DescribeInstancesInput{
        Filters: []*ec2.Filter{
            &ec2.Filter{
                Name: aws.String("tag:Name"),
                Values: []*string{
                    aws.String(req.Params[0]),
                },
            },
        },
    }

    res, err2 := svc.DescribeInstances(params)
    if err2 != nil {
        return "error", err2
    }

    for _, r := range res.Reservations {
        for _, i := range r.Instances {
            return *i.InstanceId, nil
        }
    }
    return "empty", nil
}

ビルド環境

  • AWSのCodeBuildを使用してビルドしております。CircleCI?知らない子ですね…

    • Dockerイメージはgolang:1.9.2を使用してビルドしております。
buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - wget https://github.com/Masterminds/glide/releases/download/v0.13.1/glide-v0.13.1-linux-amd64.tar.gz
      - tar xvf glide-v0.13.1-linux-amd64.tar.gz
      - install -o root -g root -m 0755 linux-amd64/glide /usr/local/bin/glide
  pre_build:
    commands:
      - /usr/local/bin/glide install
  build:
    commands:
      - GOOS=linux GOARCH=amd64 go build -buildmode=c-shared -o mod_zabbix_go.so main.go

artifacts:
  files:
    - 'mod_zabbix_go.so'
  discard-paths: no

環境設定

  • Moduleを読み込むよう設定を記述し, Zabbix Agentを起動・再起動します。
/etc/zabbix/zabbix_agentd.conf
+ LoadModulePath=/var/lib/zabbixsrv/modules
+ LoadModule=mod_zabbix_go.so
systemctl restart zabbix-agent.service

動作確認

  • 実際に確認してみますと, リクエストを飛ばすところでハングっているようです…
$ zabbix_get -s localhost -k 'go.echo[hello, ntrv]'
hello ntrv # OK!!
$ zabbix_get -s localhost -k 'go.ec2_name2id[ntrv-test]'

zabbix_get [24960]: Timeout while executing operation # i-xxxxxxと返ってくることを期待していた...

失敗した原因について

  • マルチスレッドのgoランタイムでプロセスを安全にフォークすることは不可能

    • 一般的にシングルスレッドのプログラムがマルチスレッドとなる共有ライブラリをdlopen()で呼び出した段階でforkすることが出来ない。
    • https://github.com/golang/go/issues/15538
  • 共有ライブラリをロードしたプロセスがfork()を呼び出した後, 子プロセスでGo codeを使用できない。
    • エージェントがforkする際, Copy-on-WriteでメモリマッピングをコピーするがGoランタイムスレッドをコピーしてくれない。

      • 結果, g2zで記述した関数が呼び出されると, 子プロセスに存在しないスレッドを使用しようとしてデッドロックに陥る?
    • 詳しい方, 教えて頂けるとありがたいです…

References

Zabbix負荷問題を軽減する上で考えうる別の解決方法

  • 失敗してしまったので
  1. Zabbixをやめる
  2. EC2のCloudWatchメトリクスを取得する場合には, 外部スクリプトではなくUserParameterを使用する。
    • Zabbixサーバに負荷が集中するのを防ぐため。
    • RDS等ZabbixAgentが使用出来ない場合に外部スクリプトを使用する。
  3. Zabbix Senderを使用する。
    • 別途エージェントを用意してそこでメトリクスを収集し, ZabbixサーバのZabbix Trapperに投下する。
    • 弊社ですとHTTPステータスコードやアクセス数を, Webサーバ上のtd-agentからZabbix Trapperに送っております。

最後に

今回はZabbixを爆速化しようとして失敗してしまったことをまとめました。
GoでZabbix Sender専用のエージェントを用意して, エージェント上でAWS APIの結果を収集しZabbixサーバに送ってもよさそうですね。
時間があるときに試してみようかと思います。

また今回の経験を通して, Goのことというよりはマルチスレッドプログラミングが分かっていなかったということを痛感いたしました。Golangの文法が簡単だからと言ってなめておりました。
そのあたりの知識を身に着けなければなと考えております。

CYBIRDエンジニア Advent Calendar 2017の24日目は@koki_yamadaさんの”Unityのコード編集にVimを使ってみた”です!
私の冬休みの宿題はneobundle.vim/neocomplete.vimdein.vim/deoplete.nvimに置き換えることなので参考にしようかと思います。
どうぞお楽しみに!

続きを読む

ピヨピヨエンジニアをビシバシ鍛えた話

前置き

去年から合わせて3回、計3名のピヨピヨエンジニアにいろいろ教える機会があり、今後もその機会がありそうなので、今年の振り返りついでに&今後参考にするためにここでまとめておく。

前提として、ピヨピヨ側はプログラムの基本的な事(変数の概念・条件分岐・繰り返しなど)は理解している状態。
なので文系の新卒に教える感じよりは、情報系や専門の新卒だったり、エンジニアの第二新卒に教える感じ。

目標は、何か起きたときにどこらへんから調べてみてどういうものを調べればいいのか検討がつくようになること。

教えるときに心がけている事

これは今回のケースだけに当てはまるものではないかもしれないけど

先に大きな事から説明する

基本的に世界(ゴール)のおおざっぱな概要を伝えて、徐々にその仕組を掘り下げていく。
(Webの仕組みを教えるときに、いきなりwebサーバとかsqlの話を始めても、まず伝わらない。)

大抵の事にも言えるのだが、教える側と教えられる側の違いは、知ってるか知らないかの差で、能力の差があるというわけではない(と思っている)。
説明の内容が完璧であるとは限らないので、先に説明する内容の用途・目的を頭に入れておいてもらう事で、聞き手に必要な部分を要領良く理解してもらいやすくなる。

絵を描く

言葉とか文字だけで全部覚えられたら苦労しない。
必ず視覚的な補助を入れる。
「★★★は◯◯◯という名前で△△△が有名」みたいに言葉だけで言われるよりは、地図を見ながら言われた方が覚えやすいのと一緒。

後は、同じ概念のものを毎回同じ絵・同じ構成で描く必要はない。
伝えるべき概念が同じなら、表現の差はその概念が持つ別の姿だったり、説明しきれていない部分だったりする。
聞き手はその差分を見て、足りていない理解を補えたりする気づきになる。

理解してほしい事を、説明後に「理解していれば回答出来る、別の質問」をする

当然ながら話し手のロジックと受け手のロジックがある。
コミュニケーションのとり方も人それぞれ。
結果として、分からない部分は全て質問してもらえる、とは思わない。

要は、理解してほしい事があって、話し手はそれが相手に伝わっていればいいわけで、そこの確認が出来ればいい。

たまたまアウトプットが正解しただけでロジックがぐちゃぐちゃ、後日確認してみたら結局理解出来てませんでしたという事は往々にしてあり得る。
そこはたまたまなアウトプットでOKになってしまったテストケースの問題。

基本的に相手が理解出来ていないのは自分が悪い(自戒)

なぜ相手が理解出来ないんだろうと思ったら、大抵上に書いたような事を自分が出来ていない。
自分がしゃべりたい事だけしゃべる、ただのエゴをしてる。
このプログラムどこもおかしくないのに挙動がおかしい!!!言語のバグやああぁぁああ!!!っていうのが、大抵はただのしょーもない自分のバグ、というのと似てる。

だいたいこれを詰め込めばなんとかなるだろう的な事

まずは適当に詰め込む。
その後で手を動かし、詰まったときは「これはあのとき説明した◯◯◯の理論で…」みたいに進める。
上で書いた地図の話の感覚に近いかもしれない。
心のハードル的にも、「全く新しい概念」ではなく、「既に一度聞いた事がある・かじった事がある」という事が重要。

詰め込む内容はだいたい毎回同じで、
サーバに置いている静的なファイルがブラウザに表示されるまでの流れ
・サーバの動きはリクエストを受け取ってレスポンスを返すという事
・サーバにアクセスするにはipアドレスが必要である事
・実際にはipアドレスではなくドメイン名でアクセスしている事
・サーバではデーモンさんが常時リクエストを待ち構えているという事

サーバの動きはリクエストを受け取ってレスポンスを返すという事

クライアントとサーバってなんだ?と私は悩んだ事があるので、毎回「クライアントとサーバとは、単なる役割の事」と言っている。
どの端末でもサーバになりえるしクライアントになりえる。
yah◯◯をブラウザに表示させるためには、
1.表示内容の記載されたファイルをサーバに要求(リクエスト)
2.リクエストを受け取ったサーバはそのファイルの内容を返信(レスポンス)
3.レスポンスを受け取ったクライアントはその内容をブラウザに表示する
という流れになるとざっくり絵を描いて説明。

サーバにアクセスするにはipアドレスが必要である事

どの端末も住所を持っていて、その住所を元に通信しているという事を説明。
ここの詳しい部分はネットワークの仕組みの話になってくるので、グローバルIPとプライベートIPという2種類があるよって事だけ押さえておく。

実際にはipアドレスではなくドメイン名でアクセスしている事

ブラウザに
123.123.123.123
みたいな数字じゃなくて、
yyyy.com
みたいな文字を打ち込んでるよね、的な事の説明。
ドメインやサブドメイン、DNSサーバの話、ついでにプロトコルのhttp://が省略されてたり、ポートの:80が省略されてたりなんかする事を説明。
後々証明書入れたりとか、8080でアクセスする環境のものが出てきたときに役立つ。
プロトコルは掘り下げると戻ってこれなくなるので、通信するときのお作法みたいなもの程度の説明に留める。

後はドキュメントルートとディレクトリインデックス。
URLを見て、サーバ側にあるどのファイルを読み込んでいる・実行しているのかを意識するようにする。

サーバではデーモンさんが常時リクエストを待ち構えているという事

httpdとかsshdとかcrondとかmysqldとかとか。
これらDの一族はデーモンさんといって常時待機してる人達なのだよという説明。
とりあえずWebサーバにせよDBサーバにせよ、何かしら通信して反応あるのはこいつらがそもそも動いている = インフラ構築するときにはこいつら意識しておかないといけないと覚えておいてもらう。

だいたいこれを実技すればなんとかなるだろう的な事

詰め込んだ後は、実際にいろいろ手を動かしてみる。
やってもらう内容もだいたい毎回一緒で
サーバ立てて環境構築してサーバサイド処理&DB操作した結果を返すWebサービスの作成。
AWSを利用する機会が多く、だいたいEC2インスタンス(Amazon Linux)でLAMP環境を構築する。

・Linuxに入って操作する流れ
・EC2とVPCの設定
・yumとnpmで大抵のものはインストール出来る事
・apacheをインストールしてindex.htmlを表示
・phpをインストールしてサーバサイドで処理が行われる事の体験
・sqlの説明とmysqlをインストールしてmysqlクライアントからsqlの練習
・phpからmysqlのデータを取ってきて表示させる

暗中模索でやってて、これがどう影響してるのかといういうのが分からないとつらいので、いったんはここを変更するとこういう原理でこうなる!
という、確固たる地盤を作る。

詰め込んだ内容の原理できちんと動いているんだよというおさらいも兼ねる。
最初のうちは何が正解か分からずに、間違った理解をしたり疑心暗鬼になりがちなので結構大事。

Linuxに入って操作する流れ

基本的に端末はMacなのでMacのターミナルで練習。
lsとかcdとか。
cpとかmvとか。
grepとかfindとか。
ユーザとか権限とか。
vi(vim)の操作とか。
Linux内で生きていくのに必要最低限の操作を教える。

EC2とVPCの設定

仮想マシンとプライベートネットワークとはなんぞや。
EC2とVPCはセットで使う事が多いので、それらを使う前に軽く説明。
EC2とVPCを実際に設定しながら、ここはこういう設定でこういう意味で…みたいな。
ルートテーブル、サブネット、セキュリティグループ、etc…
結構時間かかる…
設定出来たらsshでイン!

yumとrpmで大抵のものはインストール出来る事

ミドルウェアのインストールにあたり、とりあえず説明。
とは言っても、yumは/etcの下でrpmは/usrの下にインストールされるよくらい。
ついでにコマンドが使えるようになったり、whichでここにパスが通ってるよ確認したり。

apacheをインストールしてindex.htmlを表示

ドキュメントルートとかディレクトリインデックスを確認して、パブリックIPから所定の位置に配置したindex.htmlの表示を確認。
apache止めてみたりとか。
権限変えてみたりとか。
ファイル名変えてみたりとか。

phpをインストールしてサーバサイドで処理が行われる事の体験

phpinfoとかvar_dump、echo、exitなどなど。
後々サイト構築時にデバッグするときに役立つ知識などを詰め込み。
そして表示の確認。
テンプレートエンジンなんて贅沢なものは使わず、phpの出力結果をレスポンスとして返しているだけ、という基本概念を叩き込む。

連想配列でデータの取扱とか、forで一覧の組み立て方とかとか。
mysqlでデータ引っ張って表示するときの下準備までする。

sqlの説明とmysqlをインストールしてmysqlクライアントからsqlの練習

ちょっと今までのを置いといてSQLの説明。
ID・名前・HP・攻撃力・防御力を持ってるモンスターのテーブル作って、insertで新モンスター追加したりselectで情報引っ張ってきたりの練習。

phpからmysqlのデータを取ってきて表示させる

上で実行したようなselectをphpから実行させてみる。
用意していた連想配列に取得結果をつっこんで、一覧に表示出来れば完成。

これで基礎の基礎は大丈夫(多分)

だいたい上のコースで2週間くらいな気がする。
正直この2週間で、目標にしているような、問題の箇所を特定したりなどのスキルはまだ身につかない。
が、大抵の事は、実技でやった事の拡張版だったり延長線の話なので、後は現場で。
小さな案件を、私がサポートしながらやってもらう感じ。

結構急いで書いたので、もしかしたらいろいろ抜けてるかもしれない。
次教える事があったら見返してブラッシュアップしていく。(つもり)

続きを読む

Vagrant Cloud に Amazon Linux 2 のイメージを公開した

さくっと Amazon Linux 2 を使いたかったので、Vagrant Cloud に登録してみた。

https://app.vagrantup.com/stakahashi/boxes/amazonlinux2

自分のためにも更新があれば更新していきたい所存。

TL;DR

$ vagrant init stakahashi/amazonlinux2
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'stakahashi/amazonlinux2' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'stakahashi/amazonlinux2'
    default: URL: https://vagrantcloud.com/stakahashi/amazonlinux2
==> default: Adding box 'stakahashi/amazonlinux2' (v2017.12) for provider: virtualbox
    default: Downloading: https://vagrantcloud.com/stakahashi/boxes/amazonlinux2/versions/2017.12/providers/virtualbox.box
==> default: Successfully added box 'stakahashi/amazonlinux2' (v2017.12) for 'virtualbox'!
==> default: Importing base box 'stakahashi/amazonlinux2'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'stakahashi/amazonlinux2' is up to date...
==> default: Setting the name of the VM: amazonlinux2_default_1513588712330_45863
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
    default: /vagrant => /Users/mac-user/Documents/Vagrant/amazonlinux2
$ vagrant ssh
Last login: Mon Dec 18 08:58:01 2017 from gateway

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|___|___|

https://aws.amazon.com/amazon-linux-2/
[vagrant@localhost ~]$ uname -a
Linux localhost.localdomain 4.9.62-10.57.amzn2.x86_64 #1 SMP Wed Dec 6 00:07:49 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Amazon Linux Extras repository の追加

Amazon Linux 2 では「Amazon Linux Extras repository」というリポジトリが提供されており、サポートされている言語・ソフトウェア等はこのリポジトリで提供されているようです。

https://aws.amazon.com/jp/amazon-linux-2/#Features

[root@localhost ~]# rpm -qa amazon-linux-extras
[root@localhost ~]# amazon-linux-extras list
  0  ansible2   disabled  [ =2.4.2 ]
  1  emacs   disabled  [ =25.3 ]
  2  memcached1.5   disabled  [ =1.5.1 ]
  3  nginx1.12   disabled  [ =1.12.2 ]
  4  postgresql9.6   disabled  [ =9.6.6 ]
  5  python3   disabled  [ =3.6.2 ]
  6  redis4.0   disabled  [ =4.0.5 ]
  7  R3.4   disabled  [ =3.4.3 ]
  8  rust1   disabled  [ =1.22.1 ]
  9  vim   disabled  [ =8.0 ]
 10  golang1.9   disabled  [ =1.9.2 ]
 11  ruby2.4   disabled  [ =2.4.2 ]
 12  nano   disabled  [ =2.9.1 ]
 13  php7.2   disabled  [ =7.2.0 ]

例: PHP7.2 をインストール

[root@localhost ~]# amazon-linux-extras install php7.2
  0  ansible2   disabled  [ =2.4.2 ]
  1  emacs   disabled  [ =25.3 ]
  2  memcached1.5   disabled  [ =1.5.1 ]
  3  nginx1.12   disabled  [ =1.12.2 ]
  4  postgresql9.6   disabled  [ =9.6.6 ]
  5  python3   disabled  [ =3.6.2 ]
  6  redis4.0   disabled  [ =4.0.5 ]
  7  R3.4   disabled  [ =3.4.3 ]
  8  rust1   disabled  [ =1.22.1 ]
  9  vim   disabled  [ =8.0 ]
 10  golang1.9   disabled  [ =1.9.2 ]
 11  ruby2.4   disabled  [ =2.4.2 ]
 12  nano   disabled  [ =2.9.1 ]
 13  php7.2=latest  enabled  [ =7.2.0 ]
[root@localhost ~]# php -v
PHP 7.2.0 (cli) (built: Dec 13 2017 00:38:30) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2017 Zend Technologies

続きを読む

AWS EC2にLet’s Encryptを導入【ログ】

AWS EC2にLet’s Encryptを導入

3ヶ月だけ無料で使える証明書です。
下記のサイトをみてやってみたのですが、ハマったところがあったので
そちらのメモ。
そして作業ログを掲載しておきます。
参考サイト:https://qiita.com/MashMorgan/items/56498f276c54406b1928

ハマったところ

3.証明書の発行
# certbot-auto certonly --webroot -w /var/www/html -d ドメイン名 --email hoge@example.com --debug

作業ログ

    1  cd /var/log/letsencrypt/
    2  ll
    3  cat letsencrypt.log
    4  cd /var/www/html/
    5  ls -la
    6  cd .well-known/
    7  ls
    8  ls -la
    9  cd ./
   10  cd
   11  cd /etc/httpd/conf.d/
   12  ls
   13  ll
   14  mv EC.conf EC.conf.b
   15  /etc/init.d/httpd restart
   16  cd /etc/letsencrypt/live/
   17  ls
   18  cd ec.neko-server.com/
   19  ls
   20  ll
   21  cat README 
   22  cd /etc/httpd/conf.d/
   23  ls
   24  ll
   25  cat ssl.conf
   26  ll
   27  cat ssl.conf.bk_20170730|grep -v "#"
   28  vi EC.conf.b 
   29  mv EC.conf.b EC.conf
   30  vi EC.conf 
   31  /etc/init.d/httpd restart
   32  cat EC.conf 
   33  sudo vim  EC.conf 
   34  sudo vim ec.include
   35  ls
   36  sudo vim  EC.conf 
   37  vim EC.conf.bk_20170731
   38  ls
   39  cp EC.conf EC.conf.bk_20170731 
   40  sudo cp EC.conf EC.conf.bk_20170731
   41  ls
   42  cat ec.include
   43  sudo vim  EC.conf
   44  /etc/init.d/httpd restart

続きを読む