AWS初心者がCodeBuildとCodeDeployを使ってCI/CDやってみた

[富士通システムズウェブテクノロジー Advent Calendar 2019](https://qiita.com/advent-calendar/2019/fsweb) 18日目の投稿です。
(お約束)記事の内容は全て個人の見解であり、執筆内容は執筆者自身の責任です。所属する組織は関係ありません。
執筆者は入社三年目なので、至らない点や誤り等あればご指摘いただけると泣いて喜びます。

### AWSでCI/CDやってみようと思った理由
- せっかくやるなら**自動化**でしょって思ったから
- クラウドを使ってCI/CDをできるってかっよくね？そう思ったから
- どうせやるなら記録に残った方がいいかな？と思ったから  
・・・そうです。ただの自己満です。
どうか、わがままにお付き合い下さい。

### 筆者のレベル
- リージョンの指定方法知らずにずっとオハイヨのリージョンで作業してたぐらいにはAWS初心者です
- CI/CDについてちょっとは分かる
- 他のクラウドに触れたことがある
- dockerは多少使える
- 得意と言えるほどでもないけどできる分野
  - インフラ < ミドル < アプリの順番

## 前提
- AWSのアカウント発行する
- CI/CDについての説明は省略
- MVCモデルで構築したJava言語のソースコードを使用
- ビルドツールはGradleを使用（独自docker image）
- AWSのロールについての説明は無いです
- 備忘録的に書いてるだけなので悪しからず

# ざっくりな全体構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/4d99bec5-3866-c83a-5155-28926d658461.png)

鉄板構成なんじゃないかと

# かる～く使用するツールの説明
## AWS CodeCommit
https://aws.amazon.com/jp/codecommit/
- gitリポジトリサービス
- Javaのソースコードを配備するのに使用しました

## AWS CodeBuild
https://aws.amazon.com/jp/codebuild/
- 専用のビルドスクリプトを元にビルドやらテストやらできるやつ
- デフォルトでは8種類のビルド環境を用意してくれてる
- AWS上に構築した、独自のビルド環境（dockerイメージ）も使用できる
- ビルド + S3（後述）に成果物を格納するのに使用しました

## AWS CodeDeploy
https://aws.amazon.com/jp/codedeploy/
- 専用のデプロイスクリプトを元に成果物を特定のサーバやサービスに配備したり、シェルの実行やらできるやつ
- S3（後述）に配備された成果物をEC2（後述）に構築したVMにデプロイし、成果物の展開やら実行やらをするのに使用しました

## EC2
https://aws.amazon.com/jp/ec2/
- VM構築サービス
- OSは色々選べます（今回はCentOSを選びました）
- VMにtomcatをインストールしてMVCで作ったJavaのソースコードを実行できるようにしました

## S3
https://aws.amazon.com/jp/s3/
- ストレージです
- バックアップファイルやアーカイブなど色々なデータを置くことができます
- 成果物（warファイル）の置き場として使用しました

## ECR
https://aws.amazon.com/jp/ecr/
- Container Registryです（dockerイメージ置き場だと思ってもらえれば）
- コンテナベースで作成したサービス等の配備先として使用できます
- 今回は独自のビルド環境を構築したのでそちらの配備先として使用しました
- CodeDeployに必要なagentはインストールしました

# いざ実践
## CodeCommitにリポジトリを作成する
入力された数値の足し算だけをして次画面に結果を返却するだけのプログラムを作って、CodeCommit上に格納しただけ
![スクリーンショット 2019-12-17 22.26.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/b951c6ae-908c-7791-b153-8c5345155938.png)
（ソースは公開してないです。需要があればソース公開します。）

# Codebuldeでソースコードをビルドする前に...

## ECR上にビルド環境を作成する
（やった後にDockerfileで書いていないことを非常に後悔...）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/7fbb44da-33b3-dc19-bdc0-664d30369780.png)
Gradleプロジェクトをビルドするための環境をdockerコンテナベースで用意する
- ローカルにdockerサービスをインストール
- CentOSのdockerイメージをPull + 起動
- Java + Gradleのインストール
- dockerイメージを`docker tag`コマンドでイメージ名を書き換え
- 作成したECRにイメージをPUSH

これだけでAWS上に自身が作成したdockerイメージを格納することが可能

## S3に成果物を格納する領域を作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/ba26ef6f-d271-0e21-0d14-c648efaf5208.png)
※ S3上に構築するバケット名は重複が認められていない為、独自の名前を指定して作成する。

## CodeBuile上にビルドプロジェクトを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/93e6de9a-2e86-4df7-204d-51c467b0aa56.png)  

