プライベートサブネットにあるEC2でdocker buildする

## はじめに

プライベートサブネットに配置されたEC2上で、docker buildを行う際の手順になります。  
インターネットへの通信ができない場合、ビルド時にECRやAmazon Linuxのパッケージリポジトリにどのようにアクセスすればいいのかをまとめています。

:::note info  
本ブログに記載した内容は個人の見解であり、所属する会社、組織とは全く関係ありません。
:::

:::note warn  
ビルドするイメージのベースイメージはAmazon Linux 2023（以下、AL2023）とします。
:::

## 構成

今回の構成は以下のようになっています。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571776/74b3c3eb-d6f0-2c47-5b40-41122f01464c.png)

## 手順

## 1. VPCエンドポイントの作成

他のAWSサービスと通信するため、以下のVPCエンドポイントを作成します。

| エンドポイント名 | 種別 |
| ---- | ---- |
| com.amazonaws.region.ecr.dkr | Interface |
| com.amazonaws.region.ecr.api | Interface |
| com.amazonaws.region.s3      | Gateway   |

## 2. ECRのプルスルーキャッシュ機能の有効化

Amazon ECR Public Gallery等にあるパブリックのリポジトリからpullしたイメージをベースにしてビルドしたい場合、ECRのプルスルーキャッシュを有効化する必要があります。  
プルスルーキャッシュとは、パブリックのリポジトリから、ECRのプライベートリポジトリにコンテナイメージをキャッシュできる機能です。  
設定方法については以下を参考に実行しました。  
<https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/pull-through-cache.html>  


## 3. IAMの設定

ECRへアクセスできるように以下のポリシーをEC2に付与します。  
ECRからのイメージのpullの他に、プルスルーキャッシュ機能を使うための権限を付与しています。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchImportUpstreamImage",
                "ecr:CreateRepository"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken"
            ],
            "Resource": "*"
        }
    ]
}
```

## 4. パッケージリポジトリへのアクセス

ビルド時に追加でパッケージのインストールを行いたい時があるかと思います。  
Amazon LinuxにおけるパッケージリポジトリはS3でホストされているため、S3のエンドポイントを経由することでアクセス可能です。  
なおパッケージリポジトリへのアクセスに際し、S3へのGet権限は不要です。

> **Amazon Linux 2023**  
> al2023-repos-\<region\>-de612dc2.s3.dualstack.\<region\>.amazonaws.com  
> 
> **Amazon Linux 1**  
> repo.\<region\>.amazonaws.com  
> 
> **Amazon Linux 2**  
> amazonlinux.\<region\>.amazonaws.com  
>
> 参考：<https://repost.aws/ja/knowledge-center/ec2-troubleshoot-yum-errors-al1-al2>

なお、ECR Public Gallery等から取得したパブリックなイメージの場合、アクセスするパッケージリポジトリはインターネット上のものとなっているため、S3にホストされたパッケージリポジトリへと変更する必要があります。  
`dnf install` 等でアクセスしに行く先のパッケージリポジトリはAL2023の場合、 `/etc/yum.repos.d/amazonlinux.repo` で定義されているため、このファイルを変更します。  
以下のように、mirrorlistのURLを変更します。  

:::note warn  

- `<region>`は適切なリージョンに置き換えてください。  
- `<repository-version>` は `2023.6.20241031` のように、取得しに行くパッケージリポジトリのバージョンを指定可能です。  
最新のパッケージを取得したい際は、AL2023の最新のリリースを確認し、変更してください。  
<https://docs.aws.amazon.com/ja_jp/linux/al2023/release-notes/relnotes.html>  

:::

```txt
[amazonlinux]
name=Amazon Linux 2023 repository
mirrorlist=https://al2023-repos-<region>-de612dc2.s3.dualstack.<region>.amazonaws.com/core/mirrors/<repository-version>/x86_64/mirror.list
priority=10
enabled=1
repo_gpgcheck=0
type=rpm
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-amazon-linux-2023

[amazonlinux-source]
name=Amazon Linux 2023 repository - Source packages
mirrorlist=https://al2023-repos-<region>-de612dc2.s3.dualstack.<region>.amazonaws.com/core/mirrors/<repository-version>/SRPMS/mirror.list
enabled=0
repo_gpgcheck=0
type=rpm
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-amazon-linux-2023
metadata_expire=6h

[amazonlinux-debuginfo]
name=Amazon Linux 2023 repository - Debug
mirrorlist=https://al2023-repos-<region>-de612dc2.s3.dualstack.<region>.amazonaws.com/core/mirrors/<repository-version>/debuginfo/x86_64/mirror.list
enabled=0
repo_gpgcheck=0
type=rpm
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-amazon-linux-2023
metadata_expire=6h
```

コンテナ内でこの`amazonlinux.repo`を利用する必要があるので、Dockerfileでコンテナ内にコピーして上書きするようにしておきます。

```docker
COPY ./amazonlinux.repo /etc/yum.repos.d/amazonlinux.repo 
```

## 5. ビルドの実行

手順1~3で、ビルドに必要な準備は整ったので、ビルドを実行します。
`docker build` の前に、今回のビルドではECRからベースイメージを取得するため、ECRへの認証を行っています。リージョン名やアカウントIDは正しいものに置き換えてください。

```sh
aws ecr get-login-password --region region | docker login --username AWS --password-stdin aws_account_id.dkr.ecr.region.amazonaws.com
docker build . -t test-image
```

## 最後に

普段はインターネット環境やCodeBuildでビルドしていたためあまり意識していませんでしたが、イメージやパッケージをどのように取得しているのかを理解できたので良かったです。