JenkinsおじさんのためのAWS Batch

# はじめに
## この記事の対象者
主にこんな感じの人をターゲットにしています。

- Jenkinsでジョブを管理している
- AWSをcliで触るのは実は大変…。GUIでやりたい
- Dockerはインストールはしているけれど、あんまり触ったことが無い

また、本記事執筆時点では、us-east(virginia)でのみ利用可能なので、**VPCでの利用はあまり想定していません。** （VPNを繋げば出来ると思いますが…）
本来はAuto ScalingやSPOTインスタンスと組み合わせたりといろいろあるのですが、私的事情により、志は低く、**過疎っているJenkinsサーバを廃止（サーバレス化）すること**を目標にしています。

## 対象のJenkinsジョブ
今回ターゲットにするのは、Jenkinsだと一般的と思われる以下の処理とします。

- JDKがバージョン指定で入っている
- バッチ処理の入ったリポジトリを`git clone`してくる
- シェルスクリプトからごにょごにょして、リポジトリの中身を実行する

PHPやRubyなど別言語の人は、Javaな部分は脳内で別言語に置き換えてみてください。

# AWS Batchでの流れ
Jenkinsでごく一般的なこの処理をAWS Batchでやろうとした場合、以下のような流れが一番シンプルになるかなと思います。

1. JDK等、必要な実行環境を準備した`Dockerfile`を作成する
2. Jenkinsでやっていたシェル相当のシェルスクリプトを作成する
3. リポジトリに`Dockerfile`とシェルスクリプトを追加する
4. Amazon ECRに設定を作成する
5. `Dockerfile`でビルドし、JDK及びバッチ処理のリポジトリの入ったコンテナを作成し、ECRにプッシュする
6. AWS Batchの設定（IAM Role, Compute Environment, Job Definition等）を作成する
7. AWS Batchを実行する

というわけで、ハンズオン的に進めて行きたいと思います。

## 作業手順
### 1. Dockerfileの作成
古風なエンジニアにはこちらの記事が一番わかりやすいんじゃないかと思います。

[効率的に安全な Dockerfile を作るには](http://qiita.com/pottava/items/452bf80e334bc1fee69a)

今回のケースだとJavaのバッチ（Hello.class）を動かしたいので

```
$ ls
Hello.class

$ vim Dockerfile
```

として、以下のような`Dockerfile`を作成します。

```:Dockerfile
FROM centos:6

RUN yum install -y java-1.7.0-openjdk java-1.7.0-openjdk-devel
ENV JAVA_HOME /usr/lib/jvm/java-openjdk
RUN mkdir /opt/batch-directory
COPY . /opt/batch-directory/
WORKDIR /opt/batch-directory
```

Javaは諸々の事情からOpenJDKにしていますが、Oracle Javaが必要な場合は、少し手間はかかりますが、Oracle Javaでもコンテナを作成することはできます。また、本来だとベースイメージはAmazonLinuxだったりJavaが入ったコンテナの方が良いと思いますが、保守的な方のために、敢えてCentOSにしました。（あんまり意味ないかな…）

### 2. シェルスクリプトの作成
Jenkinsにバッチを実行するためのシェルスクリプト（Jenkinsでコマンド欄に入れていたようなもの）を作ります。

```
$ ls
Dockefile
Hello.class

$ vim batch.sh
```

今回は解説用なので雑なものを用意しています。

```bash:batch.sh
#!/bin/bash

java -version
java Hello
```

### 3. Dockerfileとシェルスクリプトをリポジトリに追加
せっかく作成したので、これらのファイルをGitリポジトリに追加しましょう。（これはこの後の工程上の必須項目ではないので、一連がテストされてからでも大丈夫です）

### 4. Amazon ECRにリポジトリを作成する
Amazon EC2 Container Registry(ECR)にリポジトリを作成します。ここではリポジトリ名を入れるだけです。
![Amazon EC2 Container Service.png](https://qiita-image-store.s3.amazonaws.com/0/15830/59966ef6-60a4-f222-6596-64b74e292c06.png)


### 5. Dockerfileでビルド
先ほど付けた名前を使って、Docker buildをします。

```
$ docker build -t unagi/jenkins-ojisan .
```

### 6. コンテナをECRに登録する
タグ付けして、先ほど作成したECRに登録してあげます。

```bash
$ aws ecr get-login --region us-east-1

# これでdocker loginに必要なコマンドがでてくるので、実際はそれを使う
$ docker login -u AWS -p xxxxxx -e none https://xxxx.dkr.ecr.us-east-1.amazonaws.com
$ docker tag unagi/jenkins-ojisan:latest xxxx.ecr.us-east-1.amazonaws.com/unagi/jenkins-ojisan:latest
$ docker push xxxx.ecr.us-east-1.amazonaws.com/unagi/jenkins-ojisan:latest
```

### 7. AWS Batchの設定をつくる
Job definitionとCompute environmentを設定します。

こちらがJob definitionで、コンテナを起動するときの設定になります。環境変数を設定できるので、パラメータを渡したい場合は使う事ができます。
![AWS Batch (1).png](https://qiita-image-store.s3.amazonaws.com/0/15830/ee59b4ba-4770-a544-4e10-54a356080706.png)

S3アクセス等でIAM Roleを使いたい場合は、ここで定義する**<font color="Red">Job Role</font>**で定義する必要があります。そしてさらに分かりにくいことに、ここに表示されるIAM Roleを作るためには、**信頼するエンティティが<font color="Red">Amazon EC2 Container Service Task Role</font>(ecs-tasks.amazonaws.com)**のIAM Roleを作る必要があります。IAM Role作成時に似たようなのが沢山あるので、非常に解りづらいところです。

そして、次の画面はCompute environmentです。
![AWS Batch (2).png](https://qiita-image-store.s3.amazonaws.com/0/15830/e98721a9-558b-0792-05d8-a7805fcfffdf.png)
こちらはあまり見所は無く、淡々と設定していきます。ここで出てくるRoleは、ECSで動作するために必要なもので、コンテナで使うモノではありません。なので、適当に作成します…。

### 8. AWS Batchの実行
Job definitionsから**Submit job**して実行します。実行時に先ほど設定した環境変数を変更しながらの実行等もできます。
ちなみにこれも凄く分かりにくいのですが、Job definitionを編集したい場合は**<font color="Red">Create new version</font>**です。新しいバージョンの定義が出来てしまうので、古い方は不要になった段階で削除してしまいましょう。

### 9. 実行ログの確認
CloudWatchのログから見ます。Submitしてから起動までは少し時間がかかるので、少し待たないとログ出力はされません。

## あとがき
Jenkinsおじさん的には、Dockerが出てくるため取っつき辛い印象を持つのかなと思います。
美しくDockerを使う場合はさておき、バッチ処理をやるだけであれば、Dockerfileに書くのはバッチサーバを作るときのセットアップコマンドで、一回やってしまえばあまり難しくないです。