- 送信元に上記手順で作成したCodeCommitのリポジトリを指定する
- 環境に上記手順で作成したECR上のdockerイメージを指定する
- ビルドの仕様に`buildspecを使用する`を選択する
- アーティファクトに上記手順で作成したS3上のバケットを指定する

## buildspec.ymlを作成する
CodeCommit上のリポジトリのルートディレクリに`buildspec.yml`という名前のファイルを作成します

```
version: 0.2 
 
phases: 
  install: 
    commands:  
      - gradle -v 
  build: 
    commands: 
      - gradle war 
      - tar -cvf sampleJava.tar ./build ./appspec.yml ./deploy.sh 
       
artifacts: 
  files: 
    - ./sampleJava.tar
```
- phasesタグにはinstallジョブとbuildタグを指定
- installタグではgradleのバージョン確認コマンドのみ実行（もちろんなくてもいい）
- biuldタグではgradleのwarファイル作成コマンドと、成果物をtarに固めるコマンドを実行

## ビルドプロジェクトを動かしてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/a3b0e315-b739-4539-260e-6fb88602358a.png)
成功しました :tada:
画面をスクロールしていくとログも確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/44dffd45-6197-10cd-02eb-7643e9e26777.png)

## 成果物がS3上に格納されたことを確認
ログには格納が成功した旨がログ出力されてる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/ebc2c4e1-7b07-a2ec-2df5-afa3a7d2ebe4.png)
S3上に無事格納されてました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/0955490a-348f-eb41-d984-1e3f37716bee.png)

# CodeDeployで成果物をデプロイするまえに...

## EC2上にVMを構築する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/73f38bfc-48da-2860-ad70-a64f09f8f944.png)
- OSにCentOSを使用しました
- tomcatをインストールしました
- CodeDeploy用のagentをインストールしました

## appspec.ymlを作成する
CodeCommit上のリポジトリのルートディレクリに`appspec.yml`という名前のファイルを作成します

```
version: 0.0 
os: linux 
files: 
  - source: / 
    destination: /home/centos 
hooks: 
  ApplicationStart: 
    - location: deploy.sh 
      runas: root 
```

- 上記手順で作成したVMの`/home/centos`ディレクトリに成果物を配備します
- デプロイ時に`deploy.sh`を実行します
- `deploy.sh`の実行は`root`ユーザで行います

また、デプロイ時に実行するコマンドをまとめたシェルを作成しました

```
systemctl stop tomcat 
rm -fr /var/lib/tomcat/webapps/sampleJava/* 
mkdir /var/lib/tomcat/webapps/sampleJava 
cp /home/centos/build/libs/sampleJava.war /var/lib/tomcat/webapps 
unzip /var/lib/tomcat/webapps/sampleJava.war -d /var/lib/tomcat/webapps/sampleJava 
systemctl start tomcat 
```
- tomcatの停止
- 成果物の配備 + 展開
- tomcatの開始
を行うシェルです。

## CodeDeploy上にデプロイアプリケーションを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/798a691b-ee98-9f2d-88d9-66ce5147c9aa.png)

- デプロイグループの作成も一緒に行う
  - 環境設定にEC2インスタンスを選択する
  - タグの設定を行う（同様のタグ値・キーの設定をEC2のインスタンスにも行う）

## デプロイアプロケーションを動かしてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/e2f6f067-2aa2-65fb-129e-5942585ed9db.png)

成功しました :tada:
成功の場合はブラウザ上から成功のログを確認することはできないっぽいです
失敗の場合はちょっとだけエラー理由が表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/e670c607-7179-e03f-cb8d-9da5f77fe001.png)


## EC2に構築したVMにデプロイされたか確認する
EC2のVMのパプリックIPアドレスでブラウザからアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/f46caba5-4c7e-d2fc-c079-3805d4ee9fb1.png)
無事ブラウザからアクセスすることができました。

## 背景色を変更してもう一回CI/CDを実行する
よし。できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528188/85522485-2ee1-dd5d-9c0d-227815c5cda3.png)
エラーっぽくて心臓に悪いな...

# AWS初心者でもCodeBuildとCodeDeployを使ってCI/CDをすることができました :tada: 

## 今回得た学び
- なんかしらのツールでCI/CDやったことあればAWSだろうがなんだろうがなんとかCI/CDできる
- 新しいことを学んで実践してみて、成功した時のうれしみが半端ない
- 控えめに言ってめちゃめちゃ楽しかった

## 最後に
だらだらと書いちゃいましたが、最後まで見ていただいてありがとうございます。
今回アドカレに挑戦してみてめちゃめちゃ楽しかったです。（大事なので2回言う）
また機会があったら積極的にチャレンジしていきたいと思います！
（ネタが尽きてくるのでアドカレの場合、初週あたりに設定したほうがいいことも学んだ）

おわり。