Kubernetes用に最適化されたコンテナの構築

前書き

コンテナイメージは、Kubernetes内でアプリケーションを定義するための主要なパッケージ形式です。 ポッドやその他のオブジェクトの基盤として使用される画像は、Kubernetesの機能を活用してプラットフォームでアプリケーションを効率的に実行する上で重要な役割を果たします。 適切に設計された画像は、安全で、パフォーマンスが高く、焦点が合っています。 Kubernetesが提供する構成データまたは指示に対応し、オーケストレーションシステムが内部アプリケーションの状態を理解するために使用するエンドポイントを実装することもできます。

この記事では、高品質の画像を作成するためのいくつかの戦略を紹介し、アプリケーションをコンテナ化する際の決定を導くためのいくつかの一般的な目標について説明します。 Kubernetesで実行することを目的としたイメージの構築に焦点を当てますが、提案の多くは、他のオーケストレーションプラットフォームまたは他のコンテキストでコンテナーを実行する場合にも等しく適用されます。

効率的なコンテナイメージの特性

コンテナイメージを構築するときに実行する特定のアクションを検討する前に、優れたコンテナイメージを作成する理由について説明します。 新しい画像をデザインするときの目標は何ですか? どの特性とどのような動作が最も重要ですか?

目指すべきいくつかの特性は次のとおりです。

明確に定義された単一の目的

コンテナイメージには、単一の個別のフォーカスが必要です。 コンテナイメージを仮想マシンとして考えることは避けてください。仮想マシンでは、関連する機能をまとめてパッケージ化することが理にかなっています。 代わりに、コンテナイメージをUnixユーティリティのように扱い、1つの小さなことをうまく行うことに厳密に焦点を合わせます。 コンテナの範囲外でアプリケーションを調整して、複雑な機能を構成できます。

実行時に構成を挿入する機能を備えた汎用設計

コンテナイメージは、可能な場合は再利用を念頭に置いて設計する必要があります。 たとえば、実稼働環境に展開する前にイメージをテストするなどの基本的な要件を満たすために、実行時に構成を調整する機能が必要になることがよくあります。 小さい汎用イメージをさまざまな構成で組み合わせて、新しいイメージを作成せずに動作を変更できます。

小さな画像サイズ

Kubernetesのようなクラスター環境では、より小さいイメージには多くの利点があります。 新しいノードにすばやくダウンロードされ、多くの場合、インストールされたパッケージのセットが小さくなり、セキュリティが向上します。 コンテナイメージを縮小することにより、関連するソフトウェアの量を最小限に抑えることで、問題のデバッグがより簡単になります。

外部管理状態

クラスター環境のコンテナでは、リソース不足、スケーリング、またはノード障害による計画的および計画外のシャットダウンなど、非常に不安定なライフサイクルが発生します。 一貫性を維持し、サービスの復旧と可用性を支援し、データの損失を防ぐために、コンテナの外部の安定した場所にアプリケーションの状態を保存することが重要です。

理解しやすい

コンテナイメージをできるだけシンプルで理解しやすいものにすることが重要です。 トラブルシューティングを行う場合、コンテナイメージの構成を表示したり、コンテナの動作をテストしたりすることで、問題について簡単に推論できるため、より迅速に解決に到達できます。 コンテナイメージをマシン構成ではなく、アプリケーションのパッケージ形式と考えると、適切なバランスをとることができます。

コンテナ化されたソフトウェアのベストプラクティスに従う

イメージは、コンテナモデルに対して機能するのではなく、コンテナモデル内で機能することを目的とする必要があります。 完全なinitシステムやデーモン化アプリケーションなど、従来のシステム管理プラクティスの実装は避けてください。 Kubernetesが内部ログデーモンを使用する代わりに管理者にデータを公開できるように、標準出力にログインします。 これらはそれぞれ、完全なオペレーティングシステムのベストプラクティスとは異なります。

  • Kubernetesの機能を完全に活用*

