ローカル環境構築
Minikubeとkubectlをダウンロードする。
- https://kubernetes.io/docs/tasks/tools/install-minikube/
- https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-on-windows
kubectlはPATHを通す。Minikubeはインストーラーを実行してインストール。
minikube.exe start
minikube.exe dashboard
ブラウザが立ち上がってKubernetes Dashboardが表示される。
とりあえずノードを作る。
kubectl create deployment hello-node --image=gcr.io/hello-minikube-zero-install/hello-node
Deploymentを確認。
kubectl get deployments
Podを確認する。
kubectl get pods
Kubernetes Dashboardで確認する。
イベントを確認する。
kubectl get events
設定を確認する。
kubectl config view
設定はこんなん出ます。
apiVersion: v1
clusters:
- cluster:
certificate-authority: C:\Users\xxxxxx\.minikube\ca.crt
server: https://192.168.99.101:8443
name: minikube
contexts:
- context:
cluster: minikube
user: minikube
name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
user:
client-certificate: C:\Users\xxxxxx\.minikube\client.crt
client-key: C:\Users\xxxxxx\.minikube\client.key
サービスを作る。--type=LoadBalancerフラグはServiceをクラスタ外部に公開するということ。
kubectl expose deployment hello-node --type=LoadBalancer --port=8080
サービスを確認する。
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-node LoadBalancer 10.96.194.179 <pending> 8080:30610/TCP 3m21s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 25h
ロードバランサーをサポートするクラウドプロバイダーでは、Serviceにアクセスするための外部IPアドレスが提供されます。 Minikube では、LoadBalancerタイプはminikube serviceコマンドを使用した接続可能なServiceを作成します。
ということらしい。以下でブラウザが立ち上がる。
minikube service hello-node
用語の確認
このチュートリアルにしたがってやるよ
https://thinkit.co.jp/series/7342
Workloads…コンテナの実行に関するリソース
Pod
- Workloads リソースの最小単位
- Pod は1つ以上のコンテナから構成
- ネットワークは隔離されておらず、Pod内のコンテナはお互いにlocalhost宛で通信することが可能
- 補助するサブコンテナのことを「サイドカー」と呼ぶ
ReplicaSetとReplicationController
- Podのレプリカを生成し、指定した数のPodを維持し続ける
- ReplicationControllerは今後廃止される
- 特定のラベルがつけられたPodの数をカウントし、レプリカ数が不足している場合はtemplateからPodを生成する
Deployments ★推奨
- 複数のReplicaSetを管理しローリングアップデートやロールバックなどを実現する
- 新しいReplicaSetを作成
- 新しいReplicaSet上のレプリカ数(Pod数)を徐々に増やす
- 古いReplicaSet上のレプリカ数(Pod数)を徐々に減らす
- 古いReplicaSetはレプリカ数0で保持する
- ReplicaSetが生成される条件は「生成されるPodの内容の変更」。
- 正確にはspec.templateに変更があるとReplicaSetを新規で作成し、ローリングアップデートが行われる。
- ロールバック機能の実体はReplicaSetの切り替えと同義で、ReplicaSetは基本的には履歴としてレプリカ数を0にして形だけは残っている。
- 実際にはこのロールバック機能を使っている利用者は少なく、古いYAMLファイルを再度kubectl applyして適用したほうが良い。
StatefulSet
- データベースなどstatefulなワークロードに対応するためのリソース
- ReplicaSetとの違い
- 生成されるPod名が数字でindexingされたものになる
- PersistentVolumeを使っている場合は同じディスクを利用して再作成される
- Pod名が変わらない
- 1つずつPodを作成し、Ready状態になってから次のPodを作成し始める。
- 常にindex:0がMasterとなるような構成を取ることが可能。
DaemonSet
- 全nodeに1 podずつ配置する
Jobs
- 停止=正常終了となるようなもので使う。
- ワークロード別パラメータの使い分け(Think ITより)
ワークロード | completions | parallelism | backoffLimit |
---|---|---|---|
1回だけ実行するタスク | 1 | 1 | 1 |
N並列で実行させるタスク | M | N | P |
1個ずつ実行するワークキュー | 未指定 | 1 | P |
N並列で実行するワークキュー | 未指定 | N | P |
CronJobs
- Cronのようにスケジュールされた時間にJobを生成する
Service,LB,Network
Kubernetesでクラスタを構築すると、Podのための内部用ネットワークが構成される。Pod内のコンテナはお互いにlocalhost宛で通信することが可能。
サービスディスカバリ(DNS的な仕組み)もサービスが提供する。以下の三種類ある。
- Aレコード(kube-dnsのAレコード)を利用したサービスディスカバリ。
- IP単位で対応させるのがAレコード
- 正式なFQDNは[Service名].[Namespace名].svc.[ClusterDomain名]
- コンテナ内の/etc/resolv.confで、[Service名].[Namespace名]や[Service名]だけで名前解決できる
- SRVレコード(kube-dnsのSRVレコード)を利用したサービスディスカバリ
- IP+Port単位で対応させるのがSRVレコード
- 正式なFQDNは[**ServiceのPort名].[**Protocol].[Service名].[Namespace名].svc.[ClusterDomain名]
- 環境変数を利用したサービスディスカバリ
- 環境変数でも同じNamespaceのサービスが確認できる
サービスのタイプ別の挙動の違い
- ClusterIP
- クラスタ内からでないと疎通性のないInternal Networkに作り出されるVIPが割り当てられる
- ExternalIP
- type自体はClusterIP
- externalIPsにnodeのIPを指定することでKubernetesクラスタ外からそのIPでのアクセスができる
- ExternalIPに利用するIPは全てのnodeのIPでなくて良い
- Podへのリクエストは分散される
- NodePort
- 全てのNodeで受けたトラフィックをコンテナに転送する。ExteralIPの全ノード版
- ノード上のNodePortに到達したパケットは、さらにノードをまたいだPodへもロードバランシングされる
- externalTrafficPolicyをデフォルトのClusterからLocalに設定すると同じノードのPodに転送される
- LoadBalancer
- コンテナ内からの通信はClusterIPを利用するために、ClusterIPも自動的に確保される
- 外部のLoadBalancerと連携できるのは、GCP、AWS、Azureを始めとしたCloudProviderのみ
- 8080:30082/TCPみたいに表示されるのは、左側がVIPにアクセスした時のポートで、右側がノードのIPでアクセスしたときのポート
- Headless
- 永続性の高いStatefulSetのみで利用できる。逆に言えばこれを使いたいとき以外は関係ない
- PodのIP Addressが返ってくるService
- DNS Round Robin(DNS RR)を使ったエンドポイントを提供
- 転送先のPodのIPアドレスがクラスタ内DNSから返ってくる形で負荷分散
- spec.typeはClusterIP
- metadata.nameはStatefulSetのspec.serviceNameと同じ。
- spec.clusterIPはNone
- [Pod名].[Service名].[Namespace名].svc.[domain名]
- ExternalName
- Service名の名前解決に対してCNAMEを返す
- これ、使わない気がします
- Ingress
- L7 LoadBalancerを提供する
- 「Kind: Service」タイプのリソースではなく、「Kind: Ingress」タイプのリソース
Config
環境変数を渡す際にはpodテンプレートにenvまたはenvFromを指定する。下記の5つの情報源から環境変数を埋め込むことができる。
- 静的設定 値をそのまま書くだけ
- Podの情報 fieldRefを使う
- Containerの情報 resourceFieldRefを使う
- Secretリソースの機密情報
- ConfigMapリソースからのKey-Value値。nginx.confやhttpd.confのような設定ファイル自体も保存可能
Storage
Volume
- 既存のボリューム(ホストの領域、NFS、Ceph、GCP Volume)などをYAML Manifestに直接指定する
- 利用者が新規でボリュームを作成したり、既存のボリュームを削除したりはできない
- YAML ManifestからVolumeリソースを作成するといった処理もない
PersistentVolume
- 新規のボリュームの作成や、既存のボリュームの削除などを行うことが可能
- YAML ManifestなどからPersistent Volumeリソースを別途作成する形
- GCPやAWSのボリュームサービスでは、Persistent VolumeプラグインとVolumeプラグインの両方が用意されている
- Persistent Volumeはクラスタにボリュームを登録するだけ
PersistentVolumeClaim
-
作成されたPersistentVolumeリソースの中からアサインするためのリソース
-
Dynamic Provisioningを利用した場合は、Persistent Volume Claimが利用されたタイミングでPersistent Volumeを動的に作成することが可能
Volumeプラグイン
-
EmptyDir Pod用の一時的なディスク領域として利用可能です。PodがTerminateされると削除されます
-
HostPath Node上の領域をコンテナにマッピング。
よく使う?kubectlのコマンド
Workload関連のコマンド
2つのコンテナを持つPodを作る。
まずはyamlファイルを作る。
apiVersion: v1
kind: Pod
metadata:
name: sample-2pod
spec:
containers:
- name: nginx-container
image: nginx:1.12
ports:
- containerPort: 80
- name: redis-container
image: redis:5.0.5
ports:
- containerPort: 6379
以下のコマンドでyamlファイルの内容を反映させる。
kubectl apply -f .\2pod_sample.yaml
コンテナの中に入る
ReplicaSetで作ったPodのコンテナの中に入ることもできるよ。
# sample-podはPodの名前。
# 複数のコンテナがPodの中に存在する場合、何も指定しないとデフォルトのコンテナが選択される。
# 特定のコンテナを指定したい場合は-cでコンテナの名前を指定する。
$ kubectl exec -it sample-2pod -c nginx-container /bin/bash
存在しているPodを確認する
kubectl get pods
Podを消す
kubectl delete pods sample-2pod
ReplicaSetを作る
yamlファイルを作る。
ReplicaSetが生成するPodは、[ReplicaSet名]−[乱数]で命名される。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: sample-rs
spec:
replicas: 3
# selectorの下のラベルの追加Podを探しにいって維持しようとする
selector:
matchLabels:
app: sample-app
template:
metadata:
# Podにつけられるラベルはここで指定して、これは上の指定と一致していないといけない
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx:1.12
ports:
- containerPort: 80
反映させる。これはPodのときと同じコマンド。ファイルが違うだけ
kubectl apply -f .\rs_sample.yaml
存在しているReplicaSetを確認する。
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
sample-rs 3 3 3 19m
$ kubectl get replicaset -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
sample-rs 3 3 3 38m nginx-container nginx:1.12 app=sample-app
オートヒーリングの確認。Podを消してみて、再作成されるのを確認する。
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
sample-2pod 2/2 Running 2 16h 172.17.0.6 minikube <none> <none>
sample-rs-776l8 1/1 Running 0 3h53m 172.17.0.8 minikube <none> <none>
sample-rs-dhjdr 1/1 Running 0 3h53m 172.17.0.9 minikube <none> <none>
sample-rs-kcbn2 1/1 Running 0 3h53m 172.17.0.7 minikube <none> <none>
$ kubectl delete pod sample-rs-dhjdr
pod "sample-rs-dhjdr" deleted
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
sample-2pod 2/2 Running 2 16h 172.17.0.6 minikube <none> <none>
sample-rs-776l8 1/1 Running 0 3h54m 172.17.0.8 minikube <none> <none>
sample-rs-kcbn2 1/1 Running 0 3h54m 172.17.0.7 minikube <none> <none>
sample-rs-w9h4r 1/1 Running 0 4s 172.17.0.9 minikube <none> <none>
ReplicaSetの詳細を確認する。
$ kubectl describe replicaset sample-rs
Name: sample-rs
Namespace: default
Selector: app=sample-app
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"name":"sample-rs","namespace":"default"},"spec":{"replicas":3,"s...
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=sample-app
Containers:
nginx-container:
Image: nginx:1.12
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 5m24s replicaset-controller Created pod: sample-rs-w9h4r
Podのスケーリング
yamlを書き換える以外の方法だと以下のコマンドを使う
$ kubectl scale replicaset sample-rs --replicas 5
Deployment(でPod)を作る
まずyamlファイルを作る
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-deployment
spec:
replicas: 3
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx:1.12
ports:
- containerPort: 80
読み込ませる
$ kubectl apply -f .\deployment_sample.yaml
存在するDeploymentを確認する
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
sample-deployment 3/3 3 3 3m30s
$ kubectl describe deployment sample-deployment
Name: sample-deployment
Namespace: default
CreationTimestamp: Sat, 28 Dec 2019 15:58:26 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"sample-deployment","namespace":"default"},"spec":{"replic...
Selector: app=sample-app
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=sample-app
Containers:
nginx-container:
Image: nginx:1.12
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: sample-deployment-c6c6778b4 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 5m55s deployment-controller Scaled up replica set sample-deployment-c6c6778b4 to 3
Deploymentのイメージは以下で更新できる。
$ kubectl set image deployment sample-deployment nginx-container=nginx:1.13
Jobを作成する。
yamlファイルを作る。
apiVersion: batch/v1
kind: Job
metadata:
name: sample-job
spec:
# 実行の回数を指定する
completions: 1
# 並列度を指定する
parallelism: 1
# 失敗を許容する回数
backoffLimit: 10
template:
spec:
containers:
- name: sleep-container
image: centos:latest
command: ["sleep"]
args: ["60"]
# spec.template.spec.restartPolicyにはOnFailureまたはNeverが指定可能
# NeverはPodが障害時には新規のPodが作成される
# OnFailureの場合には、再度同一のPodを利用してJobを再開する
restartPolicy: Never
反映させる。
$ kubectl apply -f job_sample.yml
Jobの実行状況を確認する。
$ kubectl get jobs
NAME COMPLETIONS DURATION AGE
sample-job 0/1 40s 40s
CronJobを作る。
yamlファイルを作る。
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: sample-cronjob
spec:
schedule: "*/1 * * * *"
# spec.concurrencyPolicyで指定する同時実行に関するポリシー
# - Allow(default):同時実行に対して制限を行わない
# - Forbid:前のJobが終了していない場合は次のJobは実行しない
# - Replace:前のJobをキャンセルし、新たにJobを開始する
concurrencyPolicy: Forbid
# 開始時刻が遅れた場合に許容できる秒数
startingDeadlineSeconds: 30
# 保存する成功Jobの数
successfulJobsHistoryLimit: 5
# 保存する失敗Jobの数
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: sleep-container
image: centos:latest
command: ["sleep"]
args: ["30"]
restartPolicy: Never
ネットワーク関連のコマンド
サービスを作成する
apiVersion: v1
kind: Service
metadata:
name: sample-clusterip
spec:
type: ClusterIP
# 複数のPortを指定できる
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
selector:
app: sample-app
ClusterIPを静的にIPを指定する場合
apiVersion: v1
kind: Service
metadata:
name: sample-static-clusterip
spec:
type: ClusterIP
clusterIP: 10.96.253.80
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
selector:
app: sample-app
External IPを指定する
apiVersion: v1
kind: Service
metadata:
name: sample-static-clusterip
spec:
type: ClusterIP
clusterIP: 10.96.253.80
externalIPs:
- 192.168.99.101
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
selector:
app: sample-app
LoadBalancerを指定した場合
apiVersion: v1
kind: Service
metadata:
name: sample-lb
spec:
type: LoadBalancer
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
nodePort: 30082
selector:
app: sample-app
設定を適用する。
kubectl apply -f clusterip_sample.yml
作成したサービスを確認する
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d13h
sample-clusterip ClusterIP 10.96.64.65 <none> 8080/TCP 23s
サービスの詳細を確認する
kubectl describe services sample-clusterip
Name: sample-clusterip
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"sample-clusterip","namespace":"default"},"spec":{"ports":[{"name"... Selector: app=sample-app
Type: ClusterIP
IP: 10.96.64.65
Port: http-port 8080/TCP
TargetPort: 80/TCP
Endpoints: 172.17.0.11:80,172.17.0.14:80,172.17.0.16:80 + 5 more...
Session Affinity: None
Events: <none>
clusteripの動作を確認する。内部から出ないと呼べないので内部から
IPを使ってアクセスする。使えるIPはkubectl get servicesで確認したもの。
kubectl run --image=centos:7 --restart=Never --rm -ti testpod -- curl -s http://10.96.64.65:8080
Aレコードを使ってアクセスする。[Service名].[Namespace名].svc.[ClusterDomain名]
kubectl run --image=centos:7 --restart=Never --rm -ti testpod -- curl -s http://sample-clusterip.default.svc.cluster.local:8080
/etc/resolv.confの[Service名]を使ってアクセスする。
kubectl run --image=centos:7 --restart=Never --rm -ti testpod -- curl -s http://sample-clusterip:8080
SRVレコードを使ってアクセスする。[**ServiceのPort名].[**Protocol].[Service名].[Namespace名].svc.[ClusterDomain名]
kubectl run --image=centos:7 --restart=Never --rm -ti testpod -- curl -s http://_http-port._tcp.sample-clusterip.default.svc.cluster.local:8080
環境変数にもレコードと同じ内容が設定される。
$ kubectl run --image=centos:7 --restart=Never --rm -ti testpod -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=testpod
TERM=xterm
KUBERNETES_SERVICE_PORT_HTTPS=443
SAMPLE_CLUSTERIP_SERVICE_HOST=10.96.64.65
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
SAMPLE_CLUSTERIP_SERVICE_PORT=8080
SAMPLE_CLUSTERIP_PORT_8080_TCP_ADDR=10.96.64.65
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
SAMPLE_CLUSTERIP_PORT_8080_TCP=tcp://10.96.64.65:8080
SAMPLE_CLUSTERIP_PORT_8080_TCP_PROTO=tcp
SAMPLE_CLUSTERIP_PORT_8080_TCP_PORT=8080
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
SAMPLE_CLUSTERIP_SERVICE_PORT_HTTP_PORT=8080
SAMPLE_CLUSTERIP_PORT=tcp://10.96.64.65:8080
External IPで指定できるノードのIPは以下で取得できる
$ kubectl get node -o custom-columns="NAME:{metadata.name},IP:{status.addresses[].address}"
NAME IP
minikube 192.168.99.101
External IPの指定した結果を確認する
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d16h
sample-clusterip ClusterIP 10.96.64.65 <none> 8080/TCP 3h48m
sample-static-clusterip ClusterIP 10.96.253.80 192.168.99.101 8080/TCP 16m
Secretを利用する
ファイルからSecretを登録する
改行が入らないように注意
echo -n "root" > ./username
echo -n "rootpassword" > ./password
kubectl create secret generic sample-db-auth --from-file=./username --from-file=./password
yamlファイルから作成する
値はbase64でエンコード済みのものでないといけない
apiVersion: v1
kind: Secret
metadata:
name: sample-yaml-auth
type: Opaque
data:
username: cm9vdA==
password: cm9vdHBhc3N3b3Jk
kubectl apply -f ./secret_sample.yml
kubectlから直接作成する (--from-literal)
kubectl create secret generic sample-cli-auth --from-literal=username=root --from-literal=password=rootpassword
envfile(dockerの --env-fileオプションと同じ)から作成する
username=root
password=rootpassword
kubectl create secret generic sample-env-file --from-env-file ./env_secret
登録内容を確認する
kubectl describe secrets sample-db-auth
Name: sample-db-auth
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 8 bytes
username: 9 bytes
中身まで確認する
base64でエンコードされているので、デコードする必要がある
kubectl get secret sample-db-auth -o json
{
"apiVersion": "v1",
"data": {
"password": "UEBzc3cwcmQ=",
"username": "dXNlci1uYW1l"
},
"kind": "Secret",
"metadata": {
"creationTimestamp": "2019-12-31T08:01:36Z",
"name": "sample-db-auth",
"namespace": "default",
"resourceVersion": "123932",
"selfLink": "/api/v1/namespaces/default/secrets/sample-db-auth",
"uid": "d5e6188d-bbb3-496f-8b95-bb3dfc7fa4ec"
},
"type": "Opaque"
}
環境変数として利用する
apiVersion: v1
kind: Pod
metadata:
name: sample-secret-env
spec:
containers:
- name: secret-container
image: nginx:1.12
envFrom:
- secretRef:
name: sample-db-auth
kubectl apply -f .\secret_env_sample.yml
pod/sample-secret-env created
kubectl exec -it sample-secret-env env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=sample-secret-env
TERM=xterm
password=P@ssw0rd
username=user-name
ファイルとして利用する
環境変数として設定する場合との違いは以下。
Volumeマウントを利用したSecretに限り一定期間ごと(kubeletのSync Loopのタイミング)にkube-apiserverに変更を確認し、変更がある場合は入れ替えを行います。
デフォルトではSyncLoopの間隔は60秒に設定されています。この頻度を上げる場合には、kubeletのオプションとして--sync-frequencyを設定して下さい。また、環境変数を利用したSecretの場合、動的な更新はできません。
apiVersion: v1
kind: Pod
metadata:
name: sample-secret-single-volume
spec:
containers:
- name: secret-container
image: nginx:1.12
volumeMounts:
- name: config-volume
mountPath: /config
volumes:
- name: config-volume
secret:
secretName: sample-db-auth
items:
- key: username
path: username.txt
ConfigMapを利用する
ファイルから登録する
改行が入らないように注意
echo "config=true" > ./sample.conf
kubectl create configmap sample-config --from-file=./sample.conf
yamlファイルから作成する
値はbase64でどうのこうのする必要はない
apiVersion: v1
kind: ConfigMap
metadata:
name: sample-configmap
data:
thread: "16"
connection.max: "100"
connection.min: "10"
sample.properties: |
property.1=value-1
property.2=value-2
property.3=value-3
nginx.conf: |
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
kubectl apply -f ./sample-config-map.conf
kubectlから直接作成する (--from-literal)
kubectl create configmap web-config --from-literal=connection.max=100 --from-literal=connection.min=10
環境変数として利用する
環境変数として利用する場合、以下の制限がある。
環境変数で下記の2パターンを表現することができない読み込まれない
**.**が含まれる場合
改行が含まれる場合(**Key: |**で定義されているもの)
apiVersion: v1
kind: Pod
metadata:
name: sample-configmap-single-env
spec:
containers:
- name: configmap-container
image: nginx:1.12
env:
- name: CONNECTION_MAX
valueFrom:
configMapKeyRef:
name: sample-configmap
key: connection.max
kubectl apply -f configmap_single_env_sample.yml
pod/sample-configmap-single-env created
ファイルとして利用する
環境変数として設定する場合との違いはSecretの時と同じ。
apiVersion: v1
kind: Pod
metadata:
name: sample-configmap-multi-volume
spec:
containers:
- name: configmap-container
image: nginx:1.12
volumeMounts:
- name: config-volume
mountPath: /config
volumes:
- name: config-volume
configMap:
name: sample-configmap
Volumeを利用する
emptyDirを使う
apiVersion: v1
kind: Pod
metadata:
name: sample-emptydir
spec:
containers:
- image: nginx:1.12
name: nginx-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
kubectl apply -f .\emptydir-sample.yml
kubectl exec -it sample-emptydir /bin/bash
root@sample-emptydir:/# ls -l
total 72
drwxrwxrwx 2 root root 4096 Jan 1 03:41 cache
HostPathを使う
apiVersion: v1
kind: Pod
metadata:
name: sample-hostpath
spec:
containers:
- image: nginx:1.12
name: nginx-container
volumeMounts:
- mountPath: /srv
name: hostpath-sample
volumes:
- name: hostpath-sample
hostPath:
path: /data
type: DirectoryOrCreate
kubectl apply -f .\hostpath-sample.yml
kubectl exec -it sample-hostpath /bin/bash
touch /srv/test
$ minikube.exe ssh
_ _
_ _ ( ) ( )
___ ___ (_) ___ (_)| |/') _ _ | |_ __
/' _ ` _ `\| |/' _ `\| || , < ( ) ( )| '_`\ /'__`\
| ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )( ___/
(_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____)
$ ls /data
test
Kubernetesを構成しているコンポーネント
主に以下の引用です。
コンポーネント一覧
コンポーネント | 種別 | 説明 |
---|---|---|
etcd | master | Kubernetesのリソースの永続化に使われる高信頼分散KVS |
kube-apiserver | master | Kubernetesのリソースを管理するAPIサーバー |
kube-scheduler | master | Podのノードへの割り当てを行うスケジューラー |
kube-controller-manager | master | Replication Controllerなどの各種コントローラーを起動し管理するマネージャー |
kubelet | node | Podを起動し管理するエージェント(Nodeのメイン処理) |
kube-proxy | node | KubernetesのServiceが持つ仮想的なIPアドレス(cluster IP)へのアクセスをルーティングする |
kubectl | client | KubernetesのCLIクライアント |
hyperkube | misc | Kubernetes関連のバイナリを1つにまとめたall-in-oneバイナリ |
pause | misc | pod内のネットワークnamespaceを保持するコンテナ |
pod-master | add-on | High-Availability構成時にscheduler, controllerがどのMasterで動くかを調整するコンテナ |
kube-dns | add-on | クラスタ内DNSのPod |
SkyDNS | add-on | クラスタ内DNSのDNSサーバー |
kube2sky | add-on | SkyDNSにKubernetesの情報を反映させるブリッジ |
heapster | add-on | Kuernetesのパフォーマンス情報を集約する仕組み |
helm(Deployment Manager) | add-on | Kubernetesの設定をテンプレート化しデプロイを管理しやすくする仕組み |
dashboard | UI | 新しいKubernetesのダッシュボード |
kube-ui | UI | 古いKubernetesのダッシュボード |
kubedash | UI | パフォーマンス分析のダッシュボード |
コンポーネント同士がどうやって連携しあっているのかの基本的な考え方
各コンポーネントの中でReconciliation Loopというのが動いている。
Kubernetesの設計原則
API Serverのみがクラスター状態を管理するデータストア(etcd)を扱う 部分的なサーバー障害がクラスター全体のダウンにつながらないよう にする 各コンポーネントへの指示が失われても、直近の指示にもとづいて処 理を継続できるようにする
各コンポーネントは関連する設定や状態をメモリに持つが、永続化は API Serverを通じてデータストア(etcd)へ行う ユーザーや他のコンポーネントがオブジェクトを変化させたことを検 知できるよう、コンポーネントはAPI Serverをウォッチする
イベントチェーンの流れ Deployment作成の例
- クライアントがDeployment APIを呼ぶ
- Deployment Controllerが検知し、ReplicaSet APIを呼ぶ
- ReplicaSet Controllerが検知し、Pod APIを呼ぶ
- Schedulerが検知し、配置先Nodeを決定し、Pod APIを呼ぶ
- Kubeletが検知し、Pod(Container)を作成
冗長構成を組む
基本的な考え方
またこちらを見ました。https://www.slideshare.net/ToruMakabe/kubernetes-120907020
Controller ManagerとSchedulerはActive/Standby
台数
Master、Nodeともに3台以上がおすすめ Masterサーバーにetcdを同居させる場合、おすすめは3台以上で奇数 etcdの障害時、処理継続ノードの決定基準が過半数であるため Nodeサーバーは2台以上、必要なリソース量に応じて増やす Nodeサーバーが2台構成だと障害時に使えるリソースが一気に半減す るため、3台以上とするケースが多い
少なくともリージョンをまたがるようなクラスタを組まない方がいいらしい
複数のデータセンターに分散配置する場合、制約条件は遅延 etcdの死活確認、性能の観点から2~3msに抑えるのが一般的 Azureのバックボーンでも東阪は10ms程度かかる 1つのクラスターは1つの都市圏で構成するのが現実的 広域災害対策は1つのクラスターではなく、複数のクラスターで
HPA(Horizontal Pod Autoscaler)の定義
HPAはPodごとに定義できるRequestsを割り当てられるかどうかを判断基準にしていて、実際の使用量をもとにPodの配置を決めるわけではない。
Nodeに空きがないとPodがPendingになる。これを監視しているのがCluster AutoscalerでインフラのAPIを呼んでノードを追加する。
Helmを導入する
Helmはk8sのパッケージマネージャ的なものらしい。
試してみたけど、公式通りにやってもちゃんと動かないことがあるというか…残念
Goで書かれていて、以下からダウンロードしてパスを通せば導入できる。
$ helm
The Kubernetes package manager
Common actions for Helm:
- helm search: search for charts
- helm pull: download a chart to your local directory to view
- helm install: upload the chart to Kubernetes
- helm list: list releases of charts
Environment variables:
+------------------+-----------------------------------------------------------------------------+
| Name | Description |
+------------------+-----------------------------------------------------------------------------+
| $XDG_CACHE_HOME | set an alternative location for storing cached files. |
| $XDG_CONFIG_HOME | set an alternative location for storing Helm configuration. |
| $XDG_DATA_HOME | set an alternative location for storing Helm data. |
| $HELM_DRIVER | set the backend storage driver. Values are: configmap, secret, memory |
| $HELM_NO_PLUGINS | disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins. |
| $KUBECONFIG | set an alternative Kubernetes configuration file (default "~/.kube/config") |
+------------------+-----------------------------------------------------------------------------+
Helm stores configuration based on the XDG base directory specification, so
- cached files are stored in $XDG_CACHE_HOME/helm
- configuration is stored in $XDG_CONFIG_HOME/helm
- data is stored in $XDG_DATA_HOME/helm
Helmでできること
- 自分のKubernetesクラスター環境へのデプロイ(インストール)・削除(アンインストール)
- パッケージを共有する仕組み(リポジトリ)
- 新規のパッケージを開発する支援機能
Helmの構成要素
構成要素 説明 補足 helm(CLI) go言語で開発されたコマンドラインツール。 ローカルOS環境の$HELM_HOMEでポイントする場所に、設定ファイル群や、「ローカルリポジトリ」を作り出し、その上でtillerと通信してKubernetesクラスタとのやりとりを行います。 tiller(サーバー) Kubernetesクラスタ内にリソースとして定義され、動作するサーバーアプリ。 helmコマンドからの要求に基づき、apiserverを介してKubernetesクラスタ内のリソース作成・削除・情報取得などの操作を行います。 chart(チャート) Helmにおける管理対象としての「パッケージ」 実体は.tgz形式の圧縮ファイル。様々なファイル群で構成され、Kubernetesのリソースを生成するためのテンプレートファイルやデフォルト値の設定ファイルなどが含まれる。 release(リリース) chartを使って実際にデプロイ(インストール)されたクラスタ上のオブジェクトをまとめて表したもの。 リリースは、暗黙にせよ明示的にせよ、「リリース名」が必ず与えられ、識別されます。 chartリポジトリ チャートをhelmクライアントに提供するWebサーバー 仕様として定められたindex.yamlおよびchartファイル(.tgz)群をサービスすれば、それはchartリポジトリとなりえます。
Helmのクイックスタート
MySQLの環境を立ち上げる。
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
$ helm repo update
$ helm install stable/mysql --generate-name
NAME: mysql-1577664762
LAST DEPLOYED: Mon Dec 30 09:12:44 2019
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
mysql-1577664762.default.svc.cluster.local
To get your root password run:
MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default mysql-1577664762 -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo)
To connect to your database:
1. Run an Ubuntu pod that you can use as a client:
kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il
2. Install the mysql client:
$ apt-get update && apt-get install mysql-client -y
3. Connect using the mysql cli, then provide your password:
$ mysql -h mysql-1577664762 -p
To connect to your database directly from outside the K8s cluster:
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
# Execute the following command to route the connection:
kubectl port-forward svc/mysql-1577664762 3306
mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD}
MySQLの環境を調べてみる。
$ kubectl get deployments -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
mysql-1577664762 1/1 1 1 5m46s mysql-1577664762 mysql:5.7.28 app=mysql-1577664762,release=mysql-1577664762
$ kubectl describe deployments mysql-1577664762
Name: mysql-1577664762
Namespace: default
CreationTimestamp: Mon, 30 Dec 2019 09:12:10 +0900
Labels: app=mysql-1577664762
chart=mysql-1.6.2
heritage=Helm
release=mysql-1577664762
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=mysql-1577664762,release=mysql-1577664762
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: Recreate
MinReadySeconds: 0
Pod Template:
Labels: app=mysql-1577664762
release=mysql-1577664762
Service Account: default
Init Containers:
remove-lost-found:
Image: busybox:1.29.3
Port: <none>
Host Port: <none>
Command:
rm
-fr
/var/lib/mysql/lost+found
Requests:
cpu: 10m
memory: 10Mi
Environment: <none>
Mounts:
/var/lib/mysql from data (rw)
Containers:
mysql-1577664762:
Image: mysql:5.7.28
Port: 3306/TCP
Host Port: 0/TCP
Requests:
cpu: 100m
memory: 256Mi
Liveness: exec [sh -c mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}] delay=30s timeout=5s period=10s #success=1 #failure=3
Readiness: exec [sh -c mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}] delay=5s timeout=1s period=10s #success=1 #failure=3
Environment:
MYSQL_ROOT_PASSWORD: <set to the key 'mysql-root-password' in secret 'mysql-1577664762'> Optional: false
MYSQL_PASSWORD: <set to the key 'mysql-password' in secret 'mysql-1577664762'> Optional: true
MYSQL_USER:
MYSQL_DATABASE:
Mounts:
/var/lib/mysql from data (rw)
Volumes:
data:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: mysql-1577664762
ReadOnly: false
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: mysql-1577664762-d75956dbc (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 6m59s deployment-controller Scaled up replica set mysql-1577664762-d75956dbc to 1
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-1577664762-d75956dbc-bz2fm 1/1 Running 0 4m28s
$ kubectl describe pods mysql-1577664762-d75956dbc-bz2fm
Name: mysql-1577664762-d75956dbc-bz2fm
Namespace: default
Priority: 0
Node: minikube/192.168.99.101
Start Time: Mon, 30 Dec 2019 09:12:11 +0900
Labels: app=mysql-1577664762
pod-template-hash=d75956dbc
release=mysql-1577664762
Annotations: <none>
Status: Running
IP: 172.17.0.13
IPs:
IP: 172.17.0.13
Controlled By: ReplicaSet/mysql-1577664762-d75956dbc
Init Containers:
remove-lost-found:
Container ID: docker://2ef1950b5844614c38122e32fa069e03490d8d0a077d0feb94d6b79a740f97da
Image: busybox:1.29.3
Image ID: docker-pullable://busybox@sha256:8ccbac733d19c0dd4d70b4f0c1e12245b5fa3ad24758a11035ee505c629c0796
Port: <none>
Host Port: <none>
Command:
rm
-fr
/var/lib/mysql/lost+found
State: Terminated
Reason: Completed
Exit Code: 0
Started: Mon, 30 Dec 2019 09:12:18 +0900
Finished: Mon, 30 Dec 2019 09:12:18 +0900
Ready: True
Restart Count: 0
Requests:
cpu: 10m
memory: 10Mi
Environment: <none>
Mounts:
/var/lib/mysql from data (rw)
/var/run/secrets/kubernetes.io/serviceaccount from default-token-jn5v7 (ro)
Containers:
mysql-1577664762:
Container ID: docker://41735ace19ebb2f949d70d40b8b5d7f4a397369a9116230ee53dbe14f51de990
Image: mysql:5.7.28
Image ID: docker-pullable://mysql@sha256:b38555e593300df225daea22aeb104eed79fc80d2f064fde1e16e1804d00d0fc
Port: 3306/TCP
Host Port: 0/TCP
State: Running
Started: Mon, 30 Dec 2019 09:12:57 +0900
Ready: True
Restart Count: 0
Requests:
cpu: 100m
memory: 256Mi
Liveness: exec [sh -c mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}] delay=30s timeout=5s period=10s #success=1 #failure=3
Readiness: exec [sh -c mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}] delay=5s timeout=1s period=10s #success=1 #failure=3
Environment:
MYSQL_ROOT_PASSWORD: <set to the key 'mysql-root-password' in secret 'mysql-1577664762'> Optional: false
MYSQL_PASSWORD: <set to the key 'mysql-password' in secret 'mysql-1577664762'> Optional: true
MYSQL_USER:
MYSQL_DATABASE:
Mounts:
/var/lib/mysql from data (rw)
/var/run/secrets/kubernetes.io/serviceaccount from default-token-jn5v7 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
data:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: mysql-1577664762
ReadOnly: false
default-token-jn5v7:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-jn5v7
Optional: false
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling <unknown> default-scheduler error while running "VolumeBinding" filter plugin for pod "mysql-1577664762-d75956dbc-bz2fm": pod has unbound immediate PersistentVolumeClaims
Normal Scheduled <unknown> default-scheduler Successfully assigned default/mysql-1577664762-d75956dbc-bz2fm to minikube
Normal Pulling 11m kubelet, minikube Pulling image "busybox:1.29.3"
Normal Pulled 10m kubelet, minikube Successfully pulled image "busybox:1.29.3"
Normal Created 10m kubelet, minikube Created container remove-lost-found
Normal Started 10m kubelet, minikube Started container remove-lost-found
Normal Pulling 10m kubelet, minikube Pulling image "mysql:5.7.28"
Normal Pulled 10m kubelet, minikube Successfully pulled image "mysql:5.7.28"
Normal Created 10m kubelet, minikube Created container mysql-1577664762
Normal Started 10m kubelet, minikube Started container mysql-1577664762
Warning Unhealthy 10m kubelet, minikube Readiness probe failed: mysqladmin: [Warning] Using a password on the command line interface can be insecure.
mysqladmin: connect to server at 'localhost' failed
error: 'Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)'
Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists!
MySQLのrootパスワードを取得する。
$ kubectl get secret --namespace default mysql-1577664762 -o jsonpath="{.data.mysql-root-password}"
これであっているはずだけど、ここで取得できるパスワードを使っても繋がらない…