Oredemo understand series -Build and deploy Serverless Framework Golang with Docker container

俺です。

PCにシコシコ道具を整える人生が辛くなりました。
PCにぶちこむのはDockerとエディタだけでいいじゃないかと。
ビルドとデプロイといった役割はDockerコンテナに任せてしまえばいいじゃないかということで、
今回はじめてServerless Frameworkを用いたSlack appをDeployした経験を、
1億年と二千年前から何度目煎じなネタですがメモを残しておこうと思います。

# きっかけ

@T_Sumisaki にslackでEC2止めたりアゲたりする[slack app](https://github.com/t-sumisaki/awscli-commands)つくってもらい、
いざ自分のAWSのアカウントへビルド+デプロイすっかと思ったけどオラのmacOSにGolangとServerlessが入ってなかったぞ。
これからセットアップとかオラわくわくすっぞ!

ああめんどくさ。


# ビルドとデプロイをコンテナに任せる構成

PCにDockerが入ってたのでこのようにしました。

- ローカルPCのディレクトリにソースコードをgithubからcloneしてくる
- ソースコードは自分の好きなエディタで弄る
- Golangのコードビルドは[Golang1.XなDockerコンテナ](https://hub.docker.com/_/golang/)に任せる
- ServerlesアプリケーションのDeployは[serverlessなDockerコンテナ](https://hub.docker.com/r/softinstigate/serverless/)に任せる
 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/42755/e050573b-296f-e7fb-50da-47c3c2f702df.png)

# ローカルPCとコンテナのデータ共有

ローカルPCにgit cloneしたrepositoryディレクトリはDockerの[Volume](https://docs.docker.com/storage/volumes/)で共有します。
Dockerコンテナ上でビルド実行/Serverlessアプリケーションのデプロイを実現できます。

## Dockerコンテナを使ったGolangのビルド

- `-v`でローカルPCのソースコードディレクトリをDockerコンテナの `/go/src/app` と共有する
- `--rm`でDockerコンテナの実行後にイメージを削除する

```
cd <repository>
docker run --rm -v "$PWD":/go/src/app -w /go/src/app awscli-command:latest make dep-ensure
```

## Dockerコンテナを使ったServerlessアプリケーションのデプロイ

- [Dockerhub](https://hub.docker.com/r/softinstigate/serverless/)で公開されているserverlessコンテナを使います
- serverlessコンテナ起動時にローカルPCの`~/.aws/credentials`を`-v`で共有する
- serverlessコンテナ起動時にローカルPCのソースコードディレクトリを`-v`で共有する
- デプロイ対象のAWSのアカウントを`~/.aws/credentials`のエントリで指定するように`AWS_PROFILE`と`AWS_DEFAULT_REGION`を`-e`オプションで指定する
- `-rm`でDockerコンテナの実行後にイメージを削除する

※ローカルPCかつ`docker save`でコンテナをexportすることはないものの`~/.aws/credentials`を共有するのがこえー方は`saml2aws`をserverlessコンテナに入れ込み、一時的なトークンを渡しちゃえばいいと思います。

```
cd <repository>
docker run --rm -v ${HOME}/.aws/credentials:/root/.aws/credentials -v ${PWD}:/go/src/app \
-e AWS_PROFILE=${aws_profile} -e AWS_DEFAULT_REGION=${region} \
-w /go/src/app \
softinstigate/serverless sls deploy
```

# Dockerでwrappingしたことでの引数長い問題をどうするか

DockerコンテナでGolangのビルドとServerless Frameworkのデプロイを実現できるようになりますが、
引数が長くて腱鞘炎になる問題が残ります。
これら何度も繰り返す内容はMakefileで解決します。

引数長くて辛い問題は例えば、
Golang用コンテナのビルドだったり...

```
docker build -f Dockerfile . -t awscli-command:latest
```

depの依存関係解決だったり..

```
docker run --rm -v "$PWD":/go/src/app -w /go/src/app awscli-command:latest make dep-ensure
```

Golangのビルドだったり...

```
docker run --rm -v "$PWD":/go/src/app -w /go/src/app awscli-command:latest make build-golang
```

Serverlessのdeployだったり...

```
docker run --rm -v ${HOME}/.aws/credentials:/root/.aws/credentials -v ${PWD}:/go/src/app \
-e AWS_PROFILE=${aws_profile} -e AWS_DEFAULT_REGION=${region} \
-w /go/src/app \
softinstigate/serverless sls deploy
```

よく使うコマンドはshell historyではなくMakefileに保管しておきます。

- Makefile

```
aws_profile = default
region = us-east-1

build-docker-golang:
	docker build -f Dockerfile . -t awscli-command:latest
dep-ensure:
	dep ensure
build-golang:
	go get github.com/aws/aws-lambda-go/lambda
	env GOOS=linux go build -ldflags="-s -w" -o bin/igniter handler/igniter/main.go
	env GOOS=linux go build -ldflags="-s -w" -o bin/interaction handler/interaction/main.go

run-dep-ensure:
	docker run --rm -v "$PWD":/go/src/app -w /go/src/app awscli-command:latest make dep-ensure

run-build:
ifeq ($(OS),Windows_NT)
# for Windows(ToDo: get folder path)
	docker run --rm -v "$PWD":/go/src/app -w /go/src/app awscli-command:latest make build-golang
else
	docker run --rm -v "$PWD":/go/src/app -w /go/src/app awscli-command:latest make build-golang
endif

sls-deploy: 
	docker run --rm -v ${HOME}/.aws:/root/.aws -v ${PWD}:/go/src/app \
	-e AWS_PROFILE=${aws_profile} -e AWS_DEFAULT_REGION=${region} \
	-w /go/src/app \
	softinstigate/serverless sls deploy
```


- Golangのビルド

```
$ make build-docker-golang
$ make run-dep-ensure
$ make run-build
```

- Serverlessアプリケーションのデプロイ

```
$ make sls-deploy aws_profile=MYAWSPROFILE region=ap-northeast-1
```

これでDockerとエディタが入ってるPCならServerless Lambda Golangな環境のビルドとデプロイを実現できるようになりました。

今更ながら便利ですねーコンテナ。

ということで[awscliなslack app](https://github.com/t-sumisaki/awscli-commands)のUIいじるぞー。

`finish`