メモ CodeBuild docker in docker -> ECR pushなど

## やること
※この記事には画像がなく痩せた大地のようなのでCodeBuildでツラまった時に見るとかがいい


1. マネージドイメージ内でmvnビルド、生成されたjarをS3にアップロード [AWS CodeBuildの使用開始](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/getting-started.html)
2. カスタムイメージ(自作dockerイメージ)内でmvnビルド、生成されたjarをS3にアップロード
3. マネージドイメージ内でdockerイメージをビルド、ビルドしたイメージをECRにpush
4. カスタムイメージ内でdockerイメージをビルド、ビルドしたイメージをECRにpush

最終的にやりたかった事は自前のdockerイメージ内でビルドして、そのイメージをECRにpushすること
詰まった時の問題点を特定しやすくするために段階を分割してる
1でCodeBuildの設定などを把握、2でカスタムイメージ利用、3でdockerイメージビルドからpush、4で2と3を合わせる

CodeBuildからECRへのpull/push権限とdocker in docker周りが理解できれば詰まることは無くなると思う
CodeBuildはUI上からビルド開始出来る、GitHubからのwebhookなどは検証してないけどそれも出来る(サンプルにはある)
サンプルが多いのでとりあえず迷ったらサンプル集を見てみたら解決しそう、ドキュメントが揃っていてえらい
[CodeBuildサンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/samples.html)




## 環境
- AWSマネジメントコンソールにログイン出来る (ECR/IAM/CodeBuild/S3周りの権限がある)
- dockerイメージがローカルでビルド出来る
- AWS CLIがローカルで使える

## 作業
### マネージドイメージ内でmvnビルド、生成されたjarをS3にアップロード

まずはCodeBuildのイメージを掴むためにAWSが用意しているチュートリアルをやる
本家を見たほうが参考になると思う
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/getting-started.html

やること

- s3 input/outputの定義
- ビルド用プロジェクトの作成/buildspec.yml作成/s3アップロード
- CodeBuild ビルドプロジェクト作成
- ビルド実行
- ビルドログ/成果物確認

ではやっていく

##### S3バケット作成 input/output用
このサンプルではソースコード取得/成果物出力をS3バケットに行うのでそれ用のバケットを作成する

今回の名前はこんな感じ、名前は好きに付けてOK

入力用バケット: `codebuild-AWSアカウントID-yyyyMMdd-input-bucket`
出力用バケット: `codebuild-AWSアカウントID-yyyyMMdd-output-bucket`

入力用バケットはCodeBuildの`Source`で
出力用バケットはCodeBuildの`Artifacts`で指定する

※バケットが1つでも動作するが確認しやすいので入力出力を分けているらしい
※CodeBuildプロジェクトとS3バケットは同一リージョンに作成する必要がある

##### ビルド用mvnプロジェクト作成

ローカルの好きなところにmvnプロジェクト用ディレクトリを作成する
mvnプロジェクトの作成

```
mkdir codebuild_lesson
cd codebuild_lesson
mkdir -p ./src/main ./src/test
touch src/main/MessageUtil.java src/test/TestMessageUtil.java
touch pom.xml
```

それぞれのファイルに追記
実行しないので正直中身はビルドできれば何でもいい
サンプル通りに貼り付ける

```java:MessageUtil.java
public class MessageUtil {
  private String message;

  public MessageUtil(String message) {
    this.message = message;
  }

  public String printMessage() {
    System.out.println(message);
    return message;
  }

  public String salutationMessage() {
    message = "Hi!" + message;
    System.out.println(message);
    return message;
  }
}
```

```java:TestMessageUtil.java
import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

public class TestMessageUtil {

  String message = "Robert";    
  MessageUtil messageUtil = new MessageUtil(message);
   
  @Test
  public void testPrintMessage() {      
    System.out.println("Inside testPrintMessage()");     
    assertEquals(message,messageUtil.printMessage());
  }

  @Test
  public void testSalutationMessage() {
    System.out.println("Inside testSalutationMessage()");
    message = "Hi!" + "Robert";
    assertEquals(message,messageUtil.salutationMessage());
  }
}
```

```xml:pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>messageUtil</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>
  <name>Message Utility Java Sample App</name>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>	
  </dependencies>  
</project>
```