コンテナモデルに準拠するだけでなく、Kubernetesが提供する環境とツールを理解して調整することが重要です。 たとえば、稼働状態と準備状態のチェック用のエンドポイントを提供したり、構成または環境の変更に基づいて動作を調整すると、アプリケーションでKubernetesの動的展開環境を有利に活用できます。

高機能コンテナイメージを定義するいくつかの品質を確立したので、これらの目標を達成するのに役立つ戦略をさらに掘り下げることができます。

最小限の共有ベースレイヤーの再利用

最初に、コンテナイメージの作成元であるベースイメージを調べることから始めます。 各コンテナイメージは、親イメージ(開始点として使用されるイメージ)から、または抽象的な `+ scratch +`レイヤー(ファイルシステムのない空のイメージレイヤー)から構築されます。 _base image_は、基本的なオペレーティングシステムを定義し、コア機能を提供することにより、将来のイメージの基盤として機能するコンテナイメージです。 画像は、最終画像を形成するために互いに重ね合わされた1つ以上の画像レイヤーで構成されます。

`+ scratch `から直接作業する場合、標準のユーティリティやファイルシステムは利用できません。つまり、非常に限られた機能にしかアクセスできません。 ` scratch +`から直接作成された画像は非常に合理化され、最小限に抑えることができますが、その主な目的はベース画像を定義することです。 通常、すべてのイメージに対して完全なシステムを構築する必要がないように、アプリケーションを実行する基本的な環境を設定する親イメージの上にコンテナイメージを構築します。

さまざまなLinuxディストリビューションのベースイメージがありますが、選択するシステムについて慎重に検討することが最善です。 新しいマシンごとに、親イメージと追加した追加レイヤーをダウンロードする必要があります。 大きな画像の場合、これはかなりの量の帯域幅を消費し、コンテナの初回実行時の起動時間を著しく長くする可能性があります。 コンテナビルドプロセスでダウンストリームの親として使用される画像を切り詰める方法はないため、最小限の親から始めることをお勧めします。

Ubuntuのような機能豊富な環境では、使い慣れた環境でアプリケーションを実行できますが、考慮すべきトレードオフがいくつかあります。 Ubuntuイメージ(および同様の従来の配布イメージ)は、比較的大きい(100 MBを超える)傾向があります。つまり、それらから作成されたコンテナーイメージは、その重みを継承します。

Alpine Linuxは、多くの機能を非常に小さなベースイメージ(〜5MB)に正常にパッケージ化するため、ベースイメージの一般的な代替手段です。 かなりのリポジトリを備えたパッケージマネージャが含まれており、最小限のLinux環境に期待されるほとんどの標準ユーティリティがあります。

アプリケーションを設計する際には、各画像に同じ親を再利用することをお勧めします。 画像が親を共有する場合、コンテナを実行しているマシンは親レイヤーを一度だけダウンロードします。 その後は、画像間で異なるレイヤーをダウンロードするだけで済みます。 つまり、各画像に埋め込む共通の機能がある場合は、継承する共通の親画像を作成することをお勧めします。 系統を共有するイメージは、新しいサーバーにダウンロードする必要がある追加データの量を最小限に抑えるのに役立ちます。

コンテナレイヤーの管理

親イメージを選択したら、追加のソフトウェアの追加、ファイルのコピー、ポートの公開、実行するプロセスの選択により、コンテナイメージを定義できます。 イメージ構成ファイルの特定の指示(Dockerを使用している場合は + Dockerfile +)により、イメージにレイヤーが追加されます。

前のセクションで述べたのと同じ理由の多くのために、結果のサイズ、継承、ランタイムの複雑さのために、画像にレイヤーを追加する方法に注意することが重要です。 大きくて扱いにくい画像を作成しないようにするには、コンテナレイヤーの相互作用、ビルドエンジンがレイヤーをキャッシュする方法、同様の命令の微妙な違いが作成する画像に大きな影響を与える可能性について十分に理解することが重要です。

イメージレイヤーとビルドキャッシュについて

