はじめに
この記事はCertified Kubernetes Administrator資格取るために復習の目的書いています。この記事はクラスターのアーキテクチャの部分のみとなります。
内容追加していったら、いつの間にかアーキテクチャを大きく超える内容になってしまいました(涙)
2021/2/26 - この記事を投稿
2021/3/13 - CKA受験し、 合格しました (約2週間かかりました!!)
2021/3/13(土) 20:00 - 自宅で受験(子供の風呂終わってから受験しました)
2021/3/15(月) 08:02 - 合格メール受信
試験のアウトラインが以下のようになっています。
Sn | Domain | Weight |
---|---|---|
1 | Cluster Architecture, Installation & Configuration | 25% |
2 | Workloads & Scheduling | 15% |
3 | Services & Networking | 20% |
4 | Storage | 10% |
5 | Troubleshooting | 30 |
出題範囲 |
Kubernetesとは
Kubernetesとはコンテナー化したアプリケーションをオーケストレーションするためのプラットフォーム。飛行機操縦士を意味するギリシャ語から由来した名称だそうです。
公式サイトの説明
Kubernetes is a portable, extensible, open-source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation. It has a large, rapidly growing ecosystem. Kubernetes services, support, and tools are widely available.
The name Kubernetes originates from Greek, meaning helmsman or pilot.
デプロイメントの種類
この図だけで十分伝わるであろうという事で説明を省く(笑)Kubernetesの構成
k8sクラスターは下記2種類のもので構成されている。
- Node (以前はworker node)
- Control plane(以前はmaster node)
Node(以前はworker node)
Nodeは単純にコンピューターの事です。物理または仮想、どちらでもあり得る。僕らが作ったコンテナーアプリケーションが、
- podという箱に梱包され、
- nodeの中にデプロイされます
☞1つのnodeに複数のpodが存在します
☞1つのpodに1以上のコンテナーが存在します
ノードが以下のコンポネントを持つ
- kubelet
- kube-proxy
- container runtime
- Addons
- DNS
- Web UI (Dashboard)
- Container Resource Monitoring
- Cluster Level Logging
Control Plane(以前はmaster node)
K8s全体の管理(コントロール)するのが「control plane」です。ノードと同じく物理又は仮想コンピュータです。
以下の要素で構成されている
- Kube API Server
- etcd
- Kube Scheduler
- Kube Controller Manager
- Cloud Control Manager
Control Planeの構成
Kube API Server
クラスターを管理するために「Control Plane」と「node」の様々なコンポーネントとやり取りするためにAPIを公開する。
kubeadmを使ってクラスタを作成した場合はstatic podとしてデプロイされる。
Podの定義の例
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=172.17.0.21
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
- --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
- --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
- --etcd-servers=https://127.0.0.1:2379
- --insecure-port=0
- --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
- --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
- --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
- --requestheader-allowed-names=front-proxy-client
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --requestheader-extra-headers-prefix=X-Remote-Extra-
- --requestheader-group-headers=X-Remote-Group
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-cluster-ip-range=10.96.0.0/12
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
image: k8s.gcr.io/kube-apiserver:v1.19.0
name: kube-apiserver
volumeMounts:
- mountPath: /etc/ssl/certs
name: ca-certs
readOnly: true
- mountPath: /etc/ca-certificates
name: etc-ca-certificates
readOnly: true
- mountPath: /etc/kubernetes/pki
name: k8s-certs
readOnly: true
- mountPath: /usr/local/share/ca-certificates
name: usr-local-share-ca-certificates
readOnly: true
- mountPath: /usr/share/ca-certificates
name: usr-share-ca-certificates
readOnly: true
hostNetwork: true
priorityClassName: system-node-critical
volumes:
- hostPath:
path: /etc/ssl/certs
type: DirectoryOrCreate
name: ca-certs
- hostPath:
path: /etc/ca-certificates
type: DirectoryOrCreate
name: etc-ca-certificates
- hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate
name: k8s-certs
- hostPath:
path: /usr/local/share/ca-certificates
type: DirectoryOrCreate
name: usr-local-share-ca-certificates
- hostPath:
path: /usr/share/ca-certificates
type: DirectoryOrCreate
name: usr-share-ca-certificates
etcd
Key-Value系の分散型データベースです。クラスターのすべてのデータがここに保管されます。
kubeadmを使ってクラスタを作成した場合はstatic podとしてデプロイされる。
podの定義の例
apiVersion: v1
kind: Pod
metadata:
name: etcd
namespace: kube-system
spec:
containers:
- command:
- etcd
- --advertise-client-urls=https://172.17.0.21:2379 # これがetcdがListenする情報。KubeApiServerに設定する必要がある。
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --client-cert-auth=true
- --data-dir=/var/lib/etcd
- --initial-advertise-peer-urls=https://172.17.0.21:2380
- --initial-cluster=controlplane=https://172.17.0.21:2380
- --key-file=/etc/kubernetes/pki/etcd/server.key
- --listen-client-urls=https://127.0.0.1:2379,https://172.17.0.21:2379
- --listen-metrics-urls=http://127.0.0.1:2381
- --listen-peer-urls=https://172.17.0.21:2380
- --name=controlplane
- --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
- --peer-client-cert-auth=true
- --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --snapshot-count=10000
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
image: k8s.gcr.io/etcd:3.4.9-1
name: etcd
volumeMounts:
- mountPath: /var/lib/etcd
name: etcd-data
- mountPath: /etc/kubernetes/pki/etcd
name: etcd-certs
hostNetwork: true
priorityClassName: system-node-critical
volumes:
- hostPath:
path: /etc/kubernetes/pki/etcd
type: DirectoryOrCreate
name: etcd-certs
- hostPath:
path: /var/lib/etcd
type: DirectoryOrCreate
name: etcd-data
etcdを操作するためにetcdctlを使います。バージョン2と3でコマンドが少し違うのでバージョンしてコマンドを実行するのがポイント!
以下はetcdに保存しているデータのKeyのみ取得するコマンドです。
kubectl exec etcd-controlplane -n kube-system -- sh -c "ETCDCTL_API=3 etcdctl get / --prefix --keys-only --limit=10 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key"
Kube Scheduler
「pod」が作成されたけど、配置するノードがまだ決まっていないものを監視し、適切なノードを選ぶ。
※「kube scheduler」はどのノードに配置すべきか教えてくれるのみです。ノードの能力、Taint・Tolerationの設定等みて最適なノードを教えてくれます。実際にノードに配置するのが、「kubelet」の役割です。
逆に「kube scheduler」がないとpodが自動的にノードに配置されないため、明示的にノードを指定する必要がある。
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
nodeName: node01 # このようにノードを指定する
containers:
- image: nginx
name: mycontainer
kubeadmを使ってクラスタを作成した場合はstatic podとしてデプロイされる。
Podの定義の例
apiVersion: v1
kind: Pod
metadata:
name: kube-scheduler
namespace: kube-system
spec:
containers:
- command:
- kube-scheduler
- --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
- --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
- --bind-address=127.0.0.1
- --kubeconfig=/etc/kubernetes/scheduler.conf
- --leader-elect=true
- --port=0
image: k8s.gcr.io/kube-scheduler:v1.19.0
name: kube-scheduler
volumeMounts:
- mountPath: /etc/kubernetes/scheduler.conf
name: kubeconfig
readOnly: true
hostNetwork: true
priorityClassName: system-node-critical
volumes:
- hostPath:
path: /etc/kubernetes/scheduler.conf
type: FileOrCreate
name: kubeconfig
Kube Controller Manager
以下の4種類のコントローラーで構成されている。
- Node Controller:「node」が停止した時に知らせる役割
- Replication Controller:常に設定した「pod」の数を保持する
- Endpoints Controller:「service」と「pod」の紐づけのためのエンドポイントの注入
- Service Account & Token Controllers:新しいnamespaceを作った時に必要となるアカウントとAPIアクセストークンの作成
※ 複雑さをなくすために上記の4つの独立したプロセスを1つのバイナリにまとめられました。
kubeadmを使ってクラスタを作成した場合はstatic podとしてデプロイされる。
Podの定義の例
apiVersion: v1
kind: Pod
metadata:
name: kube-controller-manager
namespace: kube-system
spec:
containers:
- command:
- kube-controller-manager
- --allocate-node-cidrs=true
- --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
- --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
- --bind-address=127.0.0.1
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --cluster-cidr=10.244.0.0/16
- --cluster-name=kubernetes
- --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
- --cluster-signing-key-file=/etc/kubernetes/pki/ca.key
- --controllers=*,bootstrapsigner,tokencleaner
- --kubeconfig=/etc/kubernetes/controller-manager.conf
- --leader-elect=true
- --node-cidr-mask-size=24
- --port=0
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --root-ca-file=/etc/kubernetes/pki/ca.crt
- --service-account-private-key-file=/etc/kubernetes/pki/sa.key
- --service-cluster-ip-range=10.96.0.0/12
- --use-service-account-credentials=true
image: k8s.gcr.io/kube-controller-manager:v1.19.0
name: kube-controller-manager
volumeMounts:
- mountPath: /etc/ssl/certs
name: ca-certs
readOnly: true
- mountPath: /etc/ca-certificates
name: etc-ca-certificates
readOnly: true
- mountPath: /usr/libexec/kubernetes/kubelet-plugins/volume/exec
name: flexvolume-dir
- mountPath: /etc/kubernetes/pki
name: k8s-certs
readOnly: true
- mountPath: /etc/kubernetes/controller-manager.conf
name: kubeconfig
readOnly: true
- mountPath: /usr/local/share/ca-certificates
name: usr-local-share-ca-certificates
readOnly: true
- mountPath: /usr/share/ca-certificates
name: usr-share-ca-certificates
readOnly: true
hostNetwork: true
priorityClassName: system-node-critical
volumes:
- hostPath:
path: /etc/ssl/certs
type: DirectoryOrCreate
name: ca-certs
- hostPath:
path: /etc/ca-certificates
type: DirectoryOrCreate
name: etc-ca-certificates
- hostPath:
path: /usr/libexec/kubernetes/kubelet-plugins/volume/exec
type: DirectoryOrCreate
name: flexvolume-dir
- hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate
name: k8s-certs
- hostPath:
path: /etc/kubernetes/controller-manager.conf
type: FileOrCreate
name: kubeconfig
- hostPath:
path: /usr/local/share/ca-certificates
type: DirectoryOrCreate
name: usr-local-share-ca-certificates
- hostPath:
path: /usr/share/ca-certificates
type: DirectoryOrCreate
name: usr-share-ca-certificates
Cloud Control Manager
クラウトプロバイダーとリンクするためのもの。オンプレミスで使う場合は不要。
補足
上でkubeadmを使った場合と記載しましたが、それ以外に、サービスとして使う場合はもあります。各コンポーネントのバイナリが用意されてあるので、ダウンロードしてサービスとして実行するだけです。
nodeの構成
Kubelet
k8sクラスターの各ノードに配置されるエージェントです。podのスペックで定義してあるようにコンテナーが動いている事を保証してくれる。
/usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
--kubeconfig=/etc/kubernetes/kubelet.conf \
--config=/var/lib/kubelet/config.yaml \
--network-plugin=cni \
--pod-infra-container-image=k8s.gcr.io/pause:3.2 \
--cni-bin-dir=/opt/cni/bin \
--cni-conf-dir=/etc/cni/net.d
パラメーターで渡した設定ファイルの中身
$ cat /etc/kubernetes/kubelet.conf
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: LS0tL....<base64 encoded data>LS0tCg==
server: https://172.17.0.14:6443 #kube-api-serverの情報
name: default-cluster
contexts:
- context:
cluster: default-cluster
namespace: default
user: default-auth
name: default-context
current-context: default-context
preferences: {}
users:
- name: default-auth
user:
client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
cgroupDriver: systemd
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
logging: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
resolvConf: /run/systemd/resolve/resolv.conf
rotateCertificates: true
runtimeRequestTimeout: 0s
staticPodPath: /etc/kubernetes/manifests # ここにstatic podの定義ファイルが置いてある
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
※ 「--cni-conf-dir」のデフォルト値が「/etc/cni/net.d」です。なので、このパラメーターを指定しなかった場合はが自動的に「--cni-conf-dir=/etc/cni/net.d」とセットされる。
controlplane $ ls -al /etc/cni/net.d
total 12
drwxr-xr-x 2 root root 4096 Mar 7 04:22 .
drwxr-xr-x 3 root root 4096 Mar 7 04:21 ..
-rw-r--r-- 1 root root 318 Mar 7 04:22 10-weave.conflist
# ここを見るとたくさんのプラグインの中に「weave」を使っている事がわかる。
controlplane $ cat /etc/cni/net.d/10-weave.conflist
{
"cniVersion": "0.3.0",
"name": "weave",
"plugins": [
{
"name": "weave",
"type": "weave-net",
"hairpinMode": true
},
{
"type": "portmap",
"capabilities": {"portMappings": true},
"snat": true
}
]
}
Kube Proxy
各ノードに配置してあるネットワークプロクシである。
Podとクラスターの各コンポーネントの間に通信できるように各ノードにネットワークルールを作る。
サービスを作成した時に他のノードから通信できるようにVIPを割り当ててくれる。
/usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf \
--hostname-override=node01
kube-api-serverに指定した「-service-cluster-ip-range=10.96.0.0/12」の範囲でIPが設定されます。
パラメーターで渡した設定ファイルの中身
# controlplane$ kubectl exec kube-proxy-55bw8 -n kube-system -- cat /var/lib/kube-proxy/config.conf
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
bindAddressHardFail: false
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 0
clusterCIDR: 10.244.0.0/16 # kube-api-serverに指定した「-service-cluster-ip-range=10.96.0.0/12」の範囲
configSyncPeriod: 0s
conntrack:
maxPerCore: null
min: null
tcpCloseWaitTimeout: null
tcpEstablishedTimeout: null
detectLocalMode: ""
enableProfiling: false
healthzBindAddress: ""
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: null
minSyncPeriod: 0s
syncPeriod: 0s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
strictARP: false
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: ""
nodePortAddresses: null
oomScoreAdj: null
portRange: ""
showHiddenMetricsForVersion: ""
udpIdleTimeout: 0s
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
※実は、「kube-proxy」podの中身を見ると、ConfigMapをマウントしていることが分かる。
controlplane $ kubectl get pods -A |grep proxy
kube-system kube-proxy-dgdbc 1/1 Running 0 106m
kube-system kube-proxy-tj6bm 1/1 Running 2 106m
controlplane $ kubectl describe pod kube-proxy-dgdbc -n kube-system
Name: kube-proxy-dgdbc
Namespace: kube-system
Priority: 2000001000
Priority Class Name: system-node-critical
Node: controlplane/172.17.0.11
Start Time: Sun, 07 Mar 2021 02:17:54 +0000
Labels: controller-revision-hash=ff45b7d7d
k8s-app=kube-proxy
pod-template-generation=1
Annotations: <none>
Status: Running
IP: 172.17.0.11
IPs:
IP: 172.17.0.11
Controlled By: DaemonSet/kube-proxy
Containers:
kube-proxy:
Container ID: docker://222569a30d2a14c6e2c132a649420bd14131407f046757a08bfe9aa22b70bd73
Image: k8s.gcr.io/kube-proxy:v1.19.0
Image ID: docker-pullable://k8s.gcr.io/kube-proxy@sha256:c752ecbd04bc4517168a19323bb60fb45324eee1e480b2b97d3fd6ea0a54f42d
Port: <none>
Host Port: <none>
Command:
/usr/local/bin/kube-proxy
--config=/var/lib/kube-proxy/config.conf
--hostname-override=$(NODE_NAME)
State: Running
Started: Sun, 07 Mar 2021 02:17:55 +0000
Ready: True
Restart Count: 0
Environment:
NODE_NAME: (v1:spec.nodeName)
Mounts:
/lib/modules from lib-modules (ro)
/run/xtables.lock from xtables-lock (rw)
/var/lib/kube-proxy from kube-proxy (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-proxy-token-dszlh (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-proxy:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: kube-proxy
Optional: false
xtables-lock:
Type: HostPath (bare host directory volume)
Path: /run/xtables.lock
HostPathType: FileOrCreate
lib-modules:
Type: HostPath (bare host directory volume)
Path: /lib/modules
HostPathType:
kube-proxy-token-dszlh:
Type: Secret (a volume populated by a Secret)
SecretName: kube-proxy-token-dszlh
Optional: false
QoS Class: BestEffort
Node-Selectors: kubernetes.io/os=linux
Tolerations: op=Exists
CriticalAddonsOnly op=Exists
node.kubernetes.io/disk-pressure:NoSchedule op=Exists
node.kubernetes.io/memory-pressure:NoSchedule op=Exists
node.kubernetes.io/network-unavailable:NoSchedule op=Exists
node.kubernetes.io/not-ready:NoExecute op=Exists
node.kubernetes.io/pid-pressure:NoSchedule op=Exists
node.kubernetes.io/unreachable:NoExecute op=Exists
node.kubernetes.io/unschedulable:NoSchedule op=Exists
Events: <none>
controlplane $ kubectl describe configmap kube-proxy -n kube-system
Name: kube-proxy
Namespace: kube-system
Labels: app=kube-proxy
Annotations: kubeadm.kubernetes.io/component-config.hash: sha256:03c1a617b659fb4ef8617f375a89eef168bcd3a0d86f662f1bf20849fce238a9
Data
====
config.conf:
----
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
bindAddressHardFail: false
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 0
clusterCIDR: 10.244.0.0/16
configSyncPeriod: 0s
conntrack:
maxPerCore: null
min: null
tcpCloseWaitTimeout: null
tcpEstablishedTimeout: null
detectLocalMode: ""
enableProfiling: false
healthzBindAddress: ""
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: null
minSyncPeriod: 0s
syncPeriod: 0s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
strictARP: false
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: ""
nodePortAddresses: null
oomScoreAdj: null
portRange: ""
showHiddenMetricsForVersion: ""
udpIdleTimeout: 0s
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
kubeconfig.conf:
----
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
server: https://172.17.0.11:6443
name: default
contexts:
- context:
cluster: default
namespace: default
user: default
name: default
current-context: default
users:
- name: default
user:
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
Events: <none>
Container Runtime
コンテナーを動かすためのランタイムである。Docker以外にcontainered,CRI-O,などサポートしている。
Addons
クラスターレベルの機能を実装するためのもの。例えば、DaemonSet, Deployement.「kube-system」というnamespaceに所属する。
DNS
DNSサーバーの事です。
中身チェック
controlplane $ kubectl get pods -A -o wide -n kube-system
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
default nginx 1/1 Running 0 16m 10.32.0.3 node01 <none> <none>
kube-system coredns-f9fd979d6-gt9h2 1/1 Running 2 32m 10.32.0.2 node01 <none> <none>
kube-system coredns-f9fd979d6-n5bkk 1/1 Running 0 32m 10.44.0.1 controlplane <none> <none>
kube-system etcd-controlplane 1/1 Running 0 87m 172.17.0.11 controlplane <none> <none>
kube-system kube-apiserver-controlplane 1/1 Running 0 87m 172.17.0.11 controlplane <none> <none>
kube-system kube-controller-manager-controlplane 1/1 Running 0 87m 172.17.0.11 controlplane <none> <none>
kube-system kube-proxy-dgdbc 1/1 Running 0 87m 172.17.0.11 controlplane <none> <none>
kube-system kube-proxy-tj6bm 1/1 Running 2 86m 172.17.0.15 node01 <none> <none>
kube-system kube-scheduler-controlplane 1/1 Running 0 87m 172.17.0.11 controlplane <none> <none>
kube-system weave-net-wcsh5 2/2 Running 3 33m 172.17.0.15 node01 <none> <none>
kube-system weave-net-x5zh2 2/2 Running 1 33m 172.17.0.11 controlplane <none> <none>
controlplane $ kubectl logs coredns-f9fd979d6-gt9h2 -n kube-system
.:53
[INFO] plugin/reload: Running configuration MD5 = db32ca3650231d74073ff4cf814959a7
CoreDNS-1.7.0
linux/amd64, go1.14.4, f59c03d
# corednsというConfigMapがマウントされている事に注目
controlplane $ kubectl describe pod coredns-f9fd979d6-gt9h2 -n kube-system
Name: coredns-f9fd979d6-gt9h2
Namespace: kube-system
Priority: 2000000000
Priority Class Name: system-cluster-critical
Node: node01/172.17.0.15
Start Time: Sun, 07 Mar 2021 03:12:45 +0000
Labels: k8s-app=kube-dns
pod-template-hash=f9fd979d6
Annotations: <none>
Status: Running
IP: 10.32.0.2
IPs:
IP: 10.32.0.2
Controlled By: ReplicaSet/coredns-f9fd979d6
Containers:
coredns:
Container ID: docker://883a8b5d3e52f30990132ad757185eeea8298b27db3a04d7e0a72ae3e83f7afb
Image: k8s.gcr.io/coredns:1.7.0
Image ID: docker-pullable://k8s.gcr.io/coredns@sha256:73ca82b4ce829766d4f1f10947c3a338888f876fbed0540dc849c89ff256e90c
Ports: 53/UDP, 53/TCP, 9153/TCP
Host Ports: 0/UDP, 0/TCP, 0/TCP
Args:
-conf
/etc/coredns/Corefile
State: Running
Started: Sun, 07 Mar 2021 03:13:52 +0000
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Sun, 07 Mar 2021 03:13:27 +0000
Finished: Sun, 07 Mar 2021 03:13:37 +0000
Ready: True
Restart Count: 2
Limits:
memory: 170Mi
Requests:
cpu: 100m
memory: 70Mi
Liveness: http-get http://:8080/health delay=60s timeout=5s period=10s #success=1 #failure=5
Readiness: http-get http://:8181/ready delay=0s timeout=1s period=10s #success=1 #failure=3
Environment: <none>
Mounts:
/etc/coredns from config-volume (ro)
/var/run/secrets/kubernetes.io/serviceaccount from coredns-token-6vm22 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
config-volume:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: coredns # ここに注目!!
Optional: false
coredns-token-6vm22:
Type: Secret (a volume populated by a Secret)
SecretName: coredns-token-6vm22
Optional: false
QoS Class: Burstable
Node-Selectors: kubernetes.io/os=linux
Tolerations: CriticalAddonsOnly op=Exists
node-role.kubernetes.io/master:NoSchedule
node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 44m default-scheduler Successfully assigned kube-system/coredns-f9fd979d6-gt9h2 to node01
Warning Unhealthy 43m (x2 over 43m) kubelet, node01 Readiness probe failed: Get "http://10.32.0.2:8181/ready": dial tcp 10.32.0.2:8181: connect: connection refused
Normal Killing 43m (x2 over 43m) kubelet, node01 Stopping container coredns
Normal SandboxChanged 43m (x6 over 43m) kubelet, node01 Pod sandbox changed, it will be killed and re-created.
Normal Pulled 43m (x3 over 44m) kubelet, node01 Container image "k8s.gcr.io/coredns:1.7.0" already present on machine
Normal Created 43m (x3 over 44m) kubelet, node01 Created container coredns
Normal Started 43m (x3 over 44m) kubelet, node01 Started container coredns
controlplane $ kubectl get configmaps -n kube-system
NAME DATA AGE
coredns 1 88m
extension-apiserver-authentication 6 88m
kube-proxy 2 88m
kubeadm-config 2 88m
kubelet-config-1.19 1 88m
weave-net 0 33m
controlplane $ kubectl describe configmap coredns -n kube-system
Name: coredns
Namespace: kube-system
Labels: <none>
Annotations: <none>
Data
====
Corefile:
----
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
Events: <none>
Web UI (Dashboard)
クラスター管理するためのウエブUI。
Container Resource Monitoring
コンテナーに関する時系列メトリックをDBに保管し、そのデータを閲覧するためのUIを提供する要素。
Cluster Level Logging
コンテナーのログを保管し、参照できるインタフェースを提供する要素。
Pod
podの作成①
apiVersion: v1
kind: Pod
metadata:
name: command-demo
labels:
purpose: demonstrate-command
spec:
containers:
- name: command-demo-container
image: debian
command: ["printenv"]
args: ["HOSTNAME", "KUBERNETES_PORT"]
restartPolicy: OnFailure
kubectl create -f my-pod-definition.yml
podの編集①
my-pod-definition.ymlを開き変更を加えます。その後applyを使って反映
kubectl apply -f my-pod-definition.yml
podの削除①
kubectl delete -f my-pod-definition.yml
※ 上記のようにファイルに定義しないでコマンド実行することでPodの様々な操作が可能。
podの作成②
# nginxを使った「my-pod」というpodを作成
kubectl run my-pod --image=nginx
# コンテナー起動時のコマンドとポートを開けた状態のpodを作成
kubectl run alpine --image=alpine --port=8080 --command -- sleep 5000
# Podとサービスを一気に作成
kubectl run alpine --image=alpine --port=8080 --expose --command -- sleep 5000
※--command=falseにするとargsとして登録されます。詳しくはkubectl run --helpにて~
※ podを作成する場合は、以下のように定義ファイルを作成してから編集するのをお勧めする。
kubectl run my-pod --image=nginx --replicas=2 --dry-run=client -o yaml > my-pod-definition.yml
Podを作成せずに定義ファイルを作ってくれるので、その後ファイルを編集するのが安心できるかも!!
podの編集②
kubectl edit pod <pod-name>
podの削除②
kubectl delete pod <pod-name>
podの情報取得
# default namespaceのすべてのpodを表示(-A or --all-namespaces追加することですべてのnamespace)
kubectl get pods
# 特定のpodの情報を取得
kubectl get pod my-pod
# 特定のpodの情報を取得
kubectl describe pod my-pod
# grepを使って必要な情報だけ取得することも可
kubectl describe pod ubuntu-sleeper | grep -i image -A1
Image: ubuntu
Image ID: docker-pullable://ubuntu@sha256:703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715
Port: <none>
# ちなみにこんなこともできるよ♪
kubectl get pods -o custom-columns=POD:.metadata.name,CONT:.spec.containers[0].name,IMG:.spec.containers[0].image
POD CONT IMG
ubuntu-sleeper ubuntu ubuntu
ubuntu-sleeper-2 ubuntu ubuntu
ubuntu-sleeper-3 ubuntu ubuntu
※ 詳しくは、kubectl get pod --help
ログの表示
# 特定のpodのログを表示
kubectl logs <pod-name>
# 複数コンテナーがある場合はコンテナーの指定が必要
kubectl logs <pod-name> -c <container-name>
※1つのPodに複数のコンテナーがある場合は「kubectl logs -c」入力してからTABキーを押すとコンテナー名が表示される。
SSH to pod
# コマンド実行のみ
kubectl exec <pod-name> -- command
# interactiveモード
kubectl exec <pod-name> -it -- sh
Replicaset
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend-rs
labels:
app: guestbook
tier: frontend
spec:
replicas: 3
# selectorがReplicationControllerには存在しない!!
selector:
matchLabels:
tier: frontend
# ここからのしたはpodの定義(apiVersionとKindを抜いたもの)
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
- ReplicationControllerは古い仕様で現在は非推奨となっている
- ReplicationControllerには「selector」が存在しない
- ReplicaSetはこの定義ファイルで設定していないpodも指定できる仕様になっている。そのためselector.matchlabelsを使う
# ReplicaSetの一覧を取得
kubectl get replicasets # OR kubectl get rs
# 特定のRelicaSetの詳細情報
kubectl describe rs frontend-rs
# ReplicaSetの変更
kubectl replace -f replicaset-def.yml
# ReplicaSetの変更(変更できる項目が限られる)
kubectl edit rs frontend-rs
# Replicasの変更(ファイル指定)
kubectl scale --replicas=2 -f replicaset-def.yml
# Replicasの変更(レプリカ名指定)
kubectl scale --replicas=2 replicaset frontend-rs
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
$ kubectl create -f deploy-def.yml
deployment.apps/nginx-deployment created
- ReplicaSetの定義をほとんど変わらない(kind=Deployment&kind=ReplicaSet)
- 実は、RelicaSetのオブジェクトを作ってからDeploymentオブジェクトを作ります(そのため、deployment実行後、「kubectl get replicasets」を実行するとReplicaSet作られたことが確認できます。
- Deploymentの場合は「replicas」プロパティが任意です(つまり指定しなくてもいい;デフォルト値=1があるため)
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-877f48f6d-7mnsw 1/1 Running 0 49s
pod/nginx-deployment-877f48f6d-9t7tk 1/1 Running 0 49s
pod/nginx-deployment-877f48f6d-n6bgf 1/1 Running 0 49s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 26m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 3/3 3 3 49s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-877f48f6d 3 3 3 49s
$ kubectl rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out
Deploymentの編集
podのテンプレートの部分以外変更してもDeploymentのROが実行されない。
Note: A Deployment's rollout is triggered if and only if the Deployment's Pod template (that is, .spec.template) is changed, for example if the labels or container images of the template are updated. Other updates, such as scaling the Deployment, do not trigger a rollout.
# 設定ファイルの中身がエディターで開かれます
kubectl edit deployment nginx-deployment
# コマンドを実行するだけでも可
kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
Deploymentの履歴の確認
$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
※コマンドで変更をした時に**--record**引数を付けると、その時のコマンドも記録してくれます。
# 「nginx=nginx:1.16.2」の先頭のnginxはコンテナー名
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.16.2 --record
deployment.apps/nginx-deployment image updated
$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 kubectl set image deployment/nginx-deployment nginx=nginx:1.16.2 --record=true
または、変更後、以下のようにアノテーションを付ける事も可能!
kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image updated to 1.16.2"
Deploymentの履歴(Revision)から詳細情報の確認
kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2
RollBack
直前のバージョンに戻す
$ kubectl rollout undo deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment rolled back
リビジョン番号を指定して戻す
# 現在のimageの確認
$ kubectl describe deployment nginx-deployment |grep -i image
kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.14.2 --record=true
Image: nginx:1.14.2
# リビジョンの一覧を指定
$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
2 kubectl set image deployment nginx-deployment nginx=nginx:1.16.2 --record=true
3 kubectl set image deployment nginx-deployment nginx=nginx:1.14.2 --record=true
# 戻したいリビジョンの中身を確認
$ kubectl rollout history deployment nginx-deployment --revision=2
deployment.apps/nginx-deployment with revision #2
Pod Template:
Labels: app=nginx
pod-template-hash=7bb7dc4b6b
Annotations: kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.16.2 --record=true
Containers:
nginx:
Image: nginx:1.16.2
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
# Rollback
$ kubectl rollout undo deployment nginx-deployment --to-revision=2
deployment.apps/nginx-deployment rolled back
# 現在のimageの確認
$ kubectl describe deployment nginx-deployment |grep -i image
kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.16.2 --record=true
Image: nginx:1.16.2
Scale Deployment
$ kubectl scale deployment nginx-deployment --replicas=10
deployment.apps/nginx-deployment scaled
# CPUの利用状況に応じて勝手にスケーリングする事も可能
$ kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
horizontalpodautoscaler.autoscaling/nginx-deployment autoscaled
$ kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
※scaleしても履歴には反映されません。理由は上でも記載しましたが、「.spec.template」以外の変更はDeployment Rolloutとしてみなされないためです。
Deployment Strategy(デプロイの戦略)
2種類ある。
①Recreate
既存のpodがすべてkillしてから新しく作る戦略。
spec:
replicas: 3
strategy:
type: Recreate
②RollingUpdate
一気にすべて削除するのではなく、部分的にkillし、新しいpodを作成する戦略。
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0 # どれぐらいのpodが起動していればdeploymentを続けるかの戦略
# podの個数でもOK、個数のパーセンテージでもOK
# defalut=25%(0を指定してもデフォルト値になる)
# 例、30%が設定された場合
# maxUnavailable=30%とは、AVAILABLE=70%となる
# つまり、70%のpodが起動していれば、ほかのpodをkillしてUpdateが可能
# 今度Updateされた分を入れて70%を起動すればほかのpodをkillする事が可能
maxSurge: 2 # 一回にどれぐらいの新しいpodを作るかの戦略
# podの個数でもOK、個数のパーセンテージでもOK
# defalut=25%(0を指定してもデフォルト値になる)
# 例、30%が設定された場合
# 古いと新しいpodの数がDesired pod数の130%まで作成可能
# 古いpodを削除し、また130%なるように新しいpodを作成する
# maxUnavailableとmaxSurge両方ゼロに設定してはいけません!
コマンドを叩いてデプロイする方法 (Imperative Way)
kubectl create deployment webapp --image=nginx --replicas=3 --dry-run=client -o yaml
「kubectl create deployment」の使い方
$ kubectl create deployment --help
Create a deployment with the specified name.
Aliases:
deployment, deploy
Examples:
# Create a deployment named my-dep that runs the busybox image.
kubectl create deployment my-dep --image=busybox
# Create a deployment with command
kubectl create deployment my-dep --image=busybox -- date
# Create a deployment named my-dep that runs the nginx image with 3 replicas.
kubectl create deployment my-dep --image=nginx --replicas=3
# Create a deployment named my-dep that runs the busybox image and expose port 5701.
kubectl create deployment my-dep --image=busybox --port=5701
Options:
--allow-missing-template-keys=true: If true, ignore any errors in templates when a field or
map key is missing in the template. Only applies to golang and jsonpath output formats.
--dry-run='none': Must be "none", "server", or "client". If client strategy, only print the
object that would be sent, without sending it. If server strategy, submit server-side request
without persisting the resource.
--field-manager='kubectl-create': Name of the manager used to track field ownership.
--image=[]: Image names to run.
-o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
--port=-1: The port that this container exposes.
-r, --replicas=1: Number of replicas to create. Default is 1.
--save-config=false: If true, the configuration of current object will be saved in its
annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to
perform kubectl apply on this object in the future.
--template='': Template string or path to template file to use when -o=go-template,
-o=go-template-file. The template format is golang templates
[http://golang.org/pkg/text/template/#pkg-overview].
--validate=true: If true, use a schema to validate the input before sending it
Usage:
kubectl create deployment NAME --image=image -- [COMMAND] [args...] [options]
Use "kubectl options" for a list of global command-line options (applies to all commands).
コマンドを叩いてデプロイする方法 (Imperative Way)
# Create a service redis-service to expose the redis application within the cluster on port 6379.
kubectl expose pod redis --port=6379 --type=ClusterIP --name=redis-service --dry-run=client -o yaml
「kubectl expose」の使い方
$ kubectl expose --help
Expose a resource as a new Kubernetes service.
Looks up a deployment, service, replica set, replication controller or pod by name and uses the
selector for that resource as the selector for a new service on the specified port. A deployment or
replica set will be exposed as a service only if its selector is convertible to a selector that
service supports, i.e. when the selector contains only the matchLabels component. Note that if no
port is specified via --port and the exposed resource has multiple ports, all will be re-used by the
new service. Also if no labels are specified, the new service will re-use the labels from the
resource it exposes.
Possible resources include (case insensitive):
pod (po), service (svc), replicationcontroller (rc), deployment (deploy), replicaset (rs)
Examples:
# Create a service for a replicated nginx, which serves on port 80 and connects to the containers
on port 8000.
kubectl expose rc nginx --port=80 --target-port=8000
# Create a service for a replication controller identified by type and name specified in
"nginx-controller.yaml", which serves on port 80 and connects to the containers on port 8000.
kubectl expose -f nginx-controller.yaml --port=80 --target-port=8000
# Create a service for a pod valid-pod, which serves on port 444 with the name "frontend"
kubectl expose pod valid-pod --port=444 --name=frontend
# Create a second service based on the above service, exposing the container port 8443 as port 443
with the name "nginx-https"
kubectl expose service nginx --port=443 --target-port=8443 --name=nginx-https
# Create a service for a replicated streaming application on port 4100 balancing UDP traffic and
named 'video-stream'.
kubectl expose rc streamer --port=4100 --protocol=UDP --name=video-stream
# Create a service for a replicated nginx using replica set, which serves on port 80 and connects
to the containers on port 8000.
kubectl expose rs nginx --port=80 --target-port=8000
# Create a service for an nginx deployment, which serves on port 80 and connects to the containers
on port 8000.
kubectl expose deployment nginx --port=80 --target-port=8000
Options:
--allow-missing-template-keys=true: If true, ignore any errors in templates when a field or
map key is missing in the template. Only applies to golang and jsonpath output formats.
--cluster-ip='': ClusterIP to be assigned to the service. Leave empty to auto-allocate, or set
to 'None' to create a headless service.
--dry-run='none': Must be "none", "server", or "client". If client strategy, only print the
object that would be sent, without sending it. If server strategy, submit server-side request
without persisting the resource.
--external-ip='': Additional external IP address (not managed by Kubernetes) to accept for the
service. If this IP is routed to a node, the service can be accessed by this IP in addition to its
generated service IP.
--field-manager='kubectl-expose': Name of the manager used to track field ownership.
-f, --filename=[]: Filename, directory, or URL to files identifying the resource to expose a
service
--generator='service/v2': The name of the API generator to use. There are 2 generators:
'service/v1' and 'service/v2'. The only difference between them is that service port in v1 is named
'default', while it is left unnamed in v2. Default is 'service/v2'.
-k, --kustomize='': Process the kustomization directory. This flag can't be used together with -f
or -R.
-l, --labels='': Labels to apply to the service created by this call.
--load-balancer-ip='': IP to assign to the LoadBalancer. If empty, an ephemeral IP will be
created and used (cloud-provider specific).
--name='': The name for the newly created object.
-o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
--overrides='': An inline JSON override for the generated object. If this is non-empty, it is
used to override the generated object. Requires that the object supply a valid apiVersion field.
--port='': The port that the service should serve on. Copied from the resource being exposed,
if unspecified
--protocol='': The network protocol for the service to be created. Default is 'TCP'.
--record=false: Record current kubectl command in the resource annotation. If set to false, do
not record the command. If set to true, record the command. If not set, default to updating the
existing annotation value only if one already exists.
-R, --recursive=false: Process the directory used in -f, --filename recursively. Useful when you
want to manage related manifests organized within the same directory.
--save-config=false: If true, the configuration of current object will be saved in its
annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to
perform kubectl apply on this object in the future.
--selector='': A label selector to use for this service. Only equality-based selector
requirements are supported. If empty (the default) infer the selector from the replication
controller or replica set.)
--session-affinity='': If non-empty, set the session affinity for the service to this; legal
values: 'None', 'ClientIP'
--target-port='': Name or number for the port on the container that the service should direct
traffic to. Optional.
--template='': Template string or path to template file to use when -o=go-template,
-o=go-template-file. The template format is golang templates
[http://golang.org/pkg/text/template/#pkg-overview].
--type='': Type for this service: ClusterIP, NodePort, LoadBalancer, or ExternalName. Default
is 'ClusterIP'.
Usage:
kubectl expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP|SCTP]
[--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type]
[options]
Use "kubectl options" for a list of global command-line options (applies to all commands).
ちなみに上記の場合は「redis」podがすでに存在している前提です。以下のようにpodとサービスを1つのコマンドを実行して作ることも可能です。redis名前のpodとredis名前のサービスが作られる。
kubectl run redis --image=redis --port=6379 --expose
TODO - 下記のついては追って記載する。
- DaemonSet
Service
podがいつ終了し、再作成されるかわからない。再生されるたびにIPアドレスが変わる可能性がある。1つのpodから別のpodへipアドレスでアクセスすると、ipが変われば使えなくなる。そのあたりをDNS名を利用し、podが再作成されてもアクセスできるようにするのがこの「service」という仕組み。podが何個作成されても1つのサービス名でアクセスできる。1つのIPアドレスをクラスタ内に公開し、そこにアクセスされたら、あらかじめ設定したルールに沿ってpodに転送するからくりです。
クラスタに公開する方法として下記4種類がある。
- ClusterIp
- NodePort
- LoadBalancer
- ExternalName
ClusterIP
ClusterIPは、クラスタ内からのみアクセスできるIPアドレスを公開する。これはデフォルトのサービスタイプです。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
NodePort
nodeの特定のポートを公開し、そこで受けたアクセスをpodに転送してくれる。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: MyApp
ports:
# By default and for convenience, the `targetPort` is set to the same value as the `port` field.
- port: 80
targetPort: 80
# Optional field
# By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
nodePort: 30007
Loadbalancer
各サービスをパブリックIPを使って公開する仕組みです。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
ここから下はハンズオンの形にしたい。そっちのほうが分かりやすいと思う!!
先ずは、以下のリソースを作成します。
- 複数ノードに配置されるアプリケーション「my-deployment」
- ClusterIpを使ったサービス「clusterip-service-to-nginx-deployment」
- NodePortを使ったサービス「nodeport-service-to-nginx-deployment」
- テスト用のpod「nginx-node1 」
$ kubectl get all -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
pod/my-deployment-57d86476b6-75c2w 1/1 Running 0 17m 10.40.0.3 node02 <none> <none> app=my-deployment,pod-template-hash=57d86476b6
pod/my-deployment-57d86476b6-dhnm7 1/1 Running 0 17m 10.46.0.3 node01 <none> <none> app=my-deployment,pod-template-hash=57d86476b6
pod/my-deployment-57d86476b6-htrfk 1/1 Running 0 17m 10.32.0.3 node03 <none> <none> app=my-deployment,pod-template-hash=57d86476b6
pod/my-deployment-57d86476b6-shlb9 1/1 Running 0 17m 10.46.0.2 node01 <none> <none> app=my-deployment,pod-template-hash=57d86476b6
pod/my-deployment-57d86476b6-twn4s 1/1 Running 0 17m 10.32.0.2 node03 <none> <none> app=my-deployment,pod-template-hash=57d86476b6
pod/nginx-node1 1/1 Running 0 39m 10.46.0.1 node01 <none> <none> node=node01,tier=frontend
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR LABELS
service/clusterip-service-to-nginx-deployment ClusterIP 10.106.173.106 <none> 8080/TCP 5m31s app=my-deployment app=clusterip-service-to-nginx-deployment
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 47m <none> component=apiserver,provider=kubernetes
service/nodeport-service-to-nginx-deployment NodePort 10.103.219.247 <none> 8080:31592/TCP 11m app=my-deployment app=nodeport-service-to-nginx-deployment
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR LABELS
deployment.apps/my-deployment 5/5 5 5 17m nginx nginx app=my-deployment app=my-deployment
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR LABELS
replicaset.apps/my-deployment-57d86476b6 5 5 5 17m nginx nginx app=my-deployment,pod-template-hash=57d86476b6 app=my-deployment,pod-template-hash=57d86476b6
上記の状態でテスト用のpod「nginx-node1」から通信できるかテストしてみます。
# NodePortを使って通信
$ kubectl exec nginx-node1 -- curl http://nodeport-service-to-nginx-deployment:8080
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
<!DOCTYPE html>
<html>
<head>
...
省略
# ClusterIPを使って通信
$ kubectl exec nginx-node1 -- curl http://clusterip-service-to-nginx-deployment:8080
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 612 100 612 0 0 99k 0 --:--:-- --:--:-- --:--:-- 99k
<!DOCTYPE html>
<html>
...
省略
どちらでも問題なくアクセスできてます。このようにpodをほかからアクセスできるようにする仕組みがサービスです。
しかし、クラスターの外からアクセスすると通信ができません。
# NodePortを使って通信
$ curl http://nodeport-service-to-nginx-deployment:8080
curl: (6) Could not resolve host: nodeport-service-to-nginx-deployment
# ClusterIPを使って通信
$ curl http://clusterip-service-to-nginx-deployment:8080
curl: (6) Could not resolve host: clusterip-service-to-nginx-deployment
この時にNodePortの仕組みを利用すれば、実は外からも通信できます。
# 公開ポート(=31592)の確認
$ kubectl get svc nodeport-service-to-nginx-deployment -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nodeport-service-to-nginx-deployment NodePort 10.103.219.247 <none> 8080:31592/TCP 27m app=my-deployment
# 各ノードのIPアドレス確認
controlplane $ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
controlplane Ready master 49m v1.19.0 172.17.0.12 <none> Ubuntu 18.04.5 LTS 4.15.0-122-generic docker://19.3.13
node01 Ready <none> 49m v1.19.0 172.17.0.13 <none> Ubuntu 18.04.5 LTS 4.15.0-122-generic docker://19.3.13
node02 Ready <none> 49m v1.19.0 172.17.0.15 <none> Ubuntu 18.04.5 LTS 4.15.0-122-generic docker://19.3.13
node03 Ready <none> 49m v1.19.0 172.17.0.24 <none> Ubuntu 18.04.5 LTS 4.15.0-122-generic docker://19.3.13
# node01のアプリケーションと通信(http://<node-ip>:31592)
$ curl http://172.17.0.13:31592
<!DOCTYPE html>
...
省略
# node02のアプリケーションと通信(http://<node-ip>:31592)
$ curl http://172.17.0.15:31592
<!DOCTYPE html>
...
省略
# node03のアプリケーションと通信(http://<node-ip>:31592)
$ curl http://172.17.0.24:31592
<!DOCTYPE html>
...
省略
ポート番号は、kube-api-serverを起動する時に指定した「--service-node-port-range」の値の範囲内に指定する必要があります。kube-api-serverに指定しなかった場合は、デフォルトで30000-32767が設定されます。
でも、ノードのIP指定しないといけないのが不便ですよね。
これを解決するために「LoadBalancer」があります。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
**クラスター外からアクセスできるIPアドレスが各サービスに設定されます。そのため、複数サービスを利用したい場合はその数のIPアドレスが必要です。**クラウド上で利用した場合はIPアドレスの購入が必要かもしれません。
これらの3つのサービスをまとめると
- clusterip: クラスター外からアクセスができない
- nodeport: クラスター外からアクセスできるが、ノードのIPを指定する必要がある
- loadbalancer: ノードのIPを気にしなくて済むが、サービスが複数ある場合はコストが高い
ここで登場するのがINGRESS様だ!
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wildcard-host
spec:
rules:
- host: "foo.bar.com"
http:
paths:
- pathType: Prefix
path: "/bar"
backend:
service:
name: service1
port:
number: 80
- host: "*.foo.com"
http:
paths:
- pathType: Prefix
path: "/foo"
backend:
service:
name: service2
port:
number: 80
Ingress 使うには下記が必要
- アプリケーション
- アプリケーション公開用サービス
- Ingressコントローラー
- Ingress
# applications
app-space pod/webapp-video-84f8655bd8-g6wtw 1/1 Running 0 29m
app-space pod/webapp-wear-6ff9445955-jfwkp 1/1 Running 0 29m
# service
ingress-space service/ingress NodePort 10.108.18.119 <none> 80:30080/TCP 10m
# Ingress Controller
ingress-space deployment.apps/ingress-controller 1/1 1 1 21m
ingress-space pod/ingress-controller-5857685bf-qzvdr 1/1 Running 0 21m
# Ingress resource
app-space ingress-weear-watch-my <none> * 80 3m42s
詳細:公式サイトにて
apiVersion: v1
kind: ServiceAccount
metadata:
name: pvviewer
automountServiceAccountToken: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pvviewer-role
rules:
- apiGroups: [""]
resources: ["PersistentVolumes"]
verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pvviewer-role-binding
subjects:
- kind: ServiceAccount
name: pvview
namespace: default
roleRef:
kind: ClusterRole
name: pvviewer-role
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Pod
metadata:
name: pvviewer
spec:
serviceAccountName: pvviewer
automountServiceAccountToken: false
containers:
- name: redis
image: redis
jsonpath
# get the list of private volumes
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-log-1 100Mi RWX Retain Available 23m
pv-log-2 200Mi RWX Retain Available 23m
pv-log-3 300Mi RWX Retain Available 23m
pv-log-4 40Mi RWX Retain Available 23m
# first check the json format
$ kubectl get pv -o=json
{
"apiVersion": "v1",
"items": [
{
"apiVersion": "v1",
...
省略
# get the value for single pv
$ kubectl get pv pv-log-1 -o=jsonpath='{.spec.capacity.storage}{"\n"}'
100Mi
# get the value for all pv
$ kubectl get pv -o=jsonpath='{..spec.capacity.storage}{"\n"}'
100Mi 200Mi 300Mi 40Mi
# first check the item in loop
$ kubectl get pv -o=jsonpath='{range .items[0]} {@} {end}{"\n"}'
{"apiVersion":"v1","kind":"PersistentVolume","metadata":{"creationTimestamp":"2021-03-09T13:10:51Z","finalizers":["kubernetes.io/pv-protection"],"managedFields":[{"apiVersion":"v1","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:phase":{}}},"manager":"kube-controller-manager","operation":"Update","time":"2021-03-09T13:10:51Z"},{"apiVersion":"v1","fieldsType":"FieldsV1","fieldsV1":{"f:spec":{"f:accessModes":{},"f:capacity":{".":{},"f:storage":{}},"f:hostPath":{".":{},"f:path":{},"f:type":{}},"f:persistentVolumeReclaimPolicy":{},"f:volumeMode":{}}},"manager":"kubectl-create","operation":"Update","time":"2021-03-09T13:10:51Z"}],"name":"pv-log-1","resourceVersion":"4586","selfLink":"/api/v1/persistentvolumes/pv-log-1","uid":"6191ac63-c32f-4bce-9cee-1ed4892216d0"},"spec":{"accessModes":["ReadWriteMany"],"capacity":{"storage":"100Mi"},"hostPath":{"path":"/pv/log","type":""},"persistentVolumeReclaimPolicy":"Retain","volumeMode":"Filesystem"},"status":{"phase":"Available"}}
$ kubectl get pv -o=jsonpath='{range .items[0]} {@.spec} {end}{"\n"}'
{"accessModes":["ReadWriteMany"],"capacity":{"storage":"100Mi"},"hostPath":{"path":"/pv/log","type":""},"persistentVolumeReclaimPolicy":"Retain","volumeMode":"Filesystem"}
# then, search the specific item
$ kubectl get pv -o=jsonpath='{range .items[0]} {@.spec.capacity} {end}{"\n"}'
{"storage":"100Mi"}
$ kubectl get pv -o=jsonpath='{range .items[0]} {@.spec.capacity.storage} {end}{"\n"}'
100Mi
# if the item is found, then run the loop for all items
$ kubectl get pv -o=jsonpath='{range .items[*]} {@.spec.capacity.storage} {end}{"\n"}'
100Mi 200Mi 300Mi 40Mi
$ kubectl get pv -o=jsonpath='{range .items[*]} {@.spec.capacity.storage} {"\n"}{end}{"\n"}'
100Mi
200Mi
300Mi
40Mi
# sort
$ kubectl get pv -o=jsonpath='{range .items[*]} {@.spec.capacity.storage} {"\n"}{end}{"\n"}' --sort-by=.spec.capacity.storage
40Mi
100Mi
200Mi
300Mi
Another way
$ kubectl get pv -o=custom-columns=NAME:.metadata.name,CAPACITY:.spec.capacity.storage --sort-by=.spec.capacity.storage
NAME CAPACITY
pv-log-4 40Mi
pv-log-1 100Mi
pv-log-2 200Mi
pv-log-3 300Mi
Filtering
$ kubectl config view --kubeconfig=my-kube-config
apiVersion: v1
clusters:
- cluster:
certificate-authority: /etc/kubernetes/pki/ca.crt
server: KUBE_ADDRESS
name: development
...
省略
contexts:
- context:
cluster: kubernetes-on-aws
user: aws-user
name: aws-user@kubernetes-on-aws
- context:
cluster: test-cluster-1
user: dev-user
name: research
- context:
cluster: development
user: test-user
name: test-user@development
...
省略
$ kubectl config view --kubeconfig=my-kube-config -o=jsonpath='{.contexts[?(@.context.user=="aws-user")].name}'
aws-user@kubernetes-on-aws
補足
もし、jqコマンドが使えるなら要素探すのが楽です!!
kubectl get pv -o json | jq -c 'path(..)|[.[]|tostring]|join(".")'
""
"apiVersion"
"items"
"items.0"
"items.0.apiVersion"
"items.0.kind"
"items.0.metadata"
"items.0.metadata.creationTimestamp"
"items.0.metadata.finalizers"
"items.0.metadata.finalizers.0"
"items.0.metadata.managedFields"
...
省略
# grep を使うと探したい要素のパスが簡単に見つけられる
$ kubectl get pv -o json | jq -c 'path(..)|[.[]|tostring]|join(".")' |grep storage
"items.0.metadata.managedFields.1.fieldsV1.f:spec.f:capacity.f:storage"
"items.0.spec.capacity.storage"
"items.1.metadata.managedFields.1.fieldsV1.f:spec.f:capacity.f:storage"
"items.1.spec.capacity.storage"
"items.2.metadata.managedFields.1.fieldsV1.f:spec.f:capacity.f:storage"
"items.2.spec.capacity.storage"
"items.3.metadata.managedFields.1.fieldsV1.f:spec.f:capacity.f:storage"
"items.3.spec.capacity.storage"