ここまででmvnビルド用の用意は完了

次にCodeBuildビルド仕様ファイルの追加
アプリケーションルートに`buildspec.yml`というファイルを作成
この名前はCodeBuildが認識するためこの名前にする必要がある(プロジェクト側の設定でビルド仕様ファイル名を任意の名前に設定できるが特に問題がない場合そのままで良い)

```
touch buildspec.yml
```

```yml:buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - echo Nothing to do in the install phase...
  pre_build:
    commands:
      - echo Nothing to do in the pre_build phase...
  build:
    commands:
      - echo Build started on `date`
      - mvn install
  post_build:
    commands:
      - echo Build completed on `date`
artifacts:
  files:
    - target/messageUtil-1.0.jar
```

ビルドバージョンは最新の`0.2`を指定
`phases`にそれぞれある`install`、`pre_build`、`build`、`post_build`の4つがビルドフェーズとして存在する、名前はこれ以外に設定できないし新しいフェーズを追加することも出来ない
必要のないフェーズを省略することも出来るが`echo`で特にやることがない的なメッセージを出力しておいて必要になったら追記するような感じでやるとフェーズ名を調べる手間が省けそう
`commands`は実行したいLinuxコマンド
`artifacts`は成果物を設定した出力場所にどのファイルを配置するかの設定、このサンプルでは生成されたjarをS3に出力するがS3という設定はCodeBuildプロジェクト側で設定する

##### mvnプロジェクトをzipしてinput用s3バケットにアップロード

アプリケーションルート以下のファイルをzipして`MessageUtil.zip`というファイル名にする

```
zip -r MessageUtil.zip ./
```

生成されたファイルを`codebuild-AWSアカウントID-yyyyMMdd-input-bucket/MessageUtil.zip`にアップロードする

今回の全サンプルのソースはS3から取得するためビルド仕様ファイルの仕様をあまり読んでないが困ったらこれを読めば良さそう
[CodeBuild のビルド仕様に関するリファレンス](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-name-storage)

##### ビルドプロジェクトを作成する

入力/プロジェクト/出力が揃ったのでようやくCodeBuildプロジェクトを作成する
AWSコンソールからCodeBuildのプロジェクト作成ボタンを押す

以下設定の入力項目と値
特に書いていない箇所はデフォルト設定

Project name: `codebuild-AWSアカウントID-yyyyMMdd-mvn-project`
Source provider: `Amazon S3`
バケット: `codebuild-AWSアカウントID-yyyyMMdd-input-bucket`
S3 object key or S3 folder: `MessageUtil.zip`
Environment image: `Managed image`
Operating system: `Ubuntu`
Runtime(s): `Standard`
Image: `aws/codebuild/standard:1.0`
Artifacts Type: `Amazon S3`
Artifacts Bucket name: `codebuild-AWSアカウントID-yyyyMMdd-output-bucket`
Logs CloudWatch Logs: `チェックする`
Logs Group name: `codebuild-AWSアカウントID-yyyyMMdd-mvn-project-log`

サンプルと違う箇所はログ名を付けたくらい
この状態で作成する

##### ビルドする

ビルドプロジェクトを作成したので後はUI上でビルドを開始して結果を確認するだけ

AWSコンソールから先程作成したビルドプロジェクトに入って`Start build` -> `Start build`でビルド開始
ビルド中はタブで`Build logs`や`Phase details`などあるので確認する

Phase detailsで全ての工程がSucceededになったらS3にjarが出力されているか確認する

出力用S3バケットには以下のように出力される
`codebuild-AWSアカウントID-yyyyMMdd-output-bucket/codebuild-AWSアカウントID-yyyyMMdd-mvn-project/target/messageUtil-1.0.jar`

ここまではほぼサンプル通りのビルドなので特に問題は無いと思う


### カスタムイメージ(自作dockerイメージ)内でmvnビルド、生成されたjarをS3にアップロード
次はカスタムイメージをビルド環境にしてみる

対応するCodeBuildサンプルは以下
[CodeBuildのAmazon ECRサンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-ecr.html)
サンプルはGoプロジェクトになっているが、前回のmvnプロジェクトを使用する

やること