Dockerは、「+ RUN 」、「 COPY 」、または「 ADD +」命令を実行するたびに新しいイメージレイヤーを作成します。 イメージを再度ビルドする場合、ビルドエンジンは各命令をチェックして、操作用にキャッシュされたイメージレイヤーがあるかどうかを確認します。 キャッシュ内で一致するものが見つかった場合、命令を再実行してレイヤーを再構築するのではなく、既存の画像レイヤーを使用します。

このプロセスはビルド時間を大幅に短縮できますが、潜在的な問題を回避するために使用されるメカニズムを理解することが重要です。 `+ COPY `や ` ADD `のようなファイルコピー命令の場合、Dockerはファイルのチェックサムを比較して、操作を再度実行する必要があるかどうかを確認します。 ` RUN +`命令の場合、Dockerはその特定のコマンド文字列にキャッシュされた既存の画像レイヤーがあるかどうかを確認します。

すぐには明らかではないかもしれませんが、注意しないと、この動作によって予期しない結果が生じる可能性があります。 この一般的な例は、ローカルパッケージインデックスの更新と2つの個別のステップでのパッケージのインストールです。 この例ではUbuntuを使用しますが、基本的な前提は他のディストリビューションのベースイメージにも同様に適用されます。

パッケージのインストール例Dockerfile

FROM ubuntu:18.04
RUN apt -y update
RUN apt -y install nginx
. . .

ここで、ローカルパッケージインデックスは1つの「+ RUN」命令で更新され(「+ apt -y update」)、Nginxは別の操作でインストールされます。 これは最初に使用するときに問題なく機能します。 ただし、追加のパッケージをインストールするために後でDockerfileを更新すると、問題が発生する可能性があります。

パッケージのインストール例Dockerfile

FROM ubuntu:18.04
RUN apt -y update
RUN apt -y install nginx
. . .

2番目の命令によって実行されるインストールコマンドに2番目のパッケージを追加しました。 前のイメージビルドからかなりの時間が経過した場合、新しいビルドは失敗する可能性があります。 これは、パッケージインデックスの更新命令( + RUN apt -y update +)が変更されていないためです。そのため、Dockerはその命令に関連付けられたイメージレイヤーを再利用します。 古いパッケージインデックスを使用しているため、ローカルレコードにある `+ php-fpm +`パッケージのバージョンがリポジトリにない場合があり、2番目の命令を実行するとエラーが発生します。

このシナリオを回避するには、変更が発生したときにDockerが必要なコマンドをすべて再実行できるように、相互に依存するすべてのステップを単一の `+ RUN +`命令に必ず統合してください。

パッケージのインストール例Dockerfile

FROM ubuntu:18.04
RUN apt -y update && apt -y install nginx
. . .

この命令は、パッケージリストが変更されるたびにローカルパッケージキャッシュを更新するようになりました。

RUN命令を調整して画像レイヤーのサイズを縮小する

前の例は、Dockerのキャッシュ動作がどのように期待を覆すことができるかを示していますが、 `+ RUN `命令がDockerの階層化システムとどのように相互作用するかについて、留意すべき点がいくつかあります。 前述のように、各「 RUN +」命令の最後に、Dockerは追加のイメージレイヤーとして変更をコミットします。 生成されるイメージレイヤーの範囲を制御するために、実行するコマンドによって導入されるアーティファクトに注意を払うことにより、コミットされる最終環境で不要なファイルをクリーンアップできます。

一般に、コマンドを単一の「+ RUN 」命令に連結すると、書き込まれるレイヤーを大幅に制御できます。 各コマンドについて、レイヤーの状態を設定し( ` apt -y update `)、コアコマンドを実行し( ` apt install -y nginx php-fpm `)、不要なアーティファクトを削除してクリーンアップします。コミットされる前の環境。 たとえば、多くのDockerfileは、 ` apt `コマンドの最後に ` rm -rf / var / lib / apt / lists / * +`をチェーンし、ダウンロードされたパッケージインデックスを削除して、最終的なレイヤーサイズを縮小します。

