第1回 Pod + Service
はじめに
Kuberneteの仕組みを以下の動画で大まかに理解してください.
参考資料
基本的に書き方や使い方は公式リファレンスを読んでください.
日本語で網羅的に書かれている資料として以下がオススメです.
環境構築
簡単に構築できるKubernetes環境の例には以下があります.
- インストール型
- パブリッククラウド(有料)
Webで簡単に試すだけなら katacoda も使えます.何らかの方法でKubernetes環境を構築してください.
以下のコマンドを実行して結果が得られるか確認してください.以下ではDocker Desktopを使っています.
$ kubectl cluster-info
Kubernetes master is running at https://kubernetes.docker.internal:6443
KubeDNS is running at https://kubernetes.docker.internal:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Dockerコマンドでコンテナを起動
まずは,準備運動として以下のコンテナをdockerコマンドで立ち上げてみてください.このコンテナは80/tcpでリクエストを待ち受けます.
練習
docker run --rm -p <略>
Webブラウザからコンテナにアクセスすると,以下が表示されます.
Kubernetesの基本操作
Kubernetes上で動作するコンポーネント(要素や機能郡)を操作する基本的な方法は以下です.
- YAMLファイル
example.yml
を作成する.- コマンド例:
vi example.yml
- コマンド例:
- kubectlコマンドでデプロイする.
- コマンド例:
kubectl apply -f example.yml
- コマンド例:
- kubectlコマンドでデプロイしたコンポーネントを確認する.
- コマンド例:
kubectl get pod
- コマンド例:
kubectl get deployment
- コマンド例:
kubectl get service
- コマンド例:
Podをデプロイ
Podとは
最初に貼った動画では「さや」という例えで説明されています.
Kubernetes公式のサイトでのPodの説明を引用します.
Pod は、Kubernetesアプリケーションの基本的な実行単位です。これは、作成またはデプロイするKubernetesオブジェクトモデルの中で最小かつ最も単純な単位です。Podは、クラスターで実行されているプロセスを表します。
出典: Podについて理解する
Podとコンテナの関係は次の2パターンがあります.Podに1つのコンテナを配置するパターン(図:パターン1)と,Podに複数のコンテナを配置するパターン(図:パターン2)です.
Podの詳細は公式ドキュメントを確認してください.
Podのデプロイ
まずは,簡単なパターン1でコンテナをデプロイ(配置)していきます.操作は前述の「Kubernetesの基本操作」をもとに行います.
[手順1] YAMLファイルを作成
テキストエディタで作成するコンポーネント(要素や機能郡)の情報をYAMLファイルに記述します.YAMLはインデントでデータ階層を表現する記述形式です.ファイルの拡張子には yml
や yaml
が使われます.
ここでは pod.yaml
にPodの設定を記述します.
$ vi pod.yaml
pod.yamlの中身は以下です.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: demo-container
image: nginxdemos/hello
ports:
- containerPort: 80
pod.yamlの中身に説明を入れてみました.
# Podを記述する時のきまり
apiVersion: v1
kind: Pod
# Podの名前やラベルをはじめとする細かい情報
metadata:
name: myapp-pod # Podに名前をつける
labels:
app: myapp # ラベル app -> myapp をつける
# Podに配置するコンテナ本体の情報
spec:
containers:
- name: demo-container # コンテナに名前をつける
image: nginxdemos/hello # コンテナ名(Docker Hubの名前と一致)
ports:
- containerPort: 80 # 80番ポートを使う
詳細な解説は以下の記事を参照してください.
Kubernetes道場 3日目 - Podについてとkubectlの簡単な使い方
作業ディレクトリには,pod.yamlだけが存在する状況です.
$ ls
pod.yaml
[手順2] kubectlコマンドでデプロイ
次にpod.yamlに記述した設定をKubernetesへ適用させます.正常に実行できると以下のメッセージが出力されます.
$ kubectl apply -f pod.yaml
pod/myapp-pod created
[手順3] kubectlコマンドでデプロイされたか確認
Podが作成されているかkubectlコマンドで確認します.
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 3m23s
Podが作成されたことが確認できました.
<補足> オプション -o wide
をつけると,さらに細かい情報が確認できます.
kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-pod 1/1 Running 0 3m47s 10.1.0.160 docker-desktop <none> <none>
デプロイしたPodを以下の図に表しました.Pod の中にコンテナ が配置されています.コンテナのイメージには nginxdemos/hello を使っています.
Podの情報を細かく見るには kubectl describe
を使います.
$ kubectl describe pod myapp-pod
Name: myapp-pod
Namespace: default
Priority: 0
Node: docker-desktop/192.168.65.3
Start Time: Sat, 05 Sep 2020 20:58:29 +0900
Labels: app=myapp
Annotations: Status: Running
IP: 10.1.0.160
IPs:
IP: 10.1.0.160
Containers:
demo-container:
Container ID: docker://cc834c6900185dbc14a201a0b47b4548c627daf40ab6aace5c6919fe2ac5bdb2
Image: nginxdemos/hello
Image ID: docker-pullable://nginxdemos/hello@sha256:f5a0b2a5fe9af497c4a7c186ef6412bb91ff19d39d6ac24a4997eaed2b0bb334
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Sat, 05 Sep 2020 20:58:32 +0900
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-wf42w (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-wf42w:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-wf42w
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events: <none>
Serviceをデプロイ
Serviceとは
最初に紹介した動画ではサービスを店として例えています.
PodはKubernetesクラスタ内のIPアドレスからしかアクセスできません.また,IPアドレスは頻繁に変更されます.こうした状況下で,外部にPodを公開したりPod同士がやり取りしたりする場合は,Serviceを使います.
ServiceにはTypeとよばれるパラメータでServiceの種類が選べます.TypeにはCluster IP(初期値), NodePort, ExternalName, LoadBalancerがあります.詳細は公式ドキュメントを参照してください.
参考: Next 東京:Kubernetes のコンテナ技術ですべてをシンプルに(Brian Dorsey)
Serviceのデプロイ
それでは,Serviceを作ってみます.操作は前述の「Kubernetesの基本操作」に従います.
[手順1] YAMLファイルを作成
ここでは service.yaml
にServiceの設定を記述します.
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
spec:
type: NodePort
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
nodePort: 31080
selector:
app: myapp
service.yaml
の中身を説明します.
# Serviceを記述する時のきまり
apiVersion: v1
kind: Service
# Serviceの名前やラベルをはじめとする細かい情報
metadata:
name: myapp-svc
# Service本体の情報
spec:
# Serviceの種類. 未指定ではClusterIPになる.NodePortの詳細は割愛.
type: NodePort
# ポートの対応付け
ports:
- name: "http-port"
protocol: "TCP"
port: 8080 # ClusterIPで受け付けるポート
targetPort: 80 # Pod側のポート
nodePort: 31080 # 外部からのアクセスを受けるポート(全ノードで使用)
selector:
app: myapp
ServiceのTypeごとの細かな説明は以下の記事がオススメです.
- Cluster IP, External IP: KubernetesのDiscovery&LBリソース(その1) | Think IT(シンクイット)
- NodePort, LoadBalancer: KubernetesのDiscovery&LBリソース(その1) | Think IT(シンクイット)
[手順2] kubectlコマンドでデプロイ
設定を記述したServiceをデプロイします.
$ kubectl apply -f service.yaml
service/myapp-svc created
[手順3] kubectlコマンドでデプロイされたか確認
kubectlコマンドで確認してみます.
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 93d
myapp-svc NodePort 10.107.57.76 <none> 8080:31080/TCP 47m
実行結果にあるPORT(S)の 8080:31080/TCP
はYAMLファイルで指定した設定パラメータ port:nodePort/protocol
に対応しています.
Pod + Serviceでデプロイしたコンテナへアクセス
Webブラウザから http://localhost:31080/
へアクセスして以下のWebページが表示されるか確認します.localhostは,Kubernetesクラスタのアドレスに置き換えてください.
ここで表示されている Server address と Server name が kubectl get pod -o wide
の情報と一致するか確認してみます.
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-pod 1/1 Running 0 14h 10.1.0.160 docker-desktop <none> <none>
片付け
以下のコマンドで作成したコンポーネントを削除します.
$ kubectl delete pod myapp-pod
pod "myapp-pod" deleted
$ kubectl delete service myapp-svc
service "myapp-svc" deleted
コンポーネントが削除されているか確認します.
$ kubectl get pod
No resources found in default namespace.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 93d
練習
以下のイメージをKubernetesを使ってデプロイしてください.
起動すると以下のWebページが確認できます.
まとめ
- Dockerコンテナの実行
- Kubernetesの使い方
- Pod
- Service
- kubectlコマンド
- kubectl get xxx
- kubectl apply -f xxx
- kubectl describe xxx
第2回 YAMLの書き方 + kubectlコマンド
YAMLの書き方
Kubernetesで自由自在にコンテナをはじめとするコンポーネントを操るには,事前に定義された形式に従って設定ファイルを記述する必要があります.
ここでは基本的なYAMLの書き方をPodを例に説明します.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: demo-container
image: nginxdemos/hello
ports:
- containerPort: 80
apiVersion, kind
apiVersionは使用するコンポーネントに対応するKubernetesのAPIバージョンを記述します.
kindは使用するコンポーネントの種類を指定します.
以下にkindと対応するapiVersionの例をあげています.
- Pod: v1
- Service: v1
以下は以降の回で説明するコンポーネントです.
- Deployment: apps/v1
- DaemonSet: apps/v1
- CronJob: batch/v1beta1
- Job: batch/v1
- Ingress: networking.k8s.io/v1beta1
metadata
metadataには,作成するコンポーネントの名前やラベル,アノテーション(Annotation)を記述します.
作成後のコンポーネントを操作したり識別したりするにはこれらが使われます.
以下はmetadataの記述例です.
metadata:
name: annotations-demo
annotations:
imageregistry: "https://hub.docker.com/"
labels:
app: sample-app
app-arch: x86_64
app-version: v1.3.5
次の命名規則に従って名前付けを行う必要があります.
ラベルは、キーとバリューのベアです。正しいラベルキーは2つのセグメントを持ちます。それは/によって分割されたオプショナルなプレフィックスと名前です。名前セグメントは必須で、63文字以下である必要があり、文字列の最初と最後は英数字([a-z0-9A-Z])で、文字列の間ではこれに加えてダッシュ(-)、アンダースコア(_)、ドット(.)を使うことができます。プレフィックスはオプションです。もしプレフィックスが指定されていた場合、プレフィックスはDNSサブドメイン形式である必要があり、それはドット(.)で区切られたDNSラベルのセットで、253文字以下である必要があり、最後にスラッシュ(/)が続きます。
出典: ラベル(Labels)とセレクター(Selectors) | Kubernetes
名前セグメントは必須で、63文字以下である必要があり、文字列の最初と最後は英数字([a-z0-9A-Z])と、文字列の間にダッシュ(-)、アンダースコア(_)、ドット(.)を使うことができます。 プレフィックスはオプションです。もしプレフィックスが指定されていた場合、プレフィックスはDNSサブドメイン形式である必要があり、それはドット(.)で区切られたDNSラベルのセットで、253文字以下である必要があり、最後にスラッシュ(/)が続きます。
出典: アノテーション(Annotations) | Kubernetes
spec
作成するコンポーネントの詳細を記述します.
Podの場合は,その中に配置するコンテナごとの名前やイメージ,ポートや環境変数を指定します.
以下はPodにFluentdとデモNginxのコンテナを記述した例です.
spec:
containers:
- name: demo-container
image: nginxdemos/hello
ports:
- containerPort: 80
- name: fluentd-container
image: fluent/fluentd:v1.11-2
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch-logging"
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
- name: FLUENT_ELASTICSEARCH_SSL_VERIFY
value: "true"
- name: FLUENT_ELASTICSEARCH_SSL_VERSION
value: "TLSv1_2"
kubectlコマンド
Kubernetesクラスタへ新たにコンポーネントを追加や既存のコンポーネントを変更や削除には kubectl
コマンドを使います.kubectlコマンドを実行すると,Kubernetesクラスタのマスターノードへリクエストを送信します.マスターノードではRESTful APIサーバ(下図: kube-adi-server)が動作しており,受け取ったリクエストに応じてコンテナをはじめとするコンポーネントの制御を他のシステムと連携して行います.
kubectlで一覧と構成の取得
コマンドの基本的な形式は以下です.オプションをつけることで
kubectl get <取得したい対象>
コマンド | 説明 |
---|---|
kubectl get node | ノードの一覧を取得 |
kubectl get pod | Podの一覧を取得 |
kubectl get svc | Serviceの一覧を取得 |
kubectl get all -o wide | Pod, Service, Deployment, ReplicaSetの一覧を取得 |
kubectl get ns | Namespaceの一覧を取得 |
kubectl get pod -o json | Podの構成をJSON形式で取得 |
kubectl get svc -o yaml | Serviceの構成をYAML形式で取得 |
kubectl get all -A | 全てのNamespaceの一覧を取得 |
kubectl get -f pod.yaml | pod.yamlに記述されたコンポーネントの一覧を取得 |
練習
- pod.yamlに記述された内容をデプロイして,JSON形式で表示してください.
- kubectl get allの結果でコンポーネント名(例: pod/xxx, service/yyy)だけを表示してください.
kubectlでログを見る
kubectlコマンドのサブコマンド logs
を使うと,PodやServiceをはじめとするコンポーネントのログを見れます.コマンドの基本形式は以下です.
kubectl logs <ログを見る対象>
ここではPodのログを見てみます.
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/myapp-pod 1/1 Running 0 9m57s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18m
$ kubectl logs pod/myapp-pod
2020/09/11 03:48:45 listening on :8080
練習
- コンテナイメージchentex/random-loggerをKubernetesへデプロイしてください.
- デプロイしたコンテナのログから
WARN
を含むログのみをコマンドを使って表示してください. -
WARN
を含むログの件数をコマンドを使って取得してください.
コンテナの出力するログの例
2020-09-11T12:50:58+0000 WARN A warning that should be ignored is usually at this level and should be actionable.
2020-09-11T12:50:59+0000 ERROR An error is usually an exception that has been caught and not handled.
2020-09-11T12:50:59+0000 INFO This is less important than debug log and is often used to provide context in the current task.
2020-09-11T12:50:59+0000 DEBUG This is a debug log that shows a log that can be ignored.
2020-09-11T12:50:59+0000 INFO This is less important than debug log and is often used to provide context in the current task.
2020-09-11T12:51:00+0000 INFO This is less important than debug log and is often used to provide context in the current task.
kubectlでコンテナに入る
デプロイしたPod内のコンテナに入ってみます.
kubectl exec <オプション> <対象>
Podを構成するコンテナが複数ある場合は以下のコマンドを実行します.
kubectl exec <pod_name> --container <container_name> -- <command>
Podを構成するコンテナが1つの場合は以下のコマンドを実行します.
kubectl exec <pod_name> -- <command>
試しにコンテナを作成して,その中に入ってみます.
YAMLファイルからPodを作成してもよいのですが,ここではkubectl runコマンドを使ってみます.
以下では,Ubuntu 18.04のPodを起動して tail -f /dev/null
を実行しておきます.
kubectl run ubuntu --image=ubuntu:18.04 --command -- tail -f /dev/null
Podが作成されているか確認します.
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 2d5h
ubuntu 1/1 Running 0 4m23s
Podで動くコンテナの中に kubectl exec
で入ってみます.
コンテナから出るにはexitコマンドを使います.
$ kubectl exec -it pod/ubuntu -- /bin/bash
root@ubuntu:/#
root@ubuntu:/# hostname -I
10.1.0.13
root@ubuntu:/# exit
exit
$
練習
- Ubuntu 20.04のコンテナを含むPodを作成してください.方法は問いません.
- kubectl execコマンドを使ってコンテナに入ってください.
- コンテナの中に
htop
コマンドをインストールして,実行してください.- ヒント: apt-getコマンド OR aptコマンド
実行結果の例
kubectlでトラブルシューティング
kubectlコマンドはトラブルシュート(障害の診断や対応)に役立ちます.以下はkubectlコマンドの役立つTipsです.
出典: 40 topic of Kubernetes in 40 minutes (Yoshio Terada) - Japan Container Day 2018
最後のUbuntuコンテナのデプロイには以下のコマンドが使えます.
kubectl run -it --rm shooting --image=ubuntu:18.04 -- /bin/bash
第3回 コントローラ, Deployment
コントローラ(Controller)はPodを制御するためのコンポーネントです.
可用性やスケール,無停止入れ替えを実現しています.
例えば,ノードが故障してPod数が減少すると,コントローラは動作する他のノードでPodを作成して全体のPod数を一定に保ちます.
また,アクセス状況にあわせて柔軟にコンポーネントを制御できます.アクセスが増加したときにPod数を増やしたり,アクセスが減少したときにPod数を減らしたりできます.
コントローラの種類
コントローラには複数の種類があり,それぞれに役割や特徴があります.デプロイするPodの性質に適したコントローラを選択する必要があります.
- ReplicaSet
- Deployment
- StatefulSet
- DaemonSet
- Job
- CronJob
- ガベージコレクション
- (TTL Controller for Finished Resources)
Deploymentとは
Deploymentはコントローラの1つです.コンテナをデプロイする場面で頻繁に使われます.
Deploymentの役割が下図で紹介されています.Deploymentコントローラは,Pod数が増減した場合に増減前の数を維持したり,新たなリリースを徐々に適用や復元したり,需要に応じて柔軟にPod数を増減させたりします.
Deploymentをデプロイ
[手順1] YAMLファイルを作成
DeploymentをKubernetesの上にデプロイしていきます.
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-deploy
spec:
replicas: 3
selector:
matchLabels:
app: sample
template:
metadata:
labels:
app: sample
spec:
containers:
- name: hello-k8s
image: paulbouwer/hello-kubernetes:1.8
ports:
- containerPort: 8080
[手順2] kubectlコマンドでデプロイ
設定を記述したDeploymentをデプロイします.
$ kubectl apply -f deployment.yaml
deployment.apps/sample-deploy created
[手順3] kubectlコマンドでデプロイされたか確認
デプロイしたコンテナを確認してみます.
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
sample-deploy 3/3 3 3 38s
Pod, Deployment, ReplicaSetが作られていることが確認できます.
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/sample-deploy-795b599766-fvhv9 1/1 Running 0 3m14s
pod/sample-deploy-795b599766-qmj66 1/1 Running 0 3m14s
pod/sample-deploy-795b599766-vlr8d 1/1 Running 0 3m14s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d6h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/sample-deploy 3/3 3 3 3m14s
NAME DESIRED CURRENT READY AGE
replicaset.apps/sample-deploy-795b599766 3 3 3 3m14s
Serviceのデプロイ
Podを作成した時と同様にServiceを作成します.
[手順1] YAMLファイルを作成
apiVersion: v1
kind: Service
metadata:
name: sample-svc
spec:
type: NodePort
ports:
- name: "http-port"
protocol: "TCP"
port: 2080
targetPort: 8080
nodePort: 32080
selector:
app: sample
[手順2] kubectlコマンドでデプロイ
$ kubectl apply -f hello-k8s-svc.yaml
service/sample-svc created
[手順3] kubectlコマンドでデプロイされたか確認
sample-svcが作成されていることが分かります.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d7h
sample-svc NodePort 10.102.60.209 <none> 2080:32080/TCP 105s
ブラウザから実際に http://localhost:32080/ へアクセスしてみます.
Ctrl + Shift + Rで強制リロードをしてみます.Webサイトのpodの部分が変化するかを確かめてください.
Deployment, ReplicaSet, Podの関係を以下の図に表しました.
Self-healing
TBD
Rolling Update
TBD
練習
TBD
Deployment + Serviceでアプリをデプロイ
TBD
第4回 ConfigMap, Secret
コンテナにおける設定管理
コンテナを使ってアプリケーションを公開する場合,開発環境と本番環境でアプリケーションの動作を変更したいことがあります.例えば開発環境で動作するアプリケーションではURLを dev.example.com
に,本番環境で動作するアプリケーションではURLを www.example.com
にする場合です.
環境ごとにイメージを作成
こうした場面で考えられる最も単純な方法は,開発環境と本番環境に対応するコンテナイメージをそれぞれ準備することです.この方法では,環境が増えるにつれ次にあげる2つの問題が存在します.
- コンテナイメージの種類が増え,管理する手間が増加
- コンテナレジストリの容量を消費
単一イメージを環境変数や設定ファイルで制御
単一のコンテナイメージを設定パラメータにより制御する方法があります.ここでの設定パラメータとは,環境変数や設定ファイルを指します.例えば開発環境では,それ用の設定ファイルをコンテナへ起動時にコピーしたり,環境変数として設定を渡したりすることで開発環境用の設定を適用させます.同様に本番環境でも,対応した設定ファイルや環境変数に割り当てることでコンテナの動作を制御します.
この手法は,単一のコンテナイメージを設定パラメータ(設定ファイルや環境変数)で制御することにより,複数の環境への対応を柔軟に行えます.コンテナでアプリケーションの動作を制御する場合,この手法を使うことが一般的です.
環境変数と設定ファイル
環境変数と設定ファイルをKubernetesで指定する方法はいくつかあります.以降ではその1つであるConfigMapとSecretを説明します.