golangでFargate運用を想定したDockerfile作成（Alpineベース）

# 概要
個人アプリにて、Fargateでのコンテナ運用を行うため、golang環境のDockerfileを作成しました。

当環境の特徴として、

- DockerイメージをAlpine Linuxベースを使用し、軽量化。
- マルチステージビルド機能を使用し、ビルド環境でgolangアプリやその他バイナリを作成し、軽量化。
- Fargateで運用するコンテナの中に入ってシェル操作するため、ssm-agentを導入。

です。


# 各種ファイル

### Dockerfile

~~~dockerfile
FROM golang:1.14.4-alpine3.12 as builder

ARG SSM_AGENT_VERSION=2.3.1205.0

RUN apk add --no-cache \
         'make~=4.3-r0' \
         'git~=2.26.2-r0' \
         'gcc~=9.3.0-r2' \
         'libc-dev~=0.7.2-r3' \
         'bash~=5.0.17-r0'

RUN wget -q https://github.com/aws/amazon-ssm-agent/archive/${SSM_AGENT_VERSION}.tar.gz && \
    mkdir -p /go/src/github.com && \
    tar xzf ${SSM_AGENT_VERSION}.tar.gz && \
    mv amazon-ssm-agent-${SSM_AGENT_VERSION} /go/src/github.com/amazon-ssm-agent && \
    echo ${SSM_AGENT_VERSION} > /go/src/github.com/amazon-ssm-agent/VERSION

WORKDIR /go/src/github.com/amazon-ssm-agent

RUN gofmt -w agent && make checkstyle || ./Tools/bin/goimports -w agent && \
    make build-linux

WORKDIR /go/src/server

COPY go.mod go.sum ./

RUN go mod download

RUN go get bitbucket.org/liamstask/goose/cmd/goose

COPY . .

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/server

FROM alpine:3.12 as prod

RUN apk add --no-cache \
      'aws-cli~=1.18.55-r0' \
      'sudo~=1.9.0-r0' \
      'mysql-client~=10.4.15-r0'

RUN adduser -D ssm-user && \
    echo "Set disable_coredump false" >> /etc/sudo.conf && \
    echo "ssm-user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/ssm-agent-users && \
    mkdir -p /etc/amazon/ssm

COPY --from=builder /go/src/github.com/amazon-ssm-agent/bin/linux_amd64/ /usr/bin
COPY --from=builder /go/src/github.com/amazon-ssm-agent/bin/amazon-ssm-agent.json.template /etc/amazon/ssm/amazon-ssm-agent.json
COPY --from=builder /go/src/github.com/amazon-ssm-agent/bin/seelog_unix.xml /etc/amazon/ssm/seelog.xml
COPY --from=builder /go/bin/server /go/bin/server
COPY --from=builder /go/bin/goose /go/bin/goose

RUN mkdir -p /go/bin/db
COPY ./db/dbconf.yml /go/bin/db/dbconf.yml
COPY ./db/migrations /go/bin/db/migrations

COPY ./db/mysql/init /docker-entrypoint-initdb.d

EXPOSE 8080

COPY ./aws/docker-entrypoint.sh /

CMD ["sh", "/docker-entrypoint.sh"]
~~~

### docker-entrypoint.sh

~~~sh
#!/bin/sh

set -e

amazon-ssm-agent -register -code $SSM_ACTIVATE_CODE -id $SSM_ACTIVATE_ID -region "ap-northeast-1"
amazon-ssm-agent &

/go/bin/server
~~~

## 要点
### Alpineはssmエージェント未対応
~~~Dockerfile
※一部抜粋
RUN wget -q https://github.com/aws/amazon-ssm-agent/archive/${SSM_AGENT_VERSION}.tar.gz && \
    mkdir -p /go/src/github.com && \
    tar xzf ${SSM_AGENT_VERSION}.tar.gz && \
    mv amazon-ssm-agent-${SSM_AGENT_VERSION} /go/src/github.com/amazon-ssm-agent && \
    echo ${SSM_AGENT_VERSION} > /go/src/github.com/amazon-ssm-agent/VERSION
~~~
Alpineではssmエージェントのパッケージがないので、ソースから拾いビルドして設置する必要があります。
https://github.com/aws/amazon-ssm-agent/issues/140

### ECRスキャンはscratchベース非対応
~~~dockerfile
FROM alpine:3.12 as prod
~~~
Dockerイメージ軽量化のため、最初はscratchベースで実行環境を構築しようとしましたが、ECRはイメージスキャン未対応のことなので、実行環境もAlpineを採用しました。
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/image-scanning-troubleshooting.html

### マイグレーションツールのgooseを採用
~~~dockerfile
RUN mkdir -p /go/bin/db
COPY ./db/dbconf.yml /go/bin/db/dbconf.yml
COPY ./db/migrations /go/bin/db/migrations
~~~
開発環境でもお世話になった`goose`を本番環境でも採用しました。ビルド環境でバイナリ作成、実行環境にバイナリと必要なファイルをコピーして準備完了。ファイルの置き場所によって設定ファイル`dbconf.yml`が読み込まれなくなってしまうので、注意が必要です。

### シェルスプリクトで起動コマンド設定
~~~sh
amazon-ssm-agent -register -code $SSM_ACTIVATE_CODE -id $SSM_ACTIVATE_ID -region "ap-northeast-1"
amazon-ssm-agent &
~~~
コンテナ内で実行するため、シェルスクリプトでコマンドを投げてあげます。この時アクチベーションキーも設定しないといけないので、コンテナ内の環境変数に設定します。

## 参考資料
[Go 1.12 の開発環境と本番環境の Dockerfile を考える](https://qiita.com/takasp/items/c6288d4836e79801bb19)
[Alpine Linux に amazon-ssm-agent をインストールする](https://enomotodev.hatenablog.com/entry/2020/05/23/160731)
[AWS Fargateで動かしてるコンテナの中に入る方法](https://qiita.com/f96q/items/50ecf101b923e1cf9146)