Skip to main content

Dockerラベル / OCIコンテナアノテーションの使い方と使いどき

blog feature docker labels

2021年11月3日

0 分で読めます

ほとんどのコンテナイメージは、OCI準拠イメージのレイヤーを構築するために、FROM、RUN、COPY、ENTRYPOINTなどの命令を組み合わせたDockerfileを使ってビルドされます。しかし、意外なほどあまり使われていない命令がLABELです。この記事では、ラベル(OCI Image Specificationでは「アノテーション」と呼ばれます)とは何か、標準化された用途、そしてコンテナのセキュリティ態勢を強化するために活用できる方法について掘り下げます。

この記事では、アノテーションではなく、より一般的に使われている「ラベル」という呼び方を使います。それでは始めましょう。

Dockerイメージのラベルとは?

Dockerイメージのラベルを使うと、イメージ自体にキーと値のペアでメタデータを追加できます。このデータはイメージを使って実行するコンテナには公開されませんが、イメージのソースコードの場所、サポート担当者、イメージを作成したCIビルドなどを記録するのに役立ちます。

Docker / OCIイメージのメタデータを解説

ソフトウェアパッケージを作成したことがあれば、一般に、パッケージにはソフトウェア、設定、場合によっては機能データと、パッケージ自体に関するメタデータが含まれることをご存じでしょう。

たとえば、Javaの.jarファイルは基本的に.zipアーカイブですが、どのファイルにも最上位のMETA-INFディレクトリがあり、Java 2 Platform specによると、「Java 2 Platformがアプリケーション、拡張機能、クラスローダー、サービスを設定するために認識し、解釈する」複数のファイルやディレクトリが含まれています。人気のビルドツールMavenで作成された.jarを開くと、通常はmavenディレクトリがあり、その中には.jarのビルドに使われた有効なMavenのpom.xmlやpom.propertiesなどが含まれています。(ちなみに「POM」はMavenのProject Object Modelの略です)

RPM、APT、NPMをはじめとするほとんどのパッケージ管理ツールにも、同様のメタデータが格納されています。これらは、含まれるソフトウェアのインストールや実行時にツールが使用したり、リポジトリや実行時監視システムが利用したりします。

コマンド、エントリーポイント、ユーザー、環境変数、引数、ラベル、イメージサイズが表示されたDockerイメージの履歴を示すターミナルのスクリーンショット。

コンテナイメージのレイヤーにもメタデータが格納されています。イメージの「履歴」を一覧表示すると、ファイルシステムに変更を加えず、実行時に使われるメタデータだけを含むため、サイズが0バイトのレイヤーがよく見つかります。こうしたメタデータは、一般に次のDockerfileコマンドで追加されます。

  • USER:プロセスを実行するユーザー

  • ENV:プロセス環境に設定する変数とその値

  • ARG:コンテナのビルド環境に渡され、ビルドの範囲内で環境変数のように使われるビルド引数

  • CMD:プロセスの起動に使うコマンドやパラメーター(ENTRYPOINTも同様)

  • LABEL:実行エンジンでは使用されないキーと値のペア

これらの多くは広く知られており、あらゆるDockerfileで使われています。しかし、ラベルのメタデータはコンテナの実行に必須ではないため、見落とされがちです。

コンテナイメージのラベルを使うべき理由

イメージにラベルを使う理由はさまざまです。バージョン情報の記録、プロジェクトのメンテナーへの連絡先の追加、実行時の利用情報の記録などに活用できます。最も一般的な用途の1つは、イメージの構築に関する情報を記録し、イメージ成果物のソフトウェアサプライチェーン情報として利用することです。

Dockerラベル / OCIイメージアノテーションのメタデータの種類

標準化されたラベル

イメージの作成元や由来に関するメタデータは広く使われているため、OCIチームは「org.opencontainers.image.」をプレフィックスとする標準のキーセットを公開しています。たとえば次のようなキーがあります。

  • source:イメージのビルドに使うソースコードのURL

  • revision:パッケージ化されたソフトウェアのソース管理リビジョン識別子

  • base.digest:このイメージのベースとなるイメージのダイジェスト(ハッシュ)

  • base.name:このイメージのベースとなるイメージの参照情報

  • version:パッケージ化されたソフトウェアのバージョン

カスタムラベル

単純なキーと値のペアなので、プロジェクトや組織のニーズに合わせてほぼ自由に指定できます。たとえば、次のような項目が考えられます(いずれも「com.mycorp.myteam.」のようなプレフィックスを付けられます)。

  • ci-build:イメージを生成したCIプロジェクトの実行URL

  • releasenotes:パッケージ化されたソフトウェアのリリースノート

  • healthz:ヘルスチェック用のHTTPエンドポイント

  • docker.run:このイメージを実行するDockerコマンドの例

  • k8s.deployment:このイメージを使ったKubernetesデプロイ用のBase64エンコード済みYAML

最後の例は興味深いものです。実際、ラベルキーの値には、Base64でエンコードできるものならほぼ何でも保存できます。つまり、イメージをプルして次のようなコマンドを実行すれば、Kubernetesクラスターで使えるサンプルのYAMLデプロイファイルを取得できます。

$ docker image inspect myimage:tag | jq -r ".[].Config.Labels.\"com.mycorp.myteam.k8s.deployment\"" | base64 -d
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: snyk
  name: snyk
spec:
  replicas: 1
  selector:
    matchLabels:
      app: snyk
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: snyk
    spec:
      containers:
      - image: ericsmalling/snyklabeldemo:m
        name: snyklabeldemo
        resources: {}
status: {}

