AmazonLinux2のdockerイメージにpythonをインストールしてAWS ECRにアップする方法

AWS環境を利用している環境において、CodePipeline/CodeBuild/CodeDeploy/CodeCommitを使用している方々、多くいらっしゃると思いますが、CodeBuildで使用するDockerイメージをどこで管理するかという課題に関して記述していければと思います。

Docker-hubで管理してもいいけどAWSで一元管理したい、Docker hub側のサイトでトラブルが起きてアクセスできなくなるのは困る、Docker hubのアカウントを取得して管理するのが面倒などあるかと思いましたので、データ分析基盤のDevOpsの一環で実施した内容を記述します。

- 環境及び前提
    - 実行環境

         VirtualBox (VM)
         OS:AmazonLinux2
         docker:18.06.1-ce
         pyenv:1.2.13
         Python:3.6.5

         VirtualBoxでAmazonLinux2のboxを作成し､amazon-linux-extrasでdockerをインストールして実施しています。
         ECRのリージョンは東京リージョンで実施しています。

- 最終ゴール
CI/CDでCodeBuildを使用する際の、AWSECR内でdockerイメージの管理

# Dockerイメージ作成準備

Dockerファイルで設定を記述した後、pythonのパッケージをインストールするための準備をします。

## Dockerファイルの作成
Dockerファイル内では必要なパッケージのインストールおよび、pyenvのダウンロード、pythonのインストール、環境変数の設定を実施しています。

今回作成するイメージの基となるイメージはdockerhubのオフィシャルイメージから持ってきています。
https://hub.docker.com/_/amazonlinux

以下がDockerファイルの中身

```docker:DockerFile
FROM amazonlinux:2
ADD . .

SHELL ["/bin/bash", "-c"]
RUN yum update -y
RUN yum install -y gcc bzip2 bzip2-devel openssl openssl-devel readline readline-devel git wget gcc-c++ unixODBC-devel tar.x86_64

RUN echo 'export PYENV_ROOT="/usr/local/pyenv"' | tee -a /etc/profile.d/pyenv.sh
RUN echo 'export PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${PATH}"' | tee -a /etc/profile.d/pyenv.sh
RUN echo 'eval "$(pyenv init -)"' | tee -a /etc/profile.d/pyenv.sh

RUN git clone https://github.com/pyenv/pyenv.git /usr/local/pyenv
RUN source /etc/profile.d/pyenv.sh && pyenv install -v 3.6.5 && pyenv global 3.6.5 && pip install --upgrade pip==19.0.3 && pip install -r requirements.txt && pip install awscli

```

今回の環境はsshでログインするユーザにかかわらずデフォルトのpython2.7系ではなく、python3.6.5を利用できるようにprofile.dのpyenv.shでパスを管理しています。


## requirements.txtの作成
pipでインストールしたいパッケージとそのバージョンを記載します。
既存の環境があるなら以下のコマンドを実行しインストールするパッケージの一覧を取得してください。

```bash
pip freeze > requirements.txt 
```

既存の環境がない場合は、自作してください。


# AWS ECRの設定

AWSコンソール上でECRにdockerイメージをpushできる環境を構築します。


## リポジトリの作成
AWSコンソール画面にログインし、ECRサービスに遷移します。
そしてリポジトリを作成します。
今回はリポジトリ名を「python3.6.5」としています。

**IAMでECRへの適切な権限が与えられているユーザを用いる必要があります。**


## ECRのPermissionsの設定
**以下はイメージをダウンロードする際に必要な設定です。**
Permissions画面へ遷移し、以下のアカウントIDの部分を編集してJsonを貼り付けます。

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CodeBuildAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::アカウントID:root"
      },
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer"
      ]
    }
  ]
}

```


# ECRへのイメージpush
ECRにログインし、dockerイメージをbuild後、実際にpushします。
以下アカウントID部分を修正して利用してください。

```bash
$(aws ecr get-login --no-include-email)
docker build -t アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/python3.6.5:latest .
docker push アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/python3.6.5:latest
```

# 注意点

- dockerにログインする必要はありません。
- コマンドを使用するOSにAWS CLIをインストールしている必要があります。
- `aws configure`に指定しているaccesskeyに紐づくユーザは、ECRの利用をIAMで許可されている必要があります。
- dockerにpushできない場合はセッションが切れている場合があるので、もう一度`$(aws ecr get-login --no-include-email)`を実行する必要があります。

# まとめ
ECRで管理すればセキュリティも担保できる上に、CodeBuildからイメージをダウンロードする際の可用性が上昇するという印象でした。
特に難しいこともないので、是非試してみてください。