LoginSignup
4
3

More than 3 years have passed since last update.

【AWS】CDKでECRを構築しよう

Last updated at Posted at 2020-09-04

みなさんAWS CDK使っていますか?
私はCFnを使用していたのですがYAMLで書くのがいろいろ辛くなってきたので、最近AWS CDKに乗り換えました

という訳で今回は、AWS CDKを使ったECRの構築方法を書いていきたいと思います

環境

language python3.8 pipenv

前提

以下のコマンドがインストール済み

  • pipenv
  • aws-cdk

ディレクトリ構成

.
├── Pipfile
├── Pipfile.lock
├── README.md
├── app.py # CDKのPython用メインスクリプト
├── cdk.json # CDKのコンフィグ
├── cdk.out # CDKから出力されたCFn templateなどが格納される
├── mypy.ini
├── src
│   ├── __init__.py
│   ├── entity # リソースの実体を格納
│   ├── props # リソースのパラメータ定義クラス
│   └── stack # CFn stackを格納
└── tox.ini

ディレクトリやスクリプトの関係性

props/ -> entity/ -> stack/ -> app.py

上記のような関係性を保つことで変更に対して強くなりますし、環境ごとにパラメータを変えて管理したい場合にも対応します

インストール

必要なaws_cdkのライブラリをインストールしましょう

pipenv install aws_cdk.core aws_cdk.aws_ecr

実装

props/ecr.py

Python用のaws_cdkライブラリにも各リソースのPropsクラスがあるのですが、個人的に使い勝手がよくない印象なので、独自に定義しています
ここには必要なパラメータしか設定せずに、用途によってデフォルト値も公式のものから変更しています

CFnの場合、ライフサイクルルールをJSONテキストで書かなければなりませんが、CDKだとプロパディに値を渡すだけなので、かなり楽です

from dataclasses import dataclass
from typing import Optional

from aws_cdk.aws_ecr import TagStatus
from aws_cdk.core import RemovalPolicy

from src.props.base import Base


@dataclass(frozen=True)
class LifecycleRule(Base):
    description: Optional[str] = None
    max_image_count: int = 5
    rule_priority: int = 1
    tag_status: TagStatus = TagStatus.ANY


@dataclass(frozen=True)
class Repository(Base):
    id: str
    repository_name: str
    image_scan_on_push: Optional[bool] = None
    removal_policy: RemovalPolicy = RemovalPolicy.RETAIN

entity/ecr.py

作成したいリソースを定義を書いていきます
今回はクラスで定義していますが、インスタンス化させても良いと思います
クラスの方が個人的に体裁がよく見えるのでそうしているだけです

from typing import List, Optional

from src.entity.base import Base
from src.props.ecr import LifecycleRule, Repository


class EcrBase(Base):
    """ECR基底class"""

    repository: Repository
    lifecyle_rules: Optional[List[LifecycleRule]] = None


class SampleEcr(EcrBase):
    """Sample"""

    id = 'SampleEcr'

    repository = Repository(
        id='SampleEcrRepo',
        repository_name='sample'
    )

    lifecyle_rules = [
        LifecycleRule(
            description='Delete more than 10 images',
            max_image_count=10
        )
    ]

stack/ecr.py

ECR用のスタックを定義していきます
スタックのクラスに渡すリソース定義は基本的にentityだけになるはずです
あとは必要に応じてapp.pyで全体で共通して設定したいtagなどを引数に渡してあげましょう

from typing import Any, Type

from aws_cdk import core
from aws_cdk.aws_ecr import Repository

from src.entity.ecr import EcrBase


class EcrStack(core.Stack):
    def __init__(
            self,
            scope: core.Construct,
            entity: Type[EcrBase],
            **kwargs: Any) -> None:
        super().__init__(scope, entity.id, **kwargs)

        repo = Repository(self, **entity.repository.to_dict())

        if entity.lifecyle_rules:
            for rule in entity.lifecyle_rules:
                repo.add_lifecycle_rule(**rule.to_dict())

app.py

stack/ecr.pyに書いたスタックをデプロイするためにapp.pyに書いていきましょう

#!/usr/bin/env python3

from aws_cdk import core

from src.entity.ecr import SampleEcr
from src.stack.ecr import EcrStack


app = core.App()

# 全てのリソースに設定するタグ
tags = {'CreatedBy': 'iscream'}

EcrStack(app, entity=SampleEcr, tags=tags)

app.synth(skip_validation=False)

デプロイ

デプロイ方法は以下の2つです

pipenv run cdk deploy SampleEcr

OR

pipenv shell
cdk deploy SampleEcr

デプロイする際に注意して欲しいのはpipenvで仮想環境上でcdkコマンドを実行する点です
それを忘れると以下のようなエラーになります

Traceback (most recent call last):
  File "app.py", line 3, in <module>
    from aws_cdk import core
ModuleNotFoundError: No module named 'aws_cdk'
Subprocess exited with error 1

おわりに

CDKの場合はプログラミング言語でリソースを定義できるので、柔軟にリソースを管理することができます。
その反面、コードの設計をしっかりしないとスパゲッティになり、柔軟性がなくなり運用がつらくなります。
今回紹介した方法がベストプラクティスかはわかりませんが、ちゃんと機能ごとにディレクトリやファイルを分けて管理するだけでも運用はよくなると思います。

CDKはかなり良いプロダクトなので、ぜひ使ってみてください!!

Reference

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3