パッケージのインストール例Dockerfile

FROM ubuntu:18.04
RUN apt -y update && apt -y install nginx php-fpm
. . .

作成する画像レイヤーのサイズをさらに小さくするには、実行中のコマンドの他の意図しない副作用を制限することが役立ちます。 たとえば、明示的に宣言されたパッケージに加えて、 + apt +`はデフォルトで「推奨」パッケージもインストールします。 この振る舞いを取り除くために、 `+-no-install-recommends`を + apt`コマンドに含めることができます。 推奨パッケージが提供する機能に依存しているかどうかを調べるために、実験が必要になる場合があります。

このセクションではパッケージ管理コマンドを例として使用しましたが、これらの同じ原則は他のシナリオにも適用されます。 一般的な考え方は、前提条件を構築し、最小限の実行可能なコマンドを実行し、1つの「+ RUN +」コマンドで不要なアーティファクトをクリーンアップして、作成するレイヤーのオーバーヘッドを削減することです。

マルチステージビルドの使用

*Multi-stage builds *はDocker 17.05で導入され、開発者が作成する最終ランタイムイメージをより厳密に制御できるようになりました。 マルチステージビルドでは、Dockerfileを個別のステージを表す複数のセクションに分割できます。各セクションには、個別の親イメージを指定するための `+ FROM +`ステートメントがあります。

前のセクションでは、アプリケーションの構築とアセットの準備に使用できるイメージを定義します。 これらには多くの場合、アプリケーションの作成に必要なビルドツールと開発ファイルが含まれていますが、実行する必要はありません。 ファイルで定義された後続の各ステージは、前のステージで生成された成果物にアクセスできます。

最後の `+ FROM +`ステートメントは、アプリケーションの実行に使用されるイメージを定義します。 通常、これは、必要なランタイム要件のみをインストールし、前の段階で生成されたアプリケーションアーティファクトをコピーする縮小イメージです。

このシステムにより、ビルド段階での「+ RUN +」命令の最適化について心配する必要がなくなります。これは、これらのコンテナレイヤーが最終ランタイムイメージに存在しないためです。 ビルド段階で命令がレイヤーキャッシングとどのように相互作用するかに引き続き注意を払う必要がありますが、最終的なイメージサイズではなくビルド時間の最小化に努力を向けることができます。 画像サイズを小さくするには、最終段階の指示に注意を払うことが重要ですが、コンテナビルドのさまざまな段階を分離することで、Dockerfileをそれほど複雑にすることなく、合理化された画像を簡単に取得できます。

コンテナおよびポッドレベルでのスコープ機能

コンテナのビルド手順に関して行う選択は重要ですが、サービスをコンテナ化する方法に関する幅広い決定は、多くの場合、成功に直接影響します。 このセクションでは、アプリケーションを従来の環境からコンテナプラットフォームでの実行に最適に移行する方法についてもう少し説明します。

機能によるコンテナ化

一般に、独立した機能の各部分を個別のコンテナイメージにパッケージ化することをお勧めします。

これは、アプリケーションを頻繁に同じイメージ内でグループ化して、サイズを縮小し、VMの実行に必要なリソースを最小化する仮想マシン環境で採用されている一般的な戦略とは異なります。 コンテナはオペレーティングシステムスタック全体を仮想化しない軽量の抽象概念であるため、Kubernetesではこのトレードオフはそれほど魅力的ではありません。 そのため、Webスタック仮想マシンは、Djangoアプリケーションを提供するために、単一マシン上でGunicornアプリケーションサーバーとNginx Webサーバーをバンドルする場合がありますが、Kubernetesでは、これらは別々のコンテナーに分割される場合があります。

サービス用に1つの個別の機能を実装するコンテナを設計すると、多くの利点があります。 サービス間の標準インターフェイスが確立されている場合、各コンテナは独立して開発できます。 たとえば、Nginxコンテナは、さまざまなバックエンドへのプロキシに使用される可能性があります。また、異なる構成が指定されている場合、ロードバランサーとして使用される可能性があります。

