HEW2018 モダンなWebサービスの作成（インフラ編）

# 自己紹介

じゅんじゅんと言うニックネームで、関西を拠点に活動しているフロントエンドエンジニアです。

HAL大阪3回生です。（2018/03/11現在）

イベントや、勉強会に参加してるので是非お会いした際はお声掛けください！

# HEW2018 モダンなWebサービスの作成（インフラ編）とは

これは僕の学校のイベントの発表をQiitaの記事としてあげておくためのエントリーです。

気になる方は[こちら](https://qiita.com/konojunya/items/728357afcab505441724)をご覧ください。

インフラ以外には

- [クライアント編](https://qiita.com/konojunya/items/2a0315e2f2bce236f91a)
- [サーバーサイド編](https://qiita.com/konojunya/items/3dee37d1e9f45ccf474c)

があります。

## 環境

今回はAmazon Web Serviceの**ECS（Elastic Container Service）**と**RDS（Relational Database Service）**を使っていて、**Docker Container**をECSへ**CircleCI**からオートデプロイしています。

以下、軽く用語の説明になります。

### ECS

>Amazon Elastic Container Service (ECS) は、非常にスケーラブルかつ高性能なコンテナ管理サービスで、Docker コンテナに対応しており、Amazon EC2 インスタンスのマネージドクラスターでアプリケーションを簡単に実行できます。

わかりやすい解説: [Amazon EC2 Container Service(ECS)の概念整理](https://qiita.com/NewGyu/items/9597ed2eda763bd504d7)

### RDS

>Amazon Relational Database Service (Amazon RDS) を使用すると、クラウド内でリレーショナルデータベースを簡単に設定、運用、およびスケールできます。ハードウェアのプロビジョニング、データベースのセットアップ、パッチ適用、バックアップなどの時間がかかる管理タスクを自動化しながら、コスト効率とサイズ変更可能なキャパシティーを提供します。

わかりやすい解説: [weblio/Amazon RDS](https://www.weblio.jp/content/Amazon+RDS)

### Docker

>「Docker（ドッカー）」とは、非常に軽量なコンテナ型のアプリケーション実行環境である。dotCloud社（現Docker社）が開発し、2013年にオープンソースのプロジェクトとして公開された。ソフトウェアの高速な配布・実行や容易なイメージのカスタマイズ、導入運用の手軽さ、豊富なプレビルドイメージの提供などの理由により、当初はソフトウェアの開発やテスト段階における利用が多かったが、現在ではパブリッククラウドからオンプレミスシステムまで、さまざまなシーンで急速に普及しつつある。

わかりやすい解説: [Dockerについて基本から最近追加された機能までまとめ](https://qiita.com/yuki_ycino/items/b94ae2bf7d78685cd6f5)

### CircleCI

>Create custom environments, apply Workflows for control over your build pipeline, enjoy flexible resource allocation, and more.

わかりやすい解説: [CircleCIで出来るコト](https://qiita.com/noboru_i/items/7d300eb63ae667bf8dc2)

### オートデプロイ

今回はCircleCIを使って、GitHubのmasterブランチにpushした時にコンテナをアップロードし、ECSに通知することを意味するとします！

# 動画にまとめました

手順を全てスクショとってやっているとかなり記事の画面を占領してしまうのでYouTubeにアップロードしましたので、そちらをご覧ください

[ECS + RDSでのサービス作り](https://youtu.be/yzQ-IAhhQ0Q)

## 開発

今回はインフラなので、

- circleci
- Dockerfile
- Makefile

の説明をしていきます。

### Dockerfile

まず**Dockerfile**

```docker:Dockerfile
FROM alpine:3.6
WORKDIR /root
ENV GO_ENV production

RUN set -x \
  && apk upgrade --no-cache \
  && apk --update add tzdata \
  && cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
  && apk del tzdata \
  && rm -rf /var/cache/apk/*

RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*

ADD ./cmd/main .
ADD ./public ./public
ADD ./view ./view
ADD ./config.yml ./config.yml
ADD ./cmd/migrate .
ADD ./cmd/seed .

EXPOSE 8000

# Run it
ENTRYPOINT ["./main"]
```

1つずつ説明していきます。

```docker
FROM alpine:3.6
```

OSは軽量な`alpine`を使います

```docker
ENV GO_ENV production
```

これでDockerの環境変数を設定します。

今回は、`production`モードで動いてほしいので`production`を指定します。

```docker
ADD ./cmd/main .
ADD ./public ./public
ADD ./view ./view
ADD ./config.yml ./config.yml
ADD ./cmd/migrate .
ADD ./cmd/seed .
```

ここで、必要なファイルをDockerに移します。

```docker
EXPOSE 8000

# Run it
ENTRYPOINT ["./main"]
```

ここで、8000番ポートを開けておく設定をします。

AWSのECSのときのコンテナのポートと揃えてください。

goはビルドしているので`main`をたたけばサーバーが立ち上がるので、`ENTRYPOINT`に`./main`を指定します。

これで、`docker run`されたときに、`./main`を叩いてくれてサーバーが立ち上がります。

### Makefile

```make
create:
	cp config.yml.template config.yml
	
migrate:
	go run migration/main.go

seed: migrate
	go run seed/main.go

go/build:
	make -f .circleci/ci.mk go/build

docker/build: go/build
	make -f .circleci/ci.mk docker/build

docker/push: go/build
	env NODE_ENV=production npm run build
	make -f .circleci/ci.mk docker/build
	make -f .circleci/ci.mk login
	make -f .circleci/ci.mk docker/push
```

makefileは基本的にコマンドなどを書いておきます。

今回ここのmakefileはローカルで触る場合を基本意識していてCIから触る方は`.circleci/ci.mk`に書いています。

なので、それを呼ぶ形にしています。

### CircleCI

```makefile
# ECS
ECS_ID := 871669327434
AWS_REGION := ap-northeast-1
APP := hew2018
export AWS_REGION
export AWS_DEFAULT_REGION=$(AWS_REGION)
DOCKER_IMAGE    := $(ECS_ID).dkr.ecr.$(AWS_REGION).amazonaws.com/$(APP):latest

login:
	aws configure set region $(AWS_REGION)
	aws configure set aws_access_key_id $$AWS_ACCESS_KEY_ID
	aws configure set aws_secret_access_key $$AWS_SECRET_ACCESS_KEY
	$$(aws ecr get-login --no-include-email --registry-ids $(ECS_ID) --region $(AWS_REGION))

go/build:
	make create
	env GOOS=linux env GOARCH=amd64 env CGO_ENABLED=0 go build -o ./cmd/main main.go
	env GOOS=linux env GOARCH=amd64 env CGO_ENABLED=0 go build -o ./cmd/migrate migration/main.go
	env GOOS=linux env GOARCH=amd64 env CGO_ENABLED=0 go build -o ./cmd/seed seed/main.go

docker/build:
	docker build -t $(DOCKER_IMAGE) --build-arg GO_ENV=production .

docker/push:
	docker push $(DOCKER_IMAGE)

docker/deploy:
	.circleci/ecs-deploy --enable-rollback --timeout 300 --cluster $(APP) --service-name $(APP) --image $(DOCKER_IMAGE)
```

基本のデプロイの流れとして、

1. goをビルドする
2. dockerをビルドする
3. docker imageをpushする
4. ecs-deployでdeploy作業をする

になっています。

基本変える場所としては

```make
ECS_ID := 871669327434
AWS_REGION := ap-northeast-1
APP := hew2018
```

この3つだと思います。

ECS_IDはECSでリポジトリを作った際にかえってきたidです。
AWS_REGIONはAWSのリージョンを入力してください。
APPは、アプリケーション名を入力します。

この情報は全てリポジトリを作ったときに表示される

**`871669327434`.dkr.ecr.`ap-northeast-1`.amazonaws.com/`hew2018`:latest**

みたいなところから取得できます。

### .circleci/config.yml

ここでcircleciの設定をかきます。

まずCircleCIで、GitHubのリポジトリを紐付けておくのを忘れないでください

あと、AWSの`IAM`をつくってそのユーザーの`アクセスキー`をCircleCIの設定のほうにかいておいてください。

```yaml
version: 2
jobs:

  test:
    working_directory: /go/src/github.com/konojunya/HEW2018
    docker:
      - image: makki0205/deploy
    steps:
      - checkout
      - run:
         name: npm install
         command: npm install
      - run:
          name: component build
          command: env NODE_ENV=production npm run build
      - run:
          name: go build
          command: make -f .circleci/ci.mk go/build
      - save_cache:
          key: build-{{ epoch }}
          paths:
            - .
    
  deploy:
    working_directory: /go/src/github.com/konojunya/HEW2018
    docker:
      - image: makki0205/deploy
    steps:
      - setup_remote_docker:
          reusable: true
      - restore_cache:
          keys:
            - build
      - run:
          name: docker build
          command: make -f .circleci/ci.mk docker/build
      - run:
          name: aws login
          command: make -f .circleci/ci.mk login
      - run:
          name: docker push
          command: make -f .circleci/ci.mk docker/push
      - run:
          name: deploy
          command: make -f .circleci/ci.mk docker/deploy

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

CircleCIはバージョン2を使うので2の設定になっています。

流れは`workflow`のままです。

これでオートデプロイの環境を構築できました！

オートデプロイができるようになっているとプロダクトのコードに集中できるので少し設定が多くて難しいですがやっておいたほうがよいでしょう！

注意点として、

CircleCIの中でDockerを使う時は

```yaml
- setup_remote_docker:
          reusable: true
```

これを入れておかないと、使えないです。

# あとがき

Twitterしています！ぜひフォローください。 [@konojunya](https://twitter.com/konojunya)

ソースコードは [konojunya/HEW2018](https://github.com/konojunya/HEW2018) にあります！