- ECRリポジトリの作成
- ローカルでmvnがビルドできるdockerイメージの作成
- dockerイメージをECRにpush
- CodeBuildプロジェクトでpushしたdockerイメージを利用するように変更
- ECRリポジトリにCodeBuild実行roleからのイメージ取得権限を設定

注意点としては、ECRリポジトリにポリシー設定を行わないと同じAWSアカウントからでもpullが出来ないのでビルド時にエラーが出る
それ以外は特に前回と変わらないので前回と同じプロジェクトを編集していく

##### mvnビルド出来るdockerイメージの作成

その前にECRにリポジトリを作成しておく
UIからでもCLIからでもいいので名前を`mvn_for_ecr`としておく

アプリケーションルートにDockerfile用ディレクトリを作成する
個人的に`dockerfiles`というディレクトリにそれぞれのDockerfileを置いているのでそうする

```
mkdir -p dockerfiles/mvn_for_ecr
touch dockerfiles/mvn_for_ecr/Dockerfile
```

Dockerfileの中身は以下
[Dockerhubのmaven](https://hub.docker.com/_/maven/)をpullしてECR push用にタグ付けすれば問題なく動きそうだけど自分で色々出来るように一応Dockerfile書く

```dockerfile:dockerfiles/mvn_for_ecr/Dockerfile
FROM java:8-jdk-alpine

WORKDIR /tmp

RUN apk update && apk add openssl && apk add curl

RUN curl -OL https://archive.apache.org/dist/maven/maven-3/3.6.1/binaries/apache-maven-3.6.1-bin.tar.gz
RUN tar -xzvf apache-maven-3.6.1-bin.tar.gz
RUN mv apache-maven-3.6.1 /usr/local/bin/
ENV PATH $PATH:/usr/local/bin/apache-maven-3.6.1/bin

RUN echo $PATH
RUN which mvn

WORKDIR /app

CMD ["/bin/ash"]
```

イメージのビルド/タグ付け/push
※ECRにpush出来るようにaws ecr get-loginでdockerログインしておく

```
aws ecr get-login --region リージョン --no-include-email
> docker login -u AWS -p ~~~~~~ https://AWSアカウントID.dkr.ecr.リージョン.amazonaws.com

docker build -t mvn_for_ecr ./dockerfiles/mvn_for_ecr
docker tag mvn_for_ecr:latest AWSアカウントID.dkr.ecr.リージョン.amazonaws.com/mvn_for_ecr:1.0.0
docker push AWSアカウントID.dkr.ecr.リージョン.amazonaws.com/mvn_for_ecr:1.0.0
```

pushが完了したらAWSコンソール上でECRのリポジトリを確認する、1.0.0があればOK


##### CodeBuildプロジェクトでpushしたdockerイメージを利用するように変更

AWSコンソールで`codebuild-AWSアカウントID-yyyyMMdd-mvn-project`に入り`編集` -> `Environment`を選択して`Edit Environment`画面に入る

`Override image`を押下

New environment image: `Custom image`
Environment type: `Linux`
Image registry: `Amazon ECR`
ECR account: `My ECR account`
Amazon ECR repository: `mvn_for_ecr`
Amazon ECR image: `1.0.0`
Image pull credentials: `Project service role`
Service role: `codebuild-codebuild-AWSアカウントID-yyyyMMdd-mvn-project-service-role` ※多分ロールの名前はこんな感じ

ポイントは`Image pull credentials`を`Project service role`に設定するところ
後でECRリポジトリにポリシーで、指定しているロールからのアクセスを許可することでイメージをpull出来るようにする

ここまでの設定で一旦ビルドしてみる
※ECRリポジトリのポリシーを設定していないのでエラーが出る、一回リポジトリのポリシーを有効にすると数時間間違った設定でもSucceededになるので注意
こんな感じ at Phase details

```
BUILD_CONTAINER_UNABLE_TO_PULL_IMAGE: Unable to pull customer's container image.
CannotPullContainerError: Error response from daemon: pull access denied for AWSアカウントID.dkr.ecr.リージョン.amazonaws.com/mvn_for_ecr,
repository does not exist or may require 'docker login'
```

次にECRリポジトリ`mvn_for_ecr`のポリシーを以下のように設定する
PermissionsというリンクをクリックするとポリシーJSONを編集と出るのでそこで行う

```json:ECRリポジトリのポリシー
{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "mvn_for_ecr_policy",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::AWSアカウントID:role/service-role/codebuild-codebuild-AWSアカウントID-yyyyMMdd-mvn-project-service-role"
      },
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer"
      ]
    }
  ]
}
```

特定のロールに対してECR取得系のアクションを許す
これを保存してもう一度CodeBuildでビルドしてみると全てSucceededになると思う
ならなかったらCodeBuildのenvironmentを同じ設定で保存し直すといけるかも、検証してない


### マネージドイメージ内でdockerイメージをビルド、ビルドしたイメージをECRにpush

次はdockerイメージをビルドしてECRに対してpushする
CodeBuildサンプルは以下
[CodeBuildのDockerサンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-docker.html)

やること

- ECRリポジトリの作成(push用)
- 作成したECRリポジトリのポリシー設定
- buildspec.ymlの変更
- イメージ作成用のDockerfile作成
- プロジェクトをS3へ再アップロード
- CodeBuildのEnvironment設定

dockerイメージをCodeBuildからECRにpushするのでECRリポジトリのポリシーにpush用の権限を設定する必要がある
dockerコマンドで利用する環境変数をCodeBuildプロジェクトのEnvironmentsから設定する


##### ECRリポジトリの作成
push用リポジトリを作成する
名前は`build_from_codebuild_echoalpine`にする
今回はmvnコマンドを利用せずに単純に`docker build`や`docker push`がちゃんと行えるようになるかを確認していく

UIやCLIから作成する

##### `build_from_codebuild_echoalpine`のポリシー設定を行う


ビルドしたイメージをpushするリポジトリのポリシーJSON
pushを行うので更新系のアクションを許可するようにする
こんな感じ、ロール名は予測なのでサジェストに出てきた対応するやつを使う

```json:build_from_codebuild_echoalpine
{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "build_from_codebuild_echoalpine_policy",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::AWSアカウントID:role/service-role/codebuild-codebuild-AWSアカウントID-yyyyMMdd-mvn-project-service-role"
      },
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:CompleteLayerUpload",
        "ecr:GetAuthorizationToken",
        "ecr:InitiateLayerUpload",
        "ecr:PutImage",
        "ecr:UploadLayerPart"
      ]
    }
  ]
}
```


##### buildspec.ymlの変更
今までのbuildspec.ymlだとmvnコマンドを実行してからartifactsでS3に成果物を置くようにしていたが、今回はビルドしたdockerイメージをECRにpushするのでそれ用に書き直す


```yml:buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - echo Logging in to commands...
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - echo $DOCKER_VERSION
      - which docker
      - pwd
      - ls -l
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
```

dockerイメージを成果物として捉えるならartifactsに書きたくなるが、docker pushは`post_build`フェーズにcommandsとして書く
`pre_build`フェーズで`aws ecr get-login`コマンドがあるが、environmentsでマネージドイメージを選択するので実行可能になっている、嬉しい
いくつも環境変数を利用している、CodeBuildプロジェクトのenvironmentsで環境変数設定で定義する
`build`フェーズの`echo $DOCKER_VERSION` `which docker` `pwd` `ls -l`などはなんか確認したくて書いてる、別に必要はない

##### イメージ作成用のDockerfile作成
buildspec.yml内で`docker build`コマンドを実行しているのでDockerfileを作成する

作成したdockerfilesディレクトリに置いたほうが恐らく良いが、怠惰男になったので一旦アプリケーションルートに置く、ゴメス

```
touch Dockerfile
touch echo.sh
```


```dockerfile:Dockerfile
# 成果物を実行させるイメージを生成する
FROM alpine:3.9.3

ADD ./echo.sh /tmp/echo.sh

CMD /tmp/echo.sh
```

```shell:echo.sh
#!/bin/ash

count=0
while true
do
    echo "my alpine container build from CodeBuild!! 1.0.0"
    sleep 10
    count=$(expr $count + 1)
    if [ $count -ge 10 ]; then
      echo "echoalpineの死!!"
      exit
    fi
done
```


##### プロジェクトをS3へ再アップロード
CodeBuildプロジェクトに必要なファイルが揃ったので再びzipにしてinput用S3にアップロードする

```
zip -r MessageUtil.zip ./
```

S3にアップロードする
`codebuild-AWSアカウントID-yyyyMMdd-input-bucket/MessageUtil.zip`

##### CodeBuildのEnvironment設定

後はCodeBuildの設定を更新してビルドすれば問題ないはず、恐れずに行け。

AWSコンソールの作成しているプロジェクト -> `編集` -> `Environment`
`Edit Environment`画面で以下の設定にする

`Override image`を押下して

New environment image: `Managed image`
Operating system: `Ubuntu`
Runtime(s): `Standard`
Image: `aws/codebuild/standard:1.0`
Image version: `latest`
Privileged: `チェックする`
Service role: `arn:aws:iam::AWSアカウントID:role/service-role/codebuild-codebuild-AWSアカウントID-yyyyMMdd-mvn-project-service-role`

追加設定を開いて`Environment variables`を追加していく、以下`key`: `value`で全て`Plaintext`
AWSアカウントIDは自分のに変更、リージョンも今まで指定してきたリージョンに変更

- `IMAGE_REPO_NAME`: `build_from_codebuild_echoalpine`
- `IMAGE_TAG`: `latest`
- `AWS_ACCOUNT_ID`: `AWSアカウントID`
- `AWS_DEFAULT_REGION`: `ap-northeast-1`


最も重要なのは`Privileged`にチェックを入れること、これをチェックしないと`Cannot connect to the Docker daemon`とエラーが出てdockerが使えない
Runtimeにはdockerを指定しないといけないと思いきやStandardでOK

これでECR push用の設定は完了したのでビルド実行
恐らくSucceededになるはず(記憶を頼りに書いてる)
ECRのpush対象リポジトリに入ってイメージが追加されているか確認
動作確認もしたければローカル等にpullしてrunする、ECR pushが目的だったので動作はあまり気にしてないけど
エラーが出たときはリポジトリのポリシーとCodeBuild environments設定のPrivilegedチェックを確認してみる
…散々Privilegedチェックを書いているけど、検証時はカスタムイメージで`docker:dind`を指定してたからもしかしたらマネージドイメージでは不要かもしれない…すみません



### カスタムイメージ内でdockerイメージをビルド、ビルドしたイメージをECRにpush

※追記 2019/07/08 docker in dockerでビルドするよりもマネージドイメージ上でdocker buildコマンドを実行して、そのDockerfile内でマルチステージビルドした方が楽だと思います

さあ本命の登場だ
これまでのことを組み合わせると簡単に行けるだろうと思っていたがdocker in dockerなのでカスタムイメージ設定で苦戦した

ほぼ参考にしてないけどCodeBuild対応サンプル
[CodeBuild のカスタム Docker イメージのサンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-docker-custom-image.html)


やること

- カスタムイメージの作成
- buildspec.ymlの変更
- CodeBuildのEnvironmentsの変更

カスタムイメージではmvnを入れているけどdocker buildでは結局echoalpineをビルドしているという点は許してほしい、カスタムイメージ内でdockerが使えるようになればあとはどうにでもなる、何を作るかなど今はどうでも良いのだ…


##### カスタムイメージの作成
最も重要な点として、ベースイメージを`docker:dind`系にしないといけないということ
※dindはdocker in dockerの略
前回のベースイメージは`java:8-jdk-alpine`だったので`dind`にするとjdkをインストールしなければいけない
それではカスタムイメージのDockerfile編集

```dockerfile:dockerfiles/mvn_for_ecr/Dockerfile
FROM docker:18.09.5-dind

WORKDIR /tmp

RUN apk update && apk add openssl && apk add curl
RUN apk add openssh
RUN apk add bash

# javaのダウンロー
# ド
RUN apk add openjdk8

RUN curl -OL https://archive.apache.org/dist/maven/maven-3/3.6.1/binaries/apache-maven-3.6.1-bin.tar.gz
RUN tar -xzvf apache-maven-3.6.1-bin.tar.gz
RUN mv apache-maven-3.6.1 /usr/local/bin/
ENV PATH $PATH:/usr/local/bin/apache-maven-3.6.1/bin

RUN echo $PATH
RUN which mvn

WORKDIR /app
```

重要なのは`docker:18.09.5-dind` これ以外のイメージをFROMに指定して出来るもんなのか、dockerインストールするとか以外で

Dockerfile内でCMD指定してないのは`docker:18.09.5-dind`のCMDを利用するため、Dockerシェフは素材の味を活かす…
※そもそもCMD指定しなかったらFROMのCMDを利用するのか知らない、雰囲気でそうしてる、検証します…上記のDockerfileでCodeBuildでdockerコマンドが利用できるのはちゃんと確認した


カスタムイメージ用のDockerfileを編集したのでビルドしてECRにpushする
ここはECRにpushするサンプルとほぼ同じなのでパラメータとかを適当なものに
ここではタグを`1.1.0`にする

```
aws ecr get-login --region リージョン --no-include-email
> docker login -u AWS -p ~~~~~~ https://AWSアカウントID.dkr.ecr.リージョン.amazonaws.com

docker build -t mvn_for_ecr ./dockerfiles/mvn_for_ecr
docker tag mvn_for_ecr:latest AWSアカウントID.dkr.ecr.リージョン.amazonaws.com/mvn_for_ecr:1.1.0
docker push AWSアカウントID.dkr.ecr.リージョン.amazonaws.com/mvn_for_ecr:1.1.0
```


##### buildspec.ymlの変更
カスタムイメージを作成したので次はその中でどんなコマンドを実行するかを変更していく

```yml:buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - echo Logging in to commands...
      - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2&
      - timeout -t 15 sh -c "until docker info; do echo .; sleep 1; done"
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - docker login -u AWS -p $ECR_LOGIN_PASS https://$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - echo $DOCKER_VERSION
      - which docker
      - pwd
      - ls -l
      - which mvn
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
```

`install`フェーズに追加している`nohup...`でホスト上のdockerをコンテナ上で利用できるようにしてる的な

AWS CLIのインストールをサボってpull出来るように直接docker loginをかましているけどもっと良い方法があるはず(絶対)
そもそもこの方法だとECRへのdocker login有効期限12時間が経過する度に`$ECR_LOGIN_PASS`を更新しないといけないのでダメ
mvnコマンドを利用しない代わりにとりあえず`which mvn`でコマンドがあるかだけ確認している

buildspec.ymlの編集が完了したらまたzipしてinput用S3バケットにアップロードする
zipコマンドだけ

```
zip -r MessageUtil.zip ./
```

##### CodeBuildのEnvironmentsの変更
CodeBuildのenvironmentsを編集する

New environment image: `Custom image`
Environment type: `Linux`
Image registry: `Amazon ECR`
ECR account: `My ECR account`
Amazon ECR repository: `mvn_for_ecr`
Amazon ECR image: `1.1.0`
Image pull credentials: `Project service role`
Privileged: `チェックする`
Service role: `codebuild-codebuild-AWSアカウントID-yyyyMMdd-mvn-project-service-role`

環境変数に以下を追加
ローカルで`aws ecr get-login --region リージョン --no-include-email`を実行して-pの文字列をコピーしてくる

- `ECR_LOGIN_PASS`: `コピーした文字列`

これで更新

今回は絶対Privilegedチェック必要
ビルド実行してSucceededになってpush先のECRリポジトリが更新されていればOK
これまでの全てを組み合わせればエラーが出ても解決できるはずじゃ…(記憶とメモを頼りに書いてる)






## まとめ
後半になるにつれて雑になってきたけど多分要所は抑えているのでエラーが出たらサンプルを頼りにがんばる、ツラくなったらFutureFunkやElectroSwingを聞いて踊れ、この記事で伝えたい全てはそれだ。
困ったらBuild logsを見よう、問題はそこに出ている
AWSサービスは概念掴めばドキュメント見てterraform化とか出来るのでそこまでは
マルチステージビルドとかソース取得元とGitHubにしたりとかまだやりたいことはあるけどとりあえずこれで

## 問題
定期的に権限の有効期限が切れているので解決する

## 参考
[AWS CodeBuildの使用開始](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/getting-started.html)
[CodeBuildサンプル](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/samples.html)