Web系エンジニアのアウトプット練習場

エンジニアリングと書評が中心。たまに全然関係無い話もします。
  • 2017年12月23日

    GKEのコンテナ内のディレクトリにGCSバケットをマウントする

    Qiita
    概要 Cloud Storage FUSEを使用して、Google Kubernetes Engine(以下、GKE)で動いてるコンテナ内のディレクトリにGoogle Cloud Storage(以下、GCS)のバケットをマウントすることを目指します。 WordPressのuploadsディレクトリなど、コンテナ間で共有したいリソースがある時に便利です。 GCP側の準備 プロジェクトを作成 コンソール画面などからプロジェクトを作成します。 バケットの作成 Cloud SDKかGCPコンソール画面でバケットを作成します。 バケット名やプロジェクト名は他ユーザも含めて全プロジェクトでユニークなので、 クラスタ作成 コマンドで作成を行います。 --scopesオプションで、必ずstorage-rwかstorage-fullを指定してください。 $ gcloud container clusters create example-cluster \ --machine-type f1-micro \ --scopes storage-full Cloud Storage FUSEのインストール ベースイメージを元に、FUSEがインストールされたイメージを作っていきます。 公式ドキュメントの手順に従って準備をしていきます。 ベースイメージ 今回は例としてphp:5.6-apacheを使用します。 ベースイメージOSのバージョン名を確認 公式ドキュメントの通り、lsb_releaseコマンドを使用してOSバージョン名を確認します。 # docker run -it php:5.6-apache /bin/bash # apt-get install -y lsb-release # lsb_release -c -s jessie Apacheのユーザ名を確認 Apacheのユーザ名(=FUSEを使用するユーザ名)を確認します。 /etc/apache2/apache2.conf . . . # These need to be set in /etc/apache2/envvars User ${APACHE_RUN_USER} Group ${APACHE_RUN_GROUP} . . . /etc/apache2/envvarsで定義されている環境変数が指定されているようですので、コメントに書いてあるファイルを確認します。 . . . : ${APACHE_RUN_USER:=www-data} export APACHE_RUN_USER : ${APACHE_RUN_GROUP:=www-data} export APACHE_RUN_GROUP . . . Apacheのユーザはwww-dataであることがわかりました。 Dockerfileを用意する gcsfuseのパッケージURLを指定する際に、先程確認したOSバージョン名を使用します。 sudoもインストールしておきます。 vimをApacheの設定を確認するためにインストールしていますが、必須ではございません。 また、fuseグループを作成し、apacheのユーザをfuseグループに追加します。 末尾ではENTRYPOINTを指定しています。 FROM php:5.6-apache WORKDIR /path/to/DocumentRoot # gcsfuse-[バージョン名]を指定する RUN echo "deb http://packages.cloud.google.com/apt gcsfuse-jessie main" | tee /etc/apt/sources.list.d/gcsfuse.list RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - RUN groupadd fuse RUN usermod -aG fuse www-data RUN apt-get update -y && apt-get install -y \ gcsfuse \ sudo \ vim COPY entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod a+x /usr/local/bin/entrypoint.sh EXPOSE 80 443 ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] ENTRYPOINTを指定 この例では、ドキュメントルートをGCSにマウントしていますが、他のディレクトリでももちろん構いません。 entrypoint.sh #!/bin/bash source /etc/apache2/envvars chown -R www-data:www-data * sudo -u www-data gcsfuse example-bucket ./ exec apache2 -D FOREGROUND イメージファイルのビルド・プッシュ イメージをビルドし、GCPのContainer Registryにプッシュします。 docker build -f ./Dockerfile -t example_image:0.0.0 . docker tag example_image:0.0.0 gcr.io/example/example_image:0.0.0 gcloud docker -- push gcr.io/example/example_image:0.0.0 k8sの設定ファイルを用意 example.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: example spec: replicas: 1 template: metadata: labels: app: example tier: frontend environment : production spec: containers: - image: gcr.io/example/example_image:0.0.0 imagePullPolicy: Always name: example ports: - containerPort: 80 name: example securityContext: privileged: true --- apiVersion: v1 kind: Service metadata: name: example labels: app: example spec: selector: app: example tier: frontend environment : production type: LoadBalancer ports: - port: 80 protocol: TCP targetPort: 80 GKEにデプロイする $ gcloud container clusters get-credentials example-cluster --project example $ kubectl create -f example.yaml GKEクラスタに接続して外部IPを確認 $ kubectl get svc example 上のコマンドを実行することで表示されるEXTERNAL IPを確認します。 確認 GCSにindex.htmlをアップし、ブラウザからhttp://[確認したEXTERNAL IP]/にアクセスします。 アップした内容が表示されたら成功です。 なお、GKEにデプロイするのに少し時間がかかる(イメージのプル時間とエントリポイントの実行時間)ため、表示されない場合は少し時間を置いてからアクセスしましょう。
  • 2017年12月11日

    EC-CUBEでフロント画面テンプレートを追加

    Qiita
    EC-CUBEでオリジナルのテンプレートを作成する必要があったので、手順をメモする。 デフォルトテンプレートをコピーする $ cp -r app/template/default/ app/template/[テンプレートコード]/ $ cp -r src/Eccube/Resource/template/default/* app/template/[テンプレートコード]/ [テンプレートコード]は新たに追加するテンプレートを表す適当なコードに置き換える。 テンプレートをDBに登録する DBサーバーでmysqlクライアントを起動。 $ mysql -u [DB_USER] -p Enter password: [PASSWORD] mysql > use [DB_NAME]; テンプレートを追加登録するため、以下のコマンドを実行。 mysql > INSERT INTO `dtb_template` (`device_type_id`, `template_code`, `template_name`, `create_date`, `update_date`) VALUES ('10', '[テンプレートコード]', '[テンプレート名]', NOW(), NOW()); device_type_id device_type_id 用途 10 PC用テンプレート、レスポンシブデザイン 1 モバイル専用 2 スマホ専用 template_code, template_name template_codeは先程作成したディレクトリ名に合わせる。 template_nameは任意の文字列。2バイト文字でも可。 確認 管理画面でオーナーズストア->テンプレート->テンプレート一覧から新しいテンプレートが追加されていることを確認できる。 ここから新しいテンプレートを選択すると開発をスタートできる。
  • 2017年12月02日

    IoTシステム技術検定試験(中級)を受けてみた

    Qiita
    2017/12/2にIoTシステム技術検定試験中級を受けてきたので所感をまとめておく。 試験内容について カリキュラムは公式や前回記事を参照のこと。 発表されているカリキュラム通りの割合で各項目、公式テキストから出題された。 あとは、IoTシステムの構成に関する問題や、IoTシステムの構築に必要なPANやWANの無線通信技術に関する問題が多かった気がする。 計算問題は帯域幅の計算に関する問題が1題だけあった。 出題方法について 形式は覚えている範囲で以下のパターンがあった。 〜について正しい記述の組み合わせを選択せよ 〜について適切な記述を1つ選択せよ 〜について不適切な記述を1つ選択せよ 空欄に入る適切な語句を選択せよ 2つ空欄があり、その組み合わせを回答するもの 1つだけ空欄があるもの 試験時間について 選択式80問に対して試験時間が90分。 受験者について イケイケWebエンジニアより、古参風オッサンエンジニアが圧倒的に多かった。 まとめ 「広く浅く」な出題内容で、「IoTシステム開発入門」といった内容だった。 また、この分野は移り変わりも激しいので、注意が必要である。 例えば、公式テキストでは分散データ処理プロダクトとして、Hadoopが挙げられているが、 個人的には最近はApache Beamが良い感じだと思っている。 常に情報にアンテナを貼る必要はあるだろう。
  • 2017年11月21日

    Google Cloud IoT CoreでMQTTを試す

    Qiita
    動機 以前、AWS IoTを触ったが、 目標 Google Cloud IoT Coreを使用し、Raspberry Piから、 Cloud PubSubにメッセージをパブリッシュする。 MQTTについて パブリッシュ・サブスクライブ方式のプロトコル。 IBMのページがよくまとまっている。 GCP側の準備 プロジェクトを作成し、「APIとサービス」から「Google Cloud IoT API」を有効化する。 端末レジストリの作成 メニューから「IoT Core」を選択すると、「端末レジストリ」の作成画面となる。 パラメータ 値 レジストリID 任意の値 Cloudリージョン asia-east1 プロトコル MQTT, HTTP テレメトリーのトピック events デバイス状態のトピック state 上記画面が出るので「続行」を選択する。 端末の追加 端末の追加をクリック。 パラメータの入力 パラメータ 値 端末ID 任意 端末の通信 許可 公開鍵の形式 後述 公開鍵の値 後述 公開鍵の有効期限 省略(設定しない) 端末メタデータ 省略(設定しない) 公開鍵の登録 公式ドキュメントを参考に、Raspberry Piにて公開鍵を作成する。 opensslを使用するので、インストールされてない場合はインストールする。 $ openssl genrsa -out rsa_private.pem 2048 $ openssl rsa -in rsa_private.pem -pubout -out rsa_cert.pem rsa_cert.pemの内容を「公開鍵の値」に入力する。 rsa_private.pemは端末側に配置して使用する。 Raspberry Pi側の設定 Python環境を準備 https://qiita.com/h-sakano/items/cb8df027b81acd78bd77 サンプルコードをダウンロード こちらからMQTTクライアントのサンプルをダウンロードし、端末に配置。 このサンプルについて 内部でMQTTを使用している。 $ wget https://pki.goog/roots.pem 必要なライブラリ等をインストール $ sudo apt-get install -y build-essential libssl-dev libffi-dev $ sudo pip install -r requirements.txt $ sudo pip install google-api-python-client $ wget https://pki.goog/roots.pem $ ls cloudiot_mqtt_example.py requirements.txt rsa_private.pem roots.pem トピックにメッセージをパブリッシュ $ python cloudiot_mqtt_example.py --registry_id=iot-gateway --project_id=my_project --device_id=gateway1 --algorithm=RS256 --private_key_file=./rsa_private.pem --cloud_region=asia-east1 Creating JWT using RS256 from private key file ./rsa_private.pem Publishing message 1/100: 'iot-gateway/gateway1-payload-1' ('on_connect', 'Connection Accepted.') on_publish Publishing message 2/100: 'iot-gateway/gateway1-payload-2' on_publish Publishing message 3/100: 'iot-gateway/gateway1-payload-3' on_publish Publishing message 4/100: 'iot-gateway/gateway1-payload-4' on_publish Publishing message 5/100: 'iot-gateway/gateway1-payload-5' on_publish Publishing message 6/100: 'iot-gateway/gateway1-payload-6' on_publish Publishing トピックをサブスクライブ $ gcloud beta pubsub subscriptions create --topic events my-subscriptions $ gcloud beta pubsub subscriptions pull --auto-ack my-subscriptions ┌────────────────────────────────┬─────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ DATA │ MESSAGE_ID │ ATTRIBUTES │ ├────────────────────────────────┼─────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ iot-gateway/gateway1-payload-1 │ 173994752831401 │ deviceId=gateway1 deviceNumId=3104791428628451 deviceRegistryId=iot-gateway deviceRegistryLocation=asia-east1 projectId=factory-iot subFolder= │ └────────────────────────────────┴─────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ まとめ Google Cloud IoT CoreとRaspberry Piを使用して、PubSubにメッセージを送信することができた。 次は取得したデータを閲覧したりできるよう、PubSubと他サービスの連携を行っていきたい。
  • 2017年11月20日

    ArduinoとRaspberry Pi間をZigBeeで接続する

    Qiita
    準備 Arduino Uno Rev3 Raspberry Pi 3 Model B Arduino ワイヤレスSDシールド XBee USBインターフェースボードキット XBeeZB S2Cモジュール ワイヤーアンテナタイプ 2個 Arduino-PC間接続用のUSBケーブル Arduino側がTYPE-B XBee USBインターフェースボードキットと、PCやRaspberry Piの間の接続用のUSBケーブル インターフェースボードキット側がMicro-B 作業用PC MacでもWinでもLinuxでもできるはず 私はMac Book(Sierra)で作業を行った XBee USBインターフェースボードキットの組み立て はんだ付け いつ以来のハンダ付けかわからないため、汚いが勘弁してほしい。 はんだ付けの方法はここを参考にした。 表 裏 PWE-SELにジャンパピンを取り付ける 今回はRaspberry PiとUSBで接続する想定なので、USB側に接続。 XBeeZB S2Cモジュールを取り付ける このモジュールには向きがあるので注意すること。 Raspberry Piの準備 インターネットにWiFiで接続する、もしくは有線で接続する 作業用PCからssh接続するため。 RaspberryPiに直接ディスプレイやキーボードを接続する場合は不要 Pythonの設定 ベースのアップデートと必要なライブラリをインストール # ベースのアップデート $ sudo apt-get update $ sudo apt-get upgrade -y $ sudo apt-get dist-upgrade # 必要なライブラリのインストール $ sudo pip install xbee 手元のRaspberry Piだとpipにsudo付けないとPermission Deniedが出るんだが、 Arduinoの準備 Arduino IDEを作業PCにインストール ワイヤレスSDシールドの接続 この後、USBケーブルでPCと接続して設定を行うので、下図の赤枠で囲っている箇所にあるSERIAL SELECTのDIPスイッチをUSB側へ倒しておく XBeeモジュールの接続 XCTUのインストール PCにインストールを行う。 XCTU SOFTWAREのDiagnostics, Utilities and MIBsから適切なOS用のインストーラを選びダウンロード。 ダウンロードの際、メンバー登録を促されるので、メンバー登録したくない人はNo thanks, register laterで回避可能。 インストールが完了したら、XCTUを起動する。 起動時に「"XCTU"を開くには、以前のJava SE 6ランタイムをインストールする必要があります。」とエラーが出た場合は、「詳しい情報」からインストールする。 XBee USBの接続 作業PCにVCP DriversページからOSに合ったドライバをダウンロードし、インストール。 その後、USBでPCに接続する。 XCTUでネットワーク設定 XBeeZB S2CモジュールをPCから認識させる USBポートが2つ以上あるPCの場合は親機(XBee USB)と子機(Arduino)を同時にPCに差して、同時に認識させることが可能。 XBee USB側(親機)のXBeeZB S2Cモジュールの認識 赤枠で囲ったアイコンからモジュールを検索できる。 モジュールが見つかるので、「Add selected devices」でモジュールを追加。 Arduino側(子機)のXBeeZB S2Cモジュールの認識 ArduinoをPCに接続し、同じ手順で認識させる。 認識されない場合に試すこと 突然XBee USB側のXBeeモジュールがXCTUに認識されなくなった 接続しようとしたところ上記の画面が出て認識されなくなった。 その後、モジュール追加アイコンから再度試すが、同じ画面が。 Product familyとFunction setを聞かれたので、それぞれXC24C・ZIGBEE TH Reqを選択した。 リカバリー終了後、再度認識するが試すが、同じ画面が出る。 どうしたものかと思いながら、 XBee USBに差してるXBeeモジュールは認識されるが、同じモジュールをArduino側に差したら認識されない XBee USBでとりあえず認識させて、スパナのアイコンのXBee Recoverから、XBee USBを差しているUSBポート、Product family(XC24C)とFunction set(ZIGBEE TH Req)を選択してファームウェアのリカバリーを行う。 リカバリーが完了したら、Arduinoに差し替えて認識させてみると正常に認識された。 と思ったらまたArduino側のXBeeモジュールが認識しなくなった ArduinoのGNDとRSTを接続してショートさせると良いらしい。 ただし、この状態のまま、Arduinoにプログラムを書き込もうとするとエラーがでたので、書き込むときは外すようにした。 理由はわからん。(追記: RSTピンをGNDに落とすというのはArduinoボードに実装されているリセットボタンを押したままにするのと同義なので、その間はArduinoが全く停止してしまうためであるとのこと。) ファームウェアアップデート UpdateアイコンからProduct family/Function set/Versionを選択し、Updateをクリック。 設定 設定を変えたら画面上部のWriteからまとめて書き込むことができる。 親機 パラメータ 略名 値 PAN ID ID 任意の値 Cordinator Enable CE Enabled[1] Destination Address High DH 子機のXBeeモジュールのMacアドレス上位4オクテット Destination Address Low DL 子機のXBeeモジュールのMacアドレス下位4オクテット API Enable AP API enabled[1] 子機 パラメータ 略名 値 PAN ID ID 親機と同じPAN ID Cordinator Enable CE Disabled[0] Destination Address High DH 親機のXBeeモジュールのMacアドレス上位4オクテット Destination Address Low DL 親機のXBeeモジュールのMacアドレス下位4オクテット API Enable AP API enabled[1] Arduinoにプログラムを書き込む XBeeライブラリをインストール Arduino IDEの「スケッチ=>ライブラリをインクルード=>ライブラリを管理」でxbeeと検索してインストール。 #include <XBee.h> // Initialize XBee ZB client XBee xbee = XBee(); // Payload byte array uint8_t payload[16]; // Send to coordinator XBeeAddress64 addr64 = XBeeAddress64(0, 0); void set_int_to_payload(int value, int index) { uint8_t *value_array; value_array = reinterpret_cast<uint8_t*>(&value); for(int i=0; i<sizeof(value); i++){ payload[i+index] = value_array[i]; } } void setup() { Serial.begin(9600); xbee.setSerial(Serial); } void loop() { delay(3000); int tid = 13; // 端末ID(テキトー) // 今回はA0から光抵抗センサの値を読み取った int cds = analogRead(0); set_int_to_payload(tid, 0); set_int_to_payload(cds, 8); // Create request for XBee ZB ZBTxRequest zbTx = ZBTxRequest(addr64, payload, sizeof(payload)); xbee.send(zbTx); } SERIAL SELECTの切り替え 書き込み終わったら、PCからUSBを外してワイヤレスシールドのスイッチをMicroの方に切り替える。 Raspberry Piのコーディング 受信用コードを記述 公式ドキュメントを参考にして、受信用コードを書く。 receive.py # coding: utf-8 from xbee import ZigBee import serial import struct import time def parseData(data): data = struct.unpack('qq', data['rf_data']) return data if __name__ == '__main__': # Setup ZigBee PORT = '/dev/ttyUSB0' BAUD_RATE = 9600 myDevice = serial.Serial(PORT, BAUD_RATE) xbee = ZigBee(myDevice) # Continuously read and print packets print(">> Waiting for data...") while True: try: data = parseData(xbee.wait_read_frame()) tid = data[0] cds = data[1] print(tid, cds) except KeyboardInterrupt: break myDevice.close() 実行 作業用PCに接続しているモジュールをRaspberryPiに差し替えて、先程のコードを実行する。 $ python receive.py >> Waiting for data... (13, 404) (13, 404) (13, 407) (13, 403) (13, 406) (13, 404) . . . 上記のように、3秒ごとにデータが送られてくれば成功。 まとめ 以下の手順を行うことで、端末間の通信を行うことができた。 各端末(RaspberryPi, Arduino, XBee USBインターフェースボード)の準備、設定 XCTUでのXBeeモジュール(親機, 子機)の接続、設定 Arduino, RaspberryPiでのコーディング 今まで無線接続といえばWifiとBluetoothしか扱ったことがなかったが、 ZigBeeも1日足らずで通信の成功まで持っていけた。