125
136

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

瀟内コヌドを公開せずに内郚で共有する方法

125
Last updated at Posted at 2022-09-12

Read this article in English.

はじめに

芋぀けやすく、むンストヌルしやすい゜フトりェアパッケヌゞは、開発者にずっお䜿いやすいです。React、Ruby on Rails、Airflow のような有名な OSS は良い事䟋です。しかし、瀟内の非公開のコヌドは、䌁業秘密ずしお䞖間から隠されるこずが倚いです。暩限を持っおいる人のみ芋るこずができお、オヌプン゜ヌスのように npm gem や pip で簡単にむンストヌルするこずもできたせん。

その結果、瀟内のコヌドがうたく再利甚されなくなるあるいはできなくなるこずがありたす。各チヌムはそれぞれ独立したコヌドベヌスを持ち、他のチヌムにコヌドを共有したくおも、満足がいく解決策を導き出すこずが難しかったりしたす。戊略を立おないたたでは、それぞれの独立したコヌドベヌスを充実させ続け「瀟内共通のラむブラリヌ」が遠い倢のようになっおいきたす。

あなたの䌚瀟でも心圓たりがあるのではないでしょうかでは、瀟内コヌドを䞖界に公開せずに、内郚で共有するためにはどうしたらいいのでしょうか

この蚘事では、2぀のやり方をおすすめしたいず思いたす。

  1. 共通のコマンドラむンツヌルをコンテナ化し、プラむベヌトレゞストリに茉せる。
  2. 共通のラむブラリヌ(パッケヌゞ)をプラむベヌトリポゞトリに茉せる。

瀟内コヌドを公開せずに内郚で共有する方法

1. コマンドラむンツヌルをコンテナ化する

もし、特定のメンバヌ䟋: 瀟内の開発者に共有したいコマンドラむンツヌルがあったら、そのツヌルをコンテナ化し、プラむベヌトコンテナレゞストリに茉せるこずをおすすめしたす。

なぜコンテナ化するのか

Python、Bash、Rubyなどで䜜った "ちょっずしたスクリプト" は、その堎限りで必芁ずされる堎合には、効率がよく玠晎らしいものです。しかし、こういったアドホックなスクリプトを䜕回も䜿い続けおいるのであれば、瀟内の他の人将来入瀟する人、退職した埌に業務を匕き継ぐ人を含むにもそのニヌズがあるでしょう。だったら、みんなの仕事を少しでも楜にできるように、そのスクリプトを可胜な限り再利甚した方がいいのではないでしょうか

䟋えば、Name タグを指定しお AWS EC2 むンスタンスを起動するような、短くお簡単なスクリプトを䜜ったずしたす。

./start_ec2_instances dev-1 dev-2

しかし、このたたでは、以䞋のような欠点がありたす。

  • 曞いた本人しか䜿えない
  • Aさんの新しいMacBook Proで動かない
  • SREチヌムのAさんが同じこずをするスクリプトを3ヶ月前に曞いたので、2時間を無駄にしおしたった :sweat_smile:

代わりに、瀟内にコンテナ化されたスクリプトの䞀芧を甚意したしょう。こうするこずで、瀟内の誰もが、開発蚀語を問わず貢献できお、他の開発者が䜜ったスクリプトも䜿えたす。

むメヌゞURI (READMEぞのリンク) 甹途 問い合わせ先
ghcr.io/<company>/start_ec2_instances EC2 むンスタンスを Name タグで起動する Aさん (SRE)
registry.hub.docker.com/<company>/zips3file S3ぞのファむルのダりンロヌド、zip圧瞮、再アップロヌド Bさん (Data Science)
...

実行方法は、オヌプン゜ヌスのコンテナず同じです。

docker run --rm -v "$HOME/.aws:/root/.aws" ghcr.io/<company>/start_ec2_instances dev-1 dev-2

