Amazon Linux に GoLang (1.5) をインストール & Gin、MongoDB (3.2) を導入し、APIサーバ を10分で作る

  • 13
    Like
  • 0
    Comment
More than 1 year has passed since last update.

今回は、AWS EC2インスタンスの立ち上げから、GoLang、Gin (Goのフレームワーク)、MongoDB、mgo (MongoDBを操作するライブラリ) を入れて、APIサーバを即席で構築する手順を整理しました。

バージョン

今回の環境は以下のバージョンで構築しました。

Version
OS Amazon Linux AMI 2016.03.1 (ami-f80e0596)
Go 1.5.3
MongoDB 3.2.6

AWS EC2 で Amazon Linuxインスタンスを作成

使用AMI: Amazon Linux AMI 2016.03.1 (HVM), SSD Volume Type - ami-29160d47

yumのアップデート

sudo yum update

GoLang のインストール

sudo yum install golang

GOPATHの設定

sudo vim ~/.bash_profile
~/.bash_profile
#configuration of golang
export GOPATH=$HOME/.go
export PATH=$HOME/.go/bin:$PATH

設定を反映

source ~/.bash_profile

GoLang の バージョンを確認

go version
go version go1.5.3 linux/amd64

Gin のインストール

go get github.com/gin-gonic/gin

GOPATH の設定が反映されているのを確認

上記手順の通りに進めた場合、GOPATH は /home/ec2-user/.go/ になっているはずですので、
この下の /src/github.com/ に gin-tonic というディレクトリが作成されていればOKです。

cd /home/ec2-user/.go/src/github.com
ll

テストコードの実行

まずはこの Gin の公式↓に掲載されているサンプルコードを試してみます。
https://github.com/gin-gonic/gin#gin-web-framework

cd /home/ec2-user/.go/src
sudo mkdir test-project
sudo vim /home/ec2-user/.go/src/test-project/index.go
index.go
package main

import "github.com/gin-gonic/gin"

func main() {
    router := gin.Default()
    router.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    router.Run() // listen and server on 0.0.0.0:8080
}
cd /home/ec2-user/.go/src/test-project
go run index.go

動作確認

ブラウザからアクセスしてみます。
(※AWSのセキュリティグループのインバウンドに 8080 を追加するのをお忘れなく)

http://(IPアドレス):8080/ping

{"message":"pong"}

と表示されれば成功です。

MongoDB のインストール

MongoDB公式のインストールガイドを参考に、インストールを進めていきます。
https://docs.mongodb.com/manual/tutorial/install-mongodb-on-amazon/

リポジトリにMongoDBを追加

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

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 mongodb-org

バージョンを確認

mongo --version
MongoDB shell version: 3.2.6

起動

sudo service mongod start

自動起動の設定

sudo chkconfig mongod on

mgo を入れる

GoLang で mongodb を使える mgo というライブラリを入れます。
https://labix.org/mgo

go get gopkg.in/mgo.v2

公式のサンプルコードを少しだけ改変して、先ほど作成した index.go ファイルにコードを追加していきます。

cd /home/ec2-user/.go/src/test-project
sudo vim index.go
index.go
package main

import (
    "github.com/gin-gonic/gin"
    mgo "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

type Castle struct {
        Name string
        Address string
        Description string
}

func main() {
        session, err := mgo.Dial("localhost")
        if err != nil {
                panic(err)
        }
        defer session.Close()

        // Optional. Switch the session to a monotonic behavior.
        session.SetMode(mgo.Monotonic, true)

        //データを登録
        c := session.DB("test").C("castle")
        err = c.Insert(&Castle{"姫路城", "兵庫県", "日本初の世界文化遺産。 「白鷺城」の愛称で親しまれる美しい城。"},
                   &Castle{"大阪城", "大阪府", "豊臣秀吉が築城。豊臣氏滅亡後は徳川幕府によって再建された。"},
                   &Castle{"鶴ヶ城", "福島県", "戊辰の戦役において新政府軍の猛攻にも落ちなかった難攻不落の名城。"},
                   &Castle{"月山富田城", "島根県", "山陰・山陽十一州を手中に収めた尼子氏が本城とし山陰・山陽制覇の拠点とした城。"})
        if err != nil {
                panic(err)
        }

        //データを削除
        _, err = c.RemoveAll(bson.M{"name": "姫路城"})

        //データを検索
        result := Castle{}
        err = c.Find(bson.M{"name": "大阪城"}).One(&result)
        if err != nil {
                panic(err)
        }
        //ヒットした1件を出力
        router := gin.Default()
        router.GET("/index", func(c *gin.Context) {
            c.JSON(200, gin.H{
            "説明": result.Description,
            })
        })

        router.Run()
}

実行

go run index.go

動作確認

ブラウザからアクセスしてみます

http://(IPアドレス):8080/index

{"説明":"豊臣秀吉が築城。豊臣氏滅亡後は徳川幕府によって再建された。"}
と出力されれば成功です。

バックグランドで実行させておく

作成した go のコードをビルドしてバックグラウンドで実行させようと思います。

cd /home/ec2-user/.go/src/test-project
go build index.go

ビルド時に、もし↓のようなエラー
go install command-line-arguments: open index: permission denied
が出る場合は、ディレクトリごと権限を付与してから再度 go build を試してみましょう。

sudo chmod -R 777 /home/ec2-user/.go/src/test-project

ビルドが成功したらバックグラウンドで実行させます。
で、GoLangに限らず一般的な話ですが、リモート接続ツール (TeraTerm とか) でEC2インスタンスに接続していると、接続が切れたらコマンド実行が止まってしまいます。
ですので、nohup を使い、リモート接続を切っても止まらないようにします。

nohup go run index.go &

これでリモート接続ツールを閉じても go のコードは動き続けます。

動いている go のコードを停止させるときは kill を使います。
ps aux でどのプロセスかを確認し、そのPIDを kill しましょう。

ps aux
kill (該当のPID)

データ全件を出力する

上のコードでは検索結果を1件だけ返していますが、データ全件を取得したい場合は次のようにコードを修正します。

index.go(修正前)
//データを検索
result := Castle{}
err = c.Find(bson.M{"name": "大阪城"}).One(&result)
    if err != nil {
        panic(err)
    }
//ヒットした1件を出力
router := gin.Default()
router.GET("/index", func(c *gin.Context) {
    c.JSON(200, gin.H{
        "説明": result.Description,
    })
})
index.go(修正後)
//データを検索
var results []Castle
err =c.Find(bson.M{}).All(&results)
if err != nil {
    panic(err)
}

//全件出力
router := gin.Default()
router.GET("/index", func(c *gin.Context) {
    c.JSON(200, results)
})

この次にやりたいこと

8080番ポートで受けるのがなんとなく嫌なので 80番ポートで Listen させたいんですが、調べてみると root 権限で実行するとか Nginxを使うとか方法がいろいろあるようなので、また試行錯誤してみようかと思ってます。
ご参考:
http://qiita.com/sfujiwara/items/b312fbdd2660e43b6717
http://matope.hatenablog.com/entry/2014/09/28/031155