展開後、各コンテナイメージを個別にスケーリングして、さまざまなリソースと負荷の制約に対処できます。 アプリケーションを複数のコンテナイメージに分割することにより、開発、編成、および展開の柔軟性が得られます。

ポッドでのコンテナーイメージの結合

Kubernetesでは、* pods *はコントロールプレーンで直接管理できる最小単位です。 ポッドは、1つ以上のコンテナと追加の構成データで構成され、これらのコンポーネントの実行方法をプラットフォームに伝えます。 ポッド内のコンテナーは常にクラスター内の同じワーカーノードでスケジュールされ、システムは失敗したコンテナーを自動的に再起動します。 ポッドの抽象化は非常に便利ですが、アプリケーションのコンポーネントをバンドルする方法についての決定の別のレイヤーを導入します。

コンテナイメージのように、ポッドは、1つのエンティティにバンドルされている機能が多すぎると柔軟性が低下します。 ポッド自体は他の抽象化を使用してスケーリングできますが、内部のコンテナを個別に管理またはスケーリングすることはできません。 したがって、前の例を引き続き使用するには、別々のNginxコンテナとGunicornコンテナを単一のポッドにバンドルして、別々に制御およびデプロイできないようにする必要があります。

ただし、機能的に異なるコンテナを1つのユニットとして結合することが理にかなっているシナリオがあります。 一般的に、これらは、追加のコンテナーがメインコンテナーのコア機能をサポートまたは強化する状況、または展開環境への適応を支援する状況として分類できます。 一般的なパターンは次のとおりです。

  • サイドカー:補助コンテナは、補助ユーティリティの役割で動作することにより、メインコンテナのコア機能を拡張します。 たとえば、リモートリポジトリが変更されると、サイドカーコンテナはログを転送したり、ファイルシステムを更新したりします。 主要なコンテナは、その中心的な責任に焦点を合わせたままですが、サイドカーによって提供される機能によって強化されます。

  • アンバサダー:アンバサダーコンテナーは、(多くの場合、複雑な)外部リソースの検出と接続を担当します。 プライマリコンテナは、内部ポッド環境を使用して、既知のインターフェイスでアンバサダーコンテナに接続できます。 アンバサダーは、バックエンドリソースを抽象化し、プライマリコンテナとリソースプール間のトラフィックをプロキシします。

  • * Adaptor *:アダプターコンテナーは、プライマリコンテナーのインターフェイス、データ、およびプロトコルを正規化して、他のコンポーネントが期待するプロパティに合わせます。 プライマリコンテナはネイティブ形式を使用して動作でき、アダプタコンテナはデータを変換および正規化して外部と通信します。

お気づきかもしれませんが、これらの各パターンは、標準の一般的なプライマリコンテナーイメージを構築し、さまざまなコンテキストと構成で展開できる戦略をサポートします。 セカンダリコンテナは、プライマリコンテナと使用されている特定の展開環境の間のギャップを埋めるのに役立ちます。 一部のサイドカーコンテナは、複数のプライマリコンテナを同じ環境条件に適合させるために再利用することもできます。 これらのパターンは、ポッド抽象化によって提供される共有ファイルシステムとネットワーク名前空間の恩恵を受けながら、標準化されたコンテナの独立した開発と柔軟な展開を可能にします。

ランタイム構成の設計

標準化された再利用可能なコンポーネントを構築したいという要望と、アプリケーションをランタイム環境に適合させるために必要な要件との間には緊張があります。 ランタイム構成は、これらの懸念間のギャップを埋める最良の方法の1つです。 コンポーネントは一般的かつ柔軟に構築されており、ソフトウェアに追加の構成情報を提供することにより、実行時に必要な動作の概要が示されます。 この標準的なアプローチは、アプリケーションに対してもコンテナに対しても機能します。