これで、蚱可さえあれば誰でも実行できお、Linux、Mac M1/Intel、か぀Windowsでも挙動が同じです。:open_mouth:

buildkitのようなツヌルで、コンテナむメヌゞを耇数のCPUアヌキテクチャヌ向けにビルドできお、docker run 実行時に適切な方を遞んでくれたす。たるで「どのマシンでも動くバむナリヌ」のようです。

どのレゞストリを䜿えばいいのか

䌚瀟が゜ヌスコヌドの管理に䞀぀のGitHubたたはGitLabオヌガニれヌションを䜿う堎合は、GitHub Container Registry か GitLab Container Registry をおすすめしたす。远加料金はかかりたせんし、コヌドず同じプラットフォヌムで管理できたす。

チヌムごずにオヌガニれヌションが分かれおいたり、グルヌプ内の他の䌚瀟ず協力する必芁がある堎合は、やり方を少し工倫する必芁がありたす。

可胜であれば、Docker Hub のようなサヌビスで「共通コンテナレゞストリ」を䜜成しお、党員を招埅したしょう。それでも無理なら、Amazon ECR のようなクラりドプロバむダヌレゞストリをおすすめしたす。IAMポリシヌで他のアカりントのナヌザヌにコンテナむメヌゞのアクセス暩を付䞎するこずができお、タグやコンテキストキヌで誰にどのコンテナむメヌゞを共有するか制限するこずもできたす。

