なにをやりたかったのか
- golangでつくってるApplicationにAPMを仕込みたかった
- 環境はECSで動かしているので、親和性を考えてX-Rayを使うことを選んだ
どんな感じに作った?
-
パッケージ管理は mod を利用
-
x-rayは amazon/aws-xray-daemon を利用
-
ECSでhostの指定は AWS_XRAY_DAEMON_ADDRESS を指定
-
具体的なコードはこんな感じ
main.go
package main
import (
"github.com/gin-gonic/gin"
apm "project/apm"
)
// GinRouter is router that API method router.
func main() {
router := gin.Default()
// helth check
router.GET("/helth", func(c *gin.Context) {
apm.TraceSeg(c, "/helth")
c.JSON(200, gin.H{
"message": "helth check ok",
})
})
// other URI
// ...
router.Run(":8080")
}
apm.go
package main
import (
"context"
"github.com/aws/aws-xray-sdk-go/xray"
_ "github.com/aws/aws-xray-sdk-go/plugins/ecs"
)
func TraceSeg(c context.Context, service string) (*context.Context) {
ctx, seg := xray.BeginSegment(c, service)
seg.Close(nil)
return &ctx
}
func TraceSubSeg(c context.Context, service string) (*context.Context) {
ctx, subSeg := xray.BeginSubsegment(c, service)
subSeg.Close(nil)
return &ctx
}
task_difinition
version: '2'
services:
api:
image: xxxxx:${CI_BUILD_REF}
mem_limit: xxxxMB
cpu_shares: xxxx
ports:
- "0:8080"
links:
- xray-daemon
environment:
AWS_REGION: xxxx
AWS_XRAY_DAEMON_ADDRESS: "xray-daemon:2000"
SERVICE: xxxxx
logging:
driver: "awslogs"
options:
awslogs-region: "ap-northeast-1"
awslogs-group: "xxxxx"
awslogs-create-group: "true"
xray-daemon:
image: amazon/aws-xray-daemon
hostname: xray-deamon
mem_limit: xxxxB
cpu_shares: xx
ports:
- "2000:2000/udp"
environment:
AWS_REGION: xxxxx
どうなったか
-
localでテストしたとき →動いた
-
docker on EC2 →動いた
-
ECS →動かなかった
[Trace] Beginning segment named /helth [Trace] Closing segment named /helth [Error] write udp 127.0.0.1:52419->127.0.0.1:2000: write: connection refused
※ ENVやprocessには変数は受け渡されていた
# EC2で動いているdocker processに変数が渡されているかの確認
[ec2-user@ip-172-28-22-74 ~]$ sudo sed "s/\x0/\n/g" /proc/5351/environ
~
AWS_XRAY_DAEMON_ADDRESS=xray-daemon:2000
~
# run している containerから変数は見れるか
root@559381b52506:/# env
GOLANG_VERSION=1.12.1
~
AWS_XRAY_DAEMON_ADDRESS=xray-daemon:2000
~
なぜ動かない?
AWSに問い合わせをしたところ、 AWS X-Ray SDK for Go の 1.0.0-rc.8 より古いバージョンでは同様の事象が発生しえる とのこと
確認してみる
modを利用してバージョン管理しているので、modの中身を見てみる
$ cat go.mod | grep xray
github.com/aws/aws-xray-sdk-go v0.9.4
→ 「v0.9.4」を利用している
go get -u でバージョンアップしてみる
$ go clean -cache
$ go get -u github.com/aws/aws-xray-sdk-go
↓
$ go build
$ grep xray go.mod
github.com/aws/aws-xray-sdk-go v0.9.4
→ 変わらない...
git commitを確認する
$ cd $GOPATH/src/github.com/aws/aws-xray-sdk-go
$ git log -1
commit 5ffa743a8b8db87a9d4449c2f63fe95a4a53a8c5 (HEAD -> master, origin/master, origin/HEAD)
Author: Christopher Radek <cjradek@gmail.com>
Date: Tue Apr 9 13:59:20 2019 -0700
upkeep: adds -race to travis test scripts (#104)

何故modで「1.0.0-rc.x」が指定されないのか
A. マイナーバージョンだから
マイナーバージョンを利用する場合は直接modを編集してあげる必要がある模様
[before]
$ cat go.mod | grep xray
github.com/aws/aws-xray-sdk-go v0.9.4
[after]
$ cat go.mod | grep xray
github.com/aws/aws-xray-sdk-go v1.0.0-rc.11
# こんな感じに動く
$ go build
go: finding github.com/aws/aws-xray-sdk-go v1.0.0-rc.11
go: finding github.com/aws/aws-sdk-go v1.17.12
go: finding github.com/stretchr/testify v1.1.4
go: finding github.com/davecgh/go-spew v0.0.0-20160907170601-6d212800a42e
go: finding github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0
go: finding github.com/DATA-DOG/go-sqlmock v1.2.0
go: finding golang.org/x/text v0.0.0-20190306152657-5d731a35f486
go: finding golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95
go: finding golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e
go: downloading github.com/aws/aws-xray-sdk-go v1.0.0-rc.11
go: extracting github.com/aws/aws-xray-sdk-go v1.0.0-rc.11
まとめ
- xray-sdk-goを利用したAPMをECS上に乗せるときはバージョンに気をつけよう
- modを利用している場合は手動でマイナーバージョンに切り替えよう