これをそのままkubectlにパイプして、すぐにデプロイすることもできます。Helmチャートも、Gitリポジトリ内の個別のYAMLファイルも必要ありません。

docker image inspect myimage:tag | jq -r ".[].Config.Labels.\"com.mycorp.myteam.k8s.deployment\"" | base64 -d | kubectl apply -f - 

deployment.apps/snyk created

Dockerラベル / OCIアノテーションを活用する

ご想像のとおり、ラベルにはCIシステムがアクセスできる任意の値を設定できます。ラベルを確認するだけで、イメージや実行中のコンテナをそのソースやドキュメントなどと関連付けられます。たとえば、組織がOCI標準のorg.opencontainers.image.sourceラベルを使って、イメージのソースとなるSCMリポジトリのURLを登録しているとします。特定のDockerホスト上で稼働しているイメージのリポジトリをすべて調べたい場合は、次のようなコマンドを実行できます。

$ docker inspect $(docker ps -q) --format='{{ .Id }} {{ index .Config.Labels "org.opencontainers.image.source" }}'

17f4ee967870c49d3ffeb1c49973071c99c63377b2f9bbf987f7c3e4a21d331c https://repo.mycorp.com/team-volton/redlion
c958ffc87c2bd5af500d24eff1ccb3ee21992a5cbcb429fafcc651aa182b66ba <no value>

出力には実行中の2つのコンテナIDが表示され、そのうちラベルが付いたコンテナについては、その値も出力されています。

Kubernetesクラスターで実行する場合は、少し複雑になります。通常、クラスターのノード上にあるコンテナエンジンのソケットにはアクセスできないためです。残念ながら、kubectlからこれらのラベルにアクセスするAPIはありません。そのため、少し工夫が必要です。次のbashスクリプトは、現在のコンテキストの名前空間で実行中のイメージを見つけ、イメージレジストリに問い合わせてイメージのメタデータを取得し、ラベル情報を返します。

$ cat labelgrep.sh
#!/bin/bash
FINDLABEL=$1
FINDVAL=$2

IMAGES=$(kubectl get pods -o json | jq -r ".items[].spec.containers[].image" | uniq)

for i in $IMAGES; do
	VAL=$(regctl image inspect ${i} --format '{{ index .Config.Labels "'${FINDLABEL}'" }}')
	if [[ "$VAL" != "" && ( "$FINDVAL" == "" || "$VAL" == "$FINDVAL") ]]; then
	  echo "[${i}] ${FINDLABEL}=${VAL}"
  fi
done

ここでは、優れたオープンソースのregclientプロジェクトが提供するregctlツールを使っています。イメージをローカル環境にプルして調査する必要がなく、レジストリから直接イメージ情報を取得できます。また、コンテナランタイムエンジンがなくても、どこでもこのスクリプトを実行できます。

では、これをクラスターに対して実行し、クラスター内で稼働しているイメージのリポジトリを確認してみましょう。

$ ./labelgrep.sh org.opencontainers.image.source
[images.mycorp.com/voltron/redlion] org.opencontainers.image.source=https://repo.mycorp.com/team-volton/redlion
[images.mycorp.com/voltron/bluelion] org.opencontainers.image.source=https://repo.mycorp.com/team-volton/bluelion

ご覧のとおり、現在クラスター内では、org.opencontainers.image.sourceラベルが付いたイメージが2つ、Pod内で実行されています。

ここでは比較的シンプルな例を紹介しましたが、考え方を応用して、組織のニーズに合ったスクリプトやAPI呼び出しを作成できるはずです。

Snykとのインテグレーション

セキュリティの観点から特に興味深いのは、Snykのイメージスキャンで、イメージラベルを使ってスキャンしたイメージとそのDockerfileを自動的に関連付けられるようになったことです。

Snykのソースコードリポジトリとのインテグレーションでは、コード内のDockerfileを静的に検出してスキャンできるほか、コンテナレジストリからインポートしたイメージもスキャンできます。しかし、最近まで両者の相互参照は自分で管理する必要がありました。Dockerfileへの参照をイメージに手動で追加するか、API呼び出しによる独自の自動化を実装する必要があったのです。

今では、DockerfileにOCI標準のorg.opencontainers.image.sourceラベルを追加し、Dockerfileを含むリポジトリのURLを指定するだけで、イメージのインポート時にSnykが自動で相互参照します。

リンクされたイメージ「docker-imageleric」が赤い注釈で強調表示された、Dockerイメージの詳細ページ。

自動的にリンクされたイメージスキャンプロジェクトの例

まとめ

まとめると、見過ごされがちなイメージのラベル/アノテーションは、イメージに直接メタデータを埋め込める強力なツールです。標準化されたキーを使えば、イメージの出所を記録できるだけでなく、デプロイツールやセキュリティツールに活用して、デプロイ環境をより的確に把握できます。

アカウント内でスキャンしているDockerfileに、OCI標準のorg.opencontainers.image.sourceラベルを追加するだけで、Snykのイメージ自動リンク機能を今すぐ利用できます。Snykアカウントをお持ちでない方は、無料で登録してすぐにお試しください。

皆さんがラベルをどのように活用しているのか気になります。今回紹介したアイデアは新しいものでしょうか。それとも、すでにプロジェクトで使っていますか?ほかにどんな方法でイメージにアノテーションを付けていますか?Snykや他のツールに実装してほしい新しいインテグレーションはありますか?アイデアをTwitterで教えてください(@ericsmalling)。ぜひお聞かせください。

開発者ファーストのコンテナセキュリティ

Snykは、コンテナイメージとKubernetesワークロードの脆弱性を検出し、自動的に修正します。