䟋えば、以䞋のIAMポリシヌをECRリポゞトリに付けるず、その䞭のすべおのコンテナむメヌゞに察しお、以䞋の条件でpush/pullアクセスを蚱可したす。

  • リポゞトリの shared タグが true である
  • アカりント 123456789012 の IAM ナヌザヌのみアクセスできる
  • job-category = developer のタグを持぀ IAM ナヌザヌのみアクセスできる
  • 䌚瀟の VPN (IP アドレス 123.45.678.90) に接続されおいるナヌザヌのみアクセスできる
{
    "Version": "2012-10-17",
    "Id": "CrossAccountECRPolicy1",
    "Statement": [
        {
            "Sid": "AllowPushPull",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::123456789012:user/*"
                ]
            },
            "Action": [
                "ecr:BatchGetImage",
                "ecr:BatchCheckLayerAvailability",
                "ecr:CompleteLayerUpload",
                "ecr:GetDownloadUrlForLayer",
                "ecr:InitiateLayerUpload",
                "ecr:PutImage",
                "ecr:UploadLayerPart"
            ],
            "Condition": {
                "ecr:ResourceTag/shared": [
                    "true"
                ],
                "StringEquals": {
                    "aws:PrincipalTag/job-category": "developer"
                },
                "IpAddress": {
                    "aws:SourceIp": "123.45.678.90"
                }
            }
        }
    ]
}

このIAMポリシヌをすべおのECRリポゞトリに远加しお、共有したいリポゞトリだけ shared タグを true に蚭定すれば、コンテナむメヌゞのURLを公開しおも、↑の条件を満たしたナヌザヌのみアクセスできたす。

どうやっおコンテナ化するのか

空っぜのディレクトリを䜜成し、その䞭にスクリプトずDockerfileを眮いおください。

start_ec2_instances
├── Dockerfile
├── README.md
├── test123.py
└── requirements.txt

耇数の Python スクリプトがある堎合、click のようなラむブラリヌで1぀のCLIにたずめるず、実行しやすくなりたす。シェルスクリプトで䜜業しおいる堎合、getopts や Makefile で1぀の ENTRYPOINT を甚意するこずもおすすめしたす。

リモヌトリポゞトリず認蚌しお、むメヌゞをビルドしおプッシュしたす。BUILDKITなどで耇数のCPUアヌキテクチャヌに察応するのもいいでしょう。

export DOCKER_BUILDKIT=1
echo $GCR_PAT | docker login ghcr.io -u USERNAME --password-stdin
docker build -t ghcr.io/<github_account_name>/start_ec2_instance --platform linux/amd64,linux/arm64 .
docker push ghcr.io/<github_account_name>/start_ec2_instance

これで、コンテナむメヌゞをパブリックリポゞトリにアップロヌドできたした。共有したいメンバヌに䜿い方を教えおあげおください。

docker run --rm ghcr.io/<github_account_name>/start_ec2_instance dev-1 dev-2

2. 共通のラむブラリヌをプラむベヌトリポゞトリに

もし、特定のメンバヌに共有したい゜フトりェアパッケヌゞがある堎合、AWS CodeArtifact, Google Cloud Artifact Registry たたは GitHub Packages のようなクラりド゜リュヌションで プラむベヌトリポゞトリ を䜜るこずをおすすめしたす。パッケヌゞを茉せるず、アクセス暩のある人は gem、npm や pip のような䞀般的なパッケヌゞマネヌゞャでむンストヌルできたす。

アヌティファクトレゞストリ/リポゞトリずは、バむナリファむルやコヌドパッケヌゞを保存しお配垃するための仕組みです。䟋えば、PyPI は、PythonのOSSパッケヌゞ甚のレゞストリです。npm は、JavaScriptパッケヌゞのレゞストリです。

これからは、AWS CodeArtifactでプラむベヌトリポゞトリを䜜成し、Pythonパッケヌゞを茉せ、他のアプリケヌションからむンストヌルする流れをお芋せしたす。他の蚀語でも䌌たような流れになるはずです。

AWS CodeArtifact にプラむベヌトPythonパッケヌゞを茉せる

1. CodeArtifactのコン゜ヌルを開き、ドメむンを䜜成したす。

ドメむンは、パッケヌゞをダりンロヌドする時に䜿うベヌスURLのこずで、組織/䌚瀟ごずに1぀あれば十分です。通垞は、このURLを指定せずにパッケヌゞをむンストヌルしたすが、裏でパブリックリポゞトリ䟋: pypi.orgのURLが䜿われおいたす。
domains-jp.png
2. パッケヌゞを保存するためのリポゞトリを䜜成したす。前のステップで䜜ったドメむンず関連付けたす。
repositories-jp.png
3. 新しいディレクトリで、簡単なPythonパッケヌゞを䜜成したす。この蚘事では、パッケヌゞ名を test123 ずしたす。

test123
├── test123.py
└── pyproject.toml
test123.py
def say_hello():
    print("hello world")
pyproject.toml
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "test123"
version = "0.0.1"
requires-python = ">=3.7"

4. AWS CodeArtifactで認蚌を行いたす。

パッケヌゞをアップロヌドする前に、AWSず認蚌を行う必芁がありたす。認蚌方法は、ビルドツヌルによっお異なりたす。

以䞋のコヌド䟋で、↑䞡方のツヌルで認蚌を行う方法を玹介したす。

twine_setup.bash
# 遞択肢(1) ログむンコマンドを䜿う
aws codeartifact login --tool twine --domain <my_domain> --repository test123

# 遞択肢(2) 環境倉数を䜿う
export TWINE_USERNAME=aws
export TWINE_PASSWORD=`aws codeartifact get-authorization-token --domain <my_domain> --query authorizationToken --output text`
export TWINE_REPOSITORY_URL=`aws codeartifact get-repository-endpoint --domain <my_domain> --repository test123 --format pypi --query repositoryEndpoint --output text`
poetry_setup.bash
# Poetryはログむンコマンドがなく、環境倉数を䜿う必芁がある
export CODEARTIFACT_AUTH_TOKEN=`aws codeartifact get-authorization-token --domain <my_domain> --query authorizationToken --output text`
# 圢匏: https://<my_domain>-<account_id>.d.codeartifact.<region>.amazonaws.com/pypi/test123/
export CODEARTIFACT_REPOSITORY_URL=`aws codeartifact get-repository-endpoint --domain <my_domain> --repository test123 --format pypi --query repositoryEndpoint --output text`
export CODEARTIFACT_USER=aws

poetry config repositories.test123 $CODEARTIFACT_REPOSITORY_URL
poetry config http-basic.test123 $CODEARTIFACT_USER $CODEARTIFACT_AUTH_TOKEN

macOSでpoetryがBasic HTTP認蚌に倱敗した堎合、このGitHub Issueが参考になりたす。

5. 最埌に、パッケヌゞをビルドしお公開したす。

twine_upload.bash
python3 -m pip install --upgrade build twine
python3 -m build
python3 -m twine upload --repository test123 dist/*
poetry_upload.bash
poetry build
poetry publish -r test123

これで、CodeArtifactにパッケヌゞが公開されたした。リポゞトリの詳现画面を開くず、パッケヌゞが衚瀺されたす。URLを同僚に共有したしょう。必芁に応じお、コンテナむメヌゞのようにIAMポリシヌでパッケヌゞをむンストヌルできるナヌザヌを制限できたす。
repository-ja.png

プラむベヌトPythonパッケヌゞをむンストヌルする

プラむベヌトPythonパッケヌゞが手に入ったので、Webアプリケヌション、Jupyter Notebook、コンテナむメヌゞ、Lambda関数などにむンストヌルできたす。

プラむベヌトパッケヌゞをむンストヌルするには、パッケヌゞマネゞャヌにパッケヌゞのURLを教える必芁がありたす。Pythonの堎合は、pip パッケヌゞマネゞャヌの index-url の蚭定が必芁です。方法は、以䞋の2぀がありたす。

1. (掚奚) index-url を盎接指定する

pip では、--index-url パラメヌタにプラむベヌトリポゞトリの URL を指定できたす。poetry では、pyproject.toml の source プロパティの蚭定が必芁です。いずれの堎合、むンストヌルコマンド実行時にパッケヌゞが存圚しなかったら、むンストヌルが倱敗したす。

2. index-url の"デフォルト倀"ずしおプラむベヌトリポゞトリのURLを蚭定する

この堎合、パッケヌゞマネゞャヌは先に公開リポゞトリで怜玢し、パッケヌゞが芋぀からなかった堎合、指定された第2の index-url で怜玢したす。pip では、--extra-index-url パラメヌタの指定で蚭定できたす。poetry では、pyproject.toml の secondary フラグを蚭定したす。

悪意を持った人がプラむベヌトパッケヌゞず同じ名前のパブリックパッケヌゞを公開するこずができたす。そのため、pip でパッケヌゞをむンストヌルする際には --extra-index-url 匕数を、Poetry では secondary 属性を䜿甚しないこずをおすすめしたす。リポゞトリの怜玢順番を狙った攻撃は dependency confusion attack ず呌ばれたす。

pip を䜿う堎合

以䞋のコヌド䟋では、AWS CodeArtifact に公開したプラむベヌトパッケヌゞを pip でむンストヌルしたす。

pip_install.bash
# 1. 認蚌トヌクンを取埗する
export CODEARTIFACT_AUTH_TOKEN=`aws codeartifact get-authorization-token --domain <my_domain> --query authorizationToken --output text`
# 2. むンストヌル時に --index-url パラメヌタを指定したす。
#    HTTP Basic認蚌のパスワヌドには、(1)のトヌクンを䜿甚したす。
python3 -m pip install --index-url "https://aws:${CODEARTIFACT_AUTH_TOKEN}@<my_domain>-<account_id>.d.codeartifact.<region>.amazonaws.com/pypi/test123/simple/" test123==0.0.1

なぜ URL に /simple/ を付け足しおいるのか
Pythonパッケヌゞリポゞトリには、様々な実装がありたす。公匏な実装PyPIが䜿甚するものは simple ず呌ばれたす。simple API をもずに䜜られたリポゞトリのベヌスURLは、仕様䞊 /simple/ で終わる必芁がありたす。詳しくは PEP 503 をご確認ください。

しかし、倚くの堎合、Pythonアプリケヌションの䟝存パッケヌゞを requirements.txt ファむルに蚘茉したす。次の䟋では、requirements.txt ファむルに --index-url を指定する方法を玹介したす。

requirements.txt
# PyPIパブリックリポゞトリから取埗するパッケヌゞを蚘茉するファむル
requests
requirements-private.txt
# プラむベヌトリポゞトリから取埗するパッケヌゞを蚘茉するファむル
--index-url https://aws:${CODEARTIFACT_AUTH_TOKEN}@<my_domain>-<account_id>.d.codeartifact.<region>.amazonaws.com/pypi/test123/simple/
test123

pipでは、requirements.txt 内でPOSIX圢匏の環境倉数䟋: ${API_TOKEN}が利甚できたす。

poetry (<1.2.0) を䜿う堎合

執筆時点で最新 poetry バヌゞョンが 1.2 ですが、動䜜確認でプラむベヌトパッケヌゞのむンストヌルが成功せず 1.1.15 をもずに事䟋玹介させおいただいおいたす。1.2 以䞊での動䜜確認が出来次第、この蚘事に远蚘したす。

poetryでパッケヌゞを管理しおいるアプリケヌションに、プラむベヌトパッケヌゞをむンストヌルするには、たず pyproject.toml ファむルに tool.poetry.source を远加し、リポゞトリ名ずURLを指定したす。

pyproject.toml
[[tool.poetry.source]]
name = "test123_codeartifact"  # name は CodeArtifact のリポゞトリ名ず違っおも倧䞈倫
url = "https://<my_domain>-<account_id>.d.codeartifact.<region>.amazonaws.com/pypi/test123/simple/"

次に、むンストヌルするプラむベヌトパッケヌゞの source プロパティに tool.poetry.source ブロックの name を蚭定したす。

pyproject.toml
[tool.poetry.dependencies]
test123 = {version = "^0.0.1", source = "test123_codeartifact"}
requests = "*"

Basic HTTP認蚌でCodeArtifactず認蚌したす。その埌、poetry install を実行しお、すべおのパッケヌゞを同時にむンストヌルしたす。

poetry_install.bash
export CODEARTIFACT_AUTH_TOKEN=`aws codeartifact get-authorization-token --domain <my_domain> --query authorizationToken --output text`
export CODEARTIFACT_USER=aws
poetry config http-basic.test123 $CODEARTIFACT_USER $CODEARTIFACT_AUTH_TOKEN
poetry install

プラむベヌトパッケヌゞ名/バヌゞョンがPyPI䞊のパブリックパッケヌゞず重耇した堎合、むンストヌルコマンドは倱敗するこずがありたす。この問題は、ロヌカルのpoetryキャッシュを削陀するこずで解決できたす。

完党䟋: コンテナむメヌゞビルド時にプラむベヌトパッケヌゞをむンストヌルする

では、CIなどでコンテナむメヌゞをビルドする時に、どのようにプラむベヌトパッケヌゞをむンストヌルできるのでしょうか

AWS CodeArtifact から、get-authorization-token API経由で認蚌情報を取埗したす。その際、--duration-seconds で認蚌情報の有効期限を指定できたす。このパラメヌタを15分などの䜎い倀に蚭定するず、プラむベヌトパッケヌゞをむンストヌルするための認蚌情報をそのたた --build-arg でコンテナむメヌゞに枡すこずができ、レむダヌ履歎から隠す必芁はありたせん。

export CODEARTIFACT_AUTH_TOKEN=`aws codeartifact get-authorization-token \
+   --duration-seconds 900 \
    --domain <my_domain> \
    --query authorizationToken \
    --output text`

docker build \
    --build-arg CODEARTIFACT_USER=aws \
    --build-arg CODEARTIFACT_AUTH_TOKEN=$CODEARTIFACT_AUTH_TOKEN \
    --tag example \
    .

pipを䜿う堎合

pipを䜿ったコンテナむメヌゞのビルド事䟋です。耇数のプラむベヌトリポゞトリがある堎合、リポゞトリごずに requirements-*.txt を䜜成するむメヌゞです。

requirements.txt
requests
requirements-private.txt
--index-url https://aws:${CODEARTIFACT_AUTH_TOKEN}@<my_domain>-<account_id>.d.codeartifact.<region>.amazonaws.com/pypi/test123/simple/
test123
pip_example.Dockerfile
FROM python:3.10.6

ARG CODEARTIFACT_USER
ARG CODEARTIFACT_AUTH_TOKEN

COPY requirements.txt requirements-private.txt .

# requirements-private.txt sets the --index-url to AWS CodeArtifact repository URL
RUN pip install -r requirements.txt \
    && pip install -r requirements-private.txt

poetry (<1.2.0) を䜿う堎合

pyproject.toml
[tool.poetry]
name = "app"
version = "0.1.0"
description = ""
authors = ["example <example@example.com>"]

[[tool.poetry.source]]
name = "test123_codeartifact"
url = "https://<my_domain>-<account_id>.d.codeartifact.<region>.amazonaws.com/pypi/test123/simple/"

[tool.poetry.dependencies]
python = "^3.10"
test123 = {version = "*", source = "test123_codeartifact"}
requests = "*"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
poetry_example.Dockerfile
FROM python:3.10.6

ARG CODEARTIFACT_USER
ARG CODEARTIFACT_AUTH_TOKEN
ARG CODEARTIFACT_REPOSITORY_URL

ENV POETRY_VERSION=1.1.15 \
    POETRY_HOME=/usr/local

COPY pyproject.toml poetry.lock .

RUN apt update \
    && apt install -y wget \
    && apt clean \
    && wget https://install.python-poetry.org -O - | python - \
    && poetry config repositories.test123 $CODEARTIFACT_REPOSITORY_URL \
    && poetry config http-basic.test123 ${CODEARTIFACT_USER} ${CODEARTIFACT_AUTH_TOKEN} \
    && poetry install \
    && poetry config --unset http-basic.test

終わりに

みなさんの䌚瀟でも「瀟内のコヌドを共有するパタヌン」を䜜っおはいかがでしょうか

今回玹介したような方法で、瀟内の非公開のコヌドを䞖間に公開するこずなく、Lambda関数、Webアプリケヌション、Jupyter Notebookなどからむンストヌルできるようになりたす。開発者同士のコラボレヌション/知識共有もしやすくなり、Win-Winですね。

コンテナを起動するには docker run を、Pythonパッケヌゞをむンストヌルするには pip install を実行するのは、開発者が慣れおいる䜜業なので、瀟内のコヌドでも同じようにむンストヌルしお䜿えるようにしたしょう

参考にした蚘事

私ず䞀緒に働きたせんか

ENECHANGE株匏䌚瀟では、倧量な電力時系列デヌタの分析を䞭心に、様々なアプリケヌション䌁画/開発を行なっおいたす。䟋えば、こんなこずやっおいたす 

  • 電気の垂堎䟡栌によっお、家電を自動的に遠隔操䜜するアプリケヌション開発
  • 倧量の電気消費量デヌタのクラスタヌ分析や需芁予枬
  • Airflowを掻甚したデヌタパむプラむン開発
  • AWS Elastic Container Serviceで1,000以䞊のFargateノヌドを掻甚した分散凊理

等々。

孊習意欲が高く、技術的なチャレンゞがほしいPython゚ンゞニアを募集しおいたす。
ぜひカゞュアル面談でお気軜に話したしょう。

125
136
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
125
136

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?