Djangoプロジェクトをデプロイするまでの練習　３回目　WebアプリケーションとCircleCIの準備

# ここでやること
ここでは、コンテナで動かすWebアプリケーションを作成し、アプリケーションのCIの設定までをおこなう。CIでは、テスト、Dockerイメージのビルド・イメージをECRへプッシュするところまで実施して準備を確認する。

イメージをビルド
`docker build -t djangoproject:ver1 .`

8000ポートでコンテナを起動
`docker run -itd --name djangoproject --mount type=bind,source="$(pwd)"/code/,target=/code/ djangoproject:ver1`

djangoプロジェクトをスタート
`docker exec djangoproject djang-admin startproject djangoproject /code/project`

helloappアプリをスタート
`docker exec djangoproject python3 /code/project/manage.py startapp helloapp /code/project/hello`


## 作業用Docker関係のファイル
この作業用Dockerというのは、主にTerraformによるAWSへの環境構築のために使用する。私の環境がWindowsなのでDockerを使用しているだけなので、必要が無ければあえて作成する必要はないかも。

Dockerfile

```Dockerfile
From python:3.7
ENV PYTHONUNBUFFERED 1
RUN apt-get update && apt-get install -y \
    vim
RUN mkdir /terraform
WORKDIR /terraform
RUN mkdir .aws
ADD .aws .aws
RUN pip install awscli
RUN wget https://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_linux_amd64.zip && \
    unzip ./terraform_0.12.24_linux_amd64.zip -d /usr/local/bin/
RUN cp -r .aws ~
```


イメージをビルド
`docker build -t work:ver1 .`

コンテナを起動
`docker run -itd --name work --mount type=bind,source="$(pwd)"/terraform/,target=/terraform/ work:ver1`


# GitHubの準備
githubにリポジトリを２つ作成（djangoproject用とterraform用）

途中、.gitignoreにterraformのプラグインが除外されておらず、100MB以上のファイルとしてはねられてしまいました。下記のコマンドで対応できました。参考にさせていただいた記事のリンクはこちら。
https://www.walbrix.com/jp/blog/2013-10-github-large-files.html

```
$ git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch でかいファイル.tar.gz' \
  --prune-empty --tag-name-filter cat -- --all
$ git commit --amend -CHEAD
$ git push
```

# CircleCIでのCIの設定
CircleCIでは、Djangoプロジェクトのビルドと、ビルドしたDockerイメージをECRにpushするまでを行う。

流れとしては、
1. Djangoプロジェクトの作成→GitHubへpush
2. CircleCIでCI実行→CircleCIからGitHubのプロジェクトがcheckoutされてDockerイメージがbuildされる
3. buildが終わったら、DockerイメージがECRにプッシュされる。
という感じです。

なので、以下の準備をしました。
- terraform用とDjangoプロジェクト用のGitリポジトリを作成
- terraformを使ったECRリポジトリの作成
- CircleCIがECRへDockerイメージをpushするためのIAMユーザー作成
- DjangoプロジェクトのCIのためのCircleCIの設定

## ECRリポジトリの作成
ECRリポジトリについては、下記のようなディレクトリ構成で作成しました。

terraform/
|-ecr/
 　|-.terraform/
 　|-aws_ecr_repository.tf
 　|-config.tf  

```aws_ecr_repository.tf
resource "aws_ecr_repository" "sample-image" {
    name = "sample-image"
}
```

```config.tf
terraform {
    backend "s3" {
      bucket	= "保管するS3バケットの名前"
      key	= "ecr/terraform.tfstate"
      region	= "ap-northeast-1"
    }
}

provider "aws" {
    region = "ap-northeast-1"
}
```

## CircleCI用のIAMユーザーの作成
IAM用のterraformのディレクトリ構成はこんな感じ。

terraform/
|-iam/
 　|-.terraform/
 　|-aws_iam_policies/
 　　|-ecr_policy.json
 　|-aws_iam_policy.tf
 　|-aws_iam_user_policy_attachment.tf
 　|-aws_iam_user.tf
 　|-config.tf  

```aws_iam_user.tf
resource "aws_iam_user" "deploy-user" {
    name = "deploy-user"
}
```

```aws_iam_policy.tf
resource "aws_iam_policy" "deploy" {
  name		= "deploy"
  path		= "/"
  description	= "deploy policy"
  policy	= file("aws_iam_policies/ecr_policy.json")
}
```

```aws_iam_user_policy_attachment.tf
resource "aws_iam_user_policy_attachment" "deploy-attach" {
  user		= aws_iam_user.deploy-user.name
  policy_arn	= aws_iam_policy.deploy.arn
}
```

```config.tf
terraform {
  backend "s3" {
    bucket = "保管するS3のバケットの名前"
    key    = "iam/terraform.tfstate"
    region = "ap-northeast-1"
  }
}

provider "aws" {
  region = "ap-northeast-1"
}
```

```ecr_policy.json
{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
	"Action": [
	  "ecr:GetAuthorizationToken",
	  "ecr:BatchCheckLayerAvailability",
	  "ecr:GetDownloadUrlForLayer",
	  "ecr:GetRepositoryPolicy",
	  "ecr:DescribeRepositories",
	  "ecr:ListImages",
	  "ecr:BatchGetImage",
	  "ecr:InitiateLayerUpload",
	  "ecr:UploadLayerPart",
	  "ecr:CompleteLayerUpload",
	  "ecr:PutImage"
	],
	"Resource": "*"
      }
    ]    
}

```

上記のtfファイルをもとに、terraform init、terraform plan、terraform applyを実行することでIAMユーザーを作成した。また、作成したユーザーの認証情報からアクセスキー関係の情報を取得しておく。これは、次のステップのCircleCIのセットアップの際に環境変数で設定しておく。


## CircleCIのセットアップ
Djangoプロジェクト用にセットアップ。circleci/config.ymlは下記の通り。

```.circleci/config.yml
version: 2.1

orbs:
  python: circleci/python@0.2.1

jobs:
  build-and-test:
    executor: python/default
    steps:
      - checkout
      - python/load-cache
      - python/install-deps
      - python/save-cache
      - run: sudo chmod u+x manage.py
      - run:
          command: ./manage.py test
          name: Test
  build-image:
    docker:
      - image: docker:18.09.0
    steps:
      - checkout
      - setup_remote_docker
      - run:
          name: install aws cli
          command: |
            apk add --no-cache --update py-pip
            pip install awscli
      - run:
          name: login ecr
          command: |
            $(aws ecr get-login --no-include-email --region ap-northeast-1)
      - run:
          name: build image
          command: |
            docker build -t ${ECR_DOMAIN}:$CIRCLE_SHA1 -t ${ECR_DOMAIN}:latest .
      - run:
          name: Push docker image
          command: |
            docker push ${ECR_DOMAIN}:$CIRCLE_SHA1
            docker push ${ECR_DOMAIN}:latest

workflows:
  main:
    jobs:
      - build-and-test
      - build-image:
          requires:
            - build-and-test
          filters:
            branches:
              only: master

```

また、下記の画像の通り、AWSへのアクセスキー関係の情報を環境変数に追加しておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580403/2961af04-5c24-ade1-2a17-e19a6aeffc9f.png)

この.circleci/config.ymlを含んだDjangoプロジェクトをGitHubにpushすると、
CircleCIのpipelineがRUN状態になり、ECRへDockerイメージがpushされる。