IoTアプリケーションを作る際に用いる言語はPythonNode.jsに限りません。よりリソースの消費が小さいCやC++を使うこともあるでしょう。そういったコンパイルを伴う言語の場合、コンパイルした後の実行ファイルをRaspberry Piに送る必要があります。そうでないと毎回Raspberry Pi上でコンパイルしなければならず、デプロイに時間がかかってしまいます。

そこで今回はクロスプラットフォームで動作するGoを使い、CircleCI上でコンパイルして、そのバイナリファイルをRaspbery Piに届ける方法を解説します。

プロジェクトについて

今回はテスト的なものなので、テストは最低限です。まず example.go を以下のように作ります。

package main

import (
    "errors"
)

func example(code string) (int,error) {
  if code == "isaax" {
       return 1,nil
  }

  return 0,errors.New("code must be isaax")
}

そして example_test.go を作ります。

package main

import (
    "testing"
)

func TestExampleSuccess(t *testing.T) {
    result, err := example("isaax")
    if err != nil {
        t.Fatalf("failed test %#v", err)
    }
    if result != 1 {
        t.Fatal("failed test")
    }
}

func TestExampleFailed(t *testing.T) {
    result, err := example("xshell")
    if err == nil {
        t.Fatal("failed test")
    }
    if result != 0 {
        t.Fatal("failed test")
    }
}

これで go test でエラーが出ないことを確認します。

$ go test
PASS
ok  	_/path/to/isaax-hello-world	0.008s

さらに main.go を作っておきます。今回は単純に5秒ごとにメッセージを出すだけです。

package main

import "fmt"
import "time"

func main() {
  for {
      fmt.Println("Hello isaax. I'm Go!")
      time.Sleep(5 * time.Second)
  }
}

CircleCIについて

CircleCIは名前の通りCIサーバを提供します。Dockerなどを使ってテスト環境を作れますので、幅広い開発環境に対応しています。GitHubとの連携も容易で、GitHubプロジェクトを指定するだけです。そうすればプルリクエストを作成すれば自動的にテストを開始してくれます。

CircleCI用の設定ファイルは .circleci/config.yml に作成します。設定内容についてはコメントを参照してください。最終的に main というバイナリファイルを生成します。YOUR_NAMEREPO_NAMEはあなたのものと書き換えてください。

# Go CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-go/ for more details
#
version: 2
jobs:
  build:
    # Dockerイメージは公式提供のものです
    docker:
      - image: circleci/golang:1.9
    # GOPATHを設定します
    environment:
      - GOPATH: /home/circleci/go
    # 実行する場所です
    working_directory: /go/src/github.com/YOUR_NAME/REPO_NAME
    # パスを設定して、テストを実行します
    steps:
      - run: echo 'export PATH=${GOPATH}/bin/:${PATH}' >> $BASH_ENV
      - checkout
      - run: go test
  deploy:
    docker:
      - image: circleci/golang:1.9
    environment:
      - GOPATH: /home/circleci/go
    working_directory: /go/src/github.com/YOUR_NAME/REPO_NAME
    # デプロイの手順は以下の通りです
    # 1. 環境変数を設定します
    # 2. ソースコードをチェックアウトします
    # 3. Raspberry Piのバイナリをビルドします
    # 4. ghrを使ってリリースをアップロードします
    steps:
      - run: echo 'export PATH=${GOPATH}/bin/:${PATH}' >> $BASH_ENV
      - checkout
      - run: env GOOS=linux GOARCH=arm GOARM=5 go build -o dist/main
      - run: go get github.com/tcnksm/ghr
      - run: ghr -t ${GITHUB_TOKEN} -u ${USER_NAME} -r ${REPO_NAME} --replace $(cat VERSION) dist/

workflows:
  version: 2
  build_and_deploy:
    jobs:
      - build
      - deploy:
          requires:
            - build 
          filters:
            branches:
              only: master

ポイントはRaspberry Pi向けのバイナリをビルドすることです。これは env GOOS=linux GOARCH=arm GOARM=5 で指定できます。そして、そのビルドしたバイナリを ghr というソフトウェアを使ってGitHubのリリースにアップロードします。また、フィルターを使ってmasterブランチが更新された時だけバイナリを生成するようにしています。

ghrを使う時にはGitHubのトークン、ユーザ名、リポジトリ名を指定します。それぞれCircleCIの環境変数として設定します。リリース先は VERSION というファイルの中に記述しておきます。例えば 0.0.1 といったバージョン番号をいれておきます。

isaaxの設定

isaax側では、スクリプト機能を使います。例えばVERSIONを0.0.1とした場合、そのファイルは https://github.com/YOUR_NAME/REPO_NAME/releases/download/0.0.1/main といったURLで取得できます。

まずpre-update(更新前に呼ばれるスクリプト)に対して以下のように設定します。

#!/bin/sh
rm main

さらにpost-update(更新完了時に呼ばれるスクリプト)に対して以下のように設定します。こちらはダウンロードに時間がかかる可能性があるのでタイムアウトを120秒としています。YOUR_NAME、REPO_NAMEはあなたのものと書き換えてください。

#!/bin/sh
VERSION=`cat VERSION`
wget https://github.com/YOUR_NAME/REPO_NAME/releases/download/$VERSION/main
chmod +x main

mainという実行ファイルを先に削除しておくことで、isaaxがプロジェクトを更新した際に残っている古いmainを実行してしまうのを防止します。リポジトリには main というファイルはありませんので、最初はエラーになるでしょう。しかしpost-updateが実行されてmainが存在する状態になればアプリケーションが動き始めます。

isaax.jsonは以下のような内容です。

{
  "name": "hello-isaax",
  "version": "",
  "description": "Go - raspberry-pi",
  "main": "main",
  "author": "",
  "license": "",
  "language":"Go",
  "scripts": {
     "start": "./main"
    },
   "dependency": null
}

バイナリファイルなのでRaspberry Pi自体にはGo環境が不要です。

運用時のコツ

VERSIONというファイルは必ず更新するようにします。このファイルはCircleCI、isaax両方で使われる大事なファイルです。このファイルを使って、どのリリース情報のバイナリをダウンロードすれば良いかが分かります。

まとめ

実行ファイルを配布する方法の場合、実行環境の構築が不要なのが大きなメリットです。特にGoは環境を指定するだけでそれに合わせたバイナリを生成してくれるので便利です。isaaxと組み合わせることで、生成されたバイナリを自動でデプロイできます。ぜひあなたのIoTプロジェクトでも活かしてください。

Isaax IoT


Leave a Reply

Your email address will not be published. Required fields are marked *