ランタイム構成を念頭に置いてビルドするには、アプリケーション開発とコンテナー化の両方のステップで先を考える必要があります。 アプリケーションは、起動または再起動するときに、コマンドラインパラメーター、構成ファイル、または環境変数から値を読み取るように設計する必要があります。 この構成の解析および挿入ロジックは、コンテナ化の前にコードで実装する必要があります。

Dockerfileを作成するとき、コンテナはランタイム構成も考慮して設計する必要があります。 コンテナには、実行時にデータを提供するための多くのメカニズムがあります。 ユーザーは、ファイルベースの構成を有効にするために、コンテナ内のボリュームとしてホストからファイルまたはディレクトリをマウントできます。 同様に、環境変数は、コンテナの起動時に内部コンテナランタイムに渡すことができます。 + CMD +`および `+ ENTRYPOINT + Dockerfile命令は、ランタイム構成情報をコマンドパラメーターとして渡すことができるように定義することもできます。

Kubernetesは、コンテナを直接管理するのではなく、ポッドなどの高レベルのオブジェクトを操作するため、構成を定義し、実行時にコンテナ環境に注入するためのメカニズムが利用可能です。 Kubernetes * ConfigMaps および Secrets *を使用すると、構成データを個別に定義し、実行時に環境変数またはファイルとしてコンテナー環境に値を投影できます。 ConfigMapは、環境、テスト段階などに基づいて変化する可能性がある構成データを格納することを目的とした汎用オブジェクトです。 シークレットも同様のインターフェイスを提供しますが、アカウントパスワードやAPIクレデンシャルなどの機密データ用に特別に設計されています。

抽象化の各層で利用可能なランタイム構成オプションを理解し、正しく使用することにより、環境が提供する値からヒントを得る柔軟なコンポーネントを構築できます。 これにより、非常に異なるシナリオで同じコンテナイメージを再利用できるようになり、アプリケーションの柔軟性が向上して開発のオーバーヘッドが削減されます。

コンテナを使用したプロセス管理の実装

コンテナベースの環境に移行する場合、ユーザーは多くの場合、既存のワークロードを、ほとんどまたはまったく変更せずに、新しいシステムにシフトすることから始めます。 新しい抽象化ですでに使用しているツールをラップすることにより、アプリケーションをコンテナにパッケージ化します。 通常のパターンを使用して、移行されたアプリケーションを起動して実行することは有用ですが、コンテナ内の以前の実装をドロップすると、設計が非効率になる場合があります。

サービスではなくアプリケーションのようなコンテナの処理

開発者がコンテナ内に重要なサービス管理機能を実装すると、問題が頻繁に発生します。 たとえば、コンテナ内でsystemdサービスを実行するか、Webサーバーをデーモン化することは、通常のコンピューティング環境ではベストプラクティスと見なされますが、多くの場合、コンテナモデルに固有の仮定と矛盾します。

ホストは、コンテナ内でPID(プロセスID)1として動作するプロセスに信号を送信することにより、コンテナのライフサイクルイベントを管理します。 PID 1は最初に開始されるプロセスであり、従来のコンピューティング環境ではinitシステムになります。 ただし、ホストはPID 1しか管理できないため、従来のinitシステムを使用してコンテナ内のプロセスを管理することは、プライマリアプリケーションを制御する方法がないことを意味する場合があります。 ホストは内部initシステムを起動、停止、または終了できますが、プライマリアプリケーションを直接管理することはできません。 信号は意図した動作を実行中のアプリケーションに伝播する場合がありますが、これにより複雑さが増し、必ずしも必要ではありません。

ほとんどの場合、PID 1がフォアグラウンドでプライマリアプリケーションを実行するように、コンテナー内の実行環境を単純化することをお勧めします。 複数のプロセスを実行する必要がある場合、PID 1は後続のプロセスのライフサイクルの管理を担当します。 Apacheなどの特定のアプリケーションは、接続を処理するワーカーを生成および管理することにより、これをネイティブに処理します。 他のアプリケーションの場合、ラッパースクリプト、またはhttps://github.com/Yelp/dumb-init[dumb-init]または付属のhttps://github.com/krallin/tini[tini] initのような非常に単純なinitシステム場合によってはシステムを使用できます。 選択した実装に関係なく、コンテナ内でPID 1として実行されているプロセスは、Kubernetesによって送信された「+ TERM +」シグナルに適切に応答して、期待どおりに動作する必要があります。

