Kubernetesドキュメントのこのセクションには、個々のタスクの実行方法を示すページが含まれています。タスクページは、通常、短い手順を実行することにより、1つのことを行う方法を示します。
タスクページを作成したい場合は、ドキュメントのPull Requestの作成を参照してください。
これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.
Kubernetesドキュメントのこのセクションには、個々のタスクの実行方法を示すページが含まれています。タスクページは、通常、短い手順を実行することにより、1つのことを行う方法を示します。
タスクページを作成したい場合は、ドキュメントのPull Requestの作成を参照してください。
Kubernetesのコマンドラインツールkubectl
を使用すると、Kubernetesクラスターに対してコマンドを実行できるようになります。kubectlは、アプリケーションのデプロイ、クラスターリソースの調査と管理、ログの表示などに使用できます。
kubectl
のダウンロードとインストールを行い、クラスターへのアクセスをセットアップする方法については、kubectlのインストールおよびセットアップを参照してください。
また、kubectl
リファレンスドキュメントも参照できます。
Minikubeは、Kubernetesをローカルで実行するツールです。MinikubeはシングルノードのKubernetesクラスターをパーソナルコンピューター上(Windows、macOS、Linux PCを含む)で実行することで、Kubernetesを試したり、日常的な開発作業のために利用できます。
ツールのインストールについて知りたい場合は、公式のGet Started!のガイドに従ってください。
Minikubeが起動したら、サンプルアプリケーションの実行を試すことができます。
Minikubeと同じように、kindもローカルコンピューター上でKubernetesを実行するツールです。Minikubeとは違い、kindは1種類のコンテナランタイム上でしか動作しません。実行にはDockerのインストールと設定が必要です。
Quick Startに、kindの起動に必要な手順が説明されています。
Kubernetesのコマンドラインツールであるkubectlを使用して、Kubernetesクラスターに対してコマンドを実行することができます。kubectlによってアプリケーションのデプロイや、クラスターのリソース管理、検査およびログの表示を行うことができます。kubectlの操作に関する完全なリストは、kubectlの概要を参照してください。
kubectlのバージョンは、クラスターのマイナーバージョンとの差分が1つ以内でなければなりません。たとえば、クライアントがv1.2であれば、v1.1、v1.2、v1.3のマスターで動作するはずです。最新バージョンのkubectlを使うことで、不測の事態を避けることができるでしょう。
次のコマンドにより、最新リリースをダウンロードしてください:
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
特定のバージョンをダウンロードする場合、コマンドの$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)
の部分を特定のバージョンに書き換えてください。
たとえば、Linuxへv1.23.0のバージョンをダウンロードするには、次のコマンドを入力します:
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.23.0/bin/linux/amd64/kubectl
kubectlバイナリを実行可能にしてください。
chmod +x ./kubectl
バイナリをPATHの中に移動させてください。
sudo mv ./kubectl /usr/local/bin/kubectl
インストールしたバージョンが最新であることを確認してください:
kubectl version --client
sudo apt-get update && sudo apt-get install -y apt-transport-https gnupg2
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
yum install -y kubectl
最新リリースをダウンロードしてください:
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl"
特定のバージョンをダウンロードする場合、コマンドの$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)
の部分を特定のバージョンに書き換えてください。
たとえば、macOSへv1.23.0のバージョンをダウンロードするには、次のコマンドを入力します:
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.23.0/bin/darwin/amd64/kubectl
kubectlバイナリを実行可能にしてください。
chmod +x ./kubectl
バイナリをPATHの中に移動させてください。
sudo mv ./kubectl /usr/local/bin/kubectl
インストールしたバージョンが最新であることを確認してください:
kubectl version --client
macOSでHomebrewパッケージマネージャーを使用していれば、Homebrewでkubectlをインストールすることもできます。
インストールコマンドを実行してください:
brew install kubectl
または
brew install kubernetes-cli
インストールしたバージョンが最新であることを確認してください:
kubectl version --client
macOSでMacPortsパッケージマネージャーを使用していれば、MacPortsでkubectlをインストールすることもできます。
インストールコマンドを実行してください:
sudo port selfupdate
sudo port install kubectl
インストールしたバージョンが最新であることを確認してください:
kubectl version --client
こちらのリンクから、最新リリースであるv1.23.0をダウンロードしてください。
または、curl
をインストールされていれば、次のコマンドも使用できます:
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.23.0/bin/windows/amd64/kubectl.exe
最新の安定版を入手する際は(たとえばスクリプトで使用する場合)、https://storage.googleapis.com/kubernetes-release/release/stable.txtを参照してください。
バイナリをPATHに追加します
kubectl
のバージョンがダウンロードしたものと同じであることを確認してください:
kubectl version --client
kubectl
をPATHに追加します。Docker Desktopをすでにインストールしている場合、Docker Desktopインストーラーによって追加されたPATHの前に追加するか、Docker Desktopのkubectl
を削除してください。
WindowsでPowershell Galleryパッケージマネージャーを使用していれば、Powershellでkubectlをインストールおよびアップデートすることもできます。
インストールコマンドを実行してください(必ずDownloadLocation
を指定してください):
Install-Script -Name 'install-kubectl' -Scope CurrentUser -Force
install-kubectl.ps1 [-DownloadLocation <path>]
DownloadLocation
を指定しない場合、kubectl
はユーザのTempディレクトリにインストールされます。
インストーラーは$HOME/.kube
を作成し、設定ファイルを作成します。
インストールしたバージョンが最新であることを確認してください:
kubectl version --client
Windowsへkubectlをインストールするために、ChocolateyパッケージマネージャーやScoopコマンドラインインストーラーを使用することもできます。
choco install kubernetes-cli
scoop install kubectl
インストールしたバージョンが最新であることを確認してください:
kubectl version --client
ホームディレクトリへ移動してください:
# cmd.exeを使用している場合は cd %USERPROFILE% を実行してください。
cd ~
.kube
ディレクトリを作成してください:
mkdir .kube
作成した.kube
ディレクトリへ移動してください:
cd .kube
リモートのKubernetesクラスターを使うために、kubectlを設定してください:
New-Item config -type file
Google Cloud SDKの一部として、kubectlをインストールすることもできます。
Google Cloud SDKをインストールしてください。
kubectl
のインストールコマンドを実行してください:
gcloud components install kubectl
インストールしたバージョンが最新であることを確認してください:
kubectl version --client
kubectlがKubernetesクラスターを探索し接続するために、kubeconfigファイルが必要になります。これは、kube-up.shによりクラスターを作成した際や、Minikubeクラスターを正常にデプロイした際に自動生成されます。デフォルトでは、kubectlの設定は~/.kube/config
に格納されています。
クラスターの状態を取得し、kubectlが適切に設定されていることを確認してください:
kubectl cluster-info
URLのレスポンスが表示されている場合は、kubectlはクラスターに接続するよう正しく設定されています。
以下のようなメッセージが表示されている場合は、kubectlは正しく設定されていないか、Kubernetesクラスターに接続できていません。
The connection to the server <server-name:port> was refused - did you specify the right host or port?
たとえば、ラップトップ上(ローカル環境)でKubernetesクラスターを起動するような場合、Minikubeなどのツールを最初にインストールしてから、上記のコマンドを再実行する必要があります。
kubectl cluster-infoがURLレスポンスを返したにもかかわらずクラスターにアクセスできない場合は、次のコマンドで設定が正しいことを確認してください:
kubectl cluster-info dump
kubectlはBashおよびZshの自動補完を提供しています。これにより、入力を大幅に削減することができます。
以下にBash(LinuxとmacOSの違いも含む)およびZshの自動補完の設定手順を示します。
Bashにおけるkubectlの補完スクリプトはkubectl completion bash
コマンドで生成できます。シェル内で補完スクリプトをsourceすることでkubectlの自動補完が有効になります。
ただし、補完スクリプトはbash-completionに依存しているため、このソフトウェアを最初にインストールしておく必要があります(type _init_completion
を実行することで、bash-completionがすでにインストールされていることを確認できます)。
bash-completionは多くのパッケージマネージャーから提供されています(こちらを参照してください)。apt-get install bash-completion
またはyum install bash-completion
などでインストールできます。
上記のコマンドでbash-completionの主要スクリプトである/usr/share/bash-completion/bash_completion
が作成されます。パッケージマネージャーによっては、このファイルを~/.bashrc
にて手動でsourceする必要があります。
これを調べるには、シェルをリロードしてからtype _init_completion
を実行してください。コマンドが成功していればすでに設定済みです。そうでなければ、~/.bashrc
に以下を追記してください:
source /usr/share/bash-completion/bash_completion
シェルをリロードし、type _init_completion
を実行してbash-completionが正しくインストールされていることを検証してください。
すべてのシェルセッションにてkubectlの補完スクリプトをsourceできるようにしなければなりません。これを行うには2つの方法があります:
補完スクリプトを~/.bashrc
内でsourceしてください:
echo 'source <(kubectl completion bash)' >>~/.bashrc
補完スクリプトを/etc/bash_completion.d
ディレクトリに追加してください:
kubectl completion bash >/etc/bash_completion.d/kubectl
kubectlにエイリアスを張っている場合は、以下のようにシェルの補完を拡張して使うことができます:
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -F __start_kubectl k' >>~/.bashrc
/etc/bash_completion.d
内のすべての補完スクリプトをsourceします。
どちらも同様の手法です。シェルをリロードしたあとに、kubectlの自動補完が機能するはずです。
Bashにおけるkubectlの補完スクリプトはkubectl completion bash
コマンドで生成できます。シェル内で補完スクリプトをsourceすることでkubectlの自動補完が有効になります。
ただし、補完スクリプトはbash-completionに依存しているため、事前にインストールする必要があります。
ここではBash 4.1以降の使用を前提としています。Bashのバージョンは下記のコマンドで調べることができます。
echo $BASH_VERSION
バージョンが古い場合、Homebrewを使用してインストールもしくはアップグレードできます。
brew install bash
シェルをリロードし、希望するバージョンを使用していることを確認してください。
echo $BASH_VERSION $SHELL
Homebrewは通常、/usr/local/bin/bash
にインストールします。
type _init_completion
を実行することで、bash-completionがすでにインストールされていることを確認できます。ない場合は、Homebrewを使用してインストールすることもできます:
brew install bash-completion@2
このコマンドの出力で示されたように、~/.bash_profile
に以下を追記してください:
export BASH_COMPLETION_COMPAT_DIR="/usr/local/etc/bash_completion.d"
[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"
シェルをリロードし、type _init_completion
を実行してbash-completion v2が正しくインストールされていることを検証してください。
すべてのシェルセッションにてkubectlの補完スクリプトをsourceできるようにしなければなりません。これを行うには複数の方法があります:
補完スクリプトを~/.bash_profile
内でsourceする:
echo 'source <(kubectl completion bash)' >>~/.bash_profile
補完スクリプトを/usr/local/etc/bash_completion.d
ディレクトリに追加する:
kubectl completion bash >/usr/local/etc/bash_completion.d/kubectl
kubectlにエイリアスを張っている場合は、以下のようにシェルの補完を拡張して使うことができます:
echo 'alias k=kubectl' >>~/.bash_profile
echo 'complete -F __start_kubectl k' >>~/.bash_profile
kubectlをHomwbrewでインストールした場合(前述のとおり)、kubectlの補完スクリプトはすでに/usr/local/etc/bash_completion.d/kubectl
に格納されているでしょう。この場合、なにも操作する必要はありません。
BASH_COMPLETION_COMPAT_DIR
ディレクトリ内のすべてのファイルをsourceするため、後者の2つの方法が機能します。
どの場合でも、シェルをリロードしたあとに、kubectlの自動補完が機能するはずです。
Zshにおけるkubectlの補完スクリプトはkubectl completion zsh
コマンドで生成できます。シェル内で補完スクリプトをsourceすることでkubectlの自動補完が有効になります。
すべてのシェルセッションで使用するには、~/.zshrc
に以下を追記してください:
source <(kubectl completion zsh)
kubectlにエイリアスを張っている場合は、以下のようにシェルの補完を拡張して使うことができます:
echo 'alias k=kubectl' >>~/.zshrc
echo 'compdef __start_kubectl k' >>~/.zshrc
シェルをリロードしたあとに、kubectlの自動補完が機能するはずです。
complete:13: command not found: compdef
のようなエラーが出力された場合は、以下を~/.zshrc
の先頭に追記してください:
autoload -Uz compinit
compinit
このページでは、メモリーの 要求 と 制限 をコンテナに割り当てる方法について示します。コンテナは要求されたメモリーを確保することを保証しますが、その制限を超えるメモリーの使用は許可されません。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
クラスターの各ノードには、少なくとも300MiBのメモリーが必要になります。
このページのいくつかの手順では、クラスターにてmetrics-serverサービスを実行する必要があります。すでにmetrics-serverが動作している場合、これらの手順をスキップできます。
Minikubeを動作させている場合、以下のコマンドによりmetrics-serverを有効にできます:
minikube addons enable metrics-server
metrics-serverが実行されているか、もしくはリソースメトリクスAPI (metrics.k8s.io
) の別のプロバイダが実行されていることを確認するには、以下のコマンドを実行してください:
kubectl get apiservices
リソースメトリクスAPIが利用可能であれば、出力には metrics.k8s.io
への参照が含まれます。
NAME
v1beta1.metrics.k8s.io
この練習で作成するリソースがクラスター内で分離されるよう、namespaceを作成します。
kubectl create namespace mem-example
コンテナにメモリーの要求を指定するには、コンテナのリソースマニフェストにresources:requests
フィールドを追記します。メモリーの制限を指定するには、resources:limits
を追記します。
この練習では、一つのコンテナをもつPodを作成します。コンテナに100MiBのメモリー要求と200MiBのメモリー制限を与えます。Podの設定ファイルは次のようになります:
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
設定ファイルのargs
セクションでは、コンテナ起動時の引数を与えます。"--vm-bytes", "150M"
という引数では、コンテナに150MiBのメモリーを割り当てます。
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example
Podのコンテナが起動していることを検証してください:
kubectl get pod memory-demo --namespace=mem-example
Podの詳細な情報を確認してください:
kubectl get pod memory-demo --output=yaml --namespace=mem-example
この出力では、Pod内の一つのコンテナに100MiBのメモリー要求と200MiBのメモリー制限があることを示しています。
...
resources:
limits:
memory: 200Mi
requests:
memory: 100Mi
...
kubectl top
を実行し、Podのメトリクスを取得してください:
kubectl top pod memory-demo --namespace=mem-example
この出力では、Podが約162,900,000バイト(約150MiB)のメモリーを使用していることを示しています。Podの100MiBの要求を超えていますが、200MiBの制限には収まっています。
NAME CPU(cores) MEMORY(bytes)
memory-demo <something> 162856960
Podを削除してください:
kubectl delete pod memory-demo --namespace=mem-example
ノードに利用可能なメモリーがある場合、コンテナはメモリー要求を超えることができます。しかしながら、メモリー制限を超えて使用することは許可されません。コンテナが制限を超えてメモリーを確保しようとした場合、そのコンテナは終了候補となります。コンテナが制限を超えてメモリーを消費し続ける場合、コンテナは終了されます。終了したコンテナを再起動できる場合、ほかのランタイムの失敗時と同様に、kubeletがコンテナを再起動させます。
この練習では、制限を超えてメモリーを確保しようとするPodを作成します。以下に50MiBのメモリー要求と100MiBのメモリー制限を与えたコンテナを持つ、Podの設定ファイルを示します:
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-2
namespace: mem-example
spec:
containers:
- name: memory-demo-2-ctr
image: polinux/stress
resources:
requests:
memory: "50Mi"
limits:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]
設定ファイルのargs
セクションでは、コンテナに250MiBのメモリーを割り当てており、これは100MiBの制限を十分に超えています。
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example
Podの詳細な情報を確認してください:
kubectl get pod memory-demo-2 --namespace=mem-example
この時点で、コンテナは起動中か強制終了されているでしょう。コンテナが強制終了されるまで上記のコマンドをくり返し実行してください:
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 24s
コンテナステータスの詳細な情報を取得してください:
kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example
この出力では、コンテナがメモリー不足 (OOM) により強制終了されたことを示しています。
lastState:
terminated:
containerID: docker://65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
exitCode: 137
finishedAt: 2017-06-20T20:52:19Z
reason: OOMKilled
startedAt: null
この練習のコンテナはkubeletによって再起動されます。次のコマンドを数回くり返し実行し、コンテナが強制終了と再起動を続けていることを確認してください:
kubectl get pod memory-demo-2 --namespace=mem-example
この出力では、コンテナが強制終了され、再起動され、再度強制終了および再起動が続いていることを示しています:
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 37s
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 1/1 Running 2 40s
Podの履歴について詳細な情報を確認してください:
kubectl describe pod memory-demo-2 --namespace=mem-example
この出力では、コンテナの開始とその失敗が繰り返されていることを示しています:
... Normal Created Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff Back-off restarting failed container
クラスターのノードの詳細な情報を確認してください:
kubectl describe nodes
この出力には、メモリー不足の状態のためコンテナが強制終了された記録が含まれます:
Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child
Podを削除してください:
kubectl delete pod memory-demo-2 --namespace=mem-example
メモリー要求と制限はコンテナと関連づけられていますが、Podにメモリー要求と制限が与えられていると考えるとわかりやすいでしょう。Podのメモリー要求は、Pod内のすべてのコンテナのメモリー要求の合計となります。同様に、Podのメモリー制限は、Pod内のすべてのコンテナのメモリー制限の合計となります。
Podのスケジューリングは要求に基づいています。Podはノード上で動作するうえで、そのメモリー要求に対してノードに十分利用可能なメモリーがある場合のみスケジュールされます。
この練習では、クラスター内のノードのキャパシティを超える大きさのメモリー要求を与えたPodを作成します。以下に1000GiBのメモリー要求を与えた一つのコンテナを持つ、Podの設定ファイルを示します。これは、クラスター内のノードのキャパシティを超える可能性があります。
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-3
namespace: mem-example
spec:
containers:
- name: memory-demo-3-ctr
image: polinux/stress
resources:
limits:
memory: "1000Gi"
requests:
memory: "1000Gi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example
Podの状態を確認してください:
kubectl get pod memory-demo-3 --namespace=mem-example
この出力では、Podのステータスが待機中であることを示しています。つまり、Podがどのノードに対しても実行するようスケジュールされておらず、いつまでも待機状態のままであることを表しています:
kubectl get pod memory-demo-3 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-3 0/1 Pending 0 25s
イベントを含むPodの詳細な情報を確認してください:
kubectl describe pod memory-demo-3 --namespace=mem-example
この出力では、ノードのメモリー不足のためコンテナがスケジュールされないことを示しています:
Events:
... Reason Message
------ -------
... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3).
メモリーリソースはバイト単位で示されます。メモリーをE、P、T、G、M、K、Ei、Pi、Ti、Gi、Mi、Kiという接尾辞とともに、整数型または固定小数点整数で表現できます。たとえば、以下はおおよそ同じ値を表します:
128974848, 129e6, 129M , 123Mi
Podを削除してください:
kubectl delete pod memory-demo-3 --namespace=mem-example
コンテナのメモリー制限を指定しない場合、次のいずれかの状態となります:
コンテナのメモリー使用量に上限がない状態となります。コンテナは実行中のノードで利用可能なすべてのメモリーを使用でき、その後OOM Killerが呼び出される可能性があります。さらに、OOM killの場合、リソース制限のないコンテナは強制終了される可能性が高くなります。
メモリー制限を与えられたnamespaceでコンテナを実行されると、コンテナにはデフォルトの制限値が自動的に指定されます。クラスターの管理者はLimitRangeによってメモリー制限のデフォルト値を指定できます。
クラスターで動作するコンテナにメモリー要求と制限を設定することで、クラスターのノードで利用可能なメモリーリソースを効率的に使用することができます。Podのメモリー要求を低く保つことで、Podがスケジュールされやすくなります。メモリー要求よりも大きい制限を与えることで、次の2つを実現できます:
namespaceを削除してください。これにより、今回のタスクで作成したすべてのPodが削除されます:
kubectl delete namespace mem-example
このページでは、CPUの request と limit をコンテナに割り当てる方法について示します。コンテナは設定された制限を超えてCPUを使用することはできません。システムにCPUの空き時間がある場合、コンテナには要求されたCPUを割り当てられます。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
タスク例を実行するには、クラスターに少なくとも利用可能な1 CPUが必要です。
このページのいくつかの手順では、クラスターにてmetrics-serverサービスを実行する必要があります。すでにmetrics-serverが動作している場合、これらの手順をスキップできます。
Minikubeを動作させている場合、以下のコマンドによりmetrics-serverを有効にできます:
minikube addons enable metrics-server
metrics-serverが実行されているか、もしくはリソースメトリクスAPI (metrics.k8s.io
) の別のプロバイダーが実行されていることを確認するには、以下のコマンドを実行してください:
kubectl get apiservices
リソースメトリクスAPIが利用可能であれば、出力には metrics.k8s.io
への参照が含まれます。
NAME
v1beta1.metrics.k8s.io
この練習で作成するリソースがクラスター内で分離されるよう、Namespaceを作成します。
kubectl create namespace cpu-example
コンテナにCPUの要求を指定するには、コンテナのリソースマニフェストにresources:requests
フィールドを追記します。CPUの制限を指定するには、resources:limits
を追記します。
この練習では、一つのコンテナをもつPodを作成します。コンテナに0.5 CPUの要求と1 CPUの制限を与えます。Podの設定ファイルは次のようになります:
apiVersion: v1
kind: Pod
metadata:
name: cpu-demo
namespace: cpu-example
spec:
containers:
- name: cpu-demo-ctr
image: vish/stress
resources:
limits:
cpu: "1"
requests:
cpu: "0.5"
args:
- -cpus
- "2"
設定ファイルのargs
セクションでは、コンテナ起動時の引数を与えます。-cpus "2"
という引数では、コンテナに2 CPUを割り当てます。
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/cpu-request-limit.yaml --namespace=cpu-example
Podのコンテナが起動していることを検証してください:
kubectl get pod cpu-demo --namespace=cpu-example
Podの詳細な情報を確認してください:
kubectl get pod cpu-demo --output=yaml --namespace=cpu-example
この出力では、Pod内の一つのコンテナに500ミリCPUの要求と1 CPUの制限があることを示しています。
resources:
limits:
cpu: "1"
requests:
cpu: 500m
kubectl top
を実行し、Podのメトリクスを取得してください:
kubectl top pod cpu-demo --namespace=cpu-example
この出力では、Podが974ミリCPUを使用していることを示しています。Podの設定で指定した1 CPUの制限よりわずかに小さい値です。
NAME CPU(cores) MEMORY(bytes)
cpu-demo 974m <something>
-cpu "2"
を設定することで、コンテナが2 CPU利用しようとすることを思い出してください。しかしながら、コンテナは約1 CPUしか使用することができません。コンテナが制限よりも多くのCPUリソースを利用しようとしているため、コンテナのCPUの利用が抑制されています。
CPUリソースは CPU の単位で示されます。Kubernetesにおいて1つのCPUは次に等しくなります:
小数値も利用可能です。0.5 CPUを要求するコンテナには、1 CPUを要求するコンテナの半分のCPUが与えられます。mというミリを表す接尾辞も使用できます。たとえば、100m CPU、100 milliCPU、0.1 CPUはすべて同じです。1m以上の精度は指定できません。
CPUはつねに絶対量として要求され、決して相対量としては要求されません。0.1はシングルコア、デュアルコア、48コアCPUのマシンで同じ量となります。
Podを削除してください:
kubectl delete pod cpu-demo --namespace=cpu-example
CPU要求と制限はコンテナと関連づけられていますが、PodにCPU要求と制限が与えられていると考えるとわかりやすいでしょう。PodのCPU要求は、Pod内のすべてのコンテナのCPU要求の合計となります。同様に、PodのCPU制限は、Pod内のすべてのコンテナのCPU制限の合計となります。
Podのスケジューリングはリソースの要求量に基づいています。Podはノード上で動作するうえで、そのCPU要求に対してノードに十分利用可能なCPUリソースがある場合のみスケジュールされます。
この練習では、クラスター内のノードのキャパシティを超える大きさのCPU要求を与えたPodを作成します。以下に100 CPUの要求を与えた一つのコンテナを持つ、Podの設定ファイルを示します。これは、クラスター内のノードのキャパシティを超える可能性があります。
apiVersion: v1
kind: Pod
metadata:
name: cpu-demo-2
namespace: cpu-example
spec:
containers:
- name: cpu-demo-ctr-2
image: vish/stress
resources:
limits:
cpu: "100"
requests:
cpu: "100"
args:
- -cpus
- "2"
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/resource/cpu-request-limit-2.yaml --namespace=cpu-example
Podの状態を確認してください:
kubectl get pod cpu-demo-2 --namespace=cpu-example
この出力では、Podのステータスが待機中であることを示しています。つまり、Podがどのノードに対しても実行するようスケジュールされておらず、いつまでも待機状態のままであることを表しています:
NAME READY STATUS RESTARTS AGE
cpu-demo-2 0/1 Pending 0 7m
イベントを含むPodの詳細な情報を確認してください:
kubectl describe pod cpu-demo-2 --namespace=cpu-example
この出力では、ノードのCPU不足のためコンテナがスケジュールされないことを示しています:
Events:
Reason Message
------ -------
FailedScheduling No nodes are available that match all of the following predicates:: Insufficient cpu (3).
Podを削除してください:
kubectl delete pod cpu-demo-2 --namespace=cpu-example
コンテナのCPU制限を指定しない場合、次のいずれかの状態となります:
コンテナのCPUリソースの使用量に上限がない状態となります。コンテナは実行中のノードで利用可能なすべてのCPUを使用できます。
CPU制限を与えられたnamespaceでコンテナを実行されると、コンテナにはデフォルトの制限値が自動的に指定されます。クラスターの管理者はLimitRangeによってCPU制限のデフォルト値を指定できます。
クラスターで動作するコンテナにCPU要求と制限を設定することで、クラスターのノードで利用可能なCPUリソースを効率的に使用することができます。PodのCPU要求を低く保つことで、Podがスケジュールされやすくなります。CPU要求よりも大きい制限を与えることで、次の2つを実現できます:
namespaceを削除してください:
kubectl delete namespace cpu-example
このページでは、特定のQuality of Service (QoS)クラスをPodに割り当てるための設定方法を示します。Kubernetesは、Podのスケジューリングおよび退役を決定するためにQoSクラスを用います。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
KubernetesはPodの作成時に次のいずれかのQoSクラスをPodに割り当てます:
この演習で作成するリソースがクラスター内で分離されるよう、namespaceを作成します。
kubectl create namespace qos-example
PodにGuaranteedのQoSクラスを与えるには、以下が必要になります:
以下に1つのコンテナをもつPodの設定ファイルを示します。コンテナには200MiBのメモリー制限とリクエストを与え、700ミリCPUの制限と要求を与えます。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo
namespace: qos-example
spec:
containers:
- name: qos-demo-ctr
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod.yaml --namespace=qos-example
Podの詳細な情報を確認してください:
kubectl get pod qos-demo --namespace=qos-example --output=yaml
この出力では、KubernetesがPodにGuaranteed QoSクラスを与えたことを示しています。Podのコンテナにメモリー制限と一致するメモリー要求があり、CPU制限と一致するCPU要求があることも確認できます。
spec:
containers:
...
resources:
limits:
cpu: 700m
memory: 200Mi
requests:
cpu: 700m
memory: 200Mi
...
status:
qosClass: Guaranteed
Podを削除してください:
kubectl delete pod qos-demo --namespace=qos-example
次のような場合に、Burstable QoSクラスがPodに与えられます:
以下に1つのコンテナをもつPodの設定ファイルを示します。コンテナには200MiBのメモリー制限と100MiBのメモリー要求を与えます。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-2
namespace: qos-example
spec:
containers:
- name: qos-demo-2-ctr
image: nginx
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-2.yaml --namespace=qos-example
Podの詳細な情報を確認してください:
kubectl get pod qos-demo-2 --namespace=qos-example --output=yaml
この出力では、KubernetesがPodにBurstable QoSクラスを与えたことを示しています。
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: qos-demo-2-ctr
resources:
limits:
memory: 200Mi
requests:
memory: 100Mi
...
status:
qosClass: Burstable
Podを削除してください:
kubectl delete pod qos-demo-2 --namespace=qos-example
PodにBestEffort QoSクラスを与えるには、Pod内のコンテナにはメモリーやCPUの制限や要求を指定してはなりません。
以下に1つのコンテナをもつPodの設定ファイルを示します。コンテナにはメモリーやCPUの制限や要求がありません:
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-3
namespace: qos-example
spec:
containers:
- name: qos-demo-3-ctr
image: nginx
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-3.yaml --namespace=qos-example
Podの詳細な情報を確認してください:
kubectl get pod qos-demo-3 --namespace=qos-example --output=yaml
この出力では、KubernetesがPodにBestEffort QoSクラスを与えたことを示しています。
spec:
containers:
...
resources: {}
...
status:
qosClass: BestEffort
Podを削除してください:
kubectl delete pod qos-demo-3 --namespace=qos-example
以下に2つのコンテナをもつPodの設定ファイルを示します。一方のコンテナは200MiBのメモリー要求を指定し、もう一方のコンテナには要求や制限を指定しません。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-4
namespace: qos-example
spec:
containers:
- name: qos-demo-4-ctr-1
image: nginx
resources:
requests:
memory: "200Mi"
- name: qos-demo-4-ctr-2
image: redis
このPodがBurstable QoSクラスの基準を満たしていることに注目してください。つまり、Guaranteed QoSクラスの基準に満たしておらず、一方のコンテナにはメモリー要求を与えられています。
Podを作成してください:
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-4.yaml --namespace=qos-example
Podの詳細な情報を確認してください:
kubectl get pod qos-demo-4 --namespace=qos-example --output=yaml
この出力では、KubernetesがPodにBurstable QoSクラスを与えたことを示しています:
spec:
containers:
...
name: qos-demo-4-ctr-1
resources:
requests:
memory: 200Mi
...
name: qos-demo-4-ctr-2
resources: {}
...
status:
qosClass: Burstable
Podを削除してください:
kubectl delete pod qos-demo-4 --namespace=qos-example
namespaceを削除してください:
kubectl delete namespace qos-example
Kubernetes v1.23 [stable]
このページでは、拡張リソースをコンテナに割り当てる方法について説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
この練習を始める前に、Nodeに拡張リソースをアドバタイズするの練習を行ってください。これにより、Nodeの1つがドングルリソースをアドバタイズするように設定されます。
拡張リソースをリクエストするには、コンテナのマニフェストにresources:requests
フィールドを含めます。拡張リソースは、*.kubernetes.io/
以外の任意のドメインで完全修飾されます。有効な拡張リソース名は、example.com/foo
という形式になります。ここで、example.com
はあなたの組織のドメインで、foo
は記述的なリソース名で置き換えます。
1つのコンテナからなるPodの構成ファイルを示します。
apiVersion: v1
kind: Pod
metadata:
name: extended-resource-demo
spec:
containers:
- name: extended-resource-demo-ctr
image: nginx
resources:
requests:
example.com/dongle: 3
limits:
example.com/dongle: 3
構成ファイルでは、コンテナが3つのdongleをリクエストしていることがわかります。
次のコマンドでPodを作成します。
kubectl apply -f https://k8s.io/examples/pods/resource/extended-resource-pod.yaml
Podが起動したことを確認します。
kubectl get pod extended-resource-demo
Podの説明を表示します。
kubectl describe pod extended-resource-demo
dongleのリクエストが表示されます。
Limits:
example.com/dongle: 3
Requests:
example.com/dongle: 3
以下に、1つのコンテナを持つPodの構成ファイルを示します。コンテナは2つのdongleをリクエストします。
apiVersion: v1
kind: Pod
metadata:
name: extended-resource-demo-2
spec:
containers:
- name: extended-resource-demo-2-ctr
image: nginx
resources:
requests:
example.com/dongle: 2
limits:
example.com/dongle: 2
Kubernetesは、2つのdongleのリクエストを満たすことができません。1つ目のPodが、利用可能な4つのdongleのうち3つを使用してしまっているためです。
Podを作成してみます。
kubectl apply -f https://k8s.io/examples/pods/resource/extended-resource-pod-2.yaml
Podの説明を表示します。
kubectl describe pod extended-resource-demo-2
出力にはPodがスケジュールできないことが示されます。2つのdongleが利用できるNodeが存在しないためです。
Conditions:
Type Status
PodScheduled False
...
Events:
...
... Warning FailedScheduling pod (extended-resource-demo-2) failed to fit in any node
fit failure summary on nodes : Insufficient example.com/dongle (1)
Podのステータスを表示します。
kubectl get pod extended-resource-demo-2
出力には、Podは作成されたものの、Nodeにスケジュールされなかったことが示されています。PodはPending状態になっています。
NAME READY STATUS RESTARTS AGE
extended-resource-demo-2 0/1 Pending 0 6m
この練習で作成したPodを削除します。
kubectl delete pod extended-resource-demo
kubectl delete pod extended-resource-demo-2
このページでは、ストレージにボリュームを使用するPodを構成する方法を示します。
コンテナのファイルシステムは、コンテナが存在する間のみ存続します。 そのため、コンテナが終了して再起動すると、ファイルシステムの変更は失われます。 コンテナに依存しない、より一貫したストレージを実現するには、ボリュームを使用できます。 これは、キーバリューストア(Redisなど)やデータベースなどのステートフルアプリケーションにとって特に重要です。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
この演習では、1つのコンテナを実行するPodを作成します。 今回作成するPodには、コンテナが終了して再起動した場合でもPodの寿命が続くemptyDirタイプのボリュームがあります。 これがPodの設定ファイルです:
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
emptyDir: {}
Podを作成します:
kubectl apply -f https://k8s.io/examples/pods/storage/redis.yaml
Podのコンテナが実行されていることを確認し、Podへの変更を監視します:
kubectl get pod redis --watch
出力は次のようになります:
NAME READY STATUS RESTARTS AGE
redis 1/1 Running 0 13s
別のターミナルで、実行中のコンテナへのシェルを取得します:
kubectl exec -it redis -- /bin/bash
シェルで、/data/redis
に移動し、ファイルを作成します:
root@redis:/data# cd /data/redis/
root@redis:/data/redis# echo Hello > test-file
シェルで、実行中のプロセスを一覧表示します:
root@redis:/data/redis# apt-get update
root@redis:/data/redis# apt-get install procps
root@redis:/data/redis# ps aux
出力はこのようになります:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
redis 1 0.1 0.1 33308 3828 ? Ssl 00:46 0:00 redis-server *:6379
root 12 0.0 0.0 20228 3020 ? Ss 00:47 0:00 /bin/bash
root 15 0.0 0.0 17500 2072 ? R+ 00:48 0:00 ps aux
シェルで、Redisプロセスを終了します:
root@redis:/data/redis# kill <pid>
ここで<pid>
はRedisプロセスID(PID)です。
元の端末で、Redis Podへの変更を監視します。最終的には、このようなものが表示されます:
NAME READY STATUS RESTARTS AGE
redis 1/1 Running 0 13s
redis 0/1 Completed 0 6m
redis 1/1 Running 1 6m
この時点で、コンテナは終了して再起動しました。
これは、Redis PodのrestartPolicyがAlways
であるためです。
再起動されたコンテナへのシェルを取得します:
kubectl exec -it redis -- /bin/bash
シェルで/data/redis
に移動し、test-file
がまだ存在することを確認します。
root@redis:/data/redis# cd /data/redis/
root@redis:/data/redis# ls
test-file
この演習用に作成したPodを削除します:
kubectl delete pod redis
このページでは、projected
(投影)ボリュームを使用して、既存の複数のボリュームソースを同一ディレクトリ内にマウントする方法を説明します。
現在、secret
、configMap
、downwardAPI
およびserviceAccountToken
ボリュームを投影できます。
serviceAccountToken
はボリュームタイプではありません。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
この課題では、ローカルファイルからユーザーネームおよびパスワードのSecretを作成します。
次に、単一のコンテナを実行するPodを作成し、projected
ボリュームを使用してそれぞれのSecretを同じ共有ディレクトリにマウントします。
以下にPodの設定ファイルを示します:
apiVersion: v1
kind: Pod
metadata:
name: test-projected-volume
spec:
containers:
- name: test-projected-volume
image: busybox
args:
- sleep
- "86400"
volumeMounts:
- name: all-in-one
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: all-in-one
projected:
sources:
- secret:
name: user
- secret:
name: pass
Secretを作成します:
# ユーザーネームおよびパスワードを含むファイルを作成します:
echo -n "admin" > ./username.txt
echo -n "1f2d1e2e67df" > ./password.txt
# これらのファイルからSecretを作成します:
kubectl create secret generic user --from-file=./username.txt
kubectl create secret generic pass --from-file=./password.txt
Podを作成します:
kubectl apply -f https://k8s.io/examples/pods/storage/projected.yaml
Pod内のコンテナが実行されていることを確認するため、Podの変更を監視します:
kubectl get --watch pod test-projected-volume
出力は次のようになります:
NAME READY STATUS RESTARTS AGE
test-projected-volume 1/1 Running 0 14s
別の端末にて、実行中のコンテナへのシェルを取得します:
kubectl exec -it test-projected-volume -- /bin/sh
シェル内にて、投影されたソースを含むprojected-volume
ディレクトリが存在することを確認します:
ls /projected-volume/
PodおよびSecretを削除します:
kubectl delete pod test-projected-volume
kubectl delete secret user pass
projected
ボリュームについてさらに学ぶこのページでは、Liveness Probe、Readiness ProbeおよびStartup Probeの使用方法について説明します。
kubeletは、Liveness Probeを使用して、コンテナをいつ再起動するかを認識します。 例えば、アプリケーション自体は起動しているが、処理を継続することができないデッドロック状態を検知することができます。 このような状態のコンテナを再起動することで、バグがある場合でもアプリケーションの可用性を高めることができます。
kubeletは、Readiness Probeを使用して、コンテナがトラフィックを受け入れられる状態であるかを認識します。 Podが準備ができていると見なされるのは、Pod内の全てのコンテナの準備が整ったときです。 一例として、このシグナルはServiceのバックエンドとして使用されるPodを制御するときに使用されます。 Podの準備ができていない場合、そのPodはServiceのロードバランシングから切り離されます。
kubeletは、Startup Probeを使用して、コンテナアプリケーションの起動が完了したかを認識します。 Startup Probeを使用している場合、Startup Probeが成功するまでは、Liveness Probeと Readiness Probeによるチェックを無効にし、これらがアプリケーションの起動に干渉しないようにします。 例えば、これを起動が遅いコンテナの起動チェックとして使用することで、起動する前にkubeletによって 強制終了されることを防ぐことができます。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
長期間実行されているアプリケーションの多くは、再起動されるまで回復できないような異常な状態になることがあります。 Kubernetesはこのような状況を検知し、回復するためのLiveness Probeを提供します。
この演習では、k8s.gcr.io/busybox
イメージのコンテナを起動するPodを作成します。
Podの構成ファイルは次の通りです。
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: k8s.gcr.io/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
この構成ファイルでは、Podは一つのContainer
を起動します。
periodSeconds
フィールドは、kubeletがLiveness Probeを5秒おきに行うように指定しています。
initialDelaySeconds
フィールドは、kubeletが最初のProbeを実行する前に5秒間待機するように指示しています。
Probeの動作としては、kubeletはcat /tmp/healthy
を対象のコンテナ内で実行します。
このコマンドが成功し、リターンコード0が返ると、kubeletはコンテナが問題なく動いていると判断します。
リターンコードとして0以外の値が返ると、kubeletはコンテナを終了し、再起動を行います。
このコンテナは、起動すると次のコマンドを実行します:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
コンテナが起動してから初めの30秒間は/tmp/healthy
ファイルがコンテナ内に存在します。
そのため初めの30秒間はcat /tmp/healthy
コマンドは成功し、正常なリターンコードが返ります。
その後30秒が経過すると、cat /tmp/healthy
コマンドは異常なリターンコードを返します。
このPodを起動してください:
kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml
30秒間以内に、Podのイベントを確認します。
kubectl describe pod liveness-exec
この出力結果は、Liveness Probeがまだ失敗していないことを示しています。
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
24s 24s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "k8s.gcr.io/busybox"
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "k8s.gcr.io/busybox"
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e
35秒後に、Podのイベントをもう一度確認します:
kubectl describe pod liveness-exec
出力結果の最後に、Liveness Probeが失敗していることを示すメッセージが表示されます。これによりコンテナは強制終了し、再作成されました。
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
37s 37s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "k8s.gcr.io/busybox"
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "k8s.gcr.io/busybox"
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e
2s 2s 1 {kubelet worker0} spec.containers{liveness} Warning Unhealthy Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
さらに30秒後、コンテナが再起動していることを確認します:
kubectl get pod liveness-exec
出力結果から、RESTARTS
がインクリメントされていることを確認します:
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 1m
別の種類のLiveness Probeでは、HTTP GETリクエストを使用します。
次の構成ファイルは、k8s.gcr.io/liveness
イメージを使用したコンテナを起動するPodを作成します。
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: k8s.gcr.io/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
この構成ファイルでは、Podは一つのContainer
を起動します。
periodSeconds
フィールドは、kubeletがLiveness Probeを3秒おきに行うように指定しています。
initialDelaySeconds
フィールドは、kubeletが最初のProbeを実行する前に3秒間待機するように指示しています。
Probeの動作としては、kubeletは8080ポートをリッスンしているコンテナ内のサーバーに対してHTTP GETリクエストを送ります。
サーバー内の/healthz
パスに対するハンドラーが正常なリターンコードを応答した場合、
kubeletはコンテナが問題なく動いていると判断します。
異常なリターンコードを応答すると、kubeletはコンテナを終了し、再起動を行います。
200以上400未満のコードは成功とみなされ、その他のコードは失敗とみなされます。
server.go にてサーバーのソースコードを確認することができます。
コンテナが生きている初めの10秒間は、/healthz
ハンドラーが200ステータスを返します。
その後、ハンドラーは500ステータスを返します。
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
kubeletは、コンテナが起動してから3秒後からヘルスチェックを行います。 そのため、初めのいくつかのヘルスチェックは成功します。しかし、10秒経過するとヘルスチェックは失敗し、kubeletはコンテナを終了し、再起動します。
HTTPリクエストのチェックによるLiveness Probeを試すには、以下のようにPodを作成します:
kubectl apply -f https://k8s.io/examples/pods/probe/http-liveness.yaml
10秒後、Podのイベントを表示して、Liveness Probeが失敗し、コンテナが再起動されていることを確認します。
kubectl describe pod liveness-http
v1.13以前(v1.13を含む)のリリースにおいては、Podが起動しているノードに環境変数http_proxy
(または HTTP_PROXY
)が設定されている場合、HTTPリクエストのLiveness Probeは設定されたプロキシを使用します。
v1.13より後のリリースにおいては、ローカルHTTPプロキシ環境変数の設定はHTTPリクエストのLiveness Probeに影響しません。
3つ目のLiveness ProbeはTCPソケットを使用するタイプです。 この構成においては、kubeletは指定したコンテナのソケットを開くことを試みます。 コネクションが確立できる場合はコンテナを正常とみなし、失敗する場合は異常とみなします。
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
見ての通り、TCPによるチェックの構成はHTTPによるチェックと非常に似ています。
この例では、Readiness ProbeとLiveness Probeを両方使用しています。
kubeletは、コンテナが起動してから5秒後に最初のReadiness Probeを開始します。
これはgoproxy
コンテナの8080ポートに対して接続を試みます。
このProbeが成功すると、Podは準備ができていると通知されます。kubeletはこのチェックを10秒ごとに行います。
この構成では、Readiness Probeに加えてLiveness Probeが含まれています。
kubeletは、コンテナが起動してから15秒後に最初のLiveness Probeを実行します。
Readiness Probeと同様に、これはgoproxy
コンテナの8080ポートに対して接続を試みます。
Liveness Probeが失敗した場合、コンテナは再起動されます。
TCPのチェックによるLiveness Probeを試すには、以下のようにPodを作成します:
kubectl apply -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml
15秒後、Podのイベントを表示し、Liveness Probeが行われていることを確認します:
kubectl describe pod goproxy
HTTPまたはTCPによるProbeにおいて、ContainerPort で定義した名前付きポートを使用することができます。
ports:
- name: liveness-port
containerPort: 8080
hostPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
場合によっては、最初の初期化において追加の起動時間が必要になるようなレガシーアプリケーションを扱う必要があります。 そのような場合、デッドロックに対する迅速な反応を損なうことなくLiveness Probeのパラメーターを設定することは難しい場合があります。
これに対する解決策の一つは、Liveness Probeと同じ構成のコマンドを用いるか、HTTPまたはTCPによるチェックを使用したStartup Probeをセットアップすることです。
その際、failureThreshold * periodSeconds
で計算される時間を、起動時間として想定される最も遅いケースをカバーできる十分な長さに設定します。
上記の例は、次のようになります:
ports:
- name: liveness-port
containerPort: 8080
hostPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 1
periodSeconds: 10
startupProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 30
periodSeconds: 10
Startup Probeにより、アプリケーションは起動が完了するまでに最大5分間の猶予(30 * 10 = 300秒)が与えられます。
Startup Probeに一度成功すると、その後はLiveness Probeが引き継ぎ、コンテナのデッドロックに対して迅速に反応します。
Startup Probeが成功しない場合、コンテナは300秒後に終了し、その後はPodのrestartPolicy
に従います。
アプリケーションは一時的にトラフィックを処理できないことが起こり得ます。 例えば、アプリケーションは起動時に大きなデータまたは構成ファイルを読み込む必要がある場合や、起動後に外部サービスに依存している場合があります。 このような場合、アプリケーション自体を終了させたくはありませんが、このアプリケーションに対してリクエストも送信したくないと思います。 Kubernetesは、これらの状況を検知して緩和するための機能としてReadiness Probeを提供します。 これにより、準備ができていないことを報告するコンテナを含むPodは、KubernetesのServiceを通してトラフィックを受信しないようになります。
Readiness ProbeはLiveness Probeと同様に構成します。
唯一の違いはreadinessProbe
フィールドをlivenessProbe
フィールドの代わりに利用することだけです。
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
HTTPおよびTCPによるReadiness Probeの構成もLiveness Probeと同じです。
Readiness ProbeとLiveness Probeは同じコンテナで同時に使用できます。 両方使用することで、準備できていないコンテナへのトラフィックが到達しないようにし、コンテナが失敗したときに再起動することができます。
Probe には、 Liveness ProbeおよびReadiness Probeのチェック動作をより正確に制御するために使用できるフィールドがあります:
initialDelaySeconds
: コンテナが起動してから、Liveness ProbeまたはReadiness Probeが開始されるまでの秒数。デフォルトは0秒。最小値は0。periodSeconds
: Probeが実行される頻度(秒数)。デフォルトは10秒。最小値は1。timeoutSeconds
: Probeがタイムアウトになるまでの秒数。デフォルトは1秒。最小値は1。successThreshold
: 一度Probeが失敗した後、次のProbeが成功したとみなされるための最小連続成功数。
デフォルトは1。Liveness Probeには1を設定する必要があります。最小値は1。failureThreshold
: Probeが失敗した場合、KubernetesはfailureThreshold
に設定した回数までProbeを試行します。
Liveness Probeにおいて、試行回数に到達することはコンテナを再起動することを意味します。
Readiness Probeの場合は、Podが準備できていない状態として通知されます。デフォルトは3。最小値は1。HTTPによるProbe
には、httpGet
にて設定できる追加のフィールドがあります:
host
: 接続先ホスト名。デフォルトはPod IP。おそらくはこのフィールドの代わりにhttpHeaders
内の"Host"を代わりに使用することになります。scheme
: ホストへの接続で使用するスキーマ(HTTP または HTTPS)。デフォルトは HTTP。path
: HTTPサーバーへアクセスする際のパスhttpHeaders
: リクエスト内のカスタムヘッダー。HTTPでは重複したヘッダーが許可されています。port
: コンテナにアクセスする際のポートの名前または番号。ポート番号の場合、1から65535の範囲内である必要があります。HTTPによるProbeの場合、kubeletは指定したパスとポートに対するHTTPリクエストを送ることでチェックを行います。
httpGet
のオプションであるhost
フィールドでアドレスが上書きされない限り、kubeletはPodのIPアドレスに対してProbeを送ります。
scheme
フィールドにHTTPS
がセットされている場合、kubeletは証明書の検証を行わずにHTTPSリクエストを送ります。
ほとんどのシナリオにおいては、host
フィールドを使用する必要はありません。次のシナリオは使用する場合の一例です。
仮にコンテナが127.0.0.1をリッスンしており、かつPodのhostNetwork
フィールドがtrueだとします。
その場合においては、httpGet
フィールド内のhost
には127.0.0.1をセットする必要があります。
より一般的なケースにおいてPodが仮想ホストに依存している場合は、おそらくhost
フィールドではなく、httpHeaders
フィールド内のHost
ヘッダーを使用する必要があります。
TCPによるProbeの場合、kubeletはPodの中ではなく、ノードに対してコネクションを確立するProbeを実行します。
kubeletはServiceの名前を解決できないため、host
パラメーター内でServiceの名前を使用することはできません。
また、次のAPIリファレンスも参考にしてください:
このページでは、Node Affinityを利用して、PodをKubernetesクラスター内の特定のノードに割り当てる方法を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.10. バージョンを確認するには次のコマンドを実行してください:kubectl version
.
クラスター内のノードを一覧表示して、ラベルを確認します。
kubectl get nodes --show-labels
出力は次のようになります。
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
ノードを選択して、ラベルを追加します。
kubectl label nodes <your-node-name> disktype=ssd
ここで、<your-node-name>
は選択したノードの名前で置換します。
選択したノードにdisktype=ssd
ラベルがあることを確認します。
kubectl get nodes --show-labels
出力は次のようになります。
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
この出力を見ると、worker0
ノードにdisktype=ssd
というラベルが追加されたことがわかります。
以下に示すマニフェストには、requiredDuringSchedulingIgnoredDuringExecution
にdisktype: ssd
というnode affinityを使用したPodが書かれています。このように書くと、Podはdisktype=ssd
というラベルを持つノードにだけスケジューリングされるようになります。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
マニフェストを適用して、選択したノード上にスケジューリングされるPodを作成します。
kubectl apply -f https://k8s.io/examples/pods/pod-nginx-required-affinity.yaml
Podが選択したノード上で実行されていることを確認します。
kubectl get pods --output=wide
出力は次のようになります。
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
以下に示すマニフェストには、preferredDuringSchedulingIgnoredDuringExecution
にdisktype: ssd
というnode affinityを使用したPodが書かれています。このように書くと、Podはdisktype=ssd
というラベルを持つノードに優先的にスケジューリングされるようになります。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
マニフェストを適用して、選択したノード上にスケジューリングされるPodを作成します。
kubectl apply -f https://k8s.io/examples/pods/pod-nginx-preferred-affinity.yaml
Podが選択したノード上で実行されていることを確認します。
kubectl get pods --output=wide
出力は次のようになります。
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
Node Affinityについてさらに学ぶ。
このページでは、KubernetesのPodをKubernetesクラスター上の特定のノードに割り当てる方法を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
クラスター内のノードのリストをラベル付きで表示します。
kubectl get nodes --show-labels
出力は次のようになります。
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
ノードの1つを選択して、ラベルを追加します。
kubectl label nodes <your-node-name> disktype=ssd
ここで、<your-node-name>
は選択したノードの名前です。
選択したノードにdisktype=ssd
ラベルがあることを確認します。
kubectl get nodes --show-labels
出力は次のようになります。
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
上の出力を見ると、worker0
にdisktype=ssd
というラベルがあることがわかります。
以下のPodの構成ファイルには、nodeSelectorにdisktype: ssd
を持つPodが書かれています。これにより、Podはdisktype: ssd
というラベルを持っているノードにスケジューリングされるようになります。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
構成ファイルを使用して、選択したノードにスケジューリングされるPodを作成します。
kubectl apply -f https://k8s.io/examples/pods/pod-nginx.yaml
Podが選択したノード上で実行されているをことを確認します。
kubectl get pods --output=wide
出力は次のようになります。
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
nodeName
という設定を使用して、Podを特定のノードにスケジューリングすることもできます。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: foo-node # 特定のノードにPodをスケジューリングする
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
構成ファイルを使用して、foo-node
にだけスケジューリングされるPodを作成します。
このページでは、コンテナのライフサイクルイベントにハンドラーを紐付けする方法を説明します。KubernetesはpostStartとpreStopイベントをサポートしています。Kubernetesはコンテナの起動直後にpostStartイベントを送信し、コンテナの終了直前にpreStopイベントを送信します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
この課題では、1つのコンテナを持つPodを作成します。コンテナには、postStartイベントとpreStopイベントのハンドラーがあります。
これがPodの設定ファイルです:
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
設定ファイルでは、postStartコマンドがmessage
ファイルをコンテナの/usr/share
ディレクトリに書き込むことがわかります。preStopコマンドはnginxを適切にシャットダウンします。これは、障害のためにコンテナが終了している場合に役立ちます。
Podを作成します:
kubectl apply -f https://k8s.io/examples/pods/lifecycle-events.yaml
Pod内のコンテナが実行されていることを確認します:
kubectl get pod lifecycle-demo
Pod内で実行されているコンテナでシェルを実行します:
kubectl exec -it lifecycle-demo -- /bin/bash
シェルで、postStart
ハンドラーがmessage
ファイルを作成したことを確認します:
root@lifecycle-demo:/# cat /usr/share/message
出力は、postStartハンドラーによって書き込まれたテキストを示しています。
Hello from the postStart handler
コンテナが作成された直後にKubernetesはpostStartイベントを送信します。 ただし、コンテナのエントリーポイントが呼び出される前にpostStartハンドラーが呼び出されるという保証はありません。postStartハンドラーはコンテナのコードに対して非同期的に実行されますが、postStartハンドラーが完了するまでコンテナのKubernetesによる管理はブロックされます。postStartハンドラーが完了するまで、コンテナのステータスはRUNNINGに設定されません。
Kubernetesはコンテナが終了する直前にpreStopイベントを送信します。 コンテナのKubernetesによる管理は、Podの猶予期間が終了しない限り、preStopハンドラーが完了するまでブロックされます。詳細はPodのライフサイクルを参照してください。
ConfigMapを使用すると、設定をイメージのコンテンツから切り離して、コンテナ化されたアプリケーションの移植性を維持できます。このページでは、ConfigMapを作成し、ConfigMapに保存されているデータを使用してPodを構成する一連の使用例を示します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
kubectl create configmap
またはkustomization.yaml
のConfigMap generatorを使用すると、ConfigMapを作成できます。kubectl
がkustomization.yaml
をサポートをしているのは1.14からである点に注意してください。
kubectl create configmap
を使用してConfigMapをディレクトリ、ファイル、またはリテラル値から作成します:
kubectl create configmap <map-name> <data-source>
<map-name>の部分はConfigMapに割り当てる名前で、<data-source>はデータを取得するディレクトリ、ファイル、またはリテラル値です。ConfigMapの名前は有効なDNSサブドメイン名である必要があります。
ファイルをベースにConfigMapを作成する場合、<data-source> のキーはデフォルトでファイル名になり、値はデフォルトでファイルの中身になります。
kubectl describe
または
kubectl get
を使用すると、ConfigMapに関する情報を取得できます。
kubectl create configmap
を使用すると、同一ディレクトリ内にある複数のファイルから1つのConfigMapを作成できます。ディレクトリをベースにConfigMapを作成する場合、kubectlはディレクトリ内でベース名が有効なキーであるファイルを識別し、それらのファイルを新たなConfigMapにパッケージ化します。ディレクトリ内にある通常のファイルでないものは無視されます(例: サブディレクトリ、シンボリックリンク、デバイス、パイプなど)。
例えば:
# ローカルディレクトリを作成します
mkdir -p configure-pod-container/configmap/
# `configure-pod-container/configmap/`ディレクトリにサンプルファイルをダウンロードします
wget https://kubernetes.io/examples/configmap/game.properties -O configure-pod-container/configmap/game.properties
wget https://kubernetes.io/examples/configmap/ui.properties -O configure-pod-container/configmap/ui.properties
# ConfigMapを作成します
kubectl create configmap game-config --from-file=configure-pod-container/configmap/
上記のコマンドは各ファイルをパッケージ化します。この場合、configure-pod-container/configmap/
ディレクトリのgame.properties
と ui.properties
をgame-config ConfigMapにパッケージ化します。 以下のコマンドを使用すると、ConfigMapの詳細を表示できます:
kubectl describe configmaps game-config
出力結果は以下のようになります:
Name: game-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
configure-pod-container/configmap/
ディレクトリのgame.properties
と ui.properties
ファイルはConfigMapのdata
セクションに表示されます。
kubectl get configmaps game-config -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T18:52:05Z
name: game-config
namespace: default
resourceVersion: "516"
uid: b4952dc3-d670-11e5-8cd0-68f728db1985
data:
game.properties: |
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
kubectl create configmap
を使用して、個別のファイルまたは複数のファイルからConfigMapを作成できます。
例えば、
kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties
は、以下のConfigMapを生成します:
kubectl describe configmaps game-config-2
出力結果は以下のようになります:
Name: game-config-2
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
--from-file
引数を複数回渡し、ConfigMapを複数のデータソースから作成できます。
kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties --from-file=configure-pod-container/configmap/ui.properties
以下のコマンドを使用すると、ConfigMapgame-config-2
の詳細を表示できます:
kubectl describe configmaps game-config-2
出力結果は以下のようになります:
Name: game-config-2
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
--from-env-file
オプションを利用してConfigMapをenv-fileから作成します。例えば:
# Env-filesは環境編集のリストを含んでいます。
# 以下のシンタックスルールが適用されます:
# envファイルの各行はVAR=VALの形式である必要がある。
# #で始まる行 (例えばコメント)は無視される。
# 空の行は無視される。
# クオーテーションマークは特別な扱いは処理をしない(例えばConfigMapの値の一部になる).
# `configure-pod-container/configmap/`ディレクトリにサンプルファイルをダウンロードします
wget https://kubernetes.io/examples/configmap/game-env-file.properties -O configure-pod-container/configmap/game-env-file.properties
# env-file `game-env-file.properties`は以下のようになります
cat configure-pod-container/configmap/game-env-file.properties
enemies=aliens
lives=3
allowed="true"
# このコメントと上記の空の行は無視されます
kubectl create configmap game-config-env-file \
--from-env-file=configure-pod-container/configmap/game-env-file.properties
は、以下のConfigMapを生成します:
kubectl get configmap game-config-env-file -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2017-12-27T18:36:28Z
name: game-config-env-file
namespace: default
resourceVersion: "809965"
uid: d9d1ca5b-eb34-11e7-887b-42010a8002b8
data:
allowed: '"true"'
enemies: aliens
lives: "3"
--from-env-file
を複数回渡してConfigMapを複数のデータソースから作成する場合、最後のenv-fileのみが使用されます。
--from-env-file
を複数回渡す場合の挙動は以下のように示されます:
# `configure-pod-container/configmap/`ディレクトリにサンブルファイルをダウンロードします
wget https://kubernetes.io/examples/configmap/ui-env-file.properties -O configure-pod-container/configmap/ui-env-file.properties
# ConfigMapを作成します
kubectl create configmap config-multi-env-files \
--from-env-file=configure-pod-container/configmap/game-env-file.properties \
--from-env-file=configure-pod-container/configmap/ui-env-file.properties
は、以下のConfigMapを生成します:
kubectl get configmap config-multi-env-files -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2017-12-27T18:38:34Z
name: config-multi-env-files
namespace: default
resourceVersion: "810136"
uid: 252c4572-eb35-11e7-887b-42010a8002b8
data:
color: purple
how: fairlyNice
textmode: "true"
--from-file
引数を使用する場合、ConfigMapのdata
セクションでキーにファイル名以外を定義できます:
kubectl create configmap game-config-3 --from-file=<my-key-name>=<path-to-file>
<my-key-name>
の部分はConfigMapで使うキー、<path-to-file>
はキーで表示したいデータソースファイルの場所です。
例えば:
kubectl create configmap game-config-3 --from-file=game-special-key=configure-pod-container/configmap/game.properties
は、以下のConfigMapを生成します:
kubectl get configmaps game-config-3 -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T18:54:22Z
name: game-config-3
namespace: default
resourceVersion: "530"
uid: 05f8da22-d671-11e5-8cd0-68f728db1985
data:
game-special-key: |
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
--from-literal
引数を指定してkubectl create configmap
を使用すると、コマンドラインからリテラル値を定義できます:
kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
複数のキーバリューペアを渡せます。CLIに提供された各ペアは、ConfigMapのdata
セクションで別のエントリーとして表示されます。
kubectl get configmaps special-config -o yaml
出力結果は以下のようになります:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T19:14:38Z
name: special-config
namespace: default
resourceVersion: "651"
uid: dadce046-d673-11e5-8cd0-68f728db1985
data:
special.how: very
special.type: charm
kubectl
はkustomization.yaml
を1.14からサポートしています。
ジェネレーターからConfigMapを作成して適用すると、APIサーバー上でオブジェクトを作成できます。ジェネレーターはディレクトリ内のkustomization.yaml
で指定する必要があリます。
例えば、ファイルconfigure-pod-container/configmap/game.properties
からConfigMapを生成するには、
# ConfigMapGeneratorを含むkustomization.yamlファイルを作成する
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-4
files:
- configure-pod-container/configmap/game.properties
EOF
ConfigMapを作成するためにkustomizationディレクトリを適用します。
kubectl apply -k .
configmap/game-config-4-m9dm2f92bt created
ConfigMapが作成されたことを以下のようにチェックできます:
kubectl get configmap
NAME DATA AGE
game-config-4-m9dm2f92bt 1 37s
kubectl describe configmaps/game-config-4-m9dm2f92bt
Name: game-config-4-m9dm2f92bt
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","data":{"game.properties":"enemies=aliens\nlives=3\nenemies.cheat=true\nenemies.cheat.level=noGoodRotten\nsecret.code.p...
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
Events: <none>
生成されたConfigMapの名前は、コンテンツをハッシュ化したサフィックスを持つことに注意してください。これにより、コンテンツが変更されるたびに新しいConfigMapが生成されます。
ConfigMapジェネレーターで使用するキーはファイルの名前以外を定義できます。
例えば、ファイルconfigure-pod-container/configmap/game.properties
からキーgame-special-key
を持つConfigMapを作成する場合
# ConfigMapGeneratorを含むkustomization.yamlファイルを作成する
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-5
files:
- game-special-key=configure-pod-container/configmap/game.properties
EOF
kustomizationディレクトリを適用してConfigMapを作成します。
kubectl apply -k .
configmap/game-config-5-m67dt67794 created
リテラルspecial.type=charm
とspecial.how=very
からConfigMapを作成する場合は、
以下のようにkustomization.yaml
のConfigMapジェネレーターで指定できます。
# ConfigMapGeneratorを含むkustomization.yamlファイルを作成します
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: special-config-2
literals:
- special.how=very
- special.type=charm
EOF
kustomizationディレクトリを適用してConfigMapを作成します。
kubectl apply -k .
configmap/special-config-2-c92b5mmcf2 created
ConfigMapに環境変数をキーバリューペアとして定義します:
kubectl create configmap special-config --from-literal=special.how=very
ConfigMapに定義された値special.how
をPod specificationの環境変数SPECIAL_LEVEL_KEY
に割り当てます。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
# 環境変数を定義します
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
# SPECIAL_LEVEL_KEYに割り当てる値をConfigMapが保持します
name: special-config
# 値に紐付けるキーを指定します
key: special.how
restartPolicy: Never
Podを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-single-configmap-env-variable.yaml
すると、Podの出力結果に環境変数SPECIAL_LEVEL_KEY=very
が含まれています。
先ほどの例の通り、まずはConfigMapを作成します。
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
---
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO
ConfigMapを作成します:
kubectl create -f https://kubernetes.io/examples/configmap/configmaps.yaml
Pod specificationの環境変数を定義します
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: env-config
key: log_level
restartPolicy: Never
Podを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-multiple-configmap-env-variable.yaml
すると、Podの出力結果に環境変数SPECIAL_LEVEL_KEY=very
and LOG_LEVEL=INFO
が含まれています。
複数のキーバリューペアを含むConfigMapを作成します。
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
SPECIAL_LEVEL: very
SPECIAL_TYPE: charm
ConfigMapを作成します:
kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml
envFrom
を利用して全てのConfigMapのデータをコンテナ環境変数として定義します。ConfigMapからのキーがPodの環境変数名になります。apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: special-config
restartPolicy: Never
Podを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-envFrom.yaml
すると、Podの出力結果は環境変数SPECIAL_LEVEL=very
とSPECIAL_TYPE=charm
が含まれています。
ConfigMapに環境変数を定義し、Pod specificationのcommand
セクションで$(VAR_NAME)
Kubernetes置換構文を介して使用できます。
例えば以下のPod specificationは
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: SPECIAL_LEVEL
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: SPECIAL_TYPE
restartPolicy: Never
以下コマンドの実行で作成され、
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-env-var-valueFrom.yaml
test-container
コンテナで以下の出力結果を表示します:
very charm
ファイルからConfigMapを作成するで説明したように、--from-file
を使用してConfigMapを作成する場合は、ファイル名がConfigMapのdata
セクションに保存されるキーになり、ファイルのコンテンツがキーの値になります。
このセクションの例は以下に示されているspecial-configと名付けれたConfigMapについて言及したものです。
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
SPECIAL_LEVEL: very
SPECIAL_TYPE: charm
ConfigMapを作成します:
kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml
ConfigMap名をPod specificationのvolumes
セクション配下に追加します。
これによりConfigMapデータがvolumeMounts.mountPath
で指定されたディレクトリに追加されます (このケースでは、/etc/config
に)。command
セクションはConfigMapのキーに合致したディレクトリファイルを名前別でリスト表示します。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "ls /etc/config/" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
# コンテナに追加するファイルを含むConfigMapの名前を提供する
name: special-config
restartPolicy: Never
Podを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume.yaml
Podが稼働していると、ls /etc/config/
は以下の出力結果を表示します:
SPECIAL_LEVEL
SPECIAL_TYPE
/etc/config/
ディレクトリに何かファイルがある場合、それらは削除されます。
path
フィールドを利用して特定のConfigMapのアイテム向けに希望のファイルパスを指定します。
このケースではSPECIAL_LEVEL
アイテムが/etc/config/keys
のconfig-volume
ボリュームにマウントされます。
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh","-c","cat /etc/config/keys" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: SPECIAL_LEVEL
path: keys
restartPolicy: Never
Podを作成します:
kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume-specific-key.yaml
Podが稼働していると、 cat /etc/config/keys
は以下の出力結果を表示します:
very
/etc/config/
ディレクトリのこれまでのファイルは全て削除されます
キーをファイル単位で特定のパスとアクセス許可に投影できます。Secretのユーザーガイドで構文が解説されています。
ボリュームで使用されているConfigMapが更新されている場合、投影されているキーも同じく結果的に更新されます。kubeletは定期的な同期ごとにマウントされているConfigMapが更新されているかチェックします。しかし、これはローカルのttlを基にしたキャッシュでConfigMapの現在の値を取得しています。その結果、新しいキーがPodに投影されてからConfigMapに更新されるまでのトータルの遅延はkubeletで、kubeletの同期期間(デフォルトで1分) + ConfigMapキャッシュのttl(デフォルトで1分)の長さになる可能性があります。Podのアノテーションを1つ更新すると即時のリフレッシュをトリガーできます。
ConfigMap APIリソースは構成情報をキーバリューペアとして保存します。データはPodで利用したり、コントローラーなどのシステムコンポーネントに提供できます。ConfigMapはSecretに似ていますが、機密情報を含まない文字列を含まない操作する手段を提供します。ユーザーとシステムコンポーネントはどちらも構成情報をConfigMapに保存できます。
/etc
ディレクトリとそのコンテンツのように捉えましょう。例えば、Kubernetes VolumeをConfigMapから作成した場合、ConfigMapのデータアイテムはボリューム内で個別のファイルとして表示されます。
ConfigMapのdata
フィールドは構成情報を含みます。下記の例のように、シンプルに個別のプロパティーを--from-literal
で定義、または複雑に構成ファイルまたはJSON blobsを--from-file
で定義できます。
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T19:14:38Z
name: example-config
namespace: default
data:
# --from-literalを使用してシンプルにプロパティーを定義する例
example.property.1: hello
example.property.2: world
# --from-fileを使用して複雑にプロパティーを定義する例
example.property.file: |-
property.1=value-1
property.2=value-2
property.3=value-3
ConfigMapはPod specificationを参照させる前に作成する必要があります(ConfigMapを"optional"として設定しない限り)。存在しないConfigMapを参照させた場合、Podは起動しません。同様にConfigMapに存在しないキーを参照させた場合も、Podは起動しません。
ConfigMapでenvFrom
を使用して環境変数を定義した場合、無効と判断されたキーはスキップされます。Podは起動されますが、無効な名前はイベントログに(InvalidVariableNames
)と記録されます。ログメッセージはスキップされたキーごとにリスト表示されます。例えば:
kubectl get events
出力結果は以下のようになります:
LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON SOURCE MESSAGE
0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames {kubelet, 127.0.0.1} Keys [1badkey, 2alsobad] from the EnvFrom configMap default/myconfig were skipped since they are considered invalid environment variable names.
ConfigMapは特定のNamespaceに属します。ConfigMapは同じ名前空間に属するPodからのみ参照できます。
static podsはKubeletがサポートしていないため、ConfigMapに使用できません。
Kubernetes v1.17 [stable]
このページでは、プロセス名前空間を共有するPodを構成する方法を示します。 プロセス名前空間の共有が有効になっている場合、コンテナ内のプロセスは、そのPod内の他のすべてのコンテナに表示されます。
この機能を使用して、ログハンドラーサイドカーコンテナなどの協調コンテナを構成したり、シェルなどのデバッグユーティリティを含まないコンテナイメージをトラブルシューティングしたりできます。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.10. バージョンを確認するには次のコマンドを実行してください:kubectl version
.
プロセス名前空間の共有は、v1.PodSpec
のshareProcessNamespace
フィールドを使用して有効にします。
例:
クラスターにPod nginx
を作成します:
kubectl apply -f https://k8s.io/examples/pods/share-process-namespace.yaml
shell
コンテナにアタッチしてps
を実行します:
kubectl attach -it nginx -c shell
コマンドプロンプトが表示されない場合は、Enterキーを押してみてください。
/ # ps ax
PID USER TIME COMMAND
1 root 0:00 /pause
8 root 0:00 nginx: master process nginx -g daemon off;
14 101 0:00 nginx: worker process
15 root 0:00 sh
21 root 0:00 ps ax
他のコンテナのプロセスにシグナルを送ることができます。
たとえば、ワーカープロセスを再起動するには、SIGHUP
をnginxに送信します。
この操作にはSYS_PTRACE
機能が必要です。
/ # kill -HUP 8
/ # ps ax
PID USER TIME COMMAND
1 root 0:00 /pause
8 root 0:00 nginx: master process nginx -g daemon off;
15 root 0:00 sh
22 101 0:00 nginx: worker process
23 root 0:00 ps ax
/proc/$pid/root
リンクを使用して別のコンテナイメージにアクセスすることもできます。
/ # head /proc/8/root/etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
Podは多くのリソースを共有するため、プロセスの名前空間も共有することになります。 ただし、一部のコンテナイメージは他のコンテナから分離されることが期待されるため、これらの違いを理解することが重要です:
コンテナプロセスは PID 1ではなくなります。
一部のコンテナイメージは、PID 1なしで起動することを拒否し(たとえば、systemd
を使用するコンテナ)、kill -HUP 1
などのコマンドを実行してコンテナプロセスにシグナルを送信します。
共有プロセス名前空間を持つPodでは、kill -HUP 1
はPodサンドボックスにシグナルを送ります。(上の例では/pause
)
プロセスはPod内の他のコンテナに表示されます。
これには、引数または環境変数として渡されたパスワードなど、/proc
に表示されるすべての情報が含まれます。
これらは、通常のUnixアクセス許可によってのみ保護されます。
コンテナファイルシステムは、/proc/$pid/root
リンクを介してPod内の他のコンテナに表示されます。
これによりデバッグが容易になりますが、ファイルシステム内の秘密情報はファイルシステムのアクセス許可によってのみ保護されることも意味します。
Static Podとは、APIサーバーが監視せず、特定のノード上のkubeletデーモンによって直接管理されるPodです。コントロールプレーンに管理されるPod(たとえばDeploymentなど)とは異なり、kubeletがそれぞれのstatic Podを監視(および障害時には再起動)します。
Static Podは、常に特定のノード上の1つのKubeletに紐付けられます。
kubeletは、各static Podに対して、自動的にKubernetes APIサーバー上にミラーPodの作成を試みます。つまり、ノード上で実行中のPodはAPIサーバーから検出されますが、APIサーバー自身から制御されることはないということです。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
このページの説明では、Podを実行するためにDockerを使用しており、ノード上のOSがFedoraであることを前提としています。他のディストリビューションやKubernetesのインストール方法によっては、操作が異なる場合があります。
static Podは、ファイルシステム上でホストされた設定ファイルまたはウェブ上でホストされた設定ファイルを使用して設定できます。
マニフェストは、JSONまたはYAML形式の標準のPod定義で、特定のディレクトリに置きます。kubeletの設定ファイルの中で、staticPodPath: <ディレクトリの場所>
というフィールドを使用すると、kubeletがこのディレクトリを定期的にスキャンして、YAML/JSONファイルが作成/削除されるたびに、static Podの作成/削除が行われるようになります。指定したディレクトリをスキャンする際、kubeletはドットから始まる名前のファイルを無視することに注意してください。
例として、単純なウェブサーバーをstatic Podとして実行する方法を示します。
static Podを実行したいノードを選択します。この例では、my-node1
です。
ssh my-node1
ディレクトリを選び(ここでは/etc/kubelet.d
とします)、ここにウェブサーバーのPodの定義を置きます。たとえば、/etc/kubelet.d/static-web.yaml
に置きます。
# このコマンドは、kubeletが実行中のノード上で実行してください
mkdir /etc/kubelet.d/
cat <<EOF >/etc/kubelet.d/static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
EOF
ノード上のkubeletがこのディレクトリを使用するようにするために、--pod-manifest-path=/etc/kubelet.d/
引数を付けてkubeletを実行するように設定します。Fedoraの場合、次の行が含まれるように/etc/kubernetes/kubelet
を編集します。
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --pod-manifest-path=/etc/kubelet.d/"
あるいは、kubeletの設定ファイルに、staticPodPath: <ディレクトリの場所>
フィールドを追加することでも設定できます。
kubeletを再起動します。Fedoraの場合、次のコマンドを実行します。
# このコマンドは、kubeletが実行中のノード上で実行してください
systemctl restart kubelet
kubeletは、--manifest-url=<URL>
引数で指定されたファイルを定期的にダウンロードし、Podの定義が含まれたJSON/YAMLファイルとして解釈します。kubeletは、ファイルシステム上でホストされたマニフェストでの動作方法と同じように、定期的にマニフェストを再取得します。static Podのリスト中に変更が見つかると、kubeletがその変更を適用します。
このアプローチを採用する場合、次のように設定します。
YAMLファイルを作成し、kubeletにファイルのURLを渡せるようにするために、ウェブサーバー上に保存する。
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
選択したノード上のkubeletを--manifest-url=<manifest-url>
を使用して実行することで、このウェブ上のマニフェストを使用するように設定する。Fedoraの場合、/etc/kubernetes/kubelet
に次の行が含まれるように編集します。
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --manifest-url=<マニフェストのURL"
kubeletを再起動する。Fedoraの場合、次のコマンドを実行します。
# このコマンドは、kubeletが実行中のノード上で実行してください
systemctl restart kubelet
kubeletが起動すると、定義されたすべてのstatic Podを起動します。ここまででstatic Podを設定してkubeletを再起動したため、すでに新しいstatic Podが実行中になっているはずです。
次のコマンドを(ノード上で)実行することで、(static Podを含む)実行中のコンテナを確認できます。
# このコマンドは、kubeletが実行中のノード上で実行してください
docker ps
出力は次のようになります。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f6d05272b57e nginx:latest "nginx" 8 minutes ago Up 8 minutes k8s_web.6f802af4_static-web-fk-node1_default_67e24ed9466ba55986d120c867395f3c_378e5f3c
APIサーバー上では、ミラーPodを確認できます。
kubectl get pods
NAME READY STATUS RESTARTS AGE
static-web-my-node1 1/1 Running 0 2m
static Podに付けたラベルはミラーPodに伝搬します。ミラーPodに付けたラベルは、通常のPodと同じようにセレクターなどから利用できます。
もしkubectl
を使用してAPIサーバーからミラーPodを削除しようとしても、kubeletはstatic Podを削除しません。
kubectl delete pod static-web-my-node1
pod "static-web-my-node1" deleted
Podはまだ実行中であることがわかります。
kubectl get pods
NAME READY STATUS RESTARTS AGE
static-web-my-node1 1/1 Running 0 12s
kubeletが実行中のノードに戻り、Dockerコンテナを手動で停止してみることができます。しばらくすると、kubeletが変化に気づき、Podを自動的に再起動することがわかります。
# このコマンドは、kubeletが実行中のノード上で実行してください
docker stop f6d05272b57e # 実際のコンテナIDと置き換えてください
sleep 20
docker ps
CONTAINER ID IMAGE COMMAND CREATED ...
5b920cbaf8b1 nginx:latest "nginx -g 'daemon of 2 seconds ago ...
実行中のkubeletは設定ディレクトリ(この例では/etc/kubelet.d
)の変更を定期的にスキャンし、このディレクトリ内にファイルが追加/削除されると、Podの追加/削除を行います。
# This assumes you are using filesystem-hosted static Pod configuration
# このコマンドは、kubeletが実行中のノード上で実行してください
#
mv /etc/kubelet.d/static-web.yaml /tmp
sleep 20
docker ps
# You see that no nginx container is running
mv /tmp/static-web.yaml /etc/kubelet.d/
sleep 20
docker ps
CONTAINER ID IMAGE COMMAND CREATED ...
e7a62e3427f1 nginx:latest "nginx -g 'daemon of 27 seconds ago
このページでは、Namespaceで実行されるコンテナが使用するメモリーの最小値と最大値を設定する方法を説明します。 LimitRange で最小値と最大値のメモリー値を指定します。 PodがLimitRangeによって課される制約を満たさない場合、そのNamespaceではPodを作成できません。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
クラスター内の各ノードには、少なくとも1GiBのメモリーが必要です。
この演習で作成したリソースがクラスターの他の部分から分離されるように、Namespaceを作成します。
kubectl create namespace constraints-mem-example
LimitRangeの設定ファイルです。
apiVersion: v1
kind: LimitRange
metadata:
name: mem-min-max-demo-lr
spec:
limits:
- max:
memory: 1Gi
min:
memory: 500Mi
type: Container
LimitRangeを作成します。
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints.yaml --namespace=constraints-mem-example
LimitRangeの詳細情報を表示します。
kubectl get limitrange mem-min-max-demo-lr --namespace=constraints-mem-example --output=yaml
出力されるのは、予想通りメモリー制約の最小値と最大値を示しています。 しかし、LimitRangeの設定ファイルでデフォルト値を指定していないにもかかわらず、 自動的に作成されていることに気づきます。
limits:
- default:
memory: 1Gi
defaultRequest:
memory: 1Gi
max:
memory: 1Gi
min:
memory: 500Mi
type: Container
constraints-mem-exampleNamespaceにコンテナが作成されるたびに、 Kubernetesは以下の手順を実行するようになっています。
コンテナが独自のメモリー要求と制限を指定しない場合は、デフォルトのメモリー要求と制限をコンテナに割り当てます。
コンテナに500MiB以上のメモリー要求があることを確認します。
コンテナのメモリー制限が1GiB以下であることを確認します。
以下は、1つのコンテナを持つPodの設定ファイルです。設定ファイルのコンテナ(containers)では、600MiBのメモリー要求と800MiBのメモリー制限が指定されています。これらはLimitRangeによって課される最小と最大のメモリー制約を満たしています。
apiVersion: v1
kind: Pod
metadata:
name: constraints-mem-demo
spec:
containers:
- name: constraints-mem-demo-ctr
image: nginx
resources:
limits:
memory: "800Mi"
requests:
memory: "600Mi"
Podの作成
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod.yaml --namespace=constraints-mem-example
Podのコンテナが実行されていることを確認します。
kubectl get pod constraints-mem-demo --namespace=constraints-mem-example
Podの詳細情報を見ます
kubectl get pod constraints-mem-demo --output=yaml --namespace=constraints-mem-example
出力は、コンテナが600MiBのメモリ要求と800MiBのメモリー制限になっていることを示しています。これらはLimitRangeによって課される制約を満たしています。
resources:
limits:
memory: 800Mi
requests:
memory: 600Mi
Podを消します。
kubectl delete pod constraints-mem-demo --namespace=constraints-mem-example
これは、1つのコンテナを持つPodの設定ファイルです。コンテナは800MiBのメモリー要求と1.5GiBのメモリー制限を指定しています。
apiVersion: v1
kind: Pod
metadata:
name: constraints-mem-demo-2
spec:
containers:
- name: constraints-mem-demo-2-ctr
image: nginx
resources:
limits:
memory: "1.5Gi"
requests:
memory: "800Mi"
Podを作成してみます。
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod-2.yaml --namespace=constraints-mem-example
出力は、コンテナが大きすぎるメモリー制限を指定しているため、Podが作成されないことを示しています。
Error from server (Forbidden): error when creating "examples/admin/resource/memory-constraints-pod-2.yaml":
pods "constraints-mem-demo-2" is forbidden: maximum memory usage per Container is 1Gi, but limit is 1536Mi.
これは、1つのコンテナを持つPodの設定ファイルです。コンテナは100MiBのメモリー要求と800MiBのメモリー制限を指定しています。
apiVersion: v1
kind: Pod
metadata:
name: constraints-mem-demo-3
spec:
containers:
- name: constraints-mem-demo-3-ctr
image: nginx
resources:
limits:
memory: "800Mi"
requests:
memory: "100Mi"
Podを作成してみます。
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod-3.yaml --namespace=constraints-mem-example
出力は、コンテナが小さすぎるメモリー要求を指定しているため、Podが作成されないことを示しています。
Error from server (Forbidden): error when creating "examples/admin/resource/memory-constraints-pod-3.yaml":
pods "constraints-mem-demo-3" is forbidden: minimum memory usage per Container is 500Mi, but request is 100Mi.
これは、1つのコンテナを持つPodの設定ファイルです。コンテナはメモリー要求を指定しておらず、メモリー制限も指定していません。
apiVersion: v1
kind: Pod
metadata:
name: constraints-mem-demo-4
spec:
containers:
- name: constraints-mem-demo-4-ctr
image: nginx
Podを作成します。
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod-4.yaml --namespace=constraints-mem-example
Podの詳細情報を見ます
kubectl get pod constraints-mem-demo-4 --namespace=constraints-mem-example --output=yaml
出力を見ると、Podのコンテナのメモリ要求は1GiB、メモリー制限は1GiBであることがわかります。 コンテナはどのようにしてこれらの値を取得したのでしょうか?
resources:
limits:
memory: 1Gi
requests:
memory: 1Gi
コンテナが独自のメモリー要求と制限を指定していなかったため、LimitRangeから与えられのです。 コンテナが独自のメモリー要求と制限を指定していなかったため、LimitRangeからデフォルトのメモリー要求と制限が与えられたのです。
この時点で、コンテナは起動しているかもしれませんし、起動していないかもしれません。このタスクの前提条件は、ノードが少なくとも1GiBのメモリーを持っていることであることを思い出してください。それぞれのノードが1GiBのメモリーしか持っていない場合、どのノードにも1GiBのメモリー要求に対応するのに十分な割り当て可能なメモリーがありません。たまたま2GiBのメモリーを持つノードを使用しているのであれば、おそらく1GiBのメモリーリクエストに対応するのに十分なスペースを持っていることになります。
Podを削除します。
kubectl delete pod constraints-mem-demo-4 --namespace=constraints-mem-example
LimitRangeによってNamespaceに課される最大および最小のメモリー制約は、Podが作成または更新されたときにのみ適用されます。LimitRangeを変更しても、以前に作成されたPodには影響しません。
クラスター管理者としては、Podが使用できるメモリー量に制限を課したいと思うかもしれません。
例:
クラスター内の各ノードは2GBのメモリーを持っています。クラスタ内のどのノードもその要求をサポートできないため、2GB以上のメモリーを要求するPodは受け入れたくありません。
クラスターは運用部門と開発部門で共有されています。 本番用のワークロードでは最大8GBのメモリーを消費しますが、開発用のワークロードでは512MBに制限したいとします。本番用と開発用に別々のNamespaceを作成し、それぞれのNamespaceにメモリー制限を適用します。
Namespaceを削除します。
kubectl delete namespace constraints-mem-example
Kubernetes v1.18 [beta]
Kubernetesを使用してLinuxノードとWindowsノードを混在させて実行できるため、Linuxで実行するPodとWindowsで実行するPodを混在させることができます。このページでは、Windowsノードをクラスターに登録する方法を示します。
kubectl version
.
WindowsコンテナをホストするWindowsノードを構成するには、Windows Server 2019ライセンス(またはそれ以上)を取得します。 VXLAN/オーバーレイネットワークを使用している場合は、KB4489899もインストールされている必要があります。
コントロールプレーンにアクセスできるLinuxベースのKubernetes kubeadmクラスター(kubeadmを使用したシングルコントロールプレーンクラスターの作成を参照)
LinuxベースのKubernetesコントロールプレーンノードを取得したら、ネットワーキングソリューションを選択できます。このガイドでは、簡単にするためにVXLANモードでのFlannelの使用について説明します。
FlannelのためにKubernetesコントロールプレーンを準備する
クラスター内のKubernetesコントロールプレーンでは、多少の準備が推奨されます。Flannelを使用する場合は、iptablesチェーンへのブリッジIPv4トラフィックを有効にすることをお勧めします。すべてのLinuxノードで次のコマンドを実行する必要があります:
sudo sysctl net.bridge.bridge-nf-call-iptables=1
Linux用のFlannelをダウンロードして構成する
最新のFlannelマニフェストをダウンロード:
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
VNIを4096、ポートを4789に設定するために、flannelマニフェストのnet-conf.json
セクションを変更します。次のようになります:
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan",
"VNI" : 4096,
"Port": 4789
}
}
Type
の値を"host-gw"
に変更し、VNI
とPort
を省略します。
Flannelマニフェストを適用して検証する
Flannelの構成を適用しましょう:
kubectl apply -f kube-flannel.yml
数分後、Flannel Podネットワークがデプロイされていれば、すべてのPodが実行されていることがわかります。
kubectl get pods -n kube-system
出力結果には、実行中のLinux flannel DaemonSetが含まれているはずです:
NAMESPACE NAME READY STATUS RESTARTS AGE
...
kube-system kube-flannel-ds-54954 1/1 Running 0 1m
Windows Flannelとkube-proxy DaemonSetを追加する
これで、Windows互換バージョンのFlannelおよびkube-proxyを追加できます。 互換性のあるバージョンのkube-proxyを確実に入手するには、イメージのタグを置換する必要があります。 次の例は、Kubernetesv1.23.0の使用方法を示していますが、 独自のデプロイに合わせてバージョンを調整する必要があります。
curl -L https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/kube-proxy.yml | sed 's/VERSION/v1.23.0/g' | kubectl apply -f -
kubectl apply -f https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/flannel-overlay.yml
Windowsノードでイーサネット(「Ethernet0 2」など)ではなく別のインターフェースを使用している場合は、次の行を変更する必要があります:
wins cli process run --path /k/flannel/setup.exe --args "--mode=overlay --interface=Ethernet"
flannel-host-gw.yml
またはflannel-overlay.yml
ファイルで、それに応じてインターフェースを指定します。
# 例
curl -L https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/flannel-overlay.yml | sed 's/Ethernet/Ethernet0 2/g' | kubectl apply -f -
Containers
機能をインストールし、Dockerをインストールする必要があります。
行うための指示としては、Dockerエンジンのインストール - Windowsサーバー上のエンタープライズを利用できます。
wins、kubelet、kubeadmをインストールします。
curl.exe -LO https://raw.githubusercontent.com/kubernetes-sigs/sig-windows-tools/master/kubeadm/scripts/PrepareNode.ps1
.\PrepareNode.ps1 -KubernetesVersion
kubeadm
を実行してノードに参加します
コントロールプレーンホストでkubeadm init
を実行したときに提供されたコマンドを使用します。
このコマンドがなくなった場合、またはトークンの有効期限が切れている場合は、kubeadm token create --print-join-command
(コントロールプレーンホスト上で)を実行して新しいトークンを生成します。
次のコマンドを実行して、クラスター内のWindowsノードを表示できるようになります:
kubectl get nodes -o wide
新しいノードがNotReady
状態の場合は、flannelイメージがまだダウンロード中の可能性があります。
kube-system
名前空間のflannel Podを確認することで、以前と同様に進行状況を確認できます:
kubectl -n kube-system get pods -l app=flannel
flannel Podが実行されると、ノードはReady
状態になり、ワークロードを処理できるようになります。
Kubernetes v1.18 [beta]
このページでは、kubeadmで作られたWindowsノードをアップグレードする方法について説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: 1.17. バージョンを確認するには次のコマンドを実行してください:kubectl version
.
Windowsノードから、kubeadmをアップグレードします。:
# v1.23.0を目的のバージョンに置き換えます
curl.exe -Lo C:\k\kubeadm.exe https://dl.k8s.io//bin/windows/amd64/kubeadm.exe
Kubernetes APIにアクセスできるマシンから、 ノードをスケジュール不可としてマークして、ワークロードを削除することでノードのメンテナンスを準備します:
# <node-to-drain>をドレインするノードの名前に置き換えます
kubectl drain <node-to-drain> --ignore-daemonsets
このような出力結果が表示されるはずです:
node/ip-172-31-85-18 cordoned
node/ip-172-31-85-18 drained
Windowsノードから、次のコマンドを呼び出して新しいkubelet構成を同期します:
kubeadm upgrade node
Windowsノードから、kubeletをアップグレードして再起動します:
stop-service kubelet
curl.exe -Lo C:\k\kubelet.exe https://dl.k8s.io//bin/windows/amd64/kubelet.exe
restart-service kubelet
Kubernetes APIにアクセスできるマシンから、 スケジュール可能としてマークして、ノードをオンラインに戻します:
# <node-to-drain>をノードの名前に置き換えます
kubectl uncordon <node-to-drain>
Kubernetes APIにアクセスできるマシンから、次を実行します、 もう一度v1.23.0を目的のバージョンに置き換えます:
curl -L https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/kube-proxy.yml | sed 's/VERSION/v1.23.0/g' | kubectl apply -f -
このページはKubernetesのEndpointSliceの有効化の概要を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
EndpointSliceは、KubernetesのEndpointsに対してスケーラブルで拡張可能な代替手段を提供します。Endpointsが提供する機能のベースの上に構築し、スケーラブルな方法で拡張します。Serviceが多数(100以上)のネットワークエンドポイントを持つ場合、それらは単一の大きなEndpointsリソースではなく、複数の小さなEndpointSliceに分割されます。
Kubernetes v1.17 [beta]
EndpoitSliceはベータ版の機能です。APIとEndpointSliceコントローラーはデフォルトで有効です。kube-proxyはデフォルトでEndpointSliceではなくEndpointsを使用します。
スケーラビリティと性能向上のため、kube-proxy上でEndpointSliceProxying
フィーチャーゲートを有効にできます。この変更はデータソースをEndpointSliceに移します、これはkube-proxyとKubernetes API間のトラフィックの量を削減します。
クラスター内でEndpointSliceを完全に有効にすると、各Endpointsリソースに対応するEndpointSliceリソースが表示されます。既存のEndpointsの機能をサポートすることに加えて、EndpointSliceはトポロジーなどの新しい情報を含みます。これらにより、クラスター内のネットワークエンドポイントのスケーラビリティと拡張性が大きく向上します。
Kubernetes v1.18 [stable]
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
NodeLocal DNSキャッシュは、クラスターノード上でDNSキャッシュエージェントをDaemonSetで稼働させることで、クラスターのDNSパフォーマンスを向上させます。現在のアーキテクチャーにおいて、ClusterFirstのDNSモードでのPodは、DNSクエリー用にkube-dnsのService IPに疎通します。これにより、kube-proxyによって追加されたiptablesを介してkube-dns/CoreDNSのエンドポイントへ変換されます。この新しいアーキテクチャーによって、Podは同じノード上で稼働するDNSキャッシュエージェントに対して疎通し、それによってiptablesのDNATルールとコネクショントラッキングを回避します。ローカルのキャッシュエージェントはクラスターのホスト名(デフォルトではcluster.localというサフィックス)に対するキャッシュミスがあるときはkube-dnsサービスへ問い合わせます。
現在のDNSアーキテクチャーでは、ローカルのkube-dns/CoreDNSがないとき、DNSへの秒間クエリー数が最も高いPodは他のノードへ疎通する可能性があります。ローカルでキャッシュを持つことにより、この状況におけるレイテンシーの改善に役立ちます。
iptables DNATとコネクショントラッキングをスキップすることはconntrackの競合を減らし、UDPでのDNSエントリーがconntrackテーブルを満杯にすることを避けるのに役立ちます。
ローカルのキャッシュエージェントからkube-dnsサービスへの接続がTCPにアップグレードされます。タイムアウトをしなくてはならないUDPエントリーと比べ、TCPのconntrackエントリーはコネクションクローズ時に削除されます(デフォルトの nf_conntrack_udp_timeout
は30秒です)。
DNSクエリーをUDPからTCPにアップグレードすることで、UDPパケットの欠損や、通常30秒(10秒のタイムアウトで3回再試行する)であるDNSのタイムアウトによるテイルレイテンシーを減少させます。NodeLocalキャッシュはUDPのDNSクエリーを待ち受けるため、アプリケーションを変更する必要はありません。
DNSクエリーに対するノードレベルのメトリクスと可視性を得られます。
DNSの不在応答のキャッシュも再度有効にされ、それによりkube-dnsサービスに対するクエリー数を減らします。
この図はNodeLocal DNSキャッシュが有効にされた後にDNSクエリーがあったときの流れとなります。
この機能は、下記の手順により有効化できます。
nodelocaldns.yaml
と同様のマニフェストを用意し、nodelocaldns.yaml
という名前で保存してください。
マニフェスト内の変数を正しい値に置き換えてください。
kubedns=kubectl get svc kube-dns -n kube-system -o jsonpath={.spec.clusterIP}
domain=<cluster-domain>
localdns=<node-local-address>
<cluster-domain>
はデフォルトで"cluster.local"です。<node-local-address>
はNodeLocal DNSキャッシュ用に確保されたローカルの待ち受けIPアドレスです。
kube-proxyがIPTABLESモードで稼働中のとき:
sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/__PILLAR__DNS__SERVER__/$kubedns/g" nodelocaldns.yaml
__PILLAR__CLUSTER__DNS__
と__PILLAR__UPSTREAM__SERVERS__
はnode-local-dnsというPodによって生成されます。
このモードでは、node-local-dns Podは<node-local-address>
とkube-dnsのサービスIPの両方で待ち受けるため、PodはIPアドレスでもDNSレコードのルップアップができます。
kube-proxyがIPVSモードで稼働中のとき:
sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/,__PILLAR__DNS__SERVER__//g; s/__PILLAR__CLUSTER__DNS__/$kubedns/g" nodelocaldns.yaml
このモードでは、node-local-dns Podは<node-local-address>
上のみで待ち受けます。node-local-dnsのインターフェースはkube-dnsのクラスターIPをバインドしません。なぜならばIPVSロードバランシング用に使われているインターフェースは既にこのアドレスを使用しているためです。
__PILLAR__UPSTREAM__SERVERS__
はnode-local-dns Podにより生成されます。
kubectl create -f nodelocaldns.yaml
を実行してください。
kube-proxyをIPVSモードで使用しているとき、NodeLocal DNSキャッシュが待ち受けている<node-local-address>
を使用するため、kubeletに対する--cluster-dns
フラグを修正する必要があります。IPVSモード以外のとき、--cluster-dns
フラグの値を修正する必要はありません。なぜならNodeLocal DNSキャッシュはkube-dnsのサービスIPと<node-local-address>
の両方で待ち受けているためです。
一度有効にすると、クラスターの各Node上で、kube-systemという名前空間でnode-local-dns Podが、稼働します。このPodはCoreDNSをキャッシュモードで稼働させるため、異なるプラグインによって公開された全てのCoreDNSのメトリクスがNode単位で利用可能となります。
kubectl delete -f <manifest>
を実行してDaemonSetを削除することによって、この機能を無効にできます。また、kubeletの設定に対して行った全ての変更をリバートすべきです。
このページでは、Kubernetes上でServiceトポロジーを有効にする方法の概要について説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
Serviceトポロジーは、クラスターのノードのトポロジーに基づいてトラフィックをルーティングできるようにする機能です。たとえば、あるServiceのトラフィックに対して、できるだけ同じノードや同じアベイラビリティゾーン上にあるエンドポイントを優先してルーティングするように指定できます。
トポロジーを考慮したServiceのルーティングを有効にするには、以下の前提を満たしている必要があります。
Kubernetes v1.17 [alpha]
Serviceトポロジーを有効にするには、すべてのKubernetesコンポーネントでServiceTopology
とEndpointSlice
フィーチャーゲートを有効にする必要があります。
--feature-gates="ServiceTopology=true,EndpointSlice=true"
Kubernetes v1.11 [beta]
クラウドプロバイダーはKubernetesプロジェクトとは異なるペースで開発およびリリースされるため、プロバイダー固有のコードを`cloud-controller-manager`バイナリに抽象化することでクラウドベンダーはKubernetesのコアのコードとは独立して開発が可能となりました。
cloud-controller-manager
は、cloudprovider.Interfaceを満たす任意のクラウドプロバイダーと接続できます。下位互換性のためにKubernetesのコアプロジェクトで提供されるcloud-controller-managerはkube-controller-manager
と同じクラウドライブラリを使用します。Kubernetesのコアリポジトリですでにサポートされているクラウドプロバイダーは、Kubernetesリポジトリにあるcloud-controller-managerを使用してKubernetesのコアから移行することが期待されています。
すべてのクラウドには動作させるためにそれぞれのクラウドプロバイダーの統合を行う独自の要件があり、kube-controller-manager
を実行する場合の要件とそれほど違わないようにする必要があります。一般的な経験則として、以下のものが必要です。
cloud-controller-managerを正常に実行するにはクラスター構成にいくつかの変更が必要です。
kube-apiserver
とkube-controller-manager
は**--cloud-provider
フラグを指定してはいけません**。これによりクラウドコントローラーマネージャーによって実行されるクラウド固有のループが実行されなくなります。将来このフラグは非推奨になり削除される予定です。kubelet
は--cloud-provider=external
で実行する必要があります。これは作業をスケジュールする前にクラウドコントローラーマネージャーによって初期化する必要があることをkubeletが認識できるようにするためです。クラウドコントローラーマネージャーを使用するようにクラスターを設定するとクラスターの動作がいくつか変わることに注意してください。
--cloud-provider=external
を指定したkubeletは、初期化時にNoSchedule
のnode.cloudprovider.kubernetes.io/uninitialized
汚染を追加します。これによりノードは作業をスケジュールする前に外部のコントローラーからの2回目の初期化が必要であるとマークされます。クラウドコントローラーマネージャーが使用できない場合クラスター内の新しいノードはスケジュールできないままになることに注意してください。スケジューラーはリージョンやタイプ(高CPU、GPU、高メモリ、スポットインスタンスなど)などのノードに関するクラウド固有の情報を必要とする場合があるためこの汚染は重要です。クラウドコントローラーマネージャーは以下を実装できます。
現在Kubernetesのコアでサポートされているクラウドを使用していて、クラウドコントローラーマネージャーを利用する場合は、kubernetesのコアのクラウドコントローラーマネージャーを参照してください。
Kubernetesのコアリポジトリにないクラウドコントローラーマネージャーの場合、クラウドベンダーまたはsigリードが管理するリポジトリでプロジェクトを見つけることができます。
すでにKubernetesのコアリポジトリにあるプロバイダーの場合、クラスター内でデーモンセットとしてKubernetesリポジトリ内部のクラウドコントローラーマネージャーを実行できます。以下をガイドラインとして使用してください。
# This is an example of how to setup cloud-controller-manager as a Daemonset in your cluster.
# It assumes that your masters can run pods and has the role node-role.kubernetes.io/master
# Note that this Daemonset will not work straight out of the box for your cloud, this is
# meant to be a guideline.
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cloud-controller-manager
namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: system:cloud-controller-manager
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: cloud-controller-manager
namespace: kube-system
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
k8s-app: cloud-controller-manager
name: cloud-controller-manager
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: cloud-controller-manager
template:
metadata:
labels:
k8s-app: cloud-controller-manager
spec:
serviceAccountName: cloud-controller-manager
containers:
- name: cloud-controller-manager
# for in-tree providers we use k8s.gcr.io/cloud-controller-manager
# this can be replaced with any other image for out-of-tree providers
image: k8s.gcr.io/cloud-controller-manager:v1.8.0
command:
- /usr/local/bin/cloud-controller-manager
- --cloud-provider=<YOUR_CLOUD_PROVIDER> # Add your own cloud provider here!
- --leader-elect=true
- --use-service-account-credentials
# these flags will vary for every cloud provider
- --allocate-node-cidrs=true
- --configure-cloud-routes=true
- --cluster-cidr=172.17.0.0/16
tolerations:
# this is required so CCM can bootstrap itself
- key: node.cloudprovider.kubernetes.io/uninitialized
value: "true"
effect: NoSchedule
# this is to have the daemonset runnable on master nodes
# the taint may vary depending on your cluster setup
- key: node-role.kubernetes.io/master
effect: NoSchedule
# this is to restrict CCM to only run on master nodes
# the node selector may vary depending on your cluster setup
nodeSelector:
node-role.kubernetes.io/master: ""
クラウドコントローラーマネージャーの実行にはいくつかの制限があります。これらの制限は今後のリリースで対処されますが、本番のワークロードにおいてはこれらの制限を認識することが重要です。
ボリュームの統合にはkubeletとの調整も必要になるためクラウドコントローラーマネージャーはkube-controller-manager
にあるボリュームコントローラーを実装しません。CSI(コンテナストレージインターフェイス)が進化してFlexボリュームプラグインの強力なサポートが追加されるにつれ、クラウドがボリュームと完全に統合できるようクラウドコントローラーマネージャーに必要なサポートが追加されます。Kubernetesリポジトリの外部にあるCSIボリュームプラグインの詳細についてはこちらをご覧ください。
cloud-controller-managerは、クラウドプロバイダーのAPIにクエリーを送信して、すべてのノードの情報を取得します。非常に大きなクラスターの場合、リソース要件やAPIレートリミットなどのボトルネックの可能性を考慮する必要があります。
クラウドコントローラーマネージャープロジェクトの目標はKubernetesのコアプロジェクトからクラウドに関する機能の開発を切り離すことです。残念ながら、Kubernetesプロジェクトの多くの面でクラウドプロバイダーの機能がKubernetesプロジェクトに緊密に結びついているという前提があります。そのため、この新しいアーキテクチャを採用するとクラウドプロバイダーの情報を要求する状況が発生する可能性がありますが、クラウドコントローラーマネージャーはクラウドプロバイダーへのリクエストが完了するまでその情報を返すことができない場合があります。
これの良い例は、KubeletのTLSブートストラップ機能です。TLSブートストラップはKubeletがすべてのアドレスタイプ(プライベート、パブリックなど)をクラウドプロバイダー(またはローカルメタデータサービス)に要求する能力を持っていると仮定していますが、クラウドコントローラーマネージャーは最初に初期化されない限りノードのアドレスタイプを設定できないためapiserverと通信するためにはkubeletにTLS証明書が必要です。
このイニシアチブが成熟するに連れ、今後のリリースでこれらの問題に対処するための変更が行われます。
独自のクラウドコントローラーマネージャーを構築および開発するにはクラウドコントローラーマネージャーの開発を参照してください。
cloud-controller-managerは クラウド特有の制御ロジックを組み込むKubernetesのcontrol planeコンポーネントです。クラウドコントロールマネージャーは、クラスターをクラウドプロバイダーAPIをリンクし、クラスタのみで相互作用するコンポーネントからクラウドプラットフォームで相互作用するコンポーネントを分離します。
Kubernetesと下のクラウドインフラストラクチャー間の相互運用ロジックを分離することで、cloud-controller-managerコンポーネントはクラウドプロバイダを主なKubernetesプロジェクトと比較し異なるペースで機能をリリース可能にします。
クラウドプロバイダーはKubernetesプロジェクトとは異なる速度で開発しリリースすることから、プロバイダー特有なコードをcloud-controller-manager
バイナリから抽象化することで、クラウドベンダーはコアKubernetesコードから独立して発展することができます。
Kubernetesプロジェクトは、(クラウドプロバイダーの)独自実装を組み込めるGoインターフェースを備えたcloud-controller-managerのスケルトンコードを提供しています。これは、クラウドプロバイダーがKubernetesコアからパッケージをインポートすることでcloud-controller-managerを実装できることを意味します。各クラウドプロバイダーは利用可能なクラウドプロバイダーのグローバル変数を更新するためにcloudprovider.RegisterCloudProvider
を呼び出し、独自のコードを登録します。
Kubernetesには登録されていない独自のクラウドプロバイダーのクラウドコントローラーマネージャーを構築するには、
main.go
をあなたのmain.go
のテンプレートとして利用します。上で述べたように、唯一の違いはインポートされるクラウドパッケージのみです。main.go
にインポートし、パッケージに cloudprovider.RegisterCloudProvider
を実行するための init
ブロックがあることを確認します。多くのクラウドプロバイダーはオープンソースとしてコントローラーマネージャーのコードを公開しています。新たにcloud-controller-managerをスクラッチから開発する際には、既存のKubernetesには登録されていない独自クラウドプロバイダーのコントローラーマネージャーを開始地点とすることができます。
Kubernetesに登録されているクラウドプロバイダーであれば、DaemonSetを使ってあなたのクラスターで動かすことができます。詳細についてはKubernetesクラウドコントローラーマネージャーを参照してください。
このページでは、CoreDNSのアップグレードプロセスと、kube-dnsの代わりにCoreDNSをインストールする方法を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.9. バージョンを確認するには次のコマンドを実行してください:kubectl version
.
CoreDNSは、KubernetesクラスターDNSとして稼働させることができる柔軟で拡張可能なDNSサーバーです。Kubernetesと同様に、CoreDNSプロジェクトはCNCFによってホストされています。
既存のデプロイでkube-dnsを置き換えるか、クラスターのデプロイとアップグレードを代行してくれるkubeadmのようなツールを使用することで、クラスターでkube-dnsの代わりにCoreDNSを使用することができます。
kube-dnsの手動デプロイや置き換えについては、CoreDNS GitHub projectのドキュメントを参照してください。
Kubernetesバージョン1.10以降では、kube-dns
を使用しているクラスターをkubeadm
を使用してアップグレードするときに、CoreDNSに移行することもできます。この場合、kubeadm
は、kube-dns
ConfigMapをベースにしてCoreDNS設定("Corefile")を生成し、フェデレーション、スタブドメイン、および上流のネームサーバーの設定を保持します。
kube-dnsからCoreDNSに移行する場合は、アップグレード時に必ずCoreDNS
フィーチャーゲートをtrue
に設定してください。たとえば、v1.11.0
のアップグレードは次のようになります:
kubeadm upgrade apply v1.11.0 --feature-gates=CoreDNS=true
Kubernetesバージョン1.13以降では、CoreDNS
フィーチャーゲートが削除され、CoreDNSがデフォルトで使用されます。アップグレードしたクラスターでkube-dnsを使用する場合は、こちらのガイドに従ってください。
1.11以前のバージョンでは、Corefileはアップグレード中に作成されたものによって上書きされます。カスタマイズしている場合は、既存のConfigMapを保存する必要があります。 新しいConfigMapが稼働したら、カスタマイズを再適用できます。
Kubernetesバージョン1.11以降でCoreDNSを実行している場合、アップグレード中、既存のCorefileは保持されます。
1.13以前のバージョンにkube-dnsをインストールするには、CoreDNS
フィーチャーゲートの値をfalse
に設定します:
kubeadm init --feature-gates=CoreDNS=false
バージョン1.13以降の場合は、こちらに記載されているガイドに従ってください。
CoreDNSはv1.9以降のKubernetesで使用できます。Kubernetesに同梱されているCoreDNSのバージョンと、CoreDNSに加えられた変更はこちらで確認できます。
CoreDNSだけをアップグレードしたい場合や、独自のカスタムイメージを使用したい場合は、CoreDNSを手動でアップグレードすることができます。スムーズなアップグレードのために役立つガイドラインとウォークスルーが用意されています。
リソース使用率が問題になる場合は、CoreDNSの設定を調整すると役立つ場合があります。詳細は、CoreDNSのスケーリングに関するドキュメントを参照してください。
CoreDNSは、Corefile
を変更することで、kube-dnsよりも多くのユースケースをサポートするように設定することができます。詳細はCoreDNSサイトを参照してください。
このドキュメントでは、Pod同士の通信を制御するネットワークポリシーを定義するための、KubernetesのNetworkPolicy APIを使い始める手助けをします。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.8. バージョンを確認するには次のコマンドを実行してください:kubectl version
.
ネットワークポリシーをサポートしているネットワークプロバイダーが設定済みであることを確認してください。さまざまなネットワークプロバイダーがNetworkPolicyをサポートしています。次に挙げるのは一例です。
nginx
Deploymentを作成してService経由で公開するKubernetesのネットワークポリシーの仕組みを理解するために、まずはnginx
Deploymentを作成することから始めましょう。
kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
nginx
という名前のService経由でDeploymentを公開します。
kubectl expose deployment nginx --port=80
service/nginx exposed
上記のコマンドを実行すると、nginx Podを持つDeploymentが作成され、そのDeploymentがnginx
という名前のService経由で公開されます。nginx
のPodおよびDeploymentはdefault
名前空間の中にあります。
kubectl get svc,pod
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes 10.100.0.1 <none> 443/TCP 46m
service/nginx 10.100.0.16 <none> 80/TCP 33s
NAME READY STATUS RESTARTS AGE
pod/nginx-701339712-e0qfq 1/1 Running 0 35s
これで、新しいnginx
サービスに他のPodからアクセスできるようになったはずです。default
名前空間内の他のPodからnginx
Serviceにアクセスするために、busyboxコンテナを起動します。
kubectl run busybox --rm -ti --image=busybox -- /bin/sh
シェルの中で、次のコマンドを実行します。
wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
remote file exists
nginx
Serviceへのアクセスを制限するnginx
Serviceへのアクセスを制限するために、access: true
というラベルが付いたPodだけがクエリできるようにします。次の内容でNetworkPolicyオブジェクトを作成してください。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
app: nginx
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
NetworkPolicyオブジェクトの名前は、有効なDNSサブドメイン名でなければなりません。
podSelector
が含まれています。このポリシーは、ラベルapp=nginx
の付いたPodを選択していることがわかります。このラベルは、nginx
Deployment内のPodに自動的に追加されたものです。空のpodSelector
は、その名前空間内のすべてのPodを選択します。
kubectlを使って、上記のnginx-policy.yaml
ファイルからNetworkPolicyを作成します。
kubectl apply -f https://k8s.io/examples/service/networking/nginx-policy.yaml
networkpolicy.networking.k8s.io/access-nginx created
nginx
Serviceに正しいラベルが付いていないPodからアクセスを試してみると、リクエストがタイムアウトします。
kubectl run busybox --rm -ti --image=busybox -- /bin/sh
シェルの中で、次のコマンドを実行します。
wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
wget: download timed out
正しいラベルが付いたPodを作成すると、リクエストが許可されるようになるのがわかります。
kubectl run busybox --rm -ti --labels="access=true" --image=busybox -- /bin/sh
シェルの中で、次のコマンドを実行します。
wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
remote file exists
Kubernetes v1.18 [beta]
近年、CPUやハードウェア・アクセラレーターの組み合わせによって、レイテンシーが致命的となる実行や高いスループットを求められる並列計算をサポートするシステムが増えています。このようなシステムには、通信、科学技術計算、機械学習、金融サービス、データ分析などの分野のワークロードが含まれます。このようなハイブリッドシステムは、高い性能の環境で構成されます。
最高のパフォーマンスを引き出すために、CPUの分離やメモリーおよびデバイスの位置に関する最適化が求められます。しかしながら、Kubernetesでは、これらの最適化は分断されたコンポーネントによって処理されます。
トポロジーマネージャー はKubeletコンポーネントの1つで最適化の役割を担い、コンポーネント群を調和して機能させます。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.18. バージョンを確認するには次のコマンドを実行してください:kubectl version
.
トポロジーマネージャー導入前は、KubernetesにおいてCPUマネージャーやデバイスマネージャーはそれぞれ独立してリソースの割り当てを決定します。 これは、マルチソケットのシステムでは望ましくない割り当てとなり、パフォーマンスやレイテンシーが求められるアプリケーションは、この望ましくない割り当てに悩まされます。 この場合の望ましくない例として、CPUやデバイスが異なるNUMAノードに割り当てられ、それによりレイテンシー悪化を招くことが挙げられます。
トポロジーマネージャーはKubeletコンポーネントであり、信頼できる情報源として振舞います。それによって、他のKubeletコンポーネントはトポロジーに沿ったリソース割り当ての選択を行うことができます。
トポロジーマネージャーは Hint Providers と呼ばれるコンポーネントのインターフェースを提供し、トポロジー情報を送受信します。トポロジーマネージャーは、ノード単位のポリシー群を保持します。ポリシーについて以下で説明します。
トポロジーマネージャーは Hint Providers からトポロジー情報を受け取ります。トポロジー情報は、利用可能なNUMAノードと優先割り当て表示を示すビットマスクです。トポロジーマネージャーのポリシーは、提供されたヒントに対して一連の操作を行い、ポリシーに沿ってヒントをまとめて最適な結果を得ます。もし、望ましくないヒントが保存された場合、ヒントの優先フィールドがfalseに設定されます。現在のポリシーでは、最も狭い優先マスクが優先されます。
選択されたヒントはトポロジーマネージャーの一部として保存されます。設定されたポリシーにしたがい、選択されたヒントに基づいてノードがPodを許可したり、拒否することができます。 トポロジーマネージャーに保存されたヒントは、Hint Providers が使用しリソース割り当てを決定します。
トポロジーマネージャーをサポートするには、TopologyManager
フィーチャーゲートを有効にする必要があります。Kubernetes 1.18ではデフォルトで有効です。
トポロジーマネージャは現在:
これらの条件が合致した場合、トポロジーマネージャーは要求されたリソースを調整します。
この調整をどのように実行するかカスタマイズするために、トポロジーマネージャーは2つのノブを提供します: スコープ
とポリシー
です。
スコープ
はリソースの配置を行う粒度を定義します(例:pod
やcontainer
)。そして、ポリシー
は調整を実行するための実戦略を定義します(best-effort
, restricted
, single-numa-node
等)。
現在利用可能なスコープ
とポリシー
の値について詳細は以下の通りです。
トポロジーマネージャーは、以下の複数の異なるスコープでリソースの調整を行う事が可能です:
container
(デフォルト)pod
いずれのオプションも、--topology-manager-scope
フラグによって、kubelet起動時に選択できます。
container
スコープはデフォルトで使用されます。
このスコープでは、トポロジーマネージャーは連続した複数のリソース調整を実行します。つまり、Pod内の各コンテナは、分離された配置計算がされます。言い換えると、このスコープでは、コンテナを特定のNUMAノードのセットにグループ化するという概念はありません。実際には、トポロジーマネージャーは各コンテナのNUMAノードへの配置を任意に実行します。
コンテナをグループ化するという概念は、以下のスコープで設定・実行されます。例えば、pod
スコープが挙げられます。
pod
スコープを選択するには、コマンドラインで--topology-manager-scope=pod
オプションを指定してkubeletを起動します。
このスコープでは、Pod内全てのコンテナを共通のNUMAノードのセットにグループ化することができます。トポロジーマネージャーはPodをまとめて1つとして扱い、ポッド全体(全てのコンテナ)を単一のNUMAノードまたはNUMAノードの共通セットのいずれかに割り当てようとします。以下の例は、さまざまな場面でトポロジーマネージャーが実行する調整を示します:
Pod全体に要求される特定のリソースの総量は有効なリクエスト/リミットの式に従って計算されるため、この総量の値は以下の最大値となります。
pod
スコープとsingle-numa-node
トポロジーマネージャーポリシーを併用することは、レイテンシーが重要なワークロードやIPCを行う高スループットのアプリケーションに対して特に有効です。両方のオプションを組み合わせることで、Pod内の全てのコンテナを単一のNUMAノードに配置できます。そのため、PodのNUMA間通信によるオーバーヘッドを排除することができます。
single-numa-node
ポリシーの場合、可能な割り当ての中に適切なNUMAノードのセットが存在する場合にのみ、Podが許可されます。上の例をもう一度考えてみましょう:
要約すると、トポロジーマネージャーはまずNUMAノードのセットを計算し、それをトポロジーマネージャーのポリシーと照合し、Podの拒否または許可を検証します。
トポロジーマネージャーは4つの調整ポリシーをサポートします。--topology-manager-policy
というKubeletフラグを通してポリシーを設定できます。
4つのサポートされるポリシーがあります:
none
(デフォルト)best-effort
restricted
single-numa-node
これはデフォルトのポリシーで、トポロジーの調整を実行しません。
Pod内の各コンテナに対して、best-effort
トポロジー管理ポリシーが設定されたkubeletは、各Hint Providerを呼び出してそれらのリソースの可用性を検出します。
トポロジーマネージャーはこの情報を使用し、そのコンテナの推奨されるNUMAノードのアフィニティーを保存します。アフィニティーが優先されない場合、トポロジーマネージャーはこれを保存し、Podをノードに許可します。
Hint Providers はこの情報を使ってリソースの割り当てを決定します。
Pod内の各コンテナに対して、restricted
トポロジー管理ポリシーが設定されたkubeletは各Hint Providerを呼び出してそれらのリソースの可用性を検出します。
トポロジーマネージャーはこの情報を使用し、そのコンテナの推奨されるNUMAノードのアフィニティーを保存します。アフィニティーが優先されない場合、トポロジーマネージャーはPodをそのノードに割り当てることを拒否します。この結果、PodはPodの受付失敗となりTerminated
状態になります。
Podが一度Terminated
状態になると、KubernetesスケジューラーはPodの再スケジューリングを試み ません 。Podの再デプロイをするためには、ReplicasetかDeploymenを使用してください。Topology Affinity
エラーとなったpodを再デプロイするために、外部のコントロールループを実行することも可能です。
Podが許可されれば、 Hint Providers はこの情報を使ってリソースの割り当てを決定します。
Pod内の各コンテナに対して、single-numa-node
トポロジー管理ポリシーが設定されたkubeletは各Hint Prociderを呼び出してそれらのリソースの可用性を検出します。
トポロジーマネージャーはこの情報を使用し、単一のNUMAノードアフィニティが可能かどうか決定します。
可能な場合、トポロジーマネージャーは、この情報を保存し、Hint Providers はこの情報を使ってリソースの割り当てを決定します。
不可能な場合、トポロジーマネージャーは、Podをそのノードに割り当てることを拒否します。この結果、Pod は Pod の受付失敗となりTerminated
状態になります。
Podが一度Terminated
状態になると、KubernetesスケジューラーはPodの再スケジューリングを試みません。Podの再デプロイをするためには、ReplicasetかDeploymentを使用してください。Topology Affinity
エラーとなったpodを再デプロイするために、外部のコントロールループを実行することも可能です。
以下のようなpodのSpecで定義されるコンテナを考えます:
spec:
containers:
- name: nginx
image: nginx
requests
もlimits
も定義されていないため、このPodはBestEffort
QoSクラスで実行します。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
requestsがlimitsより小さい値のため、このPodはBurstable
QoSクラスで実行します。
選択されたポリシーがnone
以外の場合、トポロジーマネージャーは、これらのPodのSpecを考慮します。トポロジーマネージャーは、Hint Providersからトポロジーヒントを取得します。CPUマネージャーポリシーがstatic
の場合、デフォルトのトポロジーヒントを返却します。これらのPodは明示的にCPUリソースを要求していないからです。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
example.com/device: "1"
requests:
memory: "200Mi"
cpu: "2"
example.com/device: "1"
整数値でCPUリクエストを指定されたこのPodは、requests
がlimits
が同じ値のため、Guaranteed
QoSクラスで実行します。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "300m"
example.com/device: "1"
requests:
memory: "200Mi"
cpu: "300m"
example.com/device: "1"
CPUの一部をリクエストで指定されたこのPodは、requests
がlimits
が同じ値のため、Guaranteed
QoSクラスで実行します。
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
example.com/deviceA: "1"
example.com/deviceB: "1"
requests:
example.com/deviceA: "1"
example.com/deviceB: "1"
CPUもメモリもリクエスト値がないため、このPodは BestEffort
QoSクラスで実行します。
トポロジーマネージャーは、上記Podを考慮します。トポロジーマネージャーは、Hint ProvidersとなるCPUマネージャーとデバイスマネージャーに問い合わせ、トポロジーヒントを取得します。
整数値でCPU要求を指定されたGuaranteed
QoSクラスのPodの場合、static
が設定されたCPUマネージャーポリシーは、排他的なCPUに関するトポロジーヒントを返却し、デバイスマネージャーは要求されたデバイスのヒントを返します。
CPUの一部を要求を指定されたGuaranteed
QoSクラスのPodの場合、排他的ではないCPU要求のためstatic
が設定されたCPUマネージャーポリシーはデフォルトのトポロジーヒントを返却します。デバイスマネージャーは要求されたデバイスのヒントを返します。
上記のGuaranteed
QoSクラスのPodに関する2ケースでは、none
で設定されたCPUマネージャーポリシーは、デフォルトのトポロジーヒントを返却します。
BestEffort
QoSクラスのPodの場合、static
が設定されたCPUマネージャーポリシーは、CPUの要求がないためデフォルトのトポロジーヒントを返却します。デバイスマネージャーは要求されたデバイスごとのヒントを返します。
トポロジーマネージャーはこの情報を使用してPodに最適なヒントを計算し保存します。保存されたヒントは Hint Providersが使用しリソースを割り当てます。
トポロジーマネージャーが許容するNUMAノードの最大値は8です。8より多いNUMAノードでは、可能なNUMAアフィニティを列挙しヒントを生成する際に、生成する状態数が爆発的に増加します。
スケジューラーはトポロジーを意識しません。そのため、ノードにスケジュールされた後に実行に失敗する可能性があります。
このページでは、Nodeに対して拡張リソースを指定する方法を説明します。拡張リソースを利用すると、Kubernetesにとって未知のノードレベルのリソースをクラスター管理者がアドバタイズできるようになります。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
kubectl get nodes
この練習で使いたいNodeを1つ選んでください。
Node上の新しい拡張リソースをアドバタイズするには、HTTPのPATCHリクエストをKubernetes APIサーバーに送ります。たとえば、Nodeの1つに4つのドングルが接続されているとします。以下に、4つのドングルリソースをNodeにアドバタイズするPATCHリクエストの例を示します。
PATCH /api/v1/nodes/<選択したNodeの名前>/status HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
Host: k8s-master:8080
[
{
"op": "add",
"path": "/status/capacity/example.com~1dongle",
"value": "4"
}
]
Kubernetesは、ドングルとは何かも、ドングルが何に利用できるのかを知る必要もないことに注意してください。上のPATCHリクエストは、ただNodeが4つのドングルと呼ばれるものを持っているとKubernetesに教えているだけです。
Kubernetes APIサーバーに簡単にリクエストを送れるように、プロキシーを実行します。
kubectl proxy
もう1つのコマンドウィンドウを開き、HTTPのPATCHリクエストを送ります。<選択したNodeの名前>
の部分は、選択したNodeの名前に置き換えてください。
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "add", "path": "/status/capacity/example.com~1dongle", "value": "4"}]' \
http://localhost:8001/api/v1/nodes/<選択したNodeの名前>/status
~1
は、PATCHのパスにおける/
という文字をエンコーディングしたものです。JSON-Patch内のoperationのpathはJSON-Pointerとして解釈されます。詳細については、IETF RFC 6901のsection 3を読んでください。
出力には、Nodeがキャパシティー4のdongleを持っていることが示されます。
"capacity": {
"cpu": "2",
"memory": "2049008Ki",
"example.com/dongle": "4",
Nodeの説明を確認します。
kubectl describe node <選択したNodeの名前>
出力には、再びdongleリソースが表示されます。
Capacity:
cpu: 2
memory: 2049008Ki
example.com/dongle: 4
これで、アプリケーション開発者は特定の数のdongleをリクエストするPodを作成できるようになりました。詳しくは、拡張リソースをコンテナに割り当てるを読んでください。
拡張リソースは、メモリやCPUリソースと同様のものです。たとえば、Nodeが持っている特定の量のメモリやCPUがNode上で動作している他のすべてのコンポーネントと共有されるのと同様に、Nodeが搭載している特定の数のdongleが他のすべてのコンポーネントと共有されます。そして、アプリケーション開発者が特定の量のメモリとCPUをリクエストするPodを作成できるのと同様に、Nodeが搭載している特定の数のdongleをリクエストするPodが作成できます。
拡張リソースはKubernetesには詳細を意図的に公開しないため、Kubernetesは拡張リソースの実体をまったく知りません。Kubernetesが知っているのは、Nodeが特定の数の拡張リソースを持っているということだけです。拡張リソースは整数値でアドバタイズしなければなりません。たとえば、Nodeは4つのdongleをアドバタイズできますが、4.5のdongleというのはアドバタイズできません。
Nodeに800GiBの特殊なディスクストレージがあるとします。この特殊なストレージの名前、たとえばexample.com/special-storageという名前の拡張リソースが作れます。そして、そのなかの一定のサイズ、たとえば100GiBのチャンクをアドバタイズできます。この場合、Nodeはexample.com/special-storageという種類のキャパシティ8のリソースを持っているとアドバタイズします。
Capacity:
...
example.com/special-storage: 8
特殊なストレージに任意のサイズのリクエストを許可したい場合、特殊なストレージを1バイトのサイズのチャンクでアドバタイズできます。その場合、example.com/special-storageという種類の800Giのリソースとしてアドバタイズします。
Capacity:
...
example.com/special-storage: 800Gi
すると、コンテナは好きなバイト数の特殊なストレージを最大800Giまでリクエストできるようになります。
以下に、dongleのアドバタイズをNodeから削除するPATCHリクエストを示します。
PATCH /api/v1/nodes/<選択したNodeの名前>/status HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
Host: k8s-master:8080
[
{
"op": "remove",
"path": "/status/capacity/example.com~1dongle",
}
]
Kubernetes APIサーバーに簡単にリクエストを送れるように、プロキシーを実行します。
kubectl proxy
もう1つのコマンドウィンドウで、HTTPのPATCHリクエストを送ります。<選択したNodeの名前>
の部分は、選択したNodeの名前に置き換えてください。
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "remove", "path": "/status/capacity/example.com~1dongle"}]' \
http://localhost:8001/api/v1/nodes/<選択したNodeの名前>/status
dongleのアドバタイズが削除されたことを検証します。
kubectl describe node <選択したNodeの名前> | grep dongle
(出力には何も表示されないはずです)
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
Secret
はデータベースにアクセスするためにPodが必要とするユーザー資格情報を含めることができます。
たとえば、データベース接続文字列はユーザー名とパスワードで構成されます。
ユーザー名はローカルマシンの./username.txt
に、パスワードは./password.txt
に保存します。
echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt
上記の2つのコマンドの-n
フラグは、生成されたファイルにテキスト末尾の余分な改行文字が含まれないようにします。
kubectl
がファイルを読み取り、内容をbase64文字列にエンコードすると、余分な改行文字もエンコードされるため、これは重要です。
kubectl create secret
コマンドはこれらのファイルをSecretにパッケージ化し、APIサーバー上にオブジェクトを作成します。
kubectl create secret generic db-user-pass \
--from-file=./username.txt \
--from-file=./password.txt
出力は次のようになります:
secret/db-user-pass created
ファイル名がデフォルトのキー名になります。オプションで--from-file=[key=]source
を使用してキー名を設定できます。たとえば:
kubectl create secret generic db-user-pass \
--from-file=username=./username.txt \
--from-file=password=./password.txt
--from-file
に指定したファイルに含まれるパスワードの特殊文字をエスケープする必要はありません。
また、--from-literal=<key>=<value>
タグを使用してSecretデータを提供することもできます。
このタグは、複数のキーと値のペアを提供するために複数回指定することができます。
$
、\
、*
、=
、!
などの特殊文字はシェルによって解釈されるため、エスケープを必要とすることに注意してください。
ほとんどのシェルでは、パスワードをエスケープする最も簡単な方法は、シングルクォート('
)で囲むことです。
たとえば、実際のパスワードがS!B\*d$zDsb=
の場合、次のようにコマンドを実行します:
kubectl create secret generic db-user-pass \
--from-literal=username=devuser \
--from-literal=password='S!B\*d$zDsb='
Secretが作成されたことを確認できます:
kubectl get secrets
出力は次のようになります:
NAME TYPE DATA AGE
db-user-pass Opaque 2 51s
Secret
の説明を参照できます:
kubectl describe secrets/db-user-pass
出力は次のようになります:
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 12 bytes
username: 5 bytes
kubectl get
とkubectl describe
コマンドはデフォルトではSecret
の内容を表示しません。
これは、Secret
が不用意に他人にさらされたり、ターミナルログに保存されたりしないようにするためです。
先ほど作成したSecretの内容を見るには、以下のコマンドを実行します:
kubectl get secret db-user-pass -o jsonpath='{.data}'
出力は次のようになります:
{"password":"MWYyZDFlMmU2N2Rm","username":"YWRtaW4="}
password
のデータをデコードします:
echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
出力は次のようになります:
1f2d1e2e67df
作成したSecretを削除するには次のコマンドを実行します:
kubectl delete secret db-user-pass
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
あらかじめYAMLまたはJSON形式でSecretのマニフェストを作成したうえで、オブジェクトを作成することができます。
Secretリソースには、data
とstringData
の2つのマップが含まれています。
data
フィールドは任意のデータを格納するのに使用され、base64でエンコードされます。
stringData
フィールドは利便性のために用意されており、Secretデータをエンコードされていない文字列として提供することができます。
data
とstringData
のキーは、英数字、-
、_
、.
で構成されている必要があります。
たとえば、data
フィールドを使用して2つの文字列をSecretに格納するには、次のように文字列をbase64に変換します:
echo -n 'admin' | base64
出力は次のようになります:
YWRtaW4=
echo -n '1f2d1e2e67df' | base64
出力は次のようになります:
MWYyZDFlMmU2N2Rm
以下のようなSecret設定ファイルを記述します:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
なお、Secretオブジェクトの名前は、有効なDNSサブドメイン名である必要があります。
base64
ユーティリティーを使用する場合、長い行を分割するために-b
オプションを使用するのは避けるべきです。
逆に、Linux ユーザーは、base64
コマンドにオプション-w 0
を追加するか、-w
オプションが利用できない場合には、パイプラインbase64 | tr -d '\n'
を追加する必要があります。
特定のシナリオでは、代わりにstringData
フィールドを使用できます。
このフィールドでは、base64エンコードされていない文字列を直接Secretに入れることができ、Secretの作成時や更新時には、その文字列がエンコードされます。
たとえば、設定ファイルを保存するためにSecretを使用しているアプリケーションをデプロイする際に、デプロイプロセス中に設定ファイルの一部を入力したい場合などが考えられます。
たとえば、次のような設定ファイルを使用しているアプリケーションの場合:
apiUrl: "https://my.api.com/api/v1"
username: "<user>"
password: "<password>"
次のような定義でSecretに格納できます:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
stringData:
config.yaml: |
apiUrl: "https://my.api.com/api/v1"
username: <user>
password: <password>
kubectl apply
でSecretを作成します:
kubectl apply -f ./secret.yaml
出力は次のようになります:
secret/mysecret created
stringData
フィールドは、書き込み専用の便利なフィールドです。Secretを取得する際には決して出力されません。たとえば、次のようなコマンドを実行した場合:
kubectl get secret mysecret -o yaml
出力は次のようになります:
apiVersion: v1
data:
config.yaml: YXBpVXJsOiAiaHR0cHM6Ly9teS5hcGkuY29tL2FwaS92MSIKdXNlcm5hbWU6IHt7dXNlcm5hbWV9fQpwYXNzd29yZDoge3twYXNzd29yZH19
kind: Secret
metadata:
creationTimestamp: 2018-11-15T20:40:59Z
name: mysecret
namespace: default
resourceVersion: "7225"
uid: c280ad2e-e916-11e8-98f2-025000000001
type: Opaque
kubectl get
とkubectl describe
コマンドはデフォルトではSecretの内容を表示しません。
これは、Secretが不用意に他人にさらされたり、ターミナルログに保存されたりしないようにするためです。
エンコードされたデータの実際の内容を確認するには、Secretのデコードを参照してください。
username
などのフィールドがdata
とstringData
の両方に指定されている場合は、stringData
の値が使われます。
たとえば、以下のようなSecretの定義の場合:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
stringData:
username: administrator
結果は以下の通りです:
apiVersion: v1
data:
username: YWRtaW5pc3RyYXRvcg==
kind: Secret
metadata:
creationTimestamp: 2018-11-15T20:46:46Z
name: mysecret
namespace: default
resourceVersion: "7579"
uid: 91460ecb-e917-11e8-98f2-025000000001
type: Opaque
YWRtaW5pc3RyYXRvcg==
をデコードするとadministrator
となります。
作成したSecretを削除するには次のコマンドを実行します:
kubectl delete secret mysecret
Kubernetes v1.14以降、kubectl
はKustomizeを使ったオブジェクト管理をサポートしています。
KustomizeはSecretやConfigMapを作成するためのリソースジェネレーターを提供します。
Kustomizeジェネレーターは、ディレクトリ内のkustomization.yaml
ファイルで指定します。
Secretを生成したら、kubectl apply
でAPIサーバー上にSecretを作成します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
kustomization.yaml
ファイルの中でsecretGenerator
を定義し、他の既存のファイルを参照することで、Secretを生成することができます。
たとえば、以下のkustomizationファイルは./username.txt
と./password.txt
を参照しています。
secretGenerator:
- name: db-user-pass
files:
- username.txt
- password.txt
また、kustomization.yaml
ファイルの中でリテラルを指定してsecretGenerator
を定義することもできます。
たとえば、以下のkustomization.yaml
ファイルにはusername
とpassword
の2つのリテラルが含まれています。
secretGenerator:
- name: db-user-pass
literals:
- username=admin
- password=1f2d1e2e67df
また、kustomization.yaml
ファイルに.env
ファイルを用意してsecretGenerator
を定義することもできます。
たとえば、以下のkustomization.yaml
ファイルは、.env.secret
ファイルからデータを取り込みます。
secretGenerator:
- name: db-user-pass
envs:
- .env.secret
なお、いずれの場合も、値をbase64エンコードする必要はありません。
kustomization.yaml
を含むディレクトリを適用して、Secretを作成します。
kubectl apply -k .
出力は次のようになります:
secret/db-user-pass-96mffmfh4k created
なお、Secretを生成する際には、データをハッシュ化し、そのハッシュ値を付加することでSecret名を生成します。 これにより、データが変更されるたびに、新しいSecretが生成されます。
Secretが作成されたことを確認できます:
kubectl get secrets
出力は次のようになります:
NAME TYPE DATA AGE
db-user-pass-96mffmfh4k Opaque 2 51s
Secretの説明を参照できます:
kubectl describe secrets/db-user-pass-96mffmfh4k
出力は次のようになります:
Name: db-user-pass-96mffmfh4k
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password.txt: 12 bytes
username.txt: 5 bytes
kubectl get
とkubectl describe
コマンドはデフォルトではSecretの内容を表示しません。
これは、Secretが不用意に他人にさらされたり、ターミナルログに保存されたりしないようにするためです。
エンコードされたデータの実際の内容を確認するには、Secretのデコードを参照してください。
作成したSecretを削除するには次のコマンドを実行します:
kubectl delete secret db-user-pass-96mffmfh4k
このページでは、Kubernetes Podでコンテナの環境変数を定義する方法を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
Podを作成するとき、そのPodで実行するコンテナに環境変数を設定することができます。環境変数を設定するには、設定ファイルに env
または envFrom
フィールドを含めます。
この演習では、1つのコンテナを実行するPodを作成します。Podの設定ファイルには、名前 DEMO_GREETING
、値 "Hello from the environment"
を持つ環境変数が定義されています。Podの設定マニフェストを以下に示します:
apiVersion: v1
kind: Pod
metadata:
name: envar-demo
labels:
purpose: demonstrate-envars
spec:
containers:
- name: envar-demo-container
image: gcr.io/google-samples/node-hello:1.0
env:
- name: DEMO_GREETING
value: "Hello from the environment"
- name: DEMO_FAREWELL
value: "Such a sweet sorrow"
マニフェストに基づいてPodを作成します:
kubectl apply -f https://k8s.io/examples/pods/inject/envars.yaml
実行中のPodを一覧表示します:
kubectl get pods -l purpose=demonstrate-envars
出力は以下のようになります:
NAME READY STATUS RESTARTS AGE
envar-demo 1/1 Running 0 9s
Podで実行しているコンテナのシェルを取得します:
kubectl exec -it envar-demo -- /bin/bash
シェルでprintenv
コマンドを実行すると、環境変数の一覧が表示されます。
# コンテナ内のシェルで以下のコマンドを実行します
printenv
出力は以下のようになります:
NODE_VERSION=4.4.2
EXAMPLE_SERVICE_PORT_8080_TCP_ADDR=10.3.245.237
HOSTNAME=envar-demo
...
DEMO_GREETING=Hello from the environment
DEMO_FAREWELL=Such a sweet sorrow
シェルを終了するには、exit
と入力します。
env
またはenvFrom
フィールドを使用して設定された環境変数は、コンテナイメージで指定された環境変数を上書きします。
Podの設定で定義した環境変数は、Podのコンテナに設定したコマンドや引数など、設定の他の場所で使用することができます。以下の設定例では、環境変数GREETING
、HONORORIFIC
、NAME
にそれぞれ Warm greetings to
、The Most Honorable
、Kubernetes
を設定しています。これらの環境変数は、env-print-demo
コンテナに渡されるCLI引数で使われます。
apiVersion: v1
kind: Pod
metadata:
name: print-greeting
spec:
containers:
- name: env-print-demo
image: bash
env:
- name: GREETING
value: "Warm greetings to"
- name: HONORIFIC
value: "The Most Honorable"
- name: NAME
value: "Kubernetes"
command: ["echo"]
args: ["$(GREETING) $(HONORIFIC) $(NAME)"]
作成されると、コンテナ上でecho Warm greetings to The Most Honorable Kubernetes
というコマンドが実行されます。
このページでは、Podが内部で実行しているコンテナに自身の情報を共有する方法を説明します。環境変数ではPodのフィールドとコンテナのフィールドを共有することができます。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
Podとコンテナのフィールドを実行中のコンテナに共有する方法は2つあります:
これら2つの方法を合わせて、Podとコンテナフィールドを共有する方法をDownward APIと呼びます。
この演習では、1つのコンテナを持つPodを作成します。Podの設定ファイルは次のとおりです:
apiVersion: v1
kind: Pod
metadata:
name: dapi-envars-fieldref
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE;
printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT;
sleep 10;
done;
env:
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MY_POD_SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
restartPolicy: Never
設定ファイルには、5つの環境変数があります。env
フィールドはEnvVarsの配列です。配列の最初の要素では、環境変数MY_NODE_NAME
の値をPodのspec.nodeName
フィールドから取得することを指定します。同様に、他の環境変数もPodのフィールドから名前を取得します。
Podを作成します:
kubectl apply -f https://k8s.io/examples/pods/inject/dapi-envars-pod.yaml
Podのコンテナが実行されていることを確認します:
kubectl get pods
コンテナのログを表示します:
kubectl logs dapi-envars-fieldref
出力には、選択した環境変数の値が表示されます:
minikube
dapi-envars-fieldref
default
172.17.0.4
default
これらの値がログにある理由を確認するには、設定ファイルのcommand
およびargs
フィールドを確認してください。コンテナが起動すると、5つの環境変数の値が標準出力に書き込まれます。これを10秒ごとに繰り返します。
次に、Podで実行しているコンテナへのシェルを取得します:
kubectl exec -it dapi-envars-fieldref -- sh
シェルで環境変数を表示します:
/# printenv
出力は、特定の環境変数にPodフィールドの値が割り当てられていることを示しています:
MY_POD_SERVICE_ACCOUNT=default
...
MY_POD_NAMESPACE=default
MY_POD_IP=172.17.0.4
...
MY_NODE_NAME=minikube
...
MY_POD_NAME=dapi-envars-fieldref
前の演習では、環境変数の値としてPodフィールドを使用しました。次の演習では、環境変数の値としてコンテナフィールドを使用します。これは、1つのコンテナを持つPodの設定ファイルです:
apiVersion: v1
kind: Pod
metadata:
name: dapi-envars-resourcefieldref
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox:1.24
command: [ "sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv MY_CPU_REQUEST MY_CPU_LIMIT;
printenv MY_MEM_REQUEST MY_MEM_LIMIT;
sleep 10;
done;
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "64Mi"
cpu: "250m"
env:
- name: MY_CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.cpu
- name: MY_CPU_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.cpu
- name: MY_MEM_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.memory
- name: MY_MEM_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.memory
restartPolicy: Never
設定ファイルには、4つの環境変数があります。env
フィールドはEnvVarsの配列です。配列の最初の要素では、環境変数MY_CPU_REQUEST
の値をtest-container
という名前のコンテナのrequests.cpu
フィールドから取得することを指定します。同様に、他の環境変数もコンテナのフィールドから値を取得します。
Podを作成します:
kubectl apply -f https://k8s.io/examples/pods/inject/dapi-envars-container.yaml
Podのコンテナが実行されていることを確認します:
kubectl get pods
コンテナのログを表示します:
kubectl logs dapi-envars-resourcefieldref
出力には、選択した環境変数の値が表示されます:
1
1
33554432
67108864
このページでは、Kubernetes Deploymentオブジェクトを使用してアプリケーションを実行する方法を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.9. バージョンを確認するには次のコマンドを実行してください:kubectl version
.
Kubernetes Deploymentオブジェクトを作成することでアプリケーションを実行できます。また、YAMLファイルでDeploymentを記述できます。例えば、このYAMLファイルはnginx:1.14.2 Dockerイメージを実行するデプロイメントを記述しています:
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
YAMLファイルに基づいてDeploymentを作成します:
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
Deploymentに関する情報を表示します:
kubectl describe deployment nginx-deployment
出力はこのようになります:
Name: nginx-deployment
Namespace: default
CreationTimestamp: Tue, 30 Aug 2016 18:11:37 -0700
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=1
Selector: app=nginx
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.14.2
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-1771418926 (2/2 replicas created)
No events.
Deploymentによって作成されたPodを一覧表示します:
kubectl get pods -l app=nginx
出力はこのようになります:
NAME READY STATUS RESTARTS AGE
nginx-deployment-1771418926-7o5ns 1/1 Running 0 16h
nginx-deployment-1771418926-r18az 1/1 Running 0 16h
Podに関する情報を表示します:
kubectl describe pod <pod-name>
ここで<pod-name>
はPodの1つの名前を指定します。
新しいYAMLファイルを適用してDeploymentを更新できます。このYAMLファイルは、Deploymentを更新してnginx 1.16.1を使用するように指定しています。
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1 # Update the version of nginx from 1.14.2 to 1.16.1
ports:
- containerPort: 80
新しいYAMLファイルを適用します:
kubectl apply -f https://k8s.io/examples/application/deployment-update.yaml
Deploymentが新しい名前でPodを作成し、古いPodを削除するのを監視します:
kubectl get pods -l app=nginx
新しいYAMLファイルを適用することで、Deployment内のPodの数を増やすことができます。このYAMLファイルはreplicas
を4に設定します。これはDeploymentが4つのPodを持つべきであることを指定します:
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 4 # Update the replicas from 2 to 4
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
新しいYAMLファイルを適用します:
kubectl apply -f https://k8s.io/examples/application/deployment-scale.yaml
Deploymentに4つのPodがあることを確認します:
kubectl get pods -l app=nginx
出力はこのようになります:
NAME READY STATUS RESTARTS AGE
nginx-deployment-148880595-4zdqq 1/1 Running 0 25s
nginx-deployment-148880595-6zgi1 1/1 Running 0 25s
nginx-deployment-148880595-fxcez 1/1 Running 0 2m
nginx-deployment-148880595-rwovn 1/1 Running 0 2m
Deploymentを名前を指定して削除します:
kubectl delete deployment nginx-deployment
複製アプリケーションを作成するための好ましい方法はDeploymentを使用することです。そして、DeploymentはReplicaSetを使用します。 DeploymentとReplicaSetがKubernetesに追加される前は、ReplicationControllerを使用して複製アプリケーションを構成していました。
このページでは、PersistentVolumeとDeploymentを使用して、Kubernetesで単一レプリカのステートフルアプリケーションを実行する方法を説明します。アプリケーションはMySQLです。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
ここで使用されているPersistentVolumeClaimsの要件を満たすには、デフォルトのStorageClassを使用して動的PersistentVolumeプロビジョナーを作成するか、PersistentVolumesを静的にプロビジョニングする必要があります。
Kubernetes Deploymentを作成し、PersistentVolumeClaimを使用して既存のPersistentVolumeに接続することで、ステートフルアプリケーションを実行できます。 たとえば、以下のYAMLファイルはMySQLを実行し、PersistentVolumeClaimを参照するDeploymentを記述しています。 このファイルは/var/lib/mysqlのボリュームマウントを定義してから、20Gのボリュームを要求するPersistentVolumeClaimを作成します。 この要求は、要件を満たす既存のボリューム、または動的プロビジョナーによって満たされます。
注:パスワードはYAMLファイル内に定義されており、これは安全ではありません。安全な解決策についてはKubernetes Secretを参照してください 。
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
clusterIP: None
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
# Use secret in real usage
- name: MYSQL_ROOT_PASSWORD
value: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
kind: PersistentVolume
apiVersion: v1
metadata:
name: mysql-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
YAMLファイルに記述されたPVとPVCをデプロイします。
kubectl create -f https://k8s.io/examples/application/mysql/mysql-pv.yaml
YAMLファイルの内容をデプロイします。
kubectl create -f https://k8s.io/examples/application/mysql/mysql-deployment.yaml
作成したDeploymentの情報を表示します。
kubectl describe deployment mysql
Name: mysql
Namespace: default
CreationTimestamp: Tue, 01 Nov 2016 11:18:45 -0700
Labels: app=mysql
Annotations: deployment.kubernetes.io/revision=1
Selector: app=mysql
Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable
StrategyType: Recreate
MinReadySeconds: 0
Pod Template:
Labels: app=mysql
Containers:
mysql:
Image: mysql:5.6
Port: 3306/TCP
Environment:
MYSQL_ROOT_PASSWORD: password
Mounts:
/var/lib/mysql from mysql-persistent-storage (rw)
Volumes:
mysql-persistent-storage:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: mysql-pv-claim
ReadOnly: false
Conditions:
Type Status Reason
---- ------ ------
Available False MinimumReplicasUnavailable
Progressing True ReplicaSetUpdated
OldReplicaSets: <none>
NewReplicaSet: mysql-63082529 (1/1 replicas created)
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
33s 33s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set mysql-63082529 to 1
Deploymentによって作成されたPodを一覧表示します。
kubectl get pods -l app=mysql
NAME READY STATUS RESTARTS AGE
mysql-63082529-2z3ki 1/1 Running 0 3m
PersistentVolumeClaimを確認します。
kubectl describe pvc mysql-pv-claim
Name: mysql-pv-claim
Namespace: default
StorageClass:
Status: Bound
Volume: mysql-pv-volume
Labels: <none>
Annotations: pv.kubernetes.io/bind-completed=yes
pv.kubernetes.io/bound-by-controller=yes
Capacity: 20Gi
Access Modes: RWO
Events: <none>
前述のYAMLファイルは、クラスター内の他のPodがデータベースにアクセスできるようにするServiceを作成します。
ServiceのオプションでclusterIP: None
を指定すると、ServiceのDNS名がPodのIPアドレスに直接解決されます。
このオプションは、ServiceのバックエンドのPodが1つのみであり、Podの数を増やす予定がない場合に適しています。
MySQLクライアントを実行してサーバーに接続します。
kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword
このコマンドは、クラスター内にMySQLクライアントを実行する新しいPodを作成し、Serviceを通じてMySQLサーバーに接続します。 接続できれば、ステートフルなMySQLデータベースが稼働していることが確認できます。
Waiting for pod default/mysql-client-274442439-zyp6i to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.
mysql>
イメージまたはDeploymentの他の部分は、kubectl apply
コマンドを使用して通常どおりに更新できます。
ステートフルアプリケーションに固有のいくつかの注意事項を以下に記載します。
strategy: type: Recreate
を使用して下さい。
この設定はKubernetesにローリングアップデートを使用 しない ように指示します。
同時に複数のPodを実行することはできないため、ローリングアップデートは使用できません。
Recreate
戦略は、更新された設定で新しいPodを作成する前に、最初のPodを停止します。名前を指定してデプロイしたオブジェクトを削除します。
kubectl delete deployment,svc mysql
kubectl delete pvc mysql-pv-claim
kubectl delete pv mysql-pv-volume
PersistentVolumeを手動でプロビジョニングした場合は、PersistentVolumeを手動で削除し、また、下層にあるリソースも解放する必要があります。 動的プロビジョニング機能を使用した場合は、PersistentVolumeClaimを削除すれば、自動的にPersistentVolumeも削除されます。 一部の動的プロビジョナー(EBSやPDなど)は、PersistentVolumeを削除すると同時に下層にあるリソースも解放します。
Deploymentオブジェクトについてもっと学ぶ
アプリケーションのデプロイについてもっと学ぶ
このページでは、StatefulSet コントローラーを使用して、レプリカを持つステートフルアプリケーションを実行する方法を説明します。 ここでの例は、非同期レプリケーションを行う複数のスレーブを持つ、単一マスターのMySQLです。
この例は本番環境向けの構成ではないことに注意してください。 具体的には、MySQLの設定が安全ではないデフォルトのままとなっています。 これはKubernetesでステートフルアプリケーションを実行するための一般的なパターンに焦点を当てるためです。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
ここで使用されているPersistentVolumeClaimsの要件を満たすには、デフォルトのStorageClassを使用して動的PersistentVolumeプロビジョナーを作成するか、PersistentVolumesを静的にプロビジョニングする必要があります。
このMySQLのデプロイの例は、1つのConfigMap、2つのService、および1つのStatefulSetから構成されます。
次のYAML設定ファイルからConfigMapを作成します。
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql
labels:
app: mysql
data:
master.cnf: |
# Apply this config only on the master.
[mysqld]
log-bin
slave.cnf: |
# Apply this config only on slaves.
[mysqld]
super-read-only
このConfigMapは、MySQLマスターとスレーブの設定を独立して制御するために、
それぞれのmy.cnf
を上書きする内容を提供します。
この場合、マスターはスレーブにレプリケーションログを提供するようにし、
スレーブはレプリケーション以外の書き込みを拒否するようにします。
ConfigMap自体に特別なことはありませんが、ConfigMapの各部分は異なるPodに適用されます。 各Podは、StatefulSetコントローラーから提供される情報に基づいて、 初期化時にConfigMapのどの部分を見るかを決定します。
以下のYAML設定ファイルからServiceを作成します。
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-services.yaml
# Headless service for stable DNS entries of StatefulSet members.
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app: mysql
spec:
ports:
- name: mysql
port: 3306
clusterIP: None
selector:
app: mysql
---
# Client service for connecting to any MySQL instance for reads.
# For writes, you must instead connect to the master: mysql-0.mysql.
apiVersion: v1
kind: Service
metadata:
name: mysql-read
labels:
app: mysql
spec:
ports:
- name: mysql
port: 3306
selector:
app: mysql
ヘッドレスサービスは、StatefulSetコントローラーが
StatefulSetの一部であるPodごとに作成するDNSエントリーのベースエントリーを提供します。
この例ではヘッドレスサービスの名前はmysql
なので、同じKubernetesクラスタの
同じ名前空間内の他のPodは、<pod-name>.mysql
を名前解決することでPodにアクセスできます。
mysql-read
と呼ばれるクライアントサービスは、独自のクラスタIPを持つ通常のServiceであり、
Ready状態のすべてのMySQL Podに接続を分散します。
Serviceのエンドポイントには、MySQLマスターとすべてのスレーブが含まれる可能性があります。
読み込みクエリーのみが、負荷分散されるクライアントサービスを使用できることに注意してください。 MySQLマスターは1つしかいないため、クライアントが書き込みを実行するためには、 (ヘッドレスサービス内のDNSエントリーを介して)MySQLのマスターPodに直接接続する必要があります。
最後に、次のYAML設定ファイルからStatefulSetを作成します。
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
serviceName: mysql
replicas: 3
template:
metadata:
labels:
app: mysql
spec:
initContainers:
- name: init-mysql
image: mysql:5.7
command:
- bash
- "-c"
- |
set -ex
# Generate mysql server-id from pod ordinal index.
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
echo [mysqld] > /mnt/conf.d/server-id.cnf
# Add an offset to avoid reserved server-id=0 value.
echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
# Copy appropriate conf.d files from config-map to emptyDir.
if [[ $ordinal -eq 0 ]]; then
cp /mnt/config-map/master.cnf /mnt/conf.d/
else
cp /mnt/config-map/slave.cnf /mnt/conf.d/
fi
volumeMounts:
- name: conf
mountPath: /mnt/conf.d
- name: config-map
mountPath: /mnt/config-map
- name: clone-mysql
image: gcr.io/google-samples/xtrabackup:1.0
command:
- bash
- "-c"
- |
set -ex
# Skip the clone if data already exists.
[[ -d /var/lib/mysql/mysql ]] && exit 0
# Skip the clone on master (ordinal index 0).
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
[[ $ordinal -eq 0 ]] && exit 0
# Clone data from previous peer.
ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
# Prepare the backup.
xtrabackup --prepare --target-dir=/var/lib/mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ALLOW_EMPTY_PASSWORD
value: "1"
ports:
- name: mysql
containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 500m
memory: 1Gi
livenessProbe:
exec:
command: ["mysqladmin", "ping"]
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
# Check we can execute queries over TCP (skip-networking is off).
command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
initialDelaySeconds: 5
periodSeconds: 2
timeoutSeconds: 1
- name: xtrabackup
image: gcr.io/google-samples/xtrabackup:1.0
ports:
- name: xtrabackup
containerPort: 3307
command:
- bash
- "-c"
- |
set -ex
cd /var/lib/mysql
# Determine binlog position of cloned data, if any.
if [[ -f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then
# XtraBackup already generated a partial "CHANGE MASTER TO" query
# because we're cloning from an existing slave. (Need to remove the tailing semicolon!)
cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in
# Ignore xtrabackup_binlog_info in this case (it's useless).
rm -f xtrabackup_slave_info xtrabackup_binlog_info
elif [[ -f xtrabackup_binlog_info ]]; then
# We're cloning directly from master. Parse binlog position.
[[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
rm -f xtrabackup_binlog_info xtrabackup_slave_info
echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\
MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
fi
# Check if we need to complete a clone by starting replication.
if [[ -f change_master_to.sql.in ]]; then
echo "Waiting for mysqld to be ready (accepting connections)"
until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done
echo "Initializing replication from clone position"
mysql -h 127.0.0.1 \
-e "$(<change_master_to.sql.in), \
MASTER_HOST='mysql-0.mysql', \
MASTER_USER='root', \
MASTER_PASSWORD='', \
MASTER_CONNECT_RETRY=10; \
START SLAVE;" || exit 1
# In case of container restart, attempt this at-most-once.
mv change_master_to.sql.in change_master_to.sql.orig
fi
# Start a server to send backups when requested by peers.
exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \
"xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 100m
memory: 100Mi
volumes:
- name: conf
emptyDir: {}
- name: config-map
configMap:
name: mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
次のコマンドを実行して起動の進行状況を確認できます。
kubectl get pods -l app=mysql --watch
しばらくすると、3つのPodすべてがRunning状態になるはずです。
NAME READY STATUS RESTARTS AGE
mysql-0 2/2 Running 0 2m
mysql-1 2/2 Running 0 1m
mysql-2 2/2 Running 0 1m
Ctrl+Cを押してウォッチをキャンセルします。 起動が進行しない場合は、始める前にで説明されているように、 PersistentVolumeの動的プロビジョニング機能が有効になっていることを確認してください。
このマニフェストでは、StatefulSetの一部としてステートフルなPodを管理するためにさまざまな手法を使用しています。 次のセクションでは、これらの手法のいくつかに焦点を当て、StatefulSetがPodを作成するときに何が起こるかを説明します。
StatefulSetコントローラーは、序数インデックスの順にPodを一度に1つずつ起動します。 各PodがReady状態を報告するまで待機してから、その次のPodの起動が開始されます。
さらに、コントローラーは各Podに <statefulset-name>-<ordinal-index>
という形式の一意で不変の名前を割り当てます。
この例の場合、Podの名前はmysql-0
、mysql-1
、そしてmysql-2
となります。
上記のStatefulSetマニフェスト内のPodテンプレートは、これらのプロパティーを利用して、 MySQLレプリケーションの起動を順序正しく実行します。
Podスペック内のコンテナを起動する前に、Podは最初に 初期化コンテナを定義された順序で実行します。
最初の初期化コンテナはinit-mysql
という名前で、序数インデックスに基づいて特別なMySQL設定ファイルを生成します。
スクリプトは、hostname
コマンドによって返されるPod名の末尾から抽出することによって、自身の序数インデックスを特定します。
それから、序数を(予約された値を避けるために数値オフセット付きで)MySQLのconf.d
ディレクトリーのserver-id.cnf
というファイルに保存します。
これは、StatefulSetコントローラーによって提供される一意で不変のIDを、同じ特性を必要とするMySQLサーバーIDの領域に変換します。
さらに、init-mysql
コンテナ内のスクリプトは、master.cnf
またはslave.cnf
のいずれかを、
ConfigMapから内容をconf.d
にコピーすることによって適用します。
このトポロジー例は単一のMySQLマスターと任意の数のスレーブで構成されているため、
スクリプトは単に序数の0
がマスターになるように、それ以外のすべてがスレーブになるように割り当てます。
StatefulSetコントローラーによる
デプロイ順序の保証と組み合わせると、
スレーブが作成される前にMySQLマスターがReady状態になるため、スレーブはレプリケーションを開始できます。
一般に、新しいPodがセットにスレーブとして参加するときは、 MySQLマスターにはすでにデータがあるかもしれないと想定する必要があります。 また、レプリケーションログが期間の先頭まで全て揃っていない場合も想定する必要があります。 これらの控えめな仮定は、実行中のStatefulSetのサイズを初期サイズに固定するのではなく、 時間の経過とともにスケールアップまたはスケールダウンできるようにするために重要です。
2番目の初期化コンテナはclone-mysql
という名前で、スレーブPodが空のPersistentVolumeで最初に起動したときに、
クローン操作を実行します。
つまり、実行中の別のPodから既存のデータをすべてコピーするので、
そのローカル状態はマスターからレプリケーションを開始するのに十分な一貫性があります。
MySQL自体はこれを行うためのメカニズムを提供していないため、この例ではPercona XtraBackupという人気のあるオープンソースツールを使用しています。
クローンの実行中は、ソースとなるMySQLサーバーのパフォーマンスが低下する可能性があります。
MySQLマスターへの影響を最小限に抑えるために、スクリプトは各Podに序数インデックスが自分より1低いPodからクローンするように指示します。
StatefulSetコントローラーは、N+1
のPodを開始する前には必ずN
のPodがReady状態であることを保証するので、この方法が機能します。
初期化コンテナが正常に完了すると、通常のコンテナが実行されます。
MySQLのPodは実際にmysqld
サーバーを実行するmysql
コンテナと、
サイドカー
として機能するxtrabackup
コンテナから成ります。
xtrabackup
サイドカーはクローンされたデータファイルを見て、
スレーブ上でMySQLレプリケーションを初期化する必要があるかどうかを決定します。
もし必要がある場合、mysqld
が準備できるのを待ってから、
XtraBackupクローンファイルから抽出されたレプリケーションパラメーターでCHANGE MASTER TO
とSTART SLAVE
コマンドを実行します。
スレーブがレプリケーションを開始すると、スレーブはMySQLマスターを記憶し、
サーバーが再起動した場合または接続が停止した場合に、自動的に再接続します。
また、スレーブはその不変のDNS名(mysql-0.mysql
)でマスターを探すため、
再スケジュールされたために新しいPod IPを取得したとしても、自動的にマスターを見つけます。
最後に、レプリケーションを開始した後、xtrabackup
コンテナはデータのクローンを要求する他のPodからの接続を待ち受けます。
StatefulSetがスケールアップした場合や、次のPodがPersistentVolumeClaimを失ってクローンをやり直す必要がある場合に備えて、
このサーバーは無期限に起動したままになります。
テストクエリーをMySQLマスター(ホスト名 mysql-0.mysql
)に送信するには、
mysql:5.7
イメージを使って一時的なコンテナーを実行し、mysql
クライアントバイナリーを実行します。
kubectl run mysql-client --image=mysql:5.7 -i --rm --restart=Never --\
mysql -h mysql-0.mysql <<EOF
CREATE DATABASE test;
CREATE TABLE test.messages (message VARCHAR(250));
INSERT INTO test.messages VALUES ('hello');
EOF
Ready状態を報告したいずれかのサーバーにテストクエリーを送信するには、ホスト名mysql-read
を使用します。
kubectl run mysql-client --image=mysql:5.7 -i -t --rm --restart=Never --\
mysql -h mysql-read -e "SELECT * FROM test.messages"
次のような出力が得られるはずです。
Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false
+---------+
| message |
+---------+
| hello |
+---------+
pod "mysql-client" deleted
mysql-read
サービスがサーバー間で接続を分散させることを実証するために、
ループでSELECT @@server_id
を実行することができます。
kubectl run mysql-client-loop --image=mysql:5.7 -i -t --rm --restart=Never --\
bash -ic "while sleep 1; do mysql -h mysql-read -e 'SELECT @@server_id,NOW()'; done"
接続の試行ごとに異なるエンドポイントが選択される可能性があるため、
報告される@@server_id
はランダムに変更されるはずです。
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 100 | 2006-01-02 15:04:05 |
+-------------+---------------------+
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 102 | 2006-01-02 15:04:06 |
+-------------+---------------------+
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 101 | 2006-01-02 15:04:07 |
+-------------+---------------------+
ループを止めたいときはCtrl+Cを押すことができますが、別のウィンドウで実行したままにしておくことで、 次の手順の効果を確認できます。
単一のサーバーではなくスレーブのプールから読み取りを行うことによって可用性が高まっていることを実証するため、
Podを強制的にReadyではない状態にする間、上記のSELECT @@server_id
ループを実行したままにしてください。
mysql
コンテナに対する
readiness probe
は、mysql -h 127.0.0.1 -e 'SELECT 1'
コマンドを実行することで、サーバーが起動していてクエリーが実行できることを確認します。
このreadiness probeを失敗させる1つの方法は、そのコマンドを壊すことです。
kubectl exec mysql-2 -c mysql -- mv /usr/bin/mysql /usr/bin/mysql.off
ここでは、mysql-2
Podの実際のコンテナのファイルシステムにアクセスし、
mysql
コマンドの名前を変更してreadiness probeがコマンドを見つけられないようにしています。
数秒後、Podはそのコンテナの1つがReadyではないと報告するはずです。以下を実行して確認できます。
kubectl get pod mysql-2
READY
列の1/2
を見てください。
NAME READY STATUS RESTARTS AGE
mysql-2 1/2 Running 0 3m
この時点で、SELECT @@server_id
ループは実行され続け、しかしもう102
が報告されないことが確認できるはずです。
init-mysql
スクリプトがserver-id
を100+$ordinal
として定義したことを思い出して下さい。
そのため、サーバーID102
はPodのmysql-2
に対応します。
それではPodを修復しましょう。すると数秒後にループ出力に再び現れるはずです。
kubectl exec mysql-2 -c mysql -- mv /usr/bin/mysql.off /usr/bin/mysql
StatefulSetは、Podが削除された場合にPodを再作成します。 これはReplicaSetがステートレスなPodに対して行うのと同様です。
kubectl delete pod mysql-2
StatefulSetコントローラーはmysql-2
Podがもう存在しないことに気付き、
同じ名前で同じPersistentVolumeClaimにリンクされた新しいPodを作成します。
サーバーID102
がしばらくの間ループ出力から消えて、また元に戻るのが確認できるはずです。
Kubernetesクラスタに複数のノードがある場合は、 drainを発行して ノードのダウンタイム(例えばノードのアップグレード時など)をシミュレートできます。
まず、あるMySQL Podがどのノード上にいるかを確認します。
kubectl get pod mysql-2 -o wide
ノード名が最後の列に表示されるはずです。
NAME READY STATUS RESTARTS AGE IP NODE
mysql-2 2/2 Running 0 15m 10.244.5.27 kubernetes-minion-group-9l2t
その後、次のコマンドを実行してノードをdrainします。
これにより、新しいPodがそのノードにスケジュールされないようにcordonされ、そして既存のPodは強制退去されます。
<node-name>
は前のステップで確認したノードの名前に置き換えてください。
この操作はノード上の他のアプリケーションに影響を与える可能性があるため、 テストクラスタでのみこの操作を実行するのが最善です。
kubectl drain <node-name> --force --delete-local-data --ignore-daemonsets
Podが別のノードに再スケジュールされる様子を確認しましょう。
kubectl get pod mysql-2 -o wide --watch
次のような出力が見られるはずです。
NAME READY STATUS RESTARTS AGE IP NODE
mysql-2 2/2 Terminating 0 15m 10.244.1.56 kubernetes-minion-group-9l2t
[...]
mysql-2 0/2 Pending 0 0s <none> kubernetes-minion-group-fjlm
mysql-2 0/2 Init:0/2 0 0s <none> kubernetes-minion-group-fjlm
mysql-2 0/2 Init:1/2 0 20s 10.244.5.32 kubernetes-minion-group-fjlm
mysql-2 0/2 PodInitializing 0 21s 10.244.5.32 kubernetes-minion-group-fjlm
mysql-2 1/2 Running 0 22s 10.244.5.32 kubernetes-minion-group-fjlm
mysql-2 2/2 Running 0 30s 10.244.5.32 kubernetes-minion-group-fjlm
また、サーバーID102
がSELECT @@server_id
ループの出力からしばらくの消えて、
そして戻ることが確認できるはずです。
それでは、ノードをuncordonして正常な状態に戻しましょう。
kubectl uncordon <node-name>
MySQLレプリケーションでは、スレーブを追加することで読み取りクエリーのキャパシティーをスケールできます。 StatefulSetを使用している場合、単一のコマンドでこれを実行できます。
kubectl scale statefulset mysql --replicas=5
次のコマンドを実行して、新しいPodが起動してくるのを確認します。
kubectl get pods -l app=mysql --watch
新しいPodが起動すると、サーバーID103
と104
がSELECT @@server_id
ループの出力に現れます。
また、これらの新しいサーバーが、これらのサーバーが存在する前に追加したデータを持っていることを確認することもできます。
kubectl run mysql-client --image=mysql:5.7 -i -t --rm --restart=Never --\
mysql -h mysql-3.mysql -e "SELECT * FROM test.messages"
Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false
+---------+
| message |
+---------+
| hello |
+---------+
pod "mysql-client" deleted
元の状態へのスケールダウンもシームレスに可能です。
kubectl scale statefulset mysql --replicas=3
ただし、スケールアップすると新しいPersistentVolumeClaimが自動的に作成されますが、 スケールダウンしてもこれらのPVCは自動的には削除されないことに注意して下さい。 このため、初期化されたPVCをそのまま置いておいくことで再スケールアップを速くしたり、 PVを削除する前にデータを抽出するといった選択が可能になります。
次のコマンドを実行してこのことを確認できます。
kubectl get pvc -l app=mysql
StatefulSetを3にスケールダウンしたにもかかわらず、5つのPVCすべてがまだ存在しています。
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
data-mysql-0 Bound pvc-8acbf5dc-b103-11e6-93fa-42010a800002 10Gi RWO 20m
data-mysql-1 Bound pvc-8ad39820-b103-11e6-93fa-42010a800002 10Gi RWO 20m
data-mysql-2 Bound pvc-8ad69a6d-b103-11e6-93fa-42010a800002 10Gi RWO 20m
data-mysql-3 Bound pvc-50043c45-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m
data-mysql-4 Bound pvc-500a9957-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m
余分なPVCを再利用するつもりがないのであれば、削除することができます。
kubectl delete pvc data-mysql-3
kubectl delete pvc data-mysql-4
SELECT @@server_id
ループを実行している端末でCtrl+Cを押すか、
別の端末から次のコマンドを実行して、ループをキャンセルします。
kubectl delete pod mysql-client-loop --now
StatefulSetを削除します。これによってPodの終了も開始されます。
kubectl delete statefulset mysql
Podが消えたことを確認します。 Podが終了処理が完了するのには少し時間がかかるかもしれません。
kubectl get pods -l app=mysql
上記のコマンドから以下の出力が戻れば、Podが終了したことがわかります。
No resources found.
ConfigMap、Services、およびPersistentVolumeClaimを削除します。
kubectl delete configmap,service,pvc -l app=mysql
PersistentVolumeを手動でプロビジョニングした場合は、それらを手動で削除し、 また、下層にあるリソースも解放する必要があります。 動的プロビジョニング機能を使用した場合は、PersistentVolumeClaimを削除すれば、自動的にPersistentVolumeも削除されます。 一部の動的プロビジョナー(EBSやPDなど)は、PersistentVolumeを削除すると同時に下層にあるリソースも解放します。
このタスクは、StatefulSetをスケールする方法を示します。StatefulSetをスケーリングするとは、レプリカの数を増減することです。
StatefulSetはKubernetesバージョン1.5以降でのみ利用可能です。
Kubernetesのバージョンを確認するには、kubectl version
を実行してください。
すべてのステートフルアプリケーションがうまくスケールできるわけではありません。StatefulSetがスケールするかどうかわからない場合は、StatefulSetの概念またはStatefulSetのチュートリアルを参照してください。
ステートフルアプリケーションクラスターが完全に健全であると確信できる場合にのみ、スケーリングを実行してください。
まず、スケールしたいStatefulSetを見つけます。
kubectl get statefulsets <stateful-set-name>
StatefulSetのレプリカ数を変更します:
kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
コマンドライン上でレプリカ数を変更する代わりに、StatefulSetにインプレースアップデートが可能です。
StatefulSetが最初に kubectl apply
で作成されたのなら、StatefulSetマニフェストの.spec.replicas
を更新してから、kubectl apply
を実行します:
kubectl apply -f <stateful-set-file-updated>
そうでなければ、kubectl edit
でそのフィールドを編集してください:
kubectl edit statefulsets <stateful-set-name>
あるいはkubectl patch
を使ってください:
kubectl patch statefulsets <stateful-set-name> -p '{"spec":{"replicas":<new-replicas>}}'
管理するステートフルPodのいずれかが異常である場合、StatefulSetをスケールダウンすることはできません。それらのステートフルPodが実行され準備ができた後にのみ、スケールダウンが行われます。
spec.replicas > 1の場合、Kubernetesは不健康なPodの理由を判断できません。それは、永続的な障害または一時的な障害の結果である可能性があります。一時的な障害は、アップグレードまたはメンテナンスに必要な再起動によって発生する可能性があります。
永続的な障害が原因でPodが正常でない場合、障害を修正せずにスケーリングすると、StatefulSetメンバーシップが正しく機能するために必要な特定の最小レプリカ数を下回る状態になる可能性があります。これにより、StatefulSetが利用できなくなる可能性があります。
一時的な障害によってPodが正常でなくなり、Podが再び使用可能になる可能性がある場合は、一時的なエラーがスケールアップまたはスケールダウン操作の妨げになる可能性があります。一部の分散データベースでは、ノードが同時に参加および脱退するときに問題があります。このような場合は、アプリケーションレベルでスケーリング操作を考えることをお勧めします。また、ステートフルアプリケーションクラスタが完全に健全であることが確実な場合にのみスケーリングを実行してください。
このタスクでは、StatefulSetを削除する方法を説明します。
Kubernetesで他のリソースを削除するのと同じ方法でStatefulSetを削除することができます。つまり、kubectl delete
コマンドを使い、StatefulSetをファイルまたは名前で指定します。
kubectl delete -f <file.yaml>
kubectl delete statefulsets <statefulset-name>
StatefulSet自体が削除された後で、関連するヘッドレスサービスを個別に削除する必要があるかもしれません。
kubectl delete service <service-name>
kubectlを使ってStatefulSetを削除すると0にスケールダウンされ、すべてのPodが削除されます。PodではなくStatefulSetだけを削除したい場合は、--cascade=orphan
を使用してください。
kubectl delete -f <file.yaml> --cascade=orphan
--cascade=orphan
をkubectl delete
に渡すことで、StatefulSetオブジェクト自身が削除された後でも、StatefulSetによって管理されていたPodは残ります。Podにapp=myapp
というラベルが付いている場合は、次のようにして削除できます:
kubectl delete pods -l app=myapp
StatefulSet内のPodを削除しても、関連付けられているボリュームは削除されません。これは、削除する前にボリュームからデータをコピーする機会があることを保証するためです。Podが終了した後にPVCを削除すると、ストレージクラスと再利用ポリシーによっては、背後にある永続ボリュームの削除がトリガーされることがあります。決してクレーム削除後にボリュームにアクセスできると想定しないでください。
関連付けられたPodを含むStatefulSet内のすべてのものを単純に削除するには、次のような一連のコマンドを実行します:
grace=$(kubectl get pods <stateful-set-pod> --template '{{.spec.terminationGracePeriodSeconds}}')
kubectl delete statefulset -l app=myapp
sleep $grace
kubectl delete pvc -l app=myapp
上の例では、Podはapp=myapp
というラベルを持っています。必要に応じてご利用のラベルに置き換えてください。
StatefulSet内の一部のPodが長期間Terminating
またはUnknown
状態のままになっていることが判明した場合は、手動でapiserverからPodを強制的に削除する必要があります。これは潜在的に危険な作業です。詳細はStatefulSet Podの強制削除を参照してください。
このページでは、StatefulSetの一部であるPodを削除する方法と、削除する際に考慮すべき事項について説明します。
StatefulSetの通常の操作では、StatefulSet Podを強制的に削除する必要はまったくありません。StatefulSetコントローラーは、StatefulSetのメンバーの作成、スケール、削除を行います。それは序数0からN-1までの指定された数のPodが生きていて準備ができていることを保証しようとします。StatefulSetは、クラスター内で実行されている特定のIDを持つ最大1つのPodがいつでも存在することを保証します。これは、StatefulSetによって提供される最大1つのセマンティクスと呼ばれます。
手動による強制削除は、StatefulSetに固有の最大1つのセマンティクスに違反する可能性があるため、慎重に行う必要があります。StatefulSetを使用して、安定したネットワークIDと安定した記憶域を必要とする分散型およびクラスター型アプリケーションを実行できます。これらのアプリケーションは、固定IDを持つ固定数のメンバーのアンサンブルに依存する構成を持つことがよくあります。同じIDを持つ複数のメンバーを持つことは悲惨なことになり、データの損失につながる可能性があります(例:定足数ベースのシステムでのスプリットブレインシナリオ)。
次のコマンドで正常なPod削除を実行できます:
kubectl delete pods <pod>
上記がグレースフルターミネーションにつながるためには、pod.Spec.TerminationGracePeriodSeconds
に0を指定してはいけません。pod.Spec.TerminationGracePeriodSeconds
を0秒に設定することは安全ではなく、StatefulSet Podには強くお勧めできません。グレースフル削除は安全で、kubeletがapiserverから名前を削除する前にPodが適切にシャットダウンすることを保証します。
Kubernetes(バージョン1.5以降)は、Nodeにアクセスできないという理由だけでPodを削除しません。到達不能なNodeで実行されているPodは、タイムアウトの後にTerminating
またはUnknown
状態になります。到達不能なNode上のPodをユーザーが適切に削除しようとすると、Podはこれらの状態に入ることもあります。そのような状態のPodをapiserverから削除することができる唯一の方法は以下の通りです:
推奨されるベストプラクティスは、1番目または2番目のアプローチを使用することです。Nodeが死んでいることが確認された(例えば、ネットワークから恒久的に切断された、電源が切られたなど)場合、Nodeオブジェクトを削除します。Nodeがネットワークパーティションに苦しんでいる場合は、これを解決するか、解決するのを待ちます。パーティションが回復すると、kubeletはPodの削除を完了し、apiserverでその名前を解放します。
通常、PodがNode上で実行されなくなるか、管理者によってそのNodeが削除されると、システムは削除を完了します。あなたはPodを強制的に削除することでこれを無効にすることができます。
強制削除はPodが終了したことをkubeletから確認するまで待ちません。強制削除がPodの削除に成功したかどうかに関係なく、apiserverから名前をすぐに解放します。これにより、StatefulSetコントローラーは、同じIDを持つ交換Podを作成できます。これは、まだ実行中のPodの複製につながる可能性があり、そのPodがまだStatefulSetの他のメンバーと通信できる場合、StatefulSetが保証するように設計されている最大1つのセマンティクスに違反します。
StatefulSetのPodを強制的に削除するということは、問題のPodがStatefulSet内の他のPodと再び接触することはなく、代わりのPodを作成するために名前が安全に解放されることを意味します。
バージョン1.5以上のkubectlを使用してPodを強制的に削除する場合は、次の手順を実行します:
kubectl delete pods <pod> --grace-period=0 --force
バージョン1.4以下のkubectlを使用している場合、--force
オプションを省略する必要があります:
kubectl delete pods <pod> --grace-period=0
これらのコマンドを実行した後でもPodがUnknown
状態のままになっている場合は、次のコマンドを使用してPodをクラスターから削除します:
kubectl patch pod <pod> -p '{"metadata":{"finalizers":null}}'
StatefulSet Podの強制削除は、常に慎重に、関連するリスクを完全に把握して実行してください。
Horizontal Pod Autoscalerは、Deployment、ReplicaSetまたはStatefulSetといったレプリケーションコントローラ内のPodの数を、観測されたCPU使用率(もしくはベータサポートの、アプリケーションによって提供されるその他のメトリクス)に基づいて自動的にスケールさせます。
このドキュメントはphp-apacheサーバーに対しHorizontal Pod Autoscalerを有効化するという例に沿ってウォークスルーで説明していきます。Horizontal Pod Autoscalerの動作についてのより詳細な情報を知りたい場合は、Horizontal Pod Autoscalerユーザーガイドをご覧ください。
この例ではバージョン1.2以上の動作するKubernetesクラスターおよびkubectlが必要です。 Metrics APIを介してメトリクスを提供するために、Metrics serverによるモニタリングがクラスター内にデプロイされている必要があります。 Horizontal Pod Autoscalerはメトリクスを収集するためにこのAPIを利用します。metrics-serverをデプロイする方法を知りたい場合はmetrics-server ドキュメントをご覧ください。
Horizontal Pod Autoscalerで複数のリソースメトリクスを利用するためには、バージョン1.6以上のKubernetesクラスターおよびkubectlが必要です。カスタムメトリクスを使えるようにするためには、あなたのクラスターがカスタムメトリクスAPIを提供するAPIサーバーと通信できる必要があります。 最後に、Kubernetesオブジェクトと関係のないメトリクスを使うにはバージョン1.10以上のKubernetesクラスターおよびkubectlが必要で、さらにあなたのクラスターが外部メトリクスAPIを提供するAPIサーバーと通信できる必要があります。 詳細についてはHorizontal Pod Autoscaler user guideをご覧ください。
Horizontal Pod Autoscalerのデモンストレーションのために、php-apacheイメージをもとにしたカスタムのDockerイメージを使います。 このDockerfileは下記のようになっています。
FROM php:5-apache
COPY index.php /var/www/html/index.php
RUN chmod a+rx index.php
これはCPU負荷の高い演算を行うindex.phpを定義しています。
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
echo "OK!";
?>
まず最初に、イメージを動かすDeploymentを起動し、Serviceとして公開しましょう。 下記の設定を使います。
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 1
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: k8s.gcr.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
以下のコマンドを実行してください。
kubectl apply -f https://k8s.io/examples/application/php-apache.yaml
deployment.apps/php-apache created
service/php-apache created
サーバーが起動したら、kubectl autoscaleを使ってautoscalerを作成しましょう。以下のコマンドで、最初のステップで作成したphp-apache deploymentによって制御されるPodレプリカ数を1から10の間に維持するHorizontal Pod Autoscalerを作成します。
簡単に言うと、HPAは(Deploymentを通じて)レプリカ数を増減させ、すべてのPodにおける平均CPU使用率を50%(それぞれのPodはkubectl run
で200 milli-coresを要求しているため、平均CPU使用率100 milli-coresを意味します)に保とうとします。
このアルゴリズムについての詳細はこちらをご覧ください。
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
以下を実行して現在のAutoscalerの状況を確認できます。
kubectl get hpa
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 18s
現在はサーバーにリクエストを送っていないため、CPU使用率が0%になっていることに注意してください(TARGET
カラムは対応するDeploymentによって制御される全てのPodの平均値を示しています。)。
Autoscalerがどのように負荷の増加に反応するか見てみましょう。 コンテナを作成し、クエリの無限ループをphp-apacheサーバーに送ってみます(これは別のターミナルで実行してください)。
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
数分以内に、下記を実行することでCPU負荷が高まっていることを確認できます。
kubectl get hpa
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 305% / 50% 1 10 1 3m
ここでは、CPU使用率はrequestの305%にまで高まっています。 結果として、Deploymentはレプリカ数7にリサイズされました。
kubectl get deployment php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 7/7 7 7 19m
ユーザー負荷を止めてこの例を終わらせましょう。
私たちがbusybox
イメージを使って作成したコンテナ内のターミナルで、<Ctrl> + C
を入力して負荷生成を終了させます。
そして結果の状態を確認します(数分後)。
kubectl get hpa
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 11m
kubectl get deployment php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 1/1 1 1 27m
ここでCPU使用率は0に下がり、HPAによってオートスケールされたレプリカ数は1に戻ります。
autoscaling/v2beta2
APIバージョンと使うと、php-apache
Deploymentをオートスケーリングする際に使う追加のメトリクスを導入することが出来ます。
まず、autoscaling/v2beta2
内のHorizontalPodAutoscalerのYAMLファイルを入手します。
kubectl get hpa.v2beta2.autoscaling -o yaml > /tmp/hpa-v2.yaml
/tmp/hpa-v2.yaml
ファイルをエディタで開くと、以下のようなYAMLファイルが見えるはずです。
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
status:
observedGeneration: 1
lastScaleTime: <some-time>
currentReplicas: 1
desiredReplicas: 1
currentMetrics:
- type: Resource
resource:
name: cpu
current:
averageUtilization: 0
averageValue: 0
targetCPUUtilizationPercentage
フィールドはmetrics
と呼ばれる配列に置換されています。
CPU使用率メトリクスは、Podコンテナで定められたリソースの割合として表されるため、リソースメトリクスです。CPU以外のリソースメトリクスを指定することもできます。デフォルトでは、他にメモリだけがリソースメトリクスとしてサポートされています。これらのリソースはクラスター間で名前が変わることはなく、そしてmetrics.k8s.io
APIが利用可能である限り常に利用可能です。
さらにtarget.type
においてUtilization
の代わりにAverageValue
を使い、target.averageUtilization
フィールドの代わりに対応するtarget.averageValue
フィールドを設定することで、リソースメトリクスをrequest値に対する割合に代わり、直接的な値に設定することも可能です。
PodメトリクスとObjectメトリクスという2つの異なる種類のメトリクスが存在し、どちらもカスタムメトリクスとみなされます。これらのメトリクスはクラスター特有の名前を持ち、利用するにはより発展的なクラスター監視設定が必要となります。
これらの代替メトリクスタイプのうち、最初のものがPodメトリクスです。これらのメトリクスはPodを説明し、Podを渡って平均され、レプリカ数を決定するためにターゲット値と比較されます。
これらはほとんどリソースメトリクス同様に機能しますが、target
の種類としてはAverageValue
のみをサポートしている点が異なります。
Podメトリクスはmetricブロックを使って以下のように指定されます。
type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
2つ目のメトリクスタイプはObjectメトリクスです。これらのメトリクスはPodを説明するかわりに、同一Namespace内の異なったオブジェクトを説明します。このメトリクスはオブジェクトから取得される必要はありません。単に説明するだけです。Objectメトリクスはtarget
の種類としてValue
とAverageValue
をサポートします。Value
では、ターゲットはAPIから返ってきたメトリクスと直接比較されます。AverageValue
では、カスタムメトリクスAPIから返ってきた値はターゲットと比較される前にPodの数で除算されます。以下の例はrequests-per-second
メトリクスのYAML表現です。
type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
name: main-route
target:
type: Value
value: 2k
もしこのようなmetricブロックを複数提供した場合、HorizontalPodAutoscalerはこれらのメトリクスを順番に処理します。 HorizontalPodAutoscalerはそれぞれのメトリクスについて推奨レプリカ数を算出し、その中で最も多いレプリカ数を採用します。
例えば、もしあなたがネットワークトラフィックについてのメトリクスを収集する監視システムを持っているなら、kubectl edit
を使って指定を次のように更新することができます。
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
- type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
name: main-route
target:
type: Value
value: 10k
status:
observedGeneration: 1
lastScaleTime: <some-time>
currentReplicas: 1
desiredReplicas: 1
currentMetrics:
- type: Resource
resource:
name: cpu
current:
averageUtilization: 0
averageValue: 0
- type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
name: main-route
current:
value: 10k
この時、HorizontalPodAutoscalerはそれぞれのPodがCPU requestの50%を使い、1秒当たり1000パケットを送信し、そしてmain-route Ingressの裏にあるすべてのPodが合計で1秒当たり10000パケットを送信する状態を保持しようとします。
多くのメトリクスパイプラインは、名前もしくは labels と呼ばれる追加の記述子の組み合わせによって説明することができます。全てのリソースメトリクス以外のメトリクスタイプ(Pod、Object、そして下で説明されている外部メトリクス)において、メトリクスパイプラインに渡す追加のラベルセレクターを指定することができます。例えば、もしあなたがhttp_requests
メトリクスをverb
ラベルとともに収集しているなら、下記のmetricブロックを指定してGETリクエストにのみ基づいてスケールさせることができます。
type: Object
object:
metric:
name: http_requests
selector: {matchLabels: {verb: GET}}
このセレクターは完全なKubernetesラベルセレクターと同じ文法を利用します。もし名前とセレクターが複数の系列に一致した場合、この監視パイプラインはどのようにして複数の系列を一つの値にまとめるかを決定します。このセレクターは付加的なもので、ターゲットオブジェクト(Pods
タイプの場合は対象Pod、Object
タイプの場合は説明されるオブジェクト)ではないオブジェクトを説明するメトリクスを選択することは出来ません。
Kubernetes上で動いているアプリケーションを、Kubernetes Namespaceと直接的な関係がないサービスを説明するメトリクスのような、Kubernetesクラスター内のオブジェクトと明確な関係が無いメトリクスを基にオートスケールする必要があるかもしれません。Kubernetes 1.10以降では、このようなユースケースを外部メトリクスによって解決できます。
外部メトリクスを使うにはあなたの監視システムについての知識が必要となります。この設定はカスタムメトリクスを使うときのものに似ています。外部メトリクスを使うとあなたの監視システムのあらゆる利用可能なメトリクスに基づいてクラスターをオートスケールできるようになります。上記のようにmetric
ブロックでname
とselector
を設定し、Object
のかわりにExternal
メトリクスタイプを使います。
もし複数の時系列がmetricSelector
により一致した場合は、それらの値の合計がHorizontalPodAutoscalerに使われます。
外部メトリクスはValue
とAverageValue
の両方のターゲットタイプをサポートしています。これらの機能はObject
タイプを利用するときとまったく同じです。
例えばもしあなたのアプリケーションがホストされたキューサービスからのタスクを処理している場合、あなたは下記のセクションをHorizontalPodAutoscalerマニフェストに追記し、未処理のタスク30個あたり1つのワーカーを必要とすることを指定します。
- type: External
external:
metric:
name: queue_messages_ready
selector: "queue=worker_tasks"
target:
type: AverageValue
averageValue: 30
可能なら、クラスター管理者がカスタムメトリクスAPIを保護することを簡単にするため、外部メトリクスのかわりにカスタムメトリクスを用いることが望ましいです。外部メトリクスAPIは潜在的に全てのメトリクスへのアクセスを許可するため、クラスター管理者はこれを公開する際には注意が必要です。
autoscaling/v2beta2
形式のHorizontalPodAutoscalerを使っている場合は、KubernetesによるHorizontalPodAutoscaler上のstatus conditionsセットを見ることができます。status conditionsはHorizontalPodAutoscalerがスケール可能かどうか、そして現時点でそれが何らかの方法で制限されているかどうかを示しています。
このconditionsはstatus.conditions
フィールドに現れます。HorizontalPodAutoscalerに影響しているconditionsを確認するために、kubectl describe hpa
を利用できます。
kubectl describe hpa cm-test
Name: cm-test
Namespace: prom
Labels: <none>
Annotations: <none>
CreationTimestamp: Fri, 16 Jun 2017 18:09:22 +0000
Reference: ReplicationController/cm-test
Metrics: ( current / target )
"http_requests" on pods: 66m / 500m
Min replicas: 1
Max replicas: 4
ReplicationController pods: 1 current / 1 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale the last scale time was sufficiently old as to warrant a new scale
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric http_requests
ScalingLimited False DesiredWithinRange the desired replica count is within the acceptable range
Events:
このHorizontalPodAutoscalerにおいて、いくつかの正常な状態のconditionsを見ることができます。まず最初に、AbleToScale
は、HPAがスケール状況を取得し、更新させることが出来るかどうかだけでなく、何らかのbackoffに関連した状況がスケーリングを妨げていないかを示しています。2番目に、ScalingActive
は、HPAが有効化されているかどうか(例えば、レプリカ数のターゲットがゼロでないこと)や、望ましいスケールを算出できるかどうかを示します。もしこれがFalse
の場合、大体はメトリクスの取得において問題があることを示しています。最後に、一番最後の状況であるScalingLimited
は、HorizontalPodAutoscalerの最大値や最小値によって望ましいスケールがキャップされていることを示しています。この指標を見てHorizontalPodAutoscaler上の最大・最小レプリカ数制限を増やす、もしくは減らす検討ができます。
全てのHorizontalPodAutoscalerおよびメトリクスAPIにおけるメトリクスはquantityとして知られる特殊な整数表記によって指定されます。例えば、10500m
という数量は10進数表記で10.5
と書くことができます。メトリクスAPIは可能であれば接尾辞を用いない整数を返し、そうでない場合は基本的にミリ単位での数量を返します。これはメトリクス値が1
と1500m
の間で、もしくは10進法表記で書かれた場合は1
と1.5
の間で変動するということを意味します。
kubectl autoscale
コマンドを使って命令的にHorizontalPodAutoscalerを作るかわりに、下記のファイルを使って宣言的に作成することができます。
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 50
下記のコマンドを実行してAutoscalerを作成します。
kubectl create -f https://k8s.io/examples/application/hpa/php-apache.yaml
horizontalpodautoscaler.autoscaling/php-apache created
CronJobは、Kubernetes v1.21で一般利用(GA)に昇格しました。古いバージョンのKubernetesを使用している場合、正確な情報を参照できるように、使用しているバージョンのKubernetesのドキュメントを参照してください。古いKubernetesのバージョンでは、batch/v1
CronJob APIはサポートされていません。
CronJobを使用すると、Jobを時間ベースのスケジュールで実行できるようになります。この自動化されたJobは、LinuxまたはUNIXシステム上のCronのように実行されます。
CronJobは、バックアップやメールの送信など、定期的なタスクや繰り返しのタスクを作成する時に便利です。CronJobはそれぞれのタスクを、たとえばアクティビティが少ない期間など、特定の時間にスケジューリングすることもできます。
CronJobには制限と特性があります。たとえば、特定の状況下では、1つのCronJobが複数のJobを作成する可能性があるため、Jobは冪等性を持つようにしなければいけません。
制限に関する詳しい情報については、CronJobを参照してください。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
CronJobには設定ファイルが必要です。次の例のCronJobの.spec
は、現在の時刻とhelloというメッセージを1分ごとに表示します。
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
次のコマンドで例のCronJobを実行します。
kubectl create -f https://k8s.io/examples/application/job/cronjob.yaml
出力は次のようになります。
cronjob.batch/hello created
CronJobを作成したら、次のコマンドで状態を取得します。
kubectl get cronjob hello
出力は次のようになります。
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 <none> 10s
コマンドの結果からわかるように、CronJobはまだスケジュールされておらず、まだ何のJobも実行していません。約1分以内にJobが作成されるのを見てみましょう。
kubectl get jobs --watch
出力は次のようになります。
NAME COMPLETIONS DURATION AGE
hello-4111706356 0/1 0s
hello-4111706356 0/1 0s 0s
hello-4111706356 1/1 5s 5s
"hello"CronJobによってスケジュールされたJobが1つ実行中になっていることがわかります。Jobを見るのをやめて、再度CronJobを表示して、Jobがスケジュールされたことを確認してみます。
kubectl get cronjob hello
出力は次のようになります。
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 50s 75s
CronJobhello
が、LAST SCHEDULE
で指定された時間にJobを正しくスケジュールしたことが確認できるはずです。現在、activeなJobの数は0です。つまり、Jobは完了または失敗したことがわかります。
それでは、最後にスケジュールされたJobの作成と、Podの1つの標準出力を表示してみましょう。
# "hello-4111706356" の部分は、あなたのシステム上のJobの名前に置き換えてください。
pods=$(kubectl get pods --selector=job-name=hello-4111706356 --output=jsonpath={.items[*].metadata.name})
Podのログを表示します。
kubectl logs $pods
出力は次のようになります。
Fri Feb 22 11:02:09 UTC 2019
Hello from the Kubernetes cluster
CronJobが必要なくなったときは、kubectl delete cronjob <cronjob name>
で削除します。
kubectl delete cronjob hello
CronJobを削除すると、すべてのJobと、そのJobが作成したPodが削除され、追加のJobの作成が停止されます。Jobの削除について詳しく知りたい場合は、ガベージコレクションを読んでください。
すべてのKubernetesの設定と同じように、CronJobにもapiVersion
、kind
、metadata
のフィールドが必要です。設定ファイルの扱い方についての一般的な情報については、アプリケーションのデプロイとkubectlを使用してリソースを管理するを読んでください。
CronJobの設定には、.spec
セクションも必要です。
spec
へのすべての修正は、それ以降の実行にのみ適用されます。
.spec.schedule
は、.spec
には必須のフィールドです。0 * * * *
や@hourly
などのCron形式の文字列を取り、Jobの作成と実行のスケジュール時間を指定します。
フォーマットにはVixie cronのステップ値(step value)も指定できます。FreeBSDのマニュアルでは次のように説明されています。
ステップ値は範囲指定と組み合わせて使用できます。範囲の後ろに
/<number>
を付けると、範囲全体で指定したnumberの値ごとにスキップすることを意味します。たとえば、0-23/2
をhoursフィールドに指定すると、2時間毎にコマンド実行を指定することになります(V7標準では代わりに0,2,4,6,8,10,12,14,16,18,20,22
と指定する必要があります)。ステップはアスタリスクの後ろにつけることもできます。そのため、「2時間毎に実行」したい場合は、単純に*/2
と指定できます。
?
はアスタリスク*
と同じ意味を持ちます。つまり、与えられたフィールドには任意の値が使えるという意味になります。
.spec.jobTemplate
はJobのテンプレートであり、必須です。Jobと完全に同一のスキーマを持ちますが、フィールドがネストされている点と、apiVersion
とkind
が存在しない点だけが異なります。Jobの.spec
を書くための情報については、JobのSpecを書くを参照してください。
.spec.startingDeadlineSeconds
フィールドはオプションです。何かの理由でスケジュールに間に合わなかった場合に適用される、Jobの開始のデッドライン(締め切り)を秒数で指定します。デッドラインを過ぎると、CronJobはJobを開始しません。この場合にデッドラインに間に合わなかったJobは、失敗したJobとしてカウントされます。もしこのフィールドが指定されなかった場合、Jobはデッドラインを持ちません。
.spec.startingDeadlineSeconds
フィールドがnull以外に設定された場合、CronJobコントローラーはJobの作成が期待される時間と現在時刻との間の時間を計測します。もしその差が制限よりも大きかった場合、その実行はスキップされます。
たとえば、この値が200
に設定された場合、実際のスケジュールの最大200秒後までに作成されるJobだけが許可されます。
.spec.concurrencyPolicy
フィールドもオプションです。このフィールドは、このCronJobで作成されたJobの並列実行をどのように扱うかを指定します。specには以下のconcurrency policyのいずれかを指定します。
Allow
(デフォルト): CronJobがJobを並列に実行することを許可します。Forbid
: CronJobの並列実行を禁止します。もし新しいJobの実行時に過去のJobがまだ完了していなかった場合、CronJobは新しいJobの実行をスキップします。Replace
: もし新しいJobの実行の時間になっても過去のJobの実行が完了していなかった場合、CronJobは現在の実行中のJobを新しいJobで置換します。concurrency policyは、同じCronJobが作成したJobにのみ適用されます。もし複数のCronJobがある場合、それぞれのJobの並列実行は常に許可されます。
.spec.suspend
フィールドもオプションです。このフィールドをtrue
に設定すると、すべての後続の実行がサスペンド(一時停止)されます。この設定はすでに実行開始したJobには適用されません。デフォルトはfalseです。
.spec.suspend
がtrue
からfalse
に変更されると、見逃されたJobは即座にスケジュールされます。
.spec.successfulJobsHistoryLimit
と.spec.failedJobsHistoryLimit
フィールドはオプションです。これらのフィールドには、完了したJobと失敗したJobをいくつ保持するかを指定します。デフォルトでは、それぞれ3と1に設定されます。リミットを0
に設定すると、対応する種類のJobを実行完了後に何も保持しなくなります。
Kubernetes v1.21 [alpha]
この例では、複数の並列ワーカープロセスを使用するKubernetesのJobを実行します。各ワーカーは、それぞれが自分のPod内で実行される異なるコンテナです。Podはコントロールプレーンが自動的に設定するインデックス値を持ち、この値を利用することで、各Podは処理するタスク全体のどの部分を処理するのかを特定できます。
Podのインデックスは、アノテーション内のbatch.kubernetes.io/job-completion-index
を整数値の文字列表現として利用できます。コンテナ化されたタスクプロセスがこのインデックスを取得できるようにするために、このアノテーションの値はdownward APIの仕組みを利用することで公開できます。利便性のために、コントロールプレーンは自動的にdownward APIを設定して、JOB_COMPLETION_INDEX
環境変数にインデックスを公開します。
以下に、この例で実行するステップの概要を示します。
あらかじめ基本的な非並列のJobの使用に慣れている必要があります。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.21. バージョンを確認するには次のコマンドを実行してください:kubectl version
.
インデックス付きJobを作成できるようにするには、APIサーバーとコントローラーマネージャー上でIndexedJob
フィーチャーゲートを有効にしていることを確認してください。
ワーカープログラムから処理アイテムにアクセスするには、いくつかの選択肢があります。
JOB_COMPLETION_INDEX
環境変数を読み込む。Jobコントローラーは、この変数をcompletion indexを含むアノテーションに自動的にリンクします。この例では、3番目のオプションを選択肢して、revユーティリティを実行したいと考えているとしましょう。このプログラムはファイルを引数として受け取り、内容を逆さまに表示します。
rev data.txt
rev
ツールはbusybox
コンテナイメージから利用できます。
これは単なる例であるため、各Podはごく簡単な処理(短い文字列を逆にする)をするだけです。現実のワークロードでは、たとえば、シーンデータをもとに60秒の動画を生成するというようなタスクを記述したJobを作成するかもしれません。ビデオレンダリングJobの各処理アイテムは、ビデオクリップの特定のフレームのレンダリングを行うものになるでしょう。その場合、インデックス付きの完了が意味するのは、クリップの最初からフレームをカウントすることで、Job内の各Podがレンダリングと公開をするのがどのフレームであるかがわかるということです。
以下は、completion modeとしてIndexed
を使用するJobのマニフェストの例です。
apiVersion: batch/v1
kind: Job
metadata:
name: 'indexed-job'
spec:
completions: 5
parallelism: 3
completionMode: Indexed
template:
spec:
restartPolicy: Never
initContainers:
- name: 'input'
image: 'docker.io/library/bash'
command:
- "bash"
- "-c"
- |
items=(foo bar baz qux xyz)
echo ${items[$JOB_COMPLETION_INDEX]} > /input/data.txt
volumeMounts:
- mountPath: /input
name: input
containers:
- name: 'worker'
image: 'docker.io/library/busybox'
command:
- "rev"
- "/input/data.txt"
volumeMounts:
- mountPath: /input
name: input
volumes:
- name: input
emptyDir: {}
上記の例では、Jobコントローラーがすべてのコンテナに設定する組み込みのJOB_COMPLETION_INDEX
環境変数を使っています。initコンテナがインデックスを静的な値にマッピングし、その値をファイルに書き込み、ファイルをemptyDir volumeを介してワーカーを実行しているコンテナと共有します。オプションとして、インデックスとコンテナに公開するためにdownward APIを使用して独自の環境変数を定義することもできます。環境変数やファイルとして設定したConfigMapから値のリストを読み込むという選択肢もあります。
他には、以下の例のように、直接downward APIを使用してアノテーションの値をボリュームファイルとして渡すこともできます。
apiVersion: batch/v1
kind: Job
metadata:
name: 'indexed-job'
spec:
completions: 5
parallelism: 3
completionMode: Indexed
template:
spec:
restartPolicy: Never
containers:
- name: 'worker'
image: 'docker.io/library/busybox'
command:
- "rev"
- "/input/data.txt"
volumeMounts:
- mountPath: /input
name: input
volumes:
- name: input
downwardAPI:
items:
- path: "data.txt"
fieldRef:
fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
次のコマンドでJobを実行します。
# このコマンドでは1番目のアプローチを使っています ($JOB_COMPLETION_INDEX に依存しています)
kubectl apply -f https://kubernetes.io/examples/application/job/indexed-job.yaml
このJobを作成したら、コントロールプレーンは指定した各インデックスごとに一連のPodを作成します。.spec.parallelism
の値が同時に実行できるPodの数を決定し、.spec.completions
の値がJobが作成するPodの合計数を決定します。
.spec.parallelism
は.spec.completions
より小さいため、コントロールプレーンは別のPodを開始する前に最初のPodの一部が完了するまで待機します。
Jobを作成したら、少し待ってから進行状況を確認します。
kubectl describe jobs/indexed-job
出力は次のようになります。
Name: indexed-job
Namespace: default
Selector: controller-uid=bf865e04-0b67-483b-9a90-74cfc4c3e756
Labels: controller-uid=bf865e04-0b67-483b-9a90-74cfc4c3e756
job-name=indexed-job
Annotations: <none>
Parallelism: 3
Completions: 5
Start Time: Thu, 11 Mar 2021 15:47:34 +0000
Pods Statuses: 2 Running / 3 Succeeded / 0 Failed
Completed Indexes: 0-2
Pod Template:
Labels: controller-uid=bf865e04-0b67-483b-9a90-74cfc4c3e756
job-name=indexed-job
Init Containers:
input:
Image: docker.io/library/bash
Port: <none>
Host Port: <none>
Command:
bash
-c
items=(foo bar baz qux xyz)
echo ${items[$JOB_COMPLETION_INDEX]} > /input/data.txt
Environment: <none>
Mounts:
/input from input (rw)
Containers:
worker:
Image: docker.io/library/busybox
Port: <none>
Host Port: <none>
Command:
rev
/input/data.txt
Environment: <none>
Mounts:
/input from input (rw)
Volumes:
input:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium:
SizeLimit: <unset>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 4s job-controller Created pod: indexed-job-njkjj
Normal SuccessfulCreate 4s job-controller Created pod: indexed-job-9kd4h
Normal SuccessfulCreate 4s job-controller Created pod: indexed-job-qjwsz
Normal SuccessfulCreate 1s job-controller Created pod: indexed-job-fdhq5
Normal SuccessfulCreate 1s job-controller Created pod: indexed-job-ncslj
この例では、各インデックスごとにカスタムの値を使用してJobを実行します。次のコマンドでPodの1つの出力を確認できます。
kubectl logs indexed-job-fdhq5 # これを対象のJobのPodの名前に一致するように変更してください。
出力は次のようになります。
xuq
ダッシュボードは、WebベースのKubernetesユーザーインターフェイスです。 ダッシュボードを使用して、コンテナ化されたアプリケーションをKubernetesクラスターにデプロイしたり、 コンテナ化されたアプリケーションをトラブルシューティングしたり、クラスターリソースを管理したりすることができます。 ダッシュボードを使用して、クラスター上で実行されているアプリケーションの概要を把握したり、 個々のKubernetesリソース(Deployments、Jobs、DaemonSetsなど)を作成または修正したりすることができます。 たとえば、Deploymentのスケール、ローリングアップデートの開始、Podの再起動、 デプロイウィザードを使用した新しいアプリケーションのデプロイなどが可能です。
ダッシュボードでは、クラスター内のKubernetesリソースの状態や、発生した可能性のあるエラーに関する情報も提供されます。
ダッシュボードUIはデフォルトではデプロイされていません。デプロイするには、以下のコマンドを実行します:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
クラスターデータを保護するために、ダッシュボードはデフォルトで最小限のRBAC構成でデプロイします。 現在、ダッシュボードはBearer Tokenによるログインのみをサポートしています。 このデモ用のトークンを作成するには、 サンプルユーザーの作成ガイドに従ってください。
以下のコマンドを実行することで、kubectlコマンドラインツールを使ってダッシュボードにアクセスすることができます:
kubectl proxy
kubectlは、ダッシュボードを http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ で利用できるようにします。
UIはコマンドを実行しているマシンから のみ アクセスできます。オプションについてはkubectl proxy --help
を参照してください。
空のクラスターでダッシュボードにアクセスすると、ウェルカムページが表示されます。
このページには、このドキュメントへのリンクと、最初のアプリケーションをデプロイするためのボタンが含まれています。
さらに、クラスターのkube-system
名前空間でデフォルトで実行されているシステムアプリケーション、たとえばダッシュボード自体を見ることができます。
ダッシュボードを使用すると、簡単なウィザードでコンテナ化されたアプリケーションをDeploymentとオプションのServiceとして作成してデプロイすることができます。 アプリケーションの詳細を手動で指定するか、アプリケーションの設定を含むYAMLまたはJSONファイルをアップロードすることができます。
任意のページの右上にあるCREATEボタンをクリックして開始します。
デプロイウィザードでは、以下の情報を入力する必要があります:
App name (必須): アプリケーションの名前です。 その名前のlabelは、デプロイされるDeploymentとServiceに追加されます。
アプリケーション名は、選択したKubernetes名前空間内で一意である必要があります。 小文字で始まり、小文字または数字で終わり、小文字、数字、ダッシュ(-)のみを含む必要があります。文字数は24文字に制限されています。先頭と末尾のスペースは無視されます。
Container image (必須): 任意のレジストリ上の公開Dockerコンテナイメージ、またはプライベートイメージ(一般的にはGoogle Container RegistryやDocker Hub上でホストされている)のURLです。 コンテナイメージの指定はコロンで終わらせる必要があります。
クラスタ全体で必要な数のPodを維持するために、Deploymentが作成されます。
Service (任意): アプリケーションのいくつかの部分(たとえばフロントエンド)では、 Serviceをクラスター外の外部、おそらくパブリックIPアドレス(外部サービス)に公開したいと思うかもしれません。
クラスター内部からしか見えないその他のサービスは、内部サービスと呼ばれます。
サービスの種類にかかわらず、サービスを作成し、コンテナがポート(受信)をリッスンする場合は、 2つのポートを指定する必要があります。 サービスは、ポート(受信)をコンテナから見たターゲットポートにマッピングして作成されます。 このサービスは、デプロイされたPodにルーティングされます。サポートされるプロトコルはTCPとUDPです。 このサービスの内部DNS名は、上記のアプリケーション名として指定した値になります。
必要に応じて、高度なオプションセクションを展開して、より多くの設定を指定することができます:
Description: ここで入力したテキストは、 アノテーションとしてDeploymentに追加され、アプリケーションの詳細に表示されます。
Labels: アプリケーションに使用するデフォルトのラベルは、アプリケーション名とバージョンです。 リリース、環境、ティア、パーティション、リリーストラックなど、Deployment、Service(存在する場合)、Podに適用する追加のラベルを指定できます。
例:
release=1.0
tier=frontend
environment=pod
track=stable
Namespace: Kubernetesは、同じ物理クラスターを基盤とする複数の仮想クラスターをサポートしています。 これらの仮想クラスタは名前空間 と呼ばれます。 これにより、リソースを論理的に名前のついたグループに分割することができます。
ダッシュボードでは、利用可能なすべての名前空間がドロップダウンリストに表示され、新しい名前空間を作成することができます。 名前空間名には、最大63文字の英数字とダッシュ(-)を含めることができますが、大文字を含めることはできません。 名前空間名は数字だけで構成されるべきではありません。 名前が10などの数値として設定されている場合、Podはデフォルトの名前空間に配置されます。
名前空間の作成に成功した場合は、デフォルトで選択されます。 作成に失敗した場合は、最初の名前空間が選択されます。
Image Pull Secret: 指定されたDockerコンテナイメージが非公開の場合、 pull secretの認証情報が必要になる場合があります。
ダッシュボードでは、利用可能なすべてのSecretがドロップダウンリストに表示され、新しいSecretを作成できます。
Secret名は DNSドメイン名の構文に従う必要があります。たとえば、new.image-pull.secret
です。
Secretの内容はbase64エンコードされ、.dockercfg
ファイルで指定されている必要があります。
Secret名は最大253文字で構成されます。
イメージプルシークレットの作成に成功した場合は、デフォルトで選択されています。作成に失敗した場合は、シークレットは適用されません。
CPU requirement (cores)とMemory requirement (MiB): コンテナの最小リソース制限を指定することができます。デフォルトでは、PodはCPUとメモリの制限がない状態で実行されます。
Run commandとRun command arguments: デフォルトでは、コンテナは指定されたDockerイメージのデフォルトのentrypointコマンドを実行します。 コマンドのオプションと引数を使ってデフォルトを上書きすることができます。
Run as privileged: この設定は、特権コンテナ内のプロセスが、ホスト上でrootとして実行されているプロセスと同等であるかどうかを決定します。特権コンテナは、 ネットワークスタックの操作やデバイスへのアクセスなどの機能を利用できます。
Environment variables: Kubernetesは環境変数を介してServiceを公開しています。
環境変数を作成したり、環境変数の値を使ってコマンドに引数を渡したりすることができます。
環境変数の値はServiceを見つけるためにアプリケーションで利用できます。
値は$(VAR_NAME)
構文を使用して他の変数を参照できます。
Kubernetesは宣言的な設定をサポートしています。 このスタイルでは、すべての設定は Kubernetes APIリソーススキーマを使用してYAMLまたは JSON設定ファイルに格納されます。
デプロイウィザードでアプリケーションの詳細を指定する代わりに、 YAMLまたはJSONファイルでアプリケーションを定義し、ダッシュボードを使用してファイルをアップロードできます。
以下のセクションでは、Kubernetes Dashboard UIのビュー、それらが提供するものとその使用方法について説明します。
クラスターにKubernetesオブジェクトが定義されている場合、ダッシュボードではそれらのオブジェクトが初期表示されます。 デフォルトでは default 名前空間のオブジェクトのみが表示されますが、これはナビゲーションメニューにある名前空間セレクターで変更できます。
ダッシュボードにはほとんどのKubernetesオブジェクトの種類が表示され、いくつかのメニューカテゴリーにグループ化されています。
クラスターと名前空間の管理者向けに、ダッシュボードにはノード、名前空間、永続ボリュームが一覧表示され、それらの詳細ビューが用意されています。 ノードリストビューには、すべてのノードにわたって集計されたCPUとメモリーのメトリクスが表示されます。 詳細ビューには、ノードのメトリクス、仕様、ステータス、割り当てられたリソース、イベント、ノード上で実行されているPodが表示されます。
選択した名前空間で実行されているすべてのアプリケーションを表示します。 このビューでは、アプリケーションがワークロードの種類(例:Deployment、ReplicaSet、StatefulSetなど)ごとに一覧表示され、各ワークロードの種類を個別に表示することができます。 リストには、ReplicaSetの準備ができたPodの数やPodの現在のメモリ使用量など、ワークロードに関する実用的な情報がまとめられています。
ワークロードの詳細ビューには、ステータスや仕様情報、オブジェクト間の表面関係が表示されます。 たとえば、ReplicaSetが制御しているPodや、新しいReplicaSet、DeploymentのためのHorizontal Pod Autoscalerなどです。
外部の世界にサービスを公開し、クラスター内でサービスを発見できるようにするKubernetesリソースを表示します。 そのため、ServiceとIngressのビューには、それらが対象とするPod、クラスター接続の内部エンドポイント、外部ユーザーの外部エンドポイントが表示されます。
ストレージビューには、アプリケーションがデータを保存するために使用するPersistentVolumeClaimリソースが表示されます。
クラスターで実行されているアプリケーションのライブ設定に使用されているすべてのKubernetesリソースを表示します。 このビューでは、設定オブジェクトの編集と管理が可能で、デフォルトで非表示になっているSecretを表示します。
Podのリストと詳細ページは、ダッシュボードに組み込まれたログビューアーにリンクしています。 このビューアーでは、単一のPodに属するコンテナからログをドリルダウンすることができます。
詳細についてはKubernetes Dashboardプロジェクトページをご覧ください。
ここでは、設定ファイルを使って複数のクラスターにアクセスする方法を紹介します。クラスター、ユーザー、コンテキストの情報を一つ以上の設定ファイルにまとめることで、kubectl config use-context
のコマンドを使ってクラスターを素早く切り替えることができます。
kubeconfig
という名前のファイルが存在するわけではありません。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
kubectlがインストールされているか確認するため、kubectl version --client
を実行してください。kubectlのバージョンは、クラスターのAPIサーバーの1つのマイナーバージョン内である必要があります。
例として、開発用のクラスターが一つ、実験用のクラスターが一つ、計二つのクラスターが存在する場合を考えます。development
と呼ばれる開発用のクラスター内では、フロントエンドの開発者はfrontend
というnamespace内で、ストレージの開発者はstorage
というnamespace内で作業をします。scratch
と呼ばれる実験用のクラスター内では、開発者はデフォルトのnamespaceで作業をするか、状況に応じて追加のnamespaceを作成します。開発用のクラスターは証明書を通しての認証を必要とします。実験用のクラスターはユーザーネームとパスワードを通しての認証を必要とします。
config-exercise
というディレクトリを作成してください。config-exercise
ディレクトリ内に、以下を含むconfig-demo
というファイルを作成してください:
apiVersion: v1
kind: Config
preferences: {}
clusters:
- cluster:
name: development
- cluster:
name: scratch
users:
- name: developer
- name: experimenter
contexts:
- context:
name: dev-frontend
- context:
name: dev-storage
- context:
name: exp-scratch
設定ファイルには、クラスター、ユーザー、コンテキストの情報が含まれています。上記のconfig-demo
設定ファイルには、二つのクラスター、二人のユーザー、三つのコンテキストの情報が含まれています。
config-exercise
ディレクトリに移動してください。クラスター情報を設定ファイルに追加するために、以下のコマンドを実行してください:
kubectl config --kubeconfig=config-demo set-cluster development --server=https://1.2.3.4 --certificate-authority=fake-ca-file
kubectl config --kubeconfig=config-demo set-cluster scratch --server=https://5.6.7.8 --insecure-skip-tls-verify
ユーザー情報を設定ファイルに追加してください:
kubectl config --kubeconfig=config-demo set-credentials developer --client-certificate=fake-cert-file --client-key=fake-key-seefile
kubectl config --kubeconfig=config-demo set-credentials experimenter --username=exp --password=some-password
kubectl --kubeconfig=config-demo config unset users.<name>
を実行すると、ユーザーを削除することができます。
kubectl --kubeconfig=config-demo config unset clusters.<name>
を実行すると、クラスターを除去することができます。
kubectl --kubeconfig=config-demo config unset contexts.<name>
を実行すると、コンテキスト情報を除去することができます。
コンテキスト情報を設定ファイルに追加してください:
kubectl config --kubeconfig=config-demo set-context dev-frontend --cluster=development --namespace=frontend --user=developer
kubectl config --kubeconfig=config-demo set-context dev-storage --cluster=development --namespace=storage --user=developer
kubectl config --kubeconfig=config-demo set-context exp-scratch --cluster=scratch --namespace=default --user=experimenter
追加した情報を確認するために、config-demo
ファイルを開いてください。config-demo
ファイルを開く代わりに、config view
のコマンドを使うこともできます。
kubectl config --kubeconfig=config-demo view
出力には、二つのクラスター、二人のユーザー、三つのコンテキストが表示されます:
apiVersion: v1
clusters:
- cluster:
certificate-authority: fake-ca-file
server: https://1.2.3.4
name: development
- cluster:
insecure-skip-tls-verify: true
server: https://5.6.7.8
name: scratch
contexts:
- context:
cluster: development
namespace: frontend
user: developer
name: dev-frontend
- context:
cluster: development
namespace: storage
user: developer
name: dev-storage
- context:
cluster: scratch
namespace: default
user: experimenter
name: exp-scratch
current-context: ""
kind: Config
preferences: {}
users:
- name: developer
user:
client-certificate: fake-cert-file
client-key: fake-key-file
- name: experimenter
user:
password: some-password
username: exp
上記のfake-ca-file
、fake-cert-file
、fake-key-file
は、証明書ファイルの実際のパスのプレースホルダーです。環境内にある証明書ファイルの実際のパスに変更してください。
証明書ファイルのパスの代わりにbase64にエンコードされたデータを使用したい場合は、キーに-data
の接尾辞を加えてください。例えば、certificate-authority-data
、client-certificate-data
、client-key-data
とできます。
それぞれのコンテキストは、クラスター、ユーザー、namespaceの三つ組からなっています。例えば、dev-frontend
は、developer
ユーザーの認証情報を使ってdevelopment
クラスターのfrontend
namespaceへのアクセスを意味しています。
現在のコンテキストを設定してください:
kubectl config --kubeconfig=config-demo use-context dev-frontend
これ以降実行されるkubectl
コマンドは、dev-frontend
に設定されたクラスターとnamespaceに適用されます。また、dev-frontend
に設定されたユーザーの認証情報を使用します。
現在のコンテキストの設定情報のみを確認するには、--minify
フラグを使用してください。
kubectl config --kubeconfig=config-demo view --minify
出力には、dev-frontend
の設定情報が表示されます:
apiVersion: v1
clusters:
- cluster:
certificate-authority: fake-ca-file
server: https://1.2.3.4
name: development
contexts:
- context:
cluster: development
namespace: frontend
user: developer
name: dev-frontend
current-context: dev-frontend
kind: Config
preferences: {}
users:
- name: developer
user:
client-certificate: fake-cert-file
client-key: fake-key-file
今度は、実験用のクラスター内でしばらく作業する場合を考えます。
現在のコンテキストをexp-scratch
に切り替えてください:
kubectl config --kubeconfig=config-demo use-context exp-scratch
これ以降実行されるkubectl
コマンドは、scratch
クラスター内のデフォルトnamespaceに適用されます。また、exp-scratch
に設定されたユーザーの認証情報を使用します。
新しく切り替えたexp-scratch
の設定を確認してください。
kubectl config --kubeconfig=config-demo view --minify
最後に、development
クラスター内のstorage
namespaceでしばらく作業する場合を考えます。
現在のコンテキストをdev-storage
に切り替えてください:
kubectl config --kubeconfig=config-demo use-context dev-storage
新しく切り替えたdev-storage
の設定を確認してください。
kubectl config --kubeconfig=config-demo view --minify
config-exercise
ディレクトリ内に、以下を含むconfig-demo-2
というファイルを作成してください:
apiVersion: v1
kind: Config
preferences: {}
contexts:
- context:
cluster: development
namespace: ramp
user: developer
name: dev-ramp-up
上記の設定ファイルは、dev-ramp-up
というコンテキストを表します。
KUBECONFIG
という環境変数が存在するかを確認してください。もし存在する場合は、後で復元できるようにバックアップしてください。例えば:
export KUBECONFIG_SAVED=$KUBECONFIG
$Env:KUBECONFIG_SAVED=$ENV:KUBECONFIG
KUBECONFIG
環境変数は、設定ファイルのパスのリストです。リスト内のパスはLinuxとMacではコロンで区切られ、Windowsではセミコロンで区切られます。KUBECONFIG
環境変数が存在する場合は、リスト内の設定ファイルの内容を確認してください。
一時的にKUBECONFIG
環境変数に以下の二つのパスを追加してください。例えば:
export KUBECONFIG=$KUBECONFIG:config-demo:config-demo-2
$Env:KUBECONFIG=("config-demo;config-demo-2")
config-exercise
ディレクトリ内から、以下のコマンドを実行してください:
kubectl config view
出力には、KUBECONFIG
環境変数に含まれる全てのファイルの情報がまとめて表示されます。config-demo-2
ファイルに設定されたdev-ramp-up
の情報と、config-demo
に設定された三つのコンテキストの情報がまとめてあることに注目してください:
contexts:
- context:
cluster: development
namespace: frontend
user: developer
name: dev-frontend
- context:
cluster: development
namespace: ramp
user: developer
name: dev-ramp-up
- context:
cluster: development
namespace: storage
user: developer
name: dev-storage
- context:
cluster: scratch
namespace: default
user: experimenter
name: exp-scratch
kubeconfigファイルに関するさらなる情報を参照するには、kubeconfigファイルを使ってクラスターへのアクセスを管理するを参照してください。
既にクラスターを所持していて、kubectl
を使ってクラスターを操作できる場合は、$HOME/.kube
ディレクトリ内にconfig
というファイルが存在する可能性が高いです。
$HOME/.kube
に移動して、そこに存在するファイルを確認してください。config
という設定ファイルが存在するはずです。他の設定ファイルも存在する可能性があります。全てのファイルの中身を確認してください。
もし$HOME/.kube/config
ファイルが存在していて、既にKUBECONFIG
環境変数に追加されていない場合は、KUBECONFIG
環境変数に追加してください。例えば:
export KUBECONFIG=$KUBECONFIG:$HOME/.kube/config
$Env:KUBECONFIG="$Env:KUBECONFIG;$HOME/.kube/config"
KUBECONFIG
環境変数内のファイルからまとめられた設定情報を確認してください。config-exercise
ディレクトリ内から、以下のコマンドを実行してください:
kubectl config view
KUBECONFIG
環境変数を元に戻してください。例えば:
export KUBECONFIG=$KUBECONFIG_SAVED
$Env:KUBECONFIG=$ENV:KUBECONFIG_SAVED
ここでは、クラスター内で稼働しているアプリケーションに外部からアクセスするために、KubernetesのServiceオブジェクトを作成する方法を紹介します。 例として、2つのインスタンスから成るアプリケーションへのロードバランシングを扱います。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
アプリケーションDeploymentの設定ファイルは以下の通りです:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
selector:
matchLabels:
run: load-balancer-example
replicas: 2
template:
metadata:
labels:
run: load-balancer-example
spec:
containers:
- name: hello-world
image: gcr.io/google-samples/node-hello:1.0
ports:
- containerPort: 8080
protocol: TCP
クラスタでHello Worldアプリケーションを稼働させます: 上記のファイルを使用し、アプリケーションのDeploymentを作成します:
kubectl apply -f https://k8s.io/examples/service/access/hello-application.yaml
このコマンドはDeploymentオブジェクトとそれに紐付くReplicaSetオブジェクトを作成します。ReplicaSetは、Hello Worldアプリケーションが稼働している2つのPodから構成されます。
Deploymentの情報を表示します:
kubectl get deployments hello-world
kubectl describe deployments hello-world
ReplicaSetオブジェクトの情報を表示します:
kubectl get replicasets
kubectl describe replicasets
Deploymentを公開するServiceオブジェクトを作成します:
kubectl expose deployment hello-world --type=NodePort --name=example-service
Serviceに関する情報を表示します:
kubectl describe services example-service
出力例は以下の通りです:
Name: example-service
Namespace: default
Labels: run=load-balancer-example
Annotations: <none>
Selector: run=load-balancer-example
Type: NodePort
IP: 10.32.0.16
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 31496/TCP
Endpoints: 10.200.1.4:8080,10.200.2.5:8080
Session Affinity: None
Events: <none>
NodePortの値を記録しておきます。上記の例では、31496です。
Hello Worldアプリーションが稼働しているPodを表示します:
kubectl get pods --selector="run=load-balancer-example" --output=wide
出力例は以下の通りです:
NAME READY STATUS ... IP NODE
hello-world-2895499144-bsbk5 1/1 Running ... 10.200.1.4 worker1
hello-world-2895499144-m1pwt 1/1 Running ... 10.200.2.5 worker2
Hello World podが稼働するNodeのうち、いずれか1つのパブリックIPアドレスを確認します。
確認方法は、使用している環境により異なります。
例として、Minikubeの場合はkubectl cluster-info
、Google Compute Engineの場合はgcloud compute instances list
によって確認できます。
選択したノード上で、NodePortの値でのTCP通信を許可するファイヤーウォールを作成します。 NodePortの値が31568の場合、31568番のポートを利用したTCP通信を許可するファイヤーウォールを作成します。 クラウドプロバイダーによって設定方法が異なります。
Hello World applicationにアクセスするために、Nodeのアドレスとポート番号を使用します:
curl http://<public-node-ip>:<node-port>
ここで <public-node-ip>
はNodeのパブリックIPアドレス、
<node-port>
はNodePort Serviceのポート番号の値を表しています。
リクエストが成功すると、下記のメッセージが表示されます:
Hello Kubernetes!
kubectl expose
コマンドの代わりに、
service configuration file
を使用してServiceを作成することもできます。
Serviceを削除するには、以下のコマンドを実行します:
kubectl delete services example-service
Hello Worldアプリケーションが稼働しているDeployment、ReplicaSet、Podを削除するには、以下のコマンドを実行します:
kubectl delete deployment hello-world
詳細は serviceを利用してアプリケーションと接続する を確認してください。
このタスクでは、フロントエンドとバックエンドのマイクロサービスを作成する方法を示します。 バックエンドのマイクロサービスは挨拶です。 フロントエンドとバックエンドは、Kubernetes Serviceオブジェクトを使用して接続されます。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
このタスクではServiceで外部ロードバランサーを使用しますが、外部ロードバランサーの使用がサポートされている環境である必要があります。 ご使用の環境がこれをサポートしていない場合は、代わりにタイプNodePortのServiceを使用できます。
バックエンドは、単純な挨拶マイクロサービスです。 バックエンドのDeploymentの構成ファイルは次のとおりです:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
selector:
matchLabels:
app: hello
tier: backend
track: stable
replicas: 7
template:
metadata:
labels:
app: hello
tier: backend
track: stable
spec:
containers:
- name: hello
image: "gcr.io/google-samples/hello-go-gke:1.0"
ports:
- name: http
containerPort: 80
バックエンドのDeploymentを作成します:
kubectl apply -f https://k8s.io/examples/service/access/hello.yaml
バックエンドのDeploymentに関する情報を表示します:
kubectl describe deployment hello
出力はこのようになります:
Name: hello
Namespace: default
CreationTimestamp: Mon, 24 Oct 2016 14:21:02 -0700
Labels: app=hello
tier=backend
track=stable
Annotations: deployment.kubernetes.io/revision=1
Selector: app=hello,tier=backend,track=stable
Replicas: 7 desired | 7 updated | 7 total | 7 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: app=hello
tier=backend
track=stable
Containers:
hello:
Image: "gcr.io/google-samples/hello-go-gke:1.0"
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: hello-3621623197 (7/7 replicas created)
Events:
...
フロントエンドをバックエンドに接続する鍵は、バックエンドServiceです。 Serviceは、バックエンドマイクロサービスに常に到達できるように、永続的なIPアドレスとDNS名のエントリを作成します。 Serviceはセレクターを使用して、トラフィックをルーティングするPodを見つけます。
まず、Service構成ファイルを調べます:
kind: Service
apiVersion: v1
metadata:
name: hello
spec:
selector:
app: hello
tier: backend
ports:
- protocol: TCP
port: 80
targetPort: http
設定ファイルで、Serviceがapp:hello
およびtier:backend
というラベルを持つPodにトラフィックをルーティングしていることがわかります。
hello
Serviceを作成します:
kubectl apply -f https://k8s.io/examples/service/access/hello-service.yaml
この時点で、バックエンドのDeploymentが実行され、そちらにトラフィックをルーティングできるServiceがあります。
バックエンドができたので、バックエンドに接続するフロントエンドを作成できます。
フロントエンドは、バックエンドServiceに指定されたDNS名を使用して、バックエンドワーカーPodに接続します。
DNS名はhello
です。これは、前のサービス設定ファイルのname
フィールドの値です。
フロントエンドDeploymentのPodは、helloバックエンドServiceを見つけるように構成されたnginxイメージを実行します。 これはnginx設定ファイルです:
upstream hello {
server hello;
}
server {
listen 80;
location / {
proxy_pass http://hello;
}
}
バックエンドと同様に、フロントエンドにはDeploymentとServiceがあります。
Serviceの設定にはtype:LoadBalancer
があります。これは、Serviceがクラウドプロバイダーのデフォルトのロードバランサーを使用することを意味します。
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
selector:
app: hello
tier: frontend
ports:
- protocol: "TCP"
port: 80
targetPort: 80
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: hello
tier: frontend
track: stable
replicas: 1
template:
metadata:
labels:
app: hello
tier: frontend
track: stable
spec:
containers:
- name: nginx
image: "gcr.io/google-samples/hello-frontend:1.0"
lifecycle:
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
フロントエンドのDeploymentとServiceを作成します:
kubectl apply -f https://k8s.io/examples/service/access/frontend.yaml
出力結果から両方のリソースが作成されたことを確認します:
deployment.apps/frontend created
service/frontend created
LoadBalancerタイプのServiceを作成したら、このコマンドを使用して外部IPを見つけることができます:
kubectl get service frontend --watch
これによりfrontend
Serviceの設定が表示され、変更が監視されます。
最初、外部IPは<pending>
としてリストされます:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend LoadBalancer 10.51.252.116 <pending> 80/TCP 10s
ただし、外部IPがプロビジョニングされるとすぐに、EXTERNAL-IP
という見出しの下に新しいIPが含まれるように構成が更新されます:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frontend LoadBalancer 10.51.252.116 XXX.XXX.XXX.XXX 80/TCP 1m
このIPを使用して、クラスターの外部からfrontend
Serviceとやり取りできるようになりました。
フロントエンドとバックエンドが接続されました。 フロントエンドServiceの外部IPに対してcurlコマンドを使用して、エンドポイントにアクセスできます。
curl http://${EXTERNAL_IP} # これを前に見たEXTERNAL-IPに置き換えます
出力には、バックエンドによって生成されたメッセージが表示されます:
{"message":"Hello"}
Serviceを削除するには、このコマンドを入力してください:
kubectl delete services frontend hello
バックエンドとフロントエンドアプリケーションを実行しているDeploymentとReplicaSetとPodを削除するために、このコマンドを入力してください:
kubectl delete deployment frontend hello
Ingressとは、クラスター内のServiceに外部からのアクセスを許可するルールを定義するAPIオブジェクトです。IngressコントローラーはIngress内に設定されたルールを満たすように動作します。
このページでは、簡単なIngressをセットアップして、HTTPのURIに応じてwebまたはweb2というServiceにリクエストをルーティングする方法を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
Launch Terminalをクリックします。
(オプション) Minikubeをローカル環境にインストールした場合は、次のコマンドを実行します。
minikube start
NGINX Ingressコントローラーを有効にするために、次のコマンドを実行します。
minikube addons enable ingress
NGINX Ingressコントローラーが起動したことを確認します。
kubectl get pods -n kube-system
出力は次のようになります。
NAME READY STATUS RESTARTS AGE
default-http-backend-59868b7dd6-xb8tq 1/1 Running 0 1m
kube-addon-manager-minikube 1/1 Running 0 3m
kube-dns-6dcb57bcc8-n4xd4 3/3 Running 0 2m
kubernetes-dashboard-5498ccf677-b8p5h 1/1 Running 0 2m
nginx-ingress-controller-5984b97644-rnkrg 1/1 Running 0 1m
storage-provisioner 1/1 Running 0 2m
次のコマンドを実行して、Deploymentを作成します。
kubectl create deployment web --image=gcr.io/google-samples/hello-app:1.0
出力は次のようになります。
deployment.apps/web created
Deploymentを公開します。
kubectl expose deployment web --type=NodePort --port=8080
出力は次のようになります。
service/web exposed
Serviceが作成され、NodePort上で利用できるようになったことを確認します。
kubectl get service web
出力は次のようになります。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web NodePort 10.104.133.249 <none> 8080:31637/TCP 12m
NodePort経由でServiceを訪問します。
minikube service web --url
出力は次のようになります。
http://172.17.0.15:31637
31637
)を入力して、Display Port(ポートを表示)をクリックしてください。
出力は次のようになります。
Hello, world!
Version: 1.0.0
Hostname: web-55b8c6998d-8k564
これで、MinikubeのIPアドレスとNodePort経由で、サンプルアプリにアクセスできるようになりました。次のステップでは、Ingressリソースを使用してアプリにアクセスできるように設定します。
以下に示すファイルは、hello-world.info経由で送られたトラフィックをServiceに送信するIngressリソースです。
以下の内容でexample-ingress.yaml
を作成します。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: hello-world.info
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 8080
次のコマンドを実行して、Ingressリソースを作成します。
kubectl apply -f https://kubernetes.io/examples/service/networking/example-ingress.yaml
出力は次のようになります。
ingress.networking.k8s.io/example-ingress created
次のコマンドで、IPアドレスが設定されていることを確認します。
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
example-ingress <none> hello-world.info 172.17.0.15 80 38s
次の行を/etc/hosts
ファイルの最後に書きます。
minikube ip
コマンドを使用すると外部のIPが取得できます。Ingressのリスト内に表示されるIPアドレスは、内部のIPになるはずです。
172.17.0.15 hello-world.info
この設定により、リクエストがhello-world.infoからMinikubeに送信されるようになります。
Ingressコントローラーがトラフィックを制御していることを確認します。
curl hello-world.info
出力は次のようになります。
Hello, world!
Version: 1.0.0
Hostname: web-55b8c6998d-8k564
次のコマンドを実行して、v2のDeploymentを作成します。
kubectl create deployment web2 --image=gcr.io/google-samples/hello-app:2.0
出力は次のようになります。
deployment.apps/web2 created
Deploymentを公開します。
kubectl expose deployment web2 --port=8080 --type=NodePort
出力は次のようになります。
service/web2 exposed
既存のexample-ingress.yaml
を編集して、以下の行を追加します。
- path: /v2
pathType: Prefix
backend:
service:
name: web2
port:
number: 8080
次のコマンドで変更を適用します。
kubectl apply -f example-ingress.yaml
出力は次のようになります。
ingress.networking/example-ingress configured
Hello Worldアプリの1番目のバージョンにアクセスします。
curl hello-world.info
出力は次のようになります。
Hello, world!
Version: 1.0.0
Hostname: web-55b8c6998d-8k564
Hello Worldアプリの2番目のバージョンにアクセスします。
curl hello-world.info/v2
出力は次のようになります。
Hello, world!
Version: 2.0.0
Hostname: web2-75cd47646f-t8cjk
このページでは、kubectlを使用して、クラスターで実行されているPodのすべてのコンテナイメージを一覧表示する方法を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
この演習では、kubectlを使用してクラスターで実行されているすべてのPodを取得し、出力をフォーマットしてそれぞれのコンテナの一覧を取得します。
kubectl get pods --all-namespaces
を使用して、すべての名前空間のPodを取得します-o jsonpath={.. image}
を使用して、コンテナイメージ名のリストのみが含まれるように出力をフォーマットします。これは、返されたjsonのimage
フィールドを再帰的に解析します。
tr
、sort
、uniq
などの標準ツールを使用して出力をフォーマットします。
tr
を使用してスペースを改行に置換します。sort
を使用して結果を並べ替えます。uniq
を使用してイメージ数を集計します。kubectl get pods --all-namespaces -o jsonpath="{..image}" |\
tr -s '[[:space:]]' '\n' |\
sort |\
uniq -c
上記のコマンドは、返されるすべてのアイテムについて、image
という名前のすべてのフィールドを再帰的に返します。
別の方法として、Pod内のimageフィールドへの絶対パスを使用することができます。これにより、フィールド名が繰り返されている場合でも正しいフィールドが取得されます。多くのフィールドは与えられたアイテム内でname
と呼ばれます:
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}"
jsonpathは次のように解釈されます:
.items[*]
: 各戻り値.spec
: 仕様の取得.containers[*]
: 各コンテナ.image
: イメージの取得kubectl get pod nginx
のように名前を指定して単一のPodを取得する場合、アイテムのリストではなく単一のPodが返されるので、パスの.items[*]
部分は省略してください。
range
を使用して要素を個別に繰り返し処理することにより、フォーマットをさらに制御できます。
kubectl get pods --all-namespaces -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |\
sort
特定のラベルに一致するPodのみを対象とするには、-lフラグを使用します。以下は、app=nginx
に一致するラベルを持つPodのみに一致します。
kubectl get pods --all-namespaces -o=jsonpath="{..image}" -l app=nginx
特定の名前空間のPodのみを対象とするには、namespaceフラグを使用します。以下はkube-system
名前空間のPodのみに一致します。
kubectl get pods --namespace kube-system -o jsonpath="{..image}"
jsonpathの代わりに、kubectlはgo-templatesを使用した出力のフォーマットをサポートしています:
kubectl get pods --all-namespaces -o go-template --template="{{range .items}}{{range .spec.containers}}{{.image}} {{end}}{{end}}"
このページでは、ボリュームを使用して、同じPodで実行されている2つのコンテナ間で通信する方法を示します。 コンテナ間でプロセス名前空間を共有することにより、プロセスが通信できるようにする方法も参照してください。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
この演習では、2つのコンテナを実行するPodを作成します。 2つのコンテナは、通信に使用できるボリュームを共有します。 これがPodの設定ファイルです:
apiVersion: v1
kind: Pod
metadata:
name: two-containers
spec:
restartPolicy: Never
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: nginx-container
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: debian-container
image: debian
volumeMounts:
- name: shared-data
mountPath: /pod-data
command: ["/bin/sh"]
args: ["-c", "echo Hello from the debian container > /pod-data/index.html"]
設定ファイルで、Podにshared-data
という名前のボリュームがあることがわかります。
設定ファイルにリストされている最初のコンテナは、nginxサーバーを実行します。
共有ボリュームのマウントパスは/usr/share/nginx/html
です。
2番目のコンテナはdebianイメージをベースとしており、/pod-data
のマウントパスを持っています。
2番目のコンテナは次のコマンドを実行してから終了します。
echo Hello from the debian container > /pod-data/index.html
2番目のコンテナがnginxサーバーのルートディレクトリにindex.html
ファイルを書き込むことに注意してください。
Podと2つのコンテナを作成します:
kubectl apply -f https://k8s.io/examples/pods/two-container-pod.yaml
Podとコンテナに関する情報を表示します:
kubectl get pod two-containers --output=yaml
こちらは出力の一部です:
apiVersion: v1
kind: Pod
metadata:
...
name: two-containers
namespace: default
...
spec:
...
containerStatuses:
- containerID: docker://c1d8abd1 ...
image: debian
...
lastState:
terminated:
...
name: debian-container
...
- containerID: docker://96c1ff2c5bb ...
image: nginx
...
name: nginx-container
...
state:
running:
...
debianコンテナが終了し、nginxコンテナがまだ実行されていることがわかります。
nginxコンテナへのシェルを取得します:
kubectl exec -it two-containers -c nginx-container -- /bin/bash
シェルで、nginxが実行されていることを確認します:
root@two-containers:/# apt-get update
root@two-containers:/# apt-get install curl procps
root@two-containers:/# ps aux
出力はこのようになります:
USER PID ... STAT START TIME COMMAND
root 1 ... Ss 21:12 0:00 nginx: master process nginx -g daemon off;
debianコンテナがnginxルートディレクトリにindex.html
ファイルを作成したことを思い出してください。
curl
を使用して、GETリクエストをnginxサーバーに送信します:
root@two-containers:/# curl localhost
出力は、nginxがdebianコンテナによって書かれたWebページを提供することを示しています:
Hello from the debian container
Podが複数のコンテナを持つことができる主な理由は、プライマリアプリケーションを支援するヘルパーアプリケーションをサポートするためです。 ヘルパーアプリケーションの典型的な例は、データプラー、データプッシャー、およびプロキシです。 多くの場合、ヘルパーアプリケーションとプライマリアプリケーションは互いに通信する必要があります。 通常、これは、この演習に示すように共有ファイルシステムを介して、またはループバックネットワークインターフェイスであるlocalhostを介して行われます。 このパターンの例は、新しい更新のためにGitリポジトリをポーリングするヘルパープログラムを伴うWebサーバーです。
この演習のボリュームは、コンテナがポッドの寿命中に通信する方法を提供します。 Podを削除して再作成すると、共有ボリュームに保存されているデータはすべて失われます。
複合コンテナのパターンの詳細
モジュラーアーキテクチャ用の複合コンテナについて学ぶ
Volumeを参照
Podを参照
このページでは、Initコンテナの実行に関連する問題を調査する方法を説明します。以下のコマンドラインの例では、Podを<pod-name>
、Initコンテナを<init-container-1>
および<init-container-2>
として参照しています。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
Podのステータスを表示します:
kubectl get pod <pod-name>
たとえば、Init:1/2
というステータスは、2つのInitコンテナのうちの1つが正常に完了したことを示します。
NAME READY STATUS RESTARTS AGE
<pod-name> 0/1 Init:1/2 0 7s
ステータス値とその意味の例については、Podのステータスを理解するを参照してください。
Initコンテナの実行に関する詳細情報を表示します:
kubectl describe pod <pod-name>
たとえば、2つのInitコンテナを持つPodでは、次のように表示されます:
Init Containers:
<init-container-1>:
Container ID: ...
...
State: Terminated
Reason: Completed
Exit Code: 0
Started: ...
Finished: ...
Ready: True
Restart Count: 0
...
<init-container-2>:
Container ID: ...
...
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 1
Started: ...
Finished: ...
Ready: False
Restart Count: 3
...
また、Pod Specのstatus.initContainerStatuses
フィールドを読むことでプログラムでInitコンテナのステータスにアクセスすることもできます。:
kubectl get pod nginx --template '{{.status.initContainerStatuses}}'
このコマンドは生のJSONで上記と同じ情報を返します。
ログにアクセスするには、Initコンテナ名とPod名を渡します。
kubectl logs <pod-name> -c <init-container-2>
シェルスクリプトを実行するInitコンテナは、実行時にコマンドを出力します。たとえば、スクリプトの始めにset -x
を実行することでBashで同じことができます。
Init:
で始まるPodステータスはInitコンテナの実行ステータスを要約します。以下の表は、Initコンテナのデバッグ中に表示される可能性のあるステータス値の例をいくつか示しています。
ステータス | 意味 |
---|---|
Init:N/M |
PodはM 個のInitコンテナを持ち、これまでにN 個完了しました。 |
Init:Error |
Initコンテナが実行に失敗しました。 |
Init:CrashLoopBackOff |
Initコンテナが繰り返し失敗しました。 |
Pending |
PodはまだInitコンテナの実行を開始していません。 |
PodInitializing or Running |
PodはすでにInitコンテナの実行を終了しています。 |
このページでは、PodとReplicationControllerをデバッグする方法を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
Podのデバッグの最初のステップは、Podを調べることです。 次のコマンドで、Podの現在の状態と最近のイベントを確認して下さい。
kubectl describe pods ${POD_NAME}
Pod内のコンテナの状態を確認します。
コンテナはすべてRunning
状態ですか?最近再起動はしましたか?
Podの状態に応じてデバッグを続けます。
PodがPending
状態でスタックしている場合、ノードにスケジュールできていないことを意味します。
一般的に、これは、何らかのタイプのリソースが不足しており、それによってスケジューリングを妨げられているためです。
上述のkubectl describe...
コマンドの出力を確認してください。
Podをスケジュールできない理由に関するスケジューラーからのメッセージがあるはずです。
理由としては以下のようなものがあります。
クラスター内のCPUまたはメモリーの供給を使い果たした可能性があります。 この場合、いくつかのことを試すことができます。
クラスターにノードを追加します。
不要なPodを終了して、
Pending
状態のPodのための空きリソースを作ります。
Podがノードよりも大きくないことを確認します。
例えば、すべてのノードのキャパシティーがcpu: 1
の場合、cpu: 1.1
を要求するPodは決してスケジュールされません。
kubectl get nodes -o <format>
コマンドでノードのキャパシティーを確認できます。
必要な情報を抽出するコマンドラインの例を以下に示します。
kubectl get nodes -o yaml | egrep '\sname:|cpu:|memory:'
kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, cap: .status.capacity}'
リソースクォータ機能では、 消費できるリソースの合計量を制限するように構成できます。 Namespaceと組み合わせて使用すると、1つのチームがすべてのリソースを占有することを防ぐことができます。
PodをhostPort
にバインドすると、Podをスケジュールできる場所の数が制限されます。
ほとんどの場合、hostPort
は不要です。Serviceオブジェクトを使用してPodを公開してください。
どうしてもhostPort
が必要な場合は、コンテナクラスター内のノードと同じ数のPodのみをスケジュールできます。
PodがWaiting
状態でスタックしている場合、Podはワーカーノードにスケジュールされていますが、そのマシンでは実行できない状態です。
この場合も、kubectl describe ...
の情報が参考になるはずです。
PodがWaiting
状態となる最も一般的な原因は、イメージをプルできないことです。
確認すべき事項が3つあります。
docker pull <image>
を実行し、イメージをプルできるかどうかを確認して下さい。Podがスケジュールされると、動作中のPodをデバッグするに説明されている方法がデバッグに使用可能です。
ReplicationControllerはかなり明快です。Podを作成できるか、できないかのどちらかです。 Podを作成できない場合は、上述の手順を参照してPodをデバッグしてください。
kubectl describe rc ${CONTROLLER_NAME}
を使用して、レプリケーションコントローラーに関連するイベントを調べることもできます。
このページでは、コンテナ終了メッセージの読み書き方法を説明します。
終了メッセージは、致命的なイベントに関する情報を、ダッシュボードや監視ソフトウェアなどのツールで簡単に取得して表示できる場所にコンテナが書き込むための手段を提供します。 ほとんどの場合、終了メッセージに入力した情報も一般的なKubernetesログに書き込まれるはずです。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
この課題では、1つのコンテナを実行するPodを作成します。 設定ファイルには、コンテナの開始時に実行されるコマンドを指定します。
apiVersion: v1
kind: Pod
metadata:
name: termination-demo
spec:
containers:
- name: termination-demo-container
image: debian
command: ["/bin/sh"]
args: ["-c", "sleep 10 && echo Sleep expired > /dev/termination-log"]
YAML設定ファイルに基づいてPodを作成します:
kubectl apply -f https://k8s.io/examples/debug/termination.yaml
YAMLファイルのcommand
フィールドとargs
フィールドで、コンテナが10秒間スリープしてから/dev/termination-log
ファイルに「Sleep expired」と書いているのがわかります。コンテナが「Sleep expired」メッセージを書き込んだ後、コンテナは終了します。
Podに関する情報を表示します:
kubectl get pod termination-demo
Podが実行されなくなるまで、上記のコマンドを繰り返します。
Podに関する詳細情報を表示します:
kubectl get pod termination-demo --output=yaml
出力には「Sleep expired」メッセージが含まれています:
apiVersion: v1
kind: Pod
...
lastState:
terminated:
containerID: ...
exitCode: 0
finishedAt: ...
message: |
Sleep expired
...
Goテンプレートを使用して、終了メッセージのみが含まれるように出力をフィルタリングします:
kubectl get pod termination-demo -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}"
Kubernetesは、コンテナのterminationMessagePath
フィールドで指定されている終了メッセージファイルから終了メッセージを取得します。デフォルト値は/dev/termination-log
です。このフィールドをカスタマイズすることで、Kubernetesに別のファイルを使うように指示できます。Kubernetesは指定されたファイルの内容を使用して、成功と失敗の両方についてコンテナのステータスメッセージを入力します。
終了メッセージはアサーションエラーメッセージのように、最終状態を簡潔に示します。kubeletは4096バイトより長いメッセージは切り詰めます。全コンテナの合計メッセージの長さの上限は12キビバイトです。デフォルトの終了メッセージのパスは/dev/termination-log
です。Pod起動後に終了メッセージのパスを設定することはできません。
次の例では、コンテナはKubernetesが取得するために終了メッセージを/tmp/my-log
に書き込みます:
apiVersion: v1
kind: Pod
metadata:
name: msg-path-demo
spec:
containers:
- name: msg-path-demo-container
image: debian
terminationMessagePath: "/tmp/my-log"
さらに、ユーザーは追加のカスタマイズをするためにContainerのterminationMessagePolicy
フィールドを設定できます。このフィールドのデフォルト値はFile
です。これは、終了メッセージが終了メッセージファイルからのみ取得されることを意味します。terminationMessagePolicy
をFallbackToLogsOnError
に設定することで、終了メッセージファイルが空でコンテナがエラーで終了した場合に、コンテナログ出力の最後のチャンクを使用するようにKubernetesに指示できます。ログ出力は、2048バイトまたは80行のどちらか小さい方に制限されています。
新規にKubernetesをインストールした環境でかなり頻繁に発生する問題は、Serviceが適切に機能しないというものです。Deployment(または他のワークロードコントローラー)を通じてPodを実行し、サービスを作成したにもかかわらず、アクセスしようとしても応答がありません。何が問題になっているのかを理解するのに、このドキュメントがきっと役立つでしょう。
ここでの多くのステップでは、クラスターで実行されているPodが見ているものを確認する必要があります。これを行う最も簡単な方法は、インタラクティブなalpineのPodを実行することです。
kubectl run -it --rm --restart=Never alpine --image=alpine sh
使用したい実行中のPodがすでにある場合は、以下のようにしてそのPod内でコマンドを実行できます。
kubectl exec <POD-NAME> -c <CONTAINER-NAME> -- <COMMAND>
このドキュメントのウォークスルーのために、いくつかのPodを実行しましょう。おそらくあなた自身のServiceをデバッグしているため、あなた自身の詳細に置き換えることもできますし、これに沿って2番目のデータポイントを取得することもできます。
kubectl create deployment hostnames --image=k8s.gcr.io/serve_hostname
deployment.apps/hostnames created
kubectl
コマンドは作成、変更されたリソースのタイプと名前を出力するため、この後のコマンドで使用することもできます。
Deploymentを3つのレプリカにスケールさせてみましょう。
kubectl scale deployment hostnames --replicas=3
deployment.apps/hostnames scaled
これは、次のYAMLでDeploymentを開始した場合と同じです。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hostnames
labels:
app: hostnames
spec:
selector:
matchLabels:
app: hostnames
replicas: 3
template:
metadata:
labels:
app: hostnames
spec:
containers:
- name: hostnames
image: k8s.gcr.io/serve_hostname
"app"ラベルはkubectl create deployment
によって、Deploymentの名前に自動的にセットされます。
Podが実行されていることを確認できます。
kubectl get pods -l app=hostnames
NAME READY STATUS RESTARTS AGE
hostnames-632524106-bbpiw 1/1 Running 0 2m
hostnames-632524106-ly40y 1/1 Running 0 2m
hostnames-632524106-tlaok 1/1 Running 0 2m
Podが機能していることも確認できます。Pod IP アドレスリストを取得し、直接テストできます。
kubectl get pods -l app=hostnames \
-o go-template='{{range .items}}{{.status.podIP}}{{"\n"}}{{end}}'
10.244.0.5
10.244.0.6
10.244.0.7
このウォークスルーに使用されるサンプルコンテナは、ポート9376でHTTPを介して独自のホスト名を提供するだけですが、独自のアプリをデバッグする場合は、Podがリッスンしているポート番号を使用する必要があります。
Pod内から実行します。
for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
wget -qO- $ep
done
次のように表示されます。
hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok
この時点で期待通りの応答が得られない場合、Podが正常でないか、想定しているポートでリッスンしていない可能性があります。なにが起きているかを確認するためにkubectl logs
が役立ちます。Podに直接に入りデバッグする場合はkubectl exec
が必要になります。
これまでにすべての計画が完了していると想定すると、Serviceが機能しない理由を調査することができます。
賢明な読者は、Serviceをまだ実際に作成していないことにお気付きかと思いますが、これは意図的です。これは時々忘れられるステップであり、最初に確認すべきことです。
存在しないServiceにアクセスしようとするとどうなるでしょうか?このServiceを名前で利用する別のPodがあると仮定すると、次のような結果が得られます。
wget -O- hostnames
Resolving hostnames (hostnames)... failed: Name or service not known.
wget: unable to resolve host address 'hostnames'
最初に確認するのは、そのServiceが実際に存在するかどうかです。
kubectl get svc hostnames
No resources found.
Error from server (NotFound): services "hostnames" not found
Serviceを作成しましょう。前と同様に、これはウォークスルー用です。ご自身のServiceの詳細を使用することもできます。
kubectl expose deployment hostnames --port=80 --target-port=9376
service/hostnames exposed
そして、念のため内容を確認します。
kubectl get svc hostnames
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostnames ClusterIP 10.0.1.175 <none> 80/TCP 5s
これで、Serviceが存在することがわかりました。
前と同様に、これは次のようなYAMLでServiceを開始した場合と同じです。
apiVersion: v1
kind: Service
metadata:
name: hostnames
spec:
selector:
app: hostnames
ports:
- name: default
protocol: TCP
port: 80
targetPort: 9376
構成の全範囲をハイライトするため、ここで作成したServiceはPodとは異なるポート番号を使用します。多くの実際のServiceでは、これらのポートは同じになる場合があります。
クライアントがサービスを使用する最も一般的な方法の1つは、DNS名を使用することです。同じNamespaceのPodから次のコマンドを実行してください。
nslookup hostnames
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
これが失敗した場合、おそらくPodとServiceが異なるNamespaceにあるため、ネームスペースで修飾された名前を試してください。(Podの中からもう一度)
nslookup hostnames.default
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
これが機能する場合、クロスネームスペース名を使用するようにアプリケーションを調整するか、同じNamespaceでアプリとServiceを実行する必要があります。これでも失敗する場合は、完全修飾名を試してください。
nslookup hostnames.default.svc.cluster.local
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default.svc.cluster.local
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
ここでのサフィックス"default.svc.cluster.local"に注意してください。"default"は、操作しているNamespaceです。"svc"は、これがServiceであることを示します。"cluster.local"はクラスタードメインであり、あなたのクラスターでは異なる場合があります。
クラスター内のノードからも試すこともできます。
nslookup hostnames.default.svc.cluster.local 10.0.0.10
Server: 10.0.0.10
Address: 10.0.0.10#53
Name: hostnames.default.svc.cluster.local
Address: 10.0.1.175
完全修飾名では検索できるのに、相対名ではできない場合、Podの/etc/resolv.conf
ファイルが正しいことを確認する必要があります。Pod内から実行します。
cat /etc/resolv.conf
次のように表示されます。
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local example.com
options ndots:5
nameserver行はクラスターのDNS Serviceを示さなければなりません。これは、--cluster-dns
フラグでkubelet
に渡されます。
search
行には、Service
名を見つけるための適切なサフィックスを含める必要があります。この場合、ローカルのNamespace
でService
を見つけるためのサフィックス(default.svc.cluster.local
)、すべてのNamespaces
でService
を見つけるためのサフィックス(svc.cluster.local
)、およびクラスターのサフィックス(cluster.local
)です。インストール方法によっては、その後に追加のレコードがある場合があります(合計6つまで)。クラスターのサフィックスは、--cluster-domain
フラグを使用してkubelet
に渡されます。このドキュメントではそれが"cluster.local"であると仮定していますが、あなたのクラスターでは異なる場合があります。その場合は、上記のすべてのコマンドでクラスターのサフィックスを変更する必要があります。
options
行では、DNSクライアントライブラリーが検索パスをまったく考慮しないようにndots
を十分に高く設定する必要があります。Kubernetesはデフォルトでこれを5に設定します。これは、生成されるすべてのDNS名をカバーするのに十分な大きさです。
上記がまだ失敗する場合、DNSルックアップがServiceに対して機能していません。一歩離れて、他の何が機能していないかを確認しましょう。KubernetesマスターのServiceは常に機能するはずです。Pod内から実行します。
nslookup kubernetes.default
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes.default
Address 1: 10.0.0.1 kubernetes.default.svc.cluster.local
これが失敗する場合は、このドキュメントのkube-proxyセクションを参照するか、このドキュメントの先頭に戻って最初からやり直してください。ただし、あなた自身のServiceをデバッグするのではなく、DNSサービスをデバッグします。
DNSサービスが正しく動作できると仮定すると、次にテストするのはIPによってServiceが動作しているかどうかです。上述のkubectl get
で確認できるIPに、クラスター内のPodからアクセスします。
for i in $(seq 1 3); do
wget -qO- 10.0.1.175:80
done
次のように表示されます。
hostnames-0uton
hostnames-bvc05
hostnames-yp2kp
Serviceが機能している場合は、正しい応答が得られるはずです。そうでない場合、おかしい可能性のあるものがいくつかあるため、続けましょう。
馬鹿げているように聞こえるかもしれませんが、Serviceが正しく定義されPodのポートとマッチすることを二度、三度と確認すべきです。Serviceを読み返して確認しましょう。
kubectl get service hostnames -o json
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "hostnames",
"namespace": "default",
"uid": "428c8b6c-24bc-11e5-936d-42010af0a9bc",
"resourceVersion": "347189",
"creationTimestamp": "2015-07-07T15:24:29Z",
"labels": {
"app": "hostnames"
}
},
"spec": {
"ports": [
{
"name": "default",
"protocol": "TCP",
"port": 80,
"targetPort": 9376,
"nodePort": 0
}
],
"selector": {
"app": "hostnames"
},
"clusterIP": "10.0.1.175",
"type": "ClusterIP",
"sessionAffinity": "None"
},
"status": {
"loadBalancer": {}
}
}
spec.ports[]
のリストのなかに定義されていますか?targetPort
はPodに対して適切ですか(いくつかのPodはServiceとは異なるポートを使用します)?targetPort
を数値で定義しようとしている場合、それは数値(9376)、文字列"9376"のどちらですか?targetPort
を名前で定義しようとしている場合、Podは同じ名前でポートを公開していますか?protocol
はPodに適切ですか?ここまで来たということは、Serviceは正しく定義され、DNSによって名前解決できることが確認できているでしょう。ここでは、実行したPodがServiceによって実際に選択されていることを確認しましょう。
以前に、Podが実行されていることを確認しました。再確認しましょう。
kubectl get pods -l app=hostnames
NAME READY STATUS RESTARTS AGE
hostnames-632524106-bbpiw 1/1 Running 0 1h
hostnames-632524106-ly40y 1/1 Running 0 1h
hostnames-632524106-tlaok 1/1 Running 0 1h
-l app=hostnames
引数はラベルセレクターで、ちょうど私たちのService
に定義されているものと同じです。
"AGE"列は、これらのPodが約1時間前のものであることを示しており、それらが正常に実行され、クラッシュしていないことを意味します。
"RESTARTS"列は、これらのポッドが頻繁にクラッシュしたり、再起動されていないことを示しています。頻繁に再起動すると、断続的な接続性の問題が発生する可能性があります。再起動回数が多い場合は、ポッドをデバッグするを参照してください。
Kubernetesシステム内には、すべてのServiceのセレクターを評価し、結果をEndpointsオブジェクトに保存するコントロールループがあります。
kubectl get endpoints hostnames
NAME ENDPOINTS
hostnames 10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376
これにより、EndpointsコントローラーがServiceの正しいPodを見つけていることを確認できます。ENDPOINTS
列が<none>
の場合、Serviceのspec.selector
フィールドが実際にPodのmetadata.labels
値を選択していることを確認する必要があります。よくある間違いは、タイプミスやその他のエラー、たとえばDeployment作成にもkubectl run
が使われた1.18以前のバージョンのように、Serviceがapp=hostnames
を選択しているのにDeploymentがrun=hostnames
を指定していることです。
この時点で、Serviceが存在し、Podを選択していることがわかります。このウォークスルーの最初に、Pod自体を確認しました。Podが実際に機能していることを確認しましょう。Serviceメカニズムをバイパスして、上記EndpointsにリストされているPodに直接アクセスすることができます。
Pod内から実行します。
for ep in 10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376; do
wget -qO- $ep
done
次のように表示されます。
hostnames-632524106-bbpiw
hostnames-632524106-ly40y
hostnames-632524106-tlaok
Endpointsリスト内の各Podは、それぞれの自身のホスト名を返すはずです。そうならない(または、あなた自身のPodの正しい振る舞いにならない)場合は、そこで何が起こっているのかを調査する必要があります。
ここに到達したのなら、Serviceは実行され、Endpointsがあり、Podが実際にサービスを提供しています。この時点で、Serviceのプロキシーメカニズム全体が疑わしいです。ひとつひとつ確認しましょう。
Serviceのデフォルト実装、およびほとんどのクラスターで使用されるものは、kube-proxyです。kube-proxyはそれぞれのノードで実行され、Serviceの抽象化を提供するための小さなメカニズムセットの1つを構成するプログラムです。クラスターがkube-proxyを使用しない場合、以下のセクションは適用されず、使用しているServiceの実装を調査する必要があります。
kube-proxy
がノード上で実行されていることを確認しましょう。ノードで実行されていれば、以下のような結果が得られるはずです。
ps auxw | grep kube-proxy
root 4194 0.4 0.1 101864 17696 ? Sl Jul04 25:43 /usr/local/bin/kube-proxy --master=https://kubernetes-master --kubeconfig=/var/lib/kube-proxy/kubeconfig --v=2
次に、マスターとの接続など、明らかな失敗をしていないことを確認します。これを行うには、ログを確認する必要があります。ログへのアクセス方法は、ノードのOSに依存します。一部のOSでは/var/log/kube-proxy.logのようなファイルですが、他のOSではjournalctl
を使用してログにアクセスします。次のように表示されます。
I1027 22:14:53.995134 5063 server.go:200] Running in resource-only container "/kube-proxy"
I1027 22:14:53.998163 5063 server.go:247] Using iptables Proxier.
I1027 22:14:53.999055 5063 server.go:255] Tearing down userspace rules. Errors here are acceptable.
I1027 22:14:54.038140 5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns-tcp" to [10.244.1.3:53]
I1027 22:14:54.038164 5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns" to [10.244.1.3:53]
I1027 22:14:54.038209 5063 proxier.go:352] Setting endpoints for "default/kubernetes:https" to [10.240.0.2:443]
I1027 22:14:54.038238 5063 proxier.go:429] Not syncing iptables until Services and Endpoints have been received from master
I1027 22:14:54.040048 5063 proxier.go:294] Adding new service "default/kubernetes:https" at 10.0.0.1:443/TCP
I1027 22:14:54.040154 5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns" at 10.0.0.10:53/UDP
I1027 22:14:54.040223 5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns-tcp" at 10.0.0.10:53/TCP
マスターに接続できないことに関するエラーメッセージが表示された場合、ノードの設定とインストール手順をダブルチェックする必要があります。
kube-proxy
が正しく実行できない理由の可能性の1つは、必須のconntrack
バイナリが見つからないことです。これは、例えばKubernetesをスクラッチからインストールするなど、クラスターのインストール方法に依存して、一部のLinuxシステムで発生する場合があります。これが該当する場合は、conntrack
パッケージを手動でインストール(例: Ubuntuではsudo apt install conntrack
)する必要があり、その後に再試行する必要があります。
kube-proxyは、いくつかのモードのいずれかで実行できます。上記のログのUsing iptables Proxier
という行は、kube-proxyが「iptables」モードで実行されていることを示しています。最も一般的な他のモードは「ipvs」です。古い「ユーザースペース」モードは、主にこれらに置き換えられました。
「iptables」モードでは、ノードに次のようなものが表示されます。
iptables-save | grep hostnames
-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376
-A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376
-A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR
各サービスのポートごとに、KUBE-SERVICES
に1つのルールと1つのKUBE-SVC- <hash>
チェーンが必要です。Podエンドポイントごとに、そのKUBE-SVC- <hash>
に少数のルールがあり、少数のルールが含まれる1つのKUBE-SEP- <hash>
チェーンがあるはずです。正確なルールは、正確な構成(NodePortとLoadBalancerを含む)に基づいて異なります。
「ipvs」モードでは、ノードに次のようなものが表示されます。
ipvsadm -ln
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
...
TCP 10.0.1.175:80 rr
-> 10.244.0.5:9376 Masq 1 0 0
-> 10.244.0.6:9376 Masq 1 0 0
-> 10.244.0.7:9376 Masq 1 0 0
...
各Serviceの各ポートに加えて、NodePort、External IP、およびLoad Balancer IPに対して、kube-proxyは仮想サーバーを作成します。Pod endpointごとに、対応する実サーバーが作成されます。この例では、サービスhostnames(10.0.1.175:80
)は3つのendpoints(10.244.0.5:9376
、10.244.0.6:9376
、10.244.0.7:9376
)を持っています。
IPVSプロキシーは、各Serviceアドレス(Cluster IP、External IP、NodePort IP、Load Balancer IPなど)毎の仮想サーバーと、Serviceのエンドポイントが存在する場合に対応する実サーバーを作成します。この例では、hostnames Service(10.0.1.175:80
)は3つのエンドポイント(10.244.0.5:9376
、10.244.0.6:9376
、10.244.0.7:9376
)を持ち、上と似た結果が得られるはずです。
まれに、「userspace」モードを使用している場合があります。
ノードから実行します。
iptables-save | grep hostnames
-A KUBE-PORTALS-CONTAINER -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j REDIRECT --to-ports 48577
-A KUBE-PORTALS-HOST -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j DNAT --to-destination 10.240.115.247:48577
サービスの各ポートには2つのルールが必要です(この例では1つだけ)-「KUBE-PORTALS-CONTAINER」と「KUBE-PORTALS-HOST」です。
「userspace」モードを使用する必要はほとんどないので、ここでこれ以上時間を費やすことはありません。
上記のいずれかが発生したと想定して、いずれかのノードからIPでサービスにアクセスをしています。
curl 10.0.1.175:80
hostnames-632524106-bbpiw
もしこれが失敗し、あなたがuserspaceプロキシーを使用している場合、プロキシーへの直接アクセスを試してみてください。もしiptablesプロキシーを使用している場合、このセクションはスキップしてください。
上記のiptables-save
の出力を振り返り、kube-proxy
がServiceに使用しているポート番号を抽出します。上記の例では"48577"です。このポートに接続してください。
curl localhost:48577
hostnames-632524106-tlaok
もしまだ失敗する場合は、kube-proxy
ログで次のような特定の行を探してください。
Setting endpoints for default/hostnames:default to [10.244.0.5:9376 10.244.0.6:9376 10.244.0.7:9376]
これらが表示されない場合は、-v
フラグを4に設定してkube-proxy
を再起動してから、再度ログを確認してください。
これはありそうに聞こえないかもしれませんが、実際には起こり、動作するはずです。これはネットワークが"hairpin"トラフィック用に適切に設定されていない場合、通常はkube-proxy
がiptables
モードで実行され、Podがブリッジネットワークに接続されている場合に発生します。Kubelet
はhairpin-mode
フラグを公開します。これにより、Serviceのエンドポイントが自身のServiceのVIPにアクセスしようとした場合に、自身への負荷分散を可能にします。hairpin-mode
フラグはhairpin-veth
またはpromiscuous-bridge
に設定する必要があります。
この問題をトラブルシューティングする一般的な手順は次のとおりです。
hairpin-mode
がhairpin-veth
またはpromiscuous-bridge
に設定されていることを確認します。次のような表示がされるはずです。この例では、hairpin-mode
はpromiscuous-bridge
に設定されています。ps auxw | grep kubelet
root 3392 1.1 0.8 186804 65208 ? Sl 00:51 11:11 /usr/local/bin/kubelet --enable-debugging-handlers=true --config=/etc/kubernetes/manifests --allow-privileged=True --v=4 --cluster-dns=10.0.0.10 --cluster-domain=cluster.local --configure-cbr0=true --cgroup-root=/ --system-cgroups=/system --hairpin-mode=promiscuous-bridge --runtime-cgroups=/docker-daemon --kubelet-cgroups=/kubelet --babysit-daemons=true --max-pods=110 --serialize-image-pulls=false --outofdisk-transition-frequency=0
hairpin-mode
を確認します。これを行うには、kubeletログを確認する必要があります。ログへのアクセス方法は、ノードのOSによって異なります。一部のOSでは/var/log/kubelet.logなどのファイルですが、他のOSではjournalctl
を使用してログにアクセスします。互換性のために、実際に使われているhairpin-mode
が--hairpin-mode
フラグと一致しない場合があることに注意してください。kubelet.logにキーワードhairpin
を含むログ行があるかどうかを確認してください。実際に使われているhairpin-mode
を示す以下のようなログ行があるはずです。I0629 00:51:43.648698 3252 kubelet.go:380] Hairpin mode set to "promiscuous-bridge"
hairpin-mode
がhairpin-veth
の場合、Kubelet
にノードの/sys
で操作する権限があることを確認します。すべてが正常に機能している場合、次のようなものが表示されます。for intf in /sys/devices/virtual/net/cbr0/brif/*; do cat $intf/hairpin_mode; done
1
1
1
1
実際に使われているhairpin-mode
がpromiscuous-bridge
の場合、Kubelet
にノード上のLinuxブリッジを操作する権限があることを確認してください。cbr0
ブリッジが使用され適切に構成されている場合、以下が表示されます。
ifconfig cbr0 |grep PROMISC
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1460 Metric:1
ここまでたどり着いたということは、とてもおかしなことが起こっています。Serviceは実行中で、Endpointsがあり、Podは実際にサービスを提供しています。DNSは動作していて、kube-proxy
も誤動作していないようです。それでも、あなたのServiceは機能していません。おそらく私たちにお知らせ頂いた方がよいでしょう。調査をお手伝いします!
Slack、ForumまたはGitHubでお問い合わせください。
詳細については、トラブルシューティングドキュメントをご覧ください。
このタスクでは、StatefulSetをデバッグする方法を説明します。
StatefulSetに属し、ラベルapp=myapp
が設定されているすべてのPodを一覧表示するには、以下のコマンドを利用できます。
kubectl get pods -l app=myapp
Podが長期間Unknown
またはTerminating
の状態になっていることがわかった場合は、それらを処理する方法についてStatefulSetの削除タスクを参照してください。
Podのデバッグガイドを使用して、StatefulSet内の個々のPodをデバッグできます。
このページはkubectl exec
を使用して実行中のコンテナへのシェルを取得する方法を説明します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
バージョンを確認するには次のコマンドを実行してください:kubectl version
.
このエクササイズでは、1つのコンテナを持つPodを作成します。 コンテナはnginxのイメージを実行します。以下がそのPodの設定ファイルです:
apiVersion: v1
kind: Pod
metadata:
name: shell-demo
spec:
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: nginx
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
Podを作成します:
kubectl apply -f https://k8s.io/examples/application/shell-demo.yaml
コンテナが実行中であることを確認します:
kubectl get pod shell-demo
実行中のコンテナへのシェルを取得します:
kubectl exec --stdin --tty shell-demo -- /bin/bash
--
はコマンドに渡す引数とkubectlの引数を分離します。
シェル内で、ルートディレクトリーのファイル一覧を表示します:
# このコマンドをコンテナ内で実行します
ls /
シェル内で、他のコマンドを試しましょう。以下がいくつかの例です:
# これらのサンプルコマンドをコンテナ内で実行することができます
ls /
cat /proc/mounts
cat /proc/1/maps
apt-get update
apt-get install -y tcpdump
tcpdump
apt-get install -y lsof
lsof
apt-get install -y procps
ps aux
ps aux | grep nginx
Podの設定ファイルを再度確認します。PodはemptyDir
ボリュームを持ち、
コンテナは/usr/share/nginx/html
ボリュームをマウントします。
シェル内で、/usr/share/nginx/html
ディレクトリにindex.html
を作成します。
# このコマンドをコンテナ内で実行します
echo 'Hello shell demo' > /usr/share/nginx/html/index.html
シェル内で、nginxサーバーにGETリクエストを送信します:
# これらのコマンドをコンテナ内のシェルで実行します
apt-get update
apt-get install curl
curl http://localhost/
出力にindex.html
ファイルに書き込んだ文字列が表示されます:
Hello shell demo
シェルを終了する場合、exit
を入力します。
exit # コンテナ内のシェルを終了する
シェルではない通常のコマンドウインドウ内で、実行中のコンテナの環境変数の一覧を表示します:
kubectl exec shell-demo env
他のコマンドを試します。以下がいくつかの例です:
kubectl exec shell-demo -- ps aux
kubectl exec shell-demo -- ls /
kubectl exec shell-demo -- cat /proc/1/mounts
Podが1つ以上のコンテナを持つ場合、--container
か-c
を使用して、kubectl exec
コマンド内でコンテナを指定します。
例えば、my-podという名前のPodがあり、そのPodが main-app と helper-app という2つのコンテナを持つとします。
以下のコマンドは main-app のコンテナへのシェルを開きます。
kubectl exec -i -t my-pod --container main-app -- /bin/bash
-i
と-t
は、ロングオプションの--stdin
と--tty
と同様です。
このページでは、kubeletの証明書のローテーションを設定する方法を説明します。
Kubernetes v1.8 [beta]
kubeletは、Kubernetes APIへの認証のために証明書を使用します。デフォルトでは、証明書は1年間の有効期限付きで発行されるため、頻繁に更新する必要はありません。
Kubernetes 1.8にはベータ機能のkubelet certificate rotationが含まれているため、現在の証明書の有効期限が近づいたときに自動的に新しい鍵を生成して、Kubernetes APIに新しい証明書をリクエストできます。新しい証明書が利用できるようになると、Kubernetes APIへの接続の認証に利用されます。
kubelet
プロセスは--rotate-certificates
という引数を受け付けます。この引数によって、現在使用している証明書の有効期限が近づいたときに、kubeletが自動的に新しい証明書をリクエストするかどうかを制御できます。証明書のローテーションはベータ機能であるため、--feature-gates=RotateKubeletClientCertificate=true
を使用してフィーチャーフラグを有効にする必要もあります。
kube-controller-manager
プロセスは、--experimental-cluster-signing-duration
という引数を受け付け、この引数で証明書が発行される期間を制御できます。
kubeletが起動すると、ブートストラップが設定されている場合(--bootstrap-kubeconfig
フラグを使用した場合)、初期証明書を使用してKubernetes APIに接続して、証明書署名リクエスト(certificate signing request、CSR)を発行します。証明書署名リクエストのステータスは、次のコマンドで表示できます。
kubectl get csr
ノード上のkubeletから発行された証明書署名リクエストは、初めはPending
状態です。証明書署名リクエストが特定の条件を満たすと、コントローラーマネージャーに自動的に承認され、Approved
状態になります。次に、コントローラーマネージャーは--experimental-cluster-signing-duration
パラメーターで指定された有効期限で発行された証明書に署名を行い、署名された証明書が証明書署名リクエストに添付されます。
kubeletは署名された証明書をKubernetes APIから取得し、ディスク上の--cert-dir
で指定された場所に書き込みます。その後、kubeletは新しい証明書を使用してKubernetes APIに接続するようになります。
署名された証明書の有効期限が近づくと、kubeletはKubernetes APIを使用して新しい証明書署名リクエストを自動的に発行します。再び、コントローラーマネージャーは証明書のリクエストを自動的に承認し、署名された証明書を証明書署名リクエストに添付します。kubeletは新しい署名された証明書をKubernetes APIから取得してディスクに書き込みます。その後、kubeletは既存のコネクションを更新して、新しい証明書でKubernetes APIに再接続します。
サービスカタログは kubernetesクラスターで稼働するアプリケーションが、クラウドプロバイダーによって提供されるデータストアサービスのように、外部のマネージドソフトウェアを容易に使えるようにするための拡張APIです。
サービスカタログを使用することでサービスブローカーが提供するマネージドサービスを、それらのサービスがどのように作成されるか、また管理されるかについての知識を無しに、一覧表示したり、プロビジョニングや使用をすることができます。
Helmを使用してKubernetesクラスターにサービスカタログをインストールします。手順の最新情報はkubernetes-sigs/service-catalogリポジトリーを参照してください。
hack/local-up-cluster.sh
を使用している場合は、環境変数KUBE_ENABLE_CLUSTER_DNS
が設定されていることを確認し、インストールスクリプトを実行してください。helm init
を実行し、HelmのサーバーサイドコンポーネントであるTillerをインストールしてください。Helmをインストールし、以下のコマンドを実行することでローカルマシンにservice-catalogのHelmリポジトリーを追加します。
helm repo add svc-cat https://kubernetes-sigs.github.io/service-catalog
以下のコマンドを実行し、インストールに成功していることを確認します。
helm search service-catalog
インストールが成功していれば、出力は以下のようになります:
NAME CHART VERSION APP VERSION DESCRIPTION
svc-cat/catalog 0.2.1 service-catalog API server and controller-manager helm chart
svc-cat/catalog-v0.2 0.2.2 service-catalog API server and controller-manager helm chart
KubernetesクラスターのRBACを有効化することで、Tiller Podにcluster-admin
アクセスを持たせます。
v0.25以前のMinikubeを使用している場合は、明示的にRBACを有効化して起動する必要があります:
minikube start --extra-config=apiserver.Authorization.Mode=RBAC
v0.26以降のMinikubeを使用している場合は、以下のコマンドを実行してください。
minikube start
v0.26以降のMinikubeを使用している場合、--extra-config
を指定しないでください。
このフラグは--extra-config=apiserver.authorization-modeを指定するものに変更されており、現在MinikubeではデフォルトでRBACが有効化されています。
古いフラグを指定すると、スタートコマンドが応答しなくなることがあります。
hack/local-up-cluster.sh
を使用している場合、環境変数AUTHORIZATION_MODE
を以下の値に設定してください:
AUTHORIZATION_MODE=Node,RBAC hack/local-up-cluster.sh -O
helm init
は、デフォルトでkube-system
のnamespaceにTiller Podをインストールし、Tillerはdefault
のServiceAccountを使用するように設定されています。
helm init
を実行する際に--tiller-namespace
または--service-account
のフラグを使用する場合、以下のコマンドの--serviceaccount
フラグには適切なnamespaceとServiceAccountを指定する必要があります。
Tillerにcluster-admin
アクセスを設定する場合:
kubectl create clusterrolebinding tiller-cluster-admin \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:default
以下のコマンドを使用して、Helmリポジトリーのrootからサービスカタログをインストールします:
helm install catalog svc-cat/catalog --namespace catalog
helm install svc-cat/catalog --name catalog --namespace catalog
サービスカタログは kubernetesクラスターで稼働するアプリケーションが、クラウドプロバイダーによって提供されるデータストアサービスのように、外部のマネージドソフトウェアを容易に使えるようにするための拡張APIです。
サービスカタログを使用することでサービスブローカーが提供するマネージドサービスを、それらのサービスがどのように作成されるか、また管理されるかについての知識を無しに、一覧表示したり、プロビジョニングや使用をすることができます。
GCPのService Catalog Installerツールを使うと、Kubernetesクラスター上にサービスカタログを簡単にインストール・アンインストールして、Google Cloudのプロジェクトに紐付けることもできます。
サービスカタログ自体は、Google Cloudだけではなく、どのような種類のマネージドサービスでも動作します。
サービスカタログの基本概念を理解してください。
Go 1.6+をインストールして、GOPATH
を設定してください。
SSLに関するファイルを生成するために必要なcfsslツールをインストールしてください。
サービスカタログを使用するには、Kubernetesクラスターのバージョンが1.7以降である必要があります。
kubectlのインストールおよびセットアップを参考に、v1.7以降のkubectlをインストールし、設定を行ってください。
サービスカタログをインストールするためには、kubectlのユーザーがcluster-adminロールにバインドされている必要があります。正しくバインドされていることを確認するには、次のコマンドを実行します。
kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=<user-name>
sc
をインストールするインストーラーは、ローカルのコンピューター上でsc
と呼ばれるCLIツールとして実行します。
go get
を使用してインストールします。
go get github.com/GoogleCloudPlatform/k8s-service-catalog/installer/cmd/sc
これで、sc
がGOPATH/bin
ディレクトリー内にインストールされたはずです。
まず、すべての依存関係がインストールされていることを確認します。次のコマンドを実行してください。
sc check
チェックが成功したら、次のように表示されるはずです。
Dependency check passed. You are good to go.
次に、バックアップに使用したいstorageclass
を指定して、installコマンドを実行します。
sc install --etcd-backup-storageclass "standard"
Kubernetesクラスターからサービスカタログをアンインストールしたい場合は、sc
ツールを使って次のコマンドを実行します。
sc uninstall
Podの/etc/hosts
ファイルにエントリーを追加すると、DNSやその他の選択肢を利用できない場合に、Podレベルでホスト名の名前解決を上書きできるようになります。このようなカスタムエントリーは、PodSpecのHostAliasesフィールドに追加できます。
HostAliasesを使用せずにファイルを修正することはおすすめできません。このファイルはkubeletが管理しており、Podの作成や再起動時に上書きされる可能性があるためです。
Nginx Podを実行すると、Pod IPが割り当てられます。
kubectl run nginx --image nginx
pod/nginx created
Pod IPを確認します。
kubectl get pods --output=wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
hostsファイルの内容は次のようになります。
kubectl exec nginx -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.200.0.4 nginx
デフォルトでは、hosts
ファイルには、localhost
やPod自身のホスト名などのIPv4とIPv6のボイラープレートだけが含まれています。
デフォルトのボイラープレートに加えて、hosts
ファイルに追加エントリーを追加できます。たとえば、foo.local
とbar.local
を127.0.0.1
に、foo.remote
とbar.remote
を10.1.2.3
にそれぞれ解決するためには、PodのHostAliasesを.spec.hostAliases
以下に設定します。
apiVersion: v1
kind: Pod
metadata:
name: hostaliases-pod
spec:
restartPolicy: Never
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "foo.local"
- "bar.local"
- ip: "10.1.2.3"
hostnames:
- "foo.remote"
- "bar.remote"
containers:
- name: cat-hosts
image: busybox
command:
- cat
args:
- "/etc/hosts"
この設定を使用したPodを開始するには、次のコマンドを実行します。
kubectl apply -f https://k8s.io/examples/service/networking/hostaliases-pod.yaml
pod/hostaliases-pod created
Podの詳細情報を表示して、IPv4アドレスと状態を確認します。
kubectl get pod --output=wide
NAME READY STATUS RESTARTS AGE IP NODE
hostaliases-pod 0/1 Completed 0 6s 10.200.0.5 worker0
hosts
ファイルの内容は次のようになります。
kubectl logs hostaliases-pod
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.200.0.5 hostaliases-pod
# Entries added by HostAliases.
127.0.0.1 foo.local bar.local
10.1.2.3 foo.remote bar.remote
ファイルの最後に追加エントリーが指定されています。
kubeletがPodの各コンテナのhosts
ファイルを管理するのは、コンテナ起動後にDockerがファイルを編集するのを防ぐためです。
コンテナ内部でhostsファイルを手動で変更するのは控えてください。
hostsファイルを手動で変更すると、コンテナが終了したときに変更が失われてしまいます。
このドキュメントでは、IPv4/IPv6デュアルスタックが有効化されたKubernetesクラスターを検証する方法について共有します。
kubectl version
.
各デュアルスタックのノードは、1つのIPv4ブロックと1つのIPv6ブロックを割り当てる必要があります。IPv4/IPv6のPodアドレスの範囲が設定されていることを検証するには、次のコマンドを実行します。例の中のノード名は、自分のクラスターの有効なデュアルスタックのノードの名前に置換してください。この例では、ノードの名前はk8s-linuxpool1-34450317-0
になっています。
kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template='{{range .spec.podCIDRs}}{{printf "%s\n" .}}{{end}}'
10.244.1.0/24
a00:100::/24
IPv4ブロックとIPv6ブロックがそれぞれ1つずつ割り当てられているはずです。
ノードが検出されたIPv4とIPv6のインターフェイスを持っていることを検証します。ノード名は自分のクラスター内の有効なノード名に置換してください。この例では、ノード名はk8s-linuxpool1-34450317-0
になっています。
kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template='{{range .status.addresses}}{{printf "%s: %s\n" .type .address}}{{end}}'
Hostname: k8s-linuxpool1-34450317-0
InternalIP: 10.240.0.5
InternalIP: 2001:1234:5678:9abc::5
PodにIPv4とIPv6のアドレスが割り当てられていることを検証します。Podの名前は自分のクラスター内の有効なPodの名前と置換してください。この例では、Podの名前はpod01
になっています。
kubectl get pods pod01 -o go-template --template='{{range .status.podIPs}}{{printf "%s\n" .ip}}{{end}}'
10.244.1.4
a00:100::4
Downward APIを使用して、status.podIPs
のfieldPath経由でPod IPを検証することもできます。次のスニペットは、Pod IPをMY_POD_IPS
という名前の環境変数経由でコンテナ内に公開する方法を示しています。
env:
- name: MY_POD_IPS
valueFrom:
fieldRef:
fieldPath: status.podIPs
次のコマンドを実行すると、MY_POD_IPS
環境変数の値をコンテナ内から表示できます。値はカンマ区切りのリストであり、PodのIPv4とIPv6のアドレスに対応しています。
kubectl exec -it pod01 -- set | grep MY_POD_IPS
MY_POD_IPS=10.244.1.4,a00:100::4
PodのIPアドレスは、コンテナ内の/etc/hosts
にも書き込まれます。次のコマンドは、デュアルスタックのPod上で/etc/hosts
に対してcatコマンドを実行します。出力を見ると、Pod用のIPv4およびIPv6のIPアドレスの両方が確認できます。
kubectl exec -it pod01 -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.244.1.4 pod01
a00:100::4 pod01
.spec.isFamilyPolicy
を明示的に定義していない、以下のようなServiceを作成してみます。Kubernetesは最初に設定したservice-cluster-ip-range
の範囲からServiceにcluster IPを割り当てて、.spec.ipFamilyPolicy
をSingleStack
に設定します。
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app: MyApp
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
kubectl
を使ってServiceのYAMLを表示します。
kubectl get svc my-service -o yaml
Serviceの.spec.ipFamilyPolicy
はSingleStack
に設定され、.spec.clusterIP
にはkube-controller-manager上の--service-cluster-ip-range
フラグで最初に設定した範囲から1つのIPv4アドレスが設定されているのがわかります。
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: default
spec:
clusterIP: 10.0.217.164
clusterIPs:
- 10.0.217.164
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 80
protocol: TCP
targetPort: 9376
selector:
app: MyApp
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
.spec.ipFamilies
内の配列の1番目の要素にIPv6
を明示的に指定した、次のようなServiceを作成してみます。Kubernetesはservice-cluster-ip-range
で設定したIPv6の範囲からcluster IPを割り当てて、.spec.ipFamilyPolicy
をSingleStack
に設定します。
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app: MyApp
spec:
ipFamilies:
- IPv6
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
kubectl
を使ってServiceのYAMLを表示します。
kubectl get svc my-service -o yaml
Serviceの.spec.ipFamilyPolicy
はSingleStack
に設定され、.spec.clusterIP
には、kube-controller-manager上の--service-cluster-ip-range
フラグで指定された最初の設定範囲から1つのIPv6アドレスが設定されているのがわかります。
apiVersion: v1
kind: Service
metadata:
labels:
app: MyApp
name: my-service
spec:
clusterIP: fd00::5118
clusterIPs:
- fd00::5118
ipFamilies:
- IPv6
ipFamilyPolicy: SingleStack
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: MyApp
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
.spec.ipFamiliePolicy
にPreferDualStack
を明示的に指定した、次のようなServiceを作成してみます。Kubernetesは(クラスターでデュアルスタックを有効化しているため)IPv4およびIPv6のアドレスの両方を割り当て、.spec.ClusterIPs
のリストから、.spec.ipFamilies
配列の最初の要素のアドレスファミリーに基づいた.spec.ClusterIP
を設定します。
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app: MyApp
spec:
ipFamilyPolicy: PreferDualStack
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
kubectl get svc
コマンドは、CLUSTER-IP
フィールドにプライマリーのIPだけしか表示しません。
kubectl get svc -l app=MyApp
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service ClusterIP 10.0.216.242 <none> 80/TCP 5s
kubectl describe
を使用して、ServiceがIPv4およびIPv6アドレスのブロックからcluster IPを割り当てられていることを検証します。その後、ServiceにIPアドレスとポートを使用してアクセスできることを検証することもできます。
kubectl describe svc -l app=MyApp
Name: my-service
Namespace: default
Labels: app=MyApp
Annotations: <none>
Selector: app=MyApp
Type: ClusterIP
IP Family Policy: PreferDualStack
IP Families: IPv4,IPv6
IP: 10.0.216.242
IPs: 10.0.216.242,fd00::af55
Port: <unset> 80/TCP
TargetPort: 9376/TCP
Endpoints: <none>
Session Affinity: None
Events: <none>
クラウドプロバイダーがIPv6を有効化した外部ロードバランサーのプロビジョニングをサポートする場合、.spec.ipFamilyPolicy
にPreferDualStack
を指定し、.spec.ipFamilies
の最初の要素をIPv6
にして、type
フィールドにLoadBalancer
を指定したServiceを作成できます。
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app: MyApp
spec:
ipFamilyPolicy: PreferDualStack
ipFamilies:
- IPv6
type: LoadBalancer
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
Serviceを確認します。
kubectl get svc -l app=MyApp
ServiceがIPv6アドレスブロックからCLUSTER-IP
のアドレスとEXTERNAL-IP
を割り当てられていることを検証します。その後、IPとポートを用いたServiceへのアクセスを検証することもできます。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service LoadBalancer fd00::7ebc 2603:1030:805::5 80:30790/TCP 35s
Kubernetes v1.10 [beta]
Kubernetesには、複数ノードに搭載されたAMDおよびNVIDIAのGPU(graphical processing unit)を管理するための実験的なサポートが含まれています。
このページでは、異なるバージョンのKubernetesを横断してGPUを使用する方法と、現時点での制限について説明します。
Kubernetesでは、GPUなどの特別なハードウェアの機能にPodがアクセスできるようにするために、デバイスプラグインが実装されています。
管理者として、ノード上に対応するハードウェアベンダーのGPUドライバーをインストールして、以下のような対応するGPUベンダーのデバイスプラグインを実行する必要があります。
上記の条件を満たしていれば、Kubernetesはamd.com/gpu
またはnvidia.com/gpu
をスケジュール可能なリソースとして公開します。
これらのGPUをコンテナから使用するには、cpu
やmemory
をリクエストするのと同じように<vendor>.com/gpu
というリソースをリクエストするだけです。ただし、GPUを使用するときにはリソースのリクエストの指定方法にいくつか制限があります。
limits
セクションでのみ指定されることが想定されている。この制限は、次のことを意味します。
requests
を省略してlimits
を指定できる。limits
とrequests
の両方で指定できるが、これら2つの値は等しくなければならない。limits
を省略してrequests
だけを指定することはできない。以下に例を示します。
apiVersion: v1
kind: Pod
metadata:
name: cuda-vector-add
spec:
restartPolicy: OnFailure
containers:
- name: cuda-vector-add
# https://github.com/kubernetes/kubernetes/blob/v1.7.11/test/images/nvidia-cuda/Dockerfile
image: "k8s.gcr.io/cuda-vector-add:v0.1"
resources:
limits:
nvidia.com/gpu: 1 # 1 GPUをリクエストしています
AMD公式のGPUデバイスプラグインには以下の要件があります。
クラスターが起動して上記の要件が満たされれば、以下のコマンドを実行することでAMDのデバイスプラグインをデプロイできます。
kubectl create -f https://raw.githubusercontent.com/RadeonOpenCompute/k8s-device-plugin/v1.10/k8s-ds-amdgpu-dp.yaml
このサードパーティーのデバイスプラグインに関する問題は、RadeonOpenCompute/k8s-device-pluginで報告できます。
現在、NVIDIAのGPU向けのデバイスプラグインの実装は2種類あります。
NVIDIA公式のGPUデバイスプラグインには以下の要件があります。
nvidia-container-runtime
を設定しなければならない。クラスターが起動して上記の要件が満たされれば、以下のコマンドを実行することでNVIDIAのデバイスプラグインがデプロイできます。
kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/1.0.0-beta4/nvidia-device-plugin.yml
このサードパーティーのデバイスプラグインに関する問題は、NVIDIA/k8s-device-pluginで報告できます。
GCEで使用されるNVIDIAのGPUデバイスプラグインは、nvidia-dockerを必要としないため、KubernetesのContainer Runtime Interface(CRI)と互換性のある任意のコンテナランタイムで動作するはずです。このデバイスプラグインはContainer-Optimized OSでテストされていて、1.9以降ではUbuntu向けの実験的なコードも含まれています。
以下のコマンドを実行すると、NVIDIAのドライバーとデバイスプラグインをインストールできます。
# NVIDIAドライバーをContainer-Optimized OSにインストールする
kubectl create -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/stable/daemonset.yaml
# NVIDIAドライバーをUbuntuにインストールする(実験的)
kubectl create -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/stable/nvidia-driver-installer/ubuntu/daemonset.yaml
# デバイスプラグインをインストールする
kubectl create -f https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.14/cluster/addons/device-plugins/nvidia-gpu/daemonset.yaml
このサードパーティーのデバイスプラグインの使用やデプロイに関する問題は、GoogleCloudPlatform/container-engine-acceleratorsで報告できます。
Googleは、GKE上でNVIDIAのGPUを使用するための手順も公開しています。
クラスター上の別のノードに異なる種類のGPUが搭載されている場合、NodeラベルとNodeセレクターを使用することで、Podを適切なノードにスケジューリングできます。
以下に例を示します。
# アクセラレーターを搭載したノードにラベルを付けます。
kubectl label nodes <node-with-k80> accelerator=nvidia-tesla-k80
kubectl label nodes <node-with-p100> accelerator=nvidia-tesla-p100
AMDのGPUデバイスを使用している場合、Node Labellerをデプロイできます。Node Labellerはコントローラーの1種で、GPUデバイスのプロパティを持つノードに自動的にラベルを付けてくれます。
現在は、このコントローラーは以下のプロパティに基づいてラベルを追加できます。
kubectl describe node cluster-node-23
Name: cluster-node-23
Roles: <none>
Labels: beta.amd.com/gpu.cu-count.64=1
beta.amd.com/gpu.device-id.6860=1
beta.amd.com/gpu.family.AI=1
beta.amd.com/gpu.simd-count.256=1
beta.amd.com/gpu.vram.16G=1
beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/hostname=cluster-node-23
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
node.alpha.kubernetes.io/ttl: 0
…
Node Labellerを使用すると、GPUの種類をPodのspec内で指定できます。
apiVersion: v1
kind: Pod
metadata:
name: cuda-vector-add
spec:
restartPolicy: OnFailure
containers:
- name: cuda-vector-add
# https://github.com/kubernetes/kubernetes/blob/v1.7.11/test/images/nvidia-cuda/Dockerfile
image: "k8s.gcr.io/cuda-vector-add:v0.1"
resources:
limits:
nvidia.com/gpu: 1
nodeSelector:
accelerator: nvidia-tesla-p100 # または nvidia-tesla-k80 など
これにより、指定した種類のGPUを搭載したノードにPodがスケジューリングされることを保証できます。
Kubernetes v1.23 [stable]
Kubernetesでは、事前割り当てされたhuge pageをPod内のアプリケーションに割り当てたり利用したりすることをサポートしています。このページでは、ユーザーがhuge pageを利用できるようにする方法について説明します。
ノードは、すべてのhuge pageリソースを、スケジュール可能なリソースとして自動的に探索・報告してくれます。
huge pageはコンテナレベルのリソース要求でhugepages-<size>
という名前のリソースを指定することで利用できます。ここで、<size>
は、特定のノード上でサポートされている整数値を使った最も小さなバイナリ表記です。たとえば、ノードが2048KiBと1048576KiBのページサイズをサポートしている場合、ノードはスケジュール可能なリソースとして、hugepages-2Mi
とhugepages-1Gi
の2つのリソースを公開します。CPUやメモリとは違い、huge pageはオーバーコミットをサポートしません。huge pageリソースをリクエストするときには、メモリやCPUリソースを同時にリクエストしなければならないことに注意してください。
1つのPodのspec内に書くことで、Podから複数のサイズのhuge pageを利用することもできます。その場合、すべてのボリュームマウントでmedium: HugePages-<hugepagesize>
という表記を使う必要があります。
apiVersion: v1
kind: Pod
metadata:
name: huge-pages-example
spec:
containers:
- name: example
image: fedora:latest
command:
- sleep
- inf
volumeMounts:
- mountPath: /hugepages-2Mi
name: hugepage-2mi
- mountPath: /hugepages-1Gi
name: hugepage-1gi
resources:
limits:
hugepages-2Mi: 100Mi
hugepages-1Gi: 2Gi
memory: 100Mi
requests:
memory: 100Mi
volumes:
- name: hugepage-2mi
emptyDir:
medium: HugePages-2Mi
- name: hugepage-1gi
emptyDir:
medium: HugePages-1Gi
Podで1種類のサイズのhuge pageをリクエストするときだけは、medium: HugePages
という表記を使うこともできます。
apiVersion: v1
kind: Pod
metadata:
name: huge-pages-example
spec:
containers:
- name: example
image: fedora:latest
command:
- sleep
- inf
volumeMounts:
- mountPath: /hugepages
name: hugepage
resources:
limits:
hugepages-2Mi: 100Mi
memory: 100Mi
requests:
memory: 100Mi
volumes:
- name: hugepage
emptyDir:
medium: HugePages
shmget()
にSHM_HUGETLB
を指定して取得したhuge pageを使用するアプリケーションは、/proc/sys/vm/hugetlb_shm_group
に一致する補助グループ(supplemental group)を使用して実行する必要があります。cpu
やmemory
のような他の計算リソースと同じようにhugepages-<size>
というトークンを使用することで制御できます。HugePageStorageMediumSize
フィーチャーゲートを使用すると有効にできます(--feature-gates=HugePageStorageMediumSize=true
)。