Kubernetesでのコンテナヘルスの管理

Kubernetesの展開とサービスは、基盤となるコンテナの再起動や実装自体の変更が必要な場合でも、長期実行プロセスとアプリケーションへの信頼性の高い永続的なアクセスのライフサイクル管理を提供します。 コンテナからサービスの健全性を監視および維持する責任を抽出することにより、健全なワークロードを管理するためのプラットフォームのツールを活用できます。

Kubernetesがコンテナを適切に管理するには、コンテナ内で実行されているアプリケーションが正常であり、作業を実行できるかどうかを理解する必要があります。 これを可能にするために、コンテナは、アプリケーションヘルスのレポートに使用できるネットワークエンドポイントまたはコマンドである活性プローブを実装できます。 Kubernetesは定期的に定義された活性プローブをチェックして、コンテナが期待どおりに動作しているかどうかを判断します。 コンテナが適切に応答しない場合、Kubernetesは機能を再確立しようとしてコンテナを再起動します。

Kubernetesは、同様の構成要素であるレディネスプローブも提供します。 準備プローブは、コンテナ内のアプリケーションが正常かどうかを示すのではなく、アプリケーションがトラフィックを受信する準備ができているかどうかを判断します。 これは、コンテナ化されたアプリケーションに、接続を受信する準備ができる前に完了する必要がある初期化ルーチンがある場合に役立ちます。 Kubernetesは準備調査を使用して、サービスにポッドを追加するか、ポッドをサービスから削除するかを決定します。

これら2つのプローブタイプのエンドポイントを定義すると、Kubernetesがコンテナを効率的に管理し、コンテナのライフサイクルの問題がサービスの可用性に影響を与えるのを防ぐことができます。 これらのタイプのヘルスリクエストに応答するメカニズムは、アプリケーション自体に組み込まれ、Dockerイメージ構成で公開される必要があります。

結論

このガイドでは、Kubernetesでコンテナ化されたアプリケーションを実行する際に留意すべき重要な考慮事項について説明しました。 繰り返しますが、私たちが行ったいくつかの提案は次のとおりです。

  • 最小限の共有可能な親イメージを使用して、最小限の膨張でイメージを構築し、起動時間を短縮します

  • マルチステージビルドを使用して、コンテナビルドとランタイム環境を分離する

  • Dockerfileの指示を組み合わせて、きれいな画像レイヤーを作成し、画像のキャッシュミスを回避します

  • 個別の機能を分離してコンテナ化し、柔軟なスケーリングと管理を可能にします

  • 単一の焦点を絞った責任を持つようにポッドを設計する

  • ヘルパーコンテナをバンドルして、メインコンテナの機能を強化したり、展開環境に適合させたりします。

  • 展開時の柔軟性を高めるために、ランタイム構成に対応するアプリケーションとコンテナを構築します

  • Kubernetesがライフサイクルイベントを管理できるように、アプリケーションをコンテナのプライマリプロセスとして実行します

  • Kubernetesがコンテナのヘルスを監視できるように、アプリケーションまたはコンテナ内でヘルスおよび活性エンドポイントを開発します

開発と実装のプロセス全体を通して、サービスの堅牢性と有効性に影響を与える可能性のある決定を下す必要があります。 コンテナ化されたアプリケーションが従来のアプリケーションと異なる方法を理解し、マネージドクラスター環境でそれらがどのように動作するかを学ぶことは、いくつかの一般的な落とし穴を回避し、Kubernetesが提供するすべての機能を利用できるようにするのに役立ちます。

前の投稿:Goの文字列パッケージの概要
次の投稿:Dockerコンテナ間でデータを共有する方法