Kubernetes
minikube で Kubernetes 環境構築 ( Hyper-V on Windows 10 )
DeploymentとServiceをyamlファイルで定義する
Kubernetes NodePort vs LoadBalancer vs Ingress? When should I use what?
目次:
Pod
Pod
の中には1つ以上のコンテナを配置する。
基本的にPod:コンテナは1:1で作成して問題ないが、コンテナ間でストレージの共有をしたい場合などは同じPodに複数コンテナを配置する。
- コンテナ 1 つ:
Pod
1 つに対してコンテナ 1 つは一番標準的なパターン - コンテナ 2 つ以上:
同一
Pod
内のコンテナは 2 種類のリソースを共有する。- ネットワーク
localhost
経由で他のコンテナに接続できる。 - ストレージ コンテナ間でストレージを共有できる。
- ネットワーク
Pod
自身は自己修復しない。
Pod
の修復はController
(例えばDeployment
)の仕事。
定義ファイル
Pod
の定義。
Pod
用に.yaml
ファイルを書くことはあまりない(はず)。
※Deployment
の.yaml
ファイルにPod
テンプレートを書く場所があるので、そこに直接書く形になる。
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox
command: ["sh", "-c", "echo Hello Kubernetes! && sleep 3600"]
ReadinessProbe: コンテナがREADYになる条件を指定する
readinessProbe
を使う
DBコンテナが立ち上がってからアプリのコンテナを立ち上げたいときなどに。
spec:
containers:
...
# 3000番ポートにつながった時にREADY状態とする場合の例
readinessProbe:
tcpSocket:
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
10秒後に必ずREADYになる例
readinessProbe:
initialDelaySeconds: 10
periodSeconds: 10
exec:
command:
- "true"
VolumeMounts: ストレージの共有
次のようなことができる。
- ホストPCのファイルをPodコンテナへ送りたいとき
- Podコンテナ間でディレクトリを共有したいとき
例:
apiVersion: extensions/v1beta1
kind: Deployment
spec:
template:
spec:
volumes:
# ConfigMapを利用してファイル共有
- name: shared-configmap-r
configMap:
name: my-configmap
- name: shared-configmap-rw
emptyDir: {}
# 空ディレクトリを作成してファイル共有
- name: shared-empty
emptyDir: {}
initContainers:
# ConfigMapを利用する場合にファイルの書き込み権限を与えるためにInitContainerを利用する
- name: copy-file
image: ellerbrock/alpine-bash-curl-ssl
command: ['sh', '-c', 'cp -R /pre/* /install']
volumeMounts:
- name: shared-configmap-r
mountPath: /pre/shared-configmap
- name: shared-configmap-rw
mountPath: /install/shared-configmap
containers:
- name: my-container
image: 'ellerbrock/alpine-bash-curl-ssl'
volumeMounts:
# ここのファイルはコンテナから読み取り専用
- name: shared-configmap-r
mountPath: /shared-configmap-r
# ここのファイルはコンテナから読み書き可能
- name: shared-configmap-rw
mountPath: /shared-configmap-rw
# ここのファイルはコンテナから読み書き可能
- name: shared-empty
mountPath: /shared-empty
例にあるように、ConfigMapをマウントしコンテナから書き込みしたい場合はInitContainerを経由する必要がある。
Deployment
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
複数のPod
を管理するもの。
定義ファイル
設定値の詳細はココ
apiVersion: apps/v1 # 固定値
kind: Deployment # 固定値
metadata:
name: nginx-deployment # Deploymentの名前
labels:
app: nginx # Podテンプレートと合わせる?
spec:
# レプリカ数
replicas: 3
# デプロイメントの履歴の数(デフォルト10)
revisionHistoryLimit: 1
# このDeployamentが管理するPodをどう見つけるかの定義
# 基本はPodテンプレートの`labels`と同じにすれば良い
selector:
matchLabels:
app: nginx
# Podテンプレート
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
# コンテナが開けるポート
ports:
- containerPort: 80
initContainers: Pod起動前に実行する処理を書く
ref: Init Containers
PodはinitContainerという初期化専用のコンテナを定義できる。 例えば、「Podが依存しているDBが起動するまで待ちたい」というような場合に便利。
ref:
- Starting containers in order on Kubernetes with InitContainers
- Kubernetes 初期化専用コンテナで、ポッド内共有ボリュームにデータを取り込む
例:
spec:
template:
spec:
initContainers:
- name: check-ready
image: alpine:3.9
# Podコンテナを起動する前に、db:3306に接続できるまで待機する
# db側でredinessProbeを指定しておけば、dbがREADYになるまでncコマンドは成功しない
command: ['sh', '-c', 'until nc -z db 3306 ; do sleep 1; done;']
containers:
- name: app
image: '***'
Service
Pod
は壊れたり生まれたりする(そのたびに IP アドレスが変わる)ため、外部からPod
(API など)へ接続したいときに困る。
Service
を介して外部から接続できるようにすると、この問題を解決できる。
定義ファイル
kind: Service
apiVersion: v1
metadata:
name: my-service # Serviceの名前。他のPodから`http://my-service`で接続できる
spec:
# デフォルトは`ClusterIP`(クラスタ内部のみ接続可能)
# `NodePort`にすると、localhost経由でホストPCから接続できる。
type: ClusterIP
# どのPodを対象にするか
selector:
app: MyApp
# 公開するポート
ports:
- protocol: TCP
port: 80
targetPort: 9376
# 複数ポートを指定する場合は`name`(半角英数字or'-')が必須
# ports:
# - name: http
# protocol: TCP
# port: 80
# targetPort: 9376
# - name: https
# protocol: TCP
# port: 443
# targetPort: 9377
type: NodePort
: ホスト PC からlocalhost
経由でService
に接続する
type: NodePort
を指定するとホストPCのポート経由でサービスに接続できる。
ローカルPCで動作確認したい場合などに便利。
spec:
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080 # 30000-32767の範囲で指定できる。省略した場合はランダムで割り当てられる
動作確認。
以下は、3000 番ポートに接続すると"Hello World!"を返す API のService
の場合の例。
# Service作成
kubectl apply -f [ファイル名].yaml
# Serviceのポートを調べる
kubectl get services
# ※出力例。この場合は`localhost:32660`で、`Service`の3000番ポートに接続できる
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# app-service NodePort 10.99.150.192 <none> 3000:32660/TCP 11m
# kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10d
# 動作確認
curl localhost:32660
# -> Hello World!
Configure Map
Pod の/etc/config/
直下に Key(ファイル名):Value(ファイル内容)の形式で保存される。
# yamlから作成
kubectl create -f config.yaml
# 確認
kubectl get configmap
# 確認(詳細)
kubectl describe configmap test-config
# Podを起動
kubectl create -f pod.yaml
# shを起動してConfigMapのValueを確認
kubectl exec -it test-pod sh
/ # cat /etc/config/test1
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config
data:
# key, value形式で設定を記述する
test1: "11111"
test2: "22222"
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: example-container
image: busybox
# あとからexecで操作するためsleepさせておく
command: ["sleep", "3600"]
# ConfigMapをマウントする
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
# ConfigMapリソースの名前を指定する(kubectl get configmapで得られる名前)
name: test-config
ConfigMapを使ってファイルをマウントする
helmを使うと簡単にファイルをPodに置ける。
apiVersion: v1
kind: ConfigMap
metadata:
name: my-files
namespace: my-namespace
data:
{{ (.Files.Glob "config/my-files/*").AsConfig | indent 2 }}
Podの初期化
https://qiita.com/petitviolet/items/41aa9abe106a29ba4667
Pod内の複数のコンテナでファイルを共有する
volumes
にemptyDir
を指定するとできる。
spec:
template:
spec:
volumes:
- name: shared-volume
emptyDir:
containers:
- name: c1
image: alpile
command: ["sh","-c"]
args: ["while true; do sleep 1; done"]
volumeMounts:
- name: shared-volume
mountPath: /hoge/shared # ここのディレクトリは勝手に生成される
- name: c2
image: alpile
command: ["sh","-c"]
args: ["while true; do sleep 1; done"]
volumeMounts:
- name: shared-volume
mountPath: /hoge/shared # ここのディレクトリは勝手に生成される
イメージのpullを強制する
デフォルトではリモートのイメージが変わったとしてもローカルに同名のイメージがあればそれを使ってしまう。
imagePullPolicy: Always
を指定すると、常にリモートのイメージをpullするようになる。
spec:
template:
spec:
containers:
- name: c1
image: alpine
imagePullPolicy: Always ## この行を追加
Volumeマウント
ローカルのファイルをPodに持っていける。
(例えば)設定ファイルを書く
config-test.yaml
aaa: 1
bbb: 2
ccc: 3
ファイルからConfigMapを生成する。
kubectl create configmap config-test --from-file=config-test.yaml
# 生成されたconfigmapの確認
kubectl get configmap config-test -o yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myDeployment
labels:
name: myDeployment
spec:
replicas: 1
template:
metadata:
labels:
name: myDeployment
spec:
# ここで任意の名前にConfigMapを紐づける
volumes:
- name: hoge
configMap:
name: config-test
containers:
- name: my_container
image: alpine
# `volumes`で定義した名前を、コンテナのパスと紐づける
volumeMounts:
- name: hoge
mountPath: /etc/config
これで、コンテナの/etc/config
にconfig-test.yaml
を持っていける。
configMapをマウントする場合はコンテナ側からは常に読み取り専用となる。
書き込みたい場合はinitContainerを利用してホスト->InitContainer(configmap)->コンテナ(emptyDir)
というようにマウントすれば良い。
コマンドの上書き
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myDeployment
labels:
name: myDeployment
spec:
template:
spec:
containers:
- name: my_container
image: alpine
# 元のエントリーポイントを上書きする
command:
- echo
- "hello"
複数コマンドを実行する例:
command: ["sh","-c"]
args: ["echo 'hoge'; /entory-point.sh"]
エントリーポイントのshell実行前に処理を差し込みたいときなどに使える。
便利コマンド
何もしない。デバッグ時にコンテナに入って何かしたいときに使える。
command: ["sh","-c"]
args: ["while true; do sleep 1; done"]
rollout
指定したデプロイメントが完了するまで待つ。
kubectl rollout deployment/[deploymentの名前]
デプロイメントのエラー解析
kubectl describe deployment [deployment name] -o yaml
起動時に複数コマンドを実行
containers:
command: ["/bin/sh","-c"]
args: ["command one; command two && command three"]
初期化処理をエントリーポイントとは別で実行
postStart
を使う。
バックグラウンド実行されるのでecho
してもkubectl logs
で見れないので注意。代わりにecho "hoge" > /usr/share/message
とかする。
https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
# `mkdir hoge`を実行する
command:
- mkdir
- hoge
プライベートレジストリのイメージを指定する
spec:
imagePullSecrets:
- name: 'docker-my-registory'
Pod の中に入る
docker exec
的な。
# PodのNAMEを確認
kubectl get pod
# 入る
kubectl exec [pod's name] -it bash
コマンド
リソースの表示
kubectl get pods
kubectl get pods -o wide
# podの名前の一覧のみ取得
kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'
PodのコンテナへホストPCのファイルをコピー
# kubectl cp [ホストPCのファイルパス] [namespace]/[PodId]:[コンテナのファイルパス]
kubectl cp ./hoge.txt mynamespace/aaa-6db96b6fd9-l9tr6://aaa.txt
# ディレクトリ配下をすべてコピー
# 末尾スラッシュのありなしは重要
kubectl cp ./fuga mynamespace/aaa-6db96b6fd9-l9tr6://fuga/
Windowsの場合はコンテナのファイルパスは//
から始めないとエラーになるので注意。
bash セッション開始
kubectl exec -ti $POD_NAME bash
# bashがないときは直接コマンドを書いたり
kubectl exec -ti $POD_NAME ls
# bashを入れる
kubectl exec -ti $POD_NAME apk add bash
# リソース一覧
kubectl get
# リソースの詳細表示
kubectl logs
# Pod内のコンテナのログ表示
kubectl logs
# Pod内のコンテナでコマンド実行
kubectl exec
podのイベントを確認する
readinessProbeが失敗したときのログとかが見れる。
kubectl describe pod [pod_name]
podが起動する(READYになる)まで待つ
kubectl rollout status [pod_name]
Docker for Windows で試す
参考 https://qiita.com/h-r-k-matsumoto/items/68f694650029ddf7351d
minikube start
Tips
デプロイメントオブジェクトの各フィールドの説明を表示する
kubectl explain deployment
kubectl explain deployment --recursive
kubectl explain deployment.metadata.name
サービスのエンドポイントを取得
kubectl describe services <SERVICE> | grep Endpoints
デプロイメントを一時的に止める
レプリカ数を0にする。
kubectl scale --replicas=0 deployment/<DEPLOYMENT_NAME>
可変なPodのコンテナ名を取得する
# 0番目のPodIdを取得する
kubectl get pods -o jsonpath="{.items[0].metadata.name}"
# 特定のPodIdを取得する
kubectl get pods --selector name=[Podのmetadata.nameの設定値] -o jsonpath="{.items[0].metadata.name}"
これを利用するとPodコンテナに対する操作が簡単にできる
# Podコンテナのログを表示
kubectl logs $(kubectl get pods --selector name=[Podのmetadata.nameの設定値] -o jsonpath="{.items[0].metadata.name}")
# Podコンテナでshセッション開始
kubectl exec -it `kubectl get pods --selector name=$1 -o jsonpath="{.items[0].metadata.name}"` sh
便利なもの
Pod
を生成
デバッグ用にellerbrock/alpine-bash-curl-ssl
はbash
とcurl
が使える軽量 Docker イメージ。
API の接続テストなどに使える。
# tmp-podデプロイメントを生成
# `--rm`をつけるとbashセッション終了時にデプロイメントを削除できる
winpty kubectl run -it --rm tmp-pod --image=ellerbrock/alpine-bash-curl-ssl bash
# 例:Serviceの接続テスト
curl app-service:3000
kubectl get
リソースを表示する。
kubectl get all
kubectl get pods
kubectl logs
などでpodの長い名前を毎回入れるのが面倒なとき用。
klog() {
# $1: string which containts part of pod's name.
# $c: container name. use if 2 or more containers in pod.
[ -z $2 ] && c="" || c="-c $2";
kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | grep app | xargs kubectl logs -f $c
}
# 使い方
klog app
klog app mysql
kubectl port-forward
# podの80番をホストの8080番にフォワードする
kubectl port-forward pod-1msdanjksdf3 8080:80
kubectl exec
Podコンテナ内でコマンドを実行する。
オプションを使いたい場合はコマンドの直前に--
を書く。
# 基本
kubectl exec -it pod-a837fam3nfa3 sh
# 指定したPodで指定したコマンドを実行する
kubectl exec -it `kubectl get pods --selector name=<podに設定したlabels.name> -o jsonpath="{.items[0].metadata.name}"` <command> ;
# podの名前を部分一致で指定してコマンドを実行する
kubectl exec -it `kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | grep $1` bash
# MySQLのクエリを実行
kubectl exec -it `kubectl get pods --selector name=hoge -o jsonpath="{.items[0].metadata.name}"` -- mysql -u root -ppassword -e "sh
ow databases;"
# MySQLのクエリを0.5秒おきに実行
kubectl exec -it `kubectl get pods --selector name=<metadata.name> -o jsonpath="{.items[0].metadata.name}"` -- bash -c 'while :; do mysql -u root -ppassword -e "select * from <db>.<table>"; sleep 0.5 ; done'
# Kafkaトピックを作成
kubectl run -ti --image=gcr.io/google_containers/kubernetes-kafka:1.0-10.2.1 createtopic --restart=Never --rm -- kafka-topics.sh --create \
--topic test \
--zookeeper zk-cs.my-kafka.svc.cluster.local:2181 \
--partitions 1 \
--replication-factor 1
# Kafkaメッセージを監視
# Kafkaメッセージ送信
kubectl run -ti --image=gcr.io/google_containers/kubernetes-kafka:1.0-10.2.1 produce --restart=Never --rm -- kafka-console-producer.sh --topic test --broker-list kafka-0.kafka-hs.my-kafka.svc.cluster.local:9093 done;
# jsonファイルの中身をkafkaのメッセージにして送信
cat hoge.json | jq -c . | xargs -I {} kubectl run -ti --image=gcr.io/google_containers/kubernetes-kafka:1.0-10.2.1 produce --restart=Never --rm -- kafka-console-producer.sh --topic test --broker-list kafka-0.kafka-hs.my-kafka.svc.cluster.local:9093 done;
すべてのリソース(Deployment, Service, ConfigMap)を一括削除
kubectl delete deployments --all
kubectl delete services --all
kubectl delete configmaps --all
kubectl delete namespaces --all
# 一行で
kubectl delete deployments --all; kubectl delete services --all; kubectl delete configmaps --all; kubectl delete namespaces --all;
動くサンプル
Pods
- ポート 3000 で"Hello World!"を出力する API
- API に curl を送信するためのコンテナ
Services
- API を外部に公開するためのサービス
api.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
labels:
app: api
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: hatakoya/hello-express
ports:
- containerPort: 3000
# 環境変数
env:
- name: HOGE
value: "123" # !! 数値は""で囲わないと謎エラーがでる !!
Namespace
namespaceを使うと、複数リソースの一括削除などができる。 デフォルトのnamespaceを設定しておくと便利。
# デフォルトnamespaceの確認
kubectl config view | grep namespace
# デフォルトnamespaceを設定
kubectl config set-context $(kubectl config current-context) --namespace=[namespaceの名前]
# namespaceを作成
kubectl create namespace [namespaceの名前]
# 一時的に違うnamespaceでコマンドを実行
kubectl -n mynamespace get all
サンプル
Couchbase
deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-couch
spec:
template:
spec:
volumes:
- name: scripts
configMap:
name: my-couch-config
containers:
- name: my-couch
image: couchbase
lifecycle:
postStart:
exec:
command: ["bash", "/etc/scripts/wait_and_insert_data.sh"]
ports:
- containerPort: 8091
- containerPort: 8092
- containerPort: 8093
- containerPort: 8094
- containerPort: 11210
readinessProbe:
tcpSocket:
port: 8091
initialDelaySeconds: 5
periodSeconds: 2
volumeMounts:
- name: scripts
mountPath: /etc/scripts
wait_and_insert_data.sh
#!/bin/sh
echo "wait..."
until curl localhost:8091 ; do
sleep 3
done
echo "ready to start"
# query, index: N1QLの実行に必要
couchbase-cli cluster-init \
--cluster=`hostname -i` \
--cluster-username=Administrator \
--cluster-password=password \
--services data,query,index
sleep 1
couchbase-cli bucket-create \
--cluster=`hostname -i` \
--username=Administrator \
--password=password \
--bucket=users \
--bucket-type=couchbase \
--bucket-ramsize=100 \
--enable-flush=1
sleep 3
# SDKから操作するためにはBucketに対応するユーザが必要
couchbase-cli user-manage \
--cluster=`hostname -i` \
--username=Administrator \
--password=password \
--set \
--roles=admin \
--auth-domain=local \
--rbac-username=users \
--rbac-password=password
kubectl create configmap my-couch-config --from-file=wait_and_insert_data.sh
kubectl apply -f deployment.yaml
Springアプリケーションを動かす
https://dzone.com/articles/quick-guide-to-microservices-with-kubernetes-sprin
FAQ
kubectl get pods
で pending から進まない
エラーメッセージを調べる
kubectl describe pods
metadata.name: Required value: name or generateName is required
ConfigMap "" is invalid:helmテンプレートをname
に使ったときに起こるよう。
printf
を使う場合は一度変数に格納し、その変数を参照するようにすると正常に動く。
もちろん値を直接name
に書いてもいい。
NG:
metadata:
name: {{ printf "%s-%s-config" my app }}
OK:
{{- $name := printf "%s-%s-config" my app -}}
metadata:
name: {{ $name }}
Proxyを経由しないでPod間通信
no_proxy
にサービスの名前を追加する。
export no_proxy=127.0.0.1,localhost,192.168.*,my-app
Pod 間の通信
service で名前解決
https://varu3.hatenablog.com/entry/2018/05/24/200311
Permission denied
./***.sh
じゃなくbash ***.sh
で実行する。
sudo
を入れる。
apt-get update
apt-get install -y sudo
Helm
Qiitaの日本語記事: (Kubernetes: パッケージマネージャHelm )[https://qiita.com/tkusumi/items/12857780d8c8463f9b9c]
インストール
管理者権限でPowerShellを立ち上げて実行。
choco install kubernetes-helm
初期化。
helm init
テンプレート
チャートのディレクトリ構成は次のようになる。
mychart/
Chart.yaml
values.yaml
charts/
templates/
...
次のコマンドでチャートのひな形を生成する。
helm create mychart
cd mychart
# ゼロから作業するときは最初に生成されたtemplatesを消す
rm -fr templates/*.*
次のコマンドでtemplates
配下の.yaml
で定義したリソースをまとめて生成できる。
helm install .
# release nameを指定する場合
helm install --name my-release .
# 既存のチャートを削除して再生成
helm install . --name my-release --replace
テンプレートの.yaml
を編集したら次のコマンドでコンテナを作りなおす。
helm del hoge --purge
helm install . --name hoge
FAQ
helm install
できなくなった
作業ディレクトリを変えたら新しい作業ディレクトリに移動してからhelm init
する。
helm init --upgrade
Web UI(ダッシュボード)
Web UIでリソース管理ができる。 https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/
導入
ダッシュボードUIをデプロイする。
kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml
ダッシュボードにアクセスできるようにする
kubectl proxy
http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/ でアクセスできる。
次に、認証のためにベアラトークンを取得する。 ref: https://github.com/kubernetes/dashboard/wiki/Creating-sample-use:
次の2つのyamlファイル作成し、それぞれkubectl apply -f
でデプロイする。
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kube-system
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kube-system
ベアラトークンを表示する。
kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')
Name: admin-user-token-***
のtokenをコピペしてダッシュボードのベアラトークンに入力する。
FAQ
EXECするとconnection closedになる
Podの中にbashが入っていないコンテナが1つでもあるとダメらしい。
spec:
containers:
- name: my-container
image: apline
command: ["sh","-c"]
args: ["apk add bash; while true; do sleep 1; done"]
bashが入っていないコンテナに、最初にbashをインストールするようにしてあげると動く。
VSCode拡張
- vscode-helm
Pod強制削除
kubectl deleteしたはずなのにSTATUSがTerminating
のまま変わらないときなどに。
kubectl delete pod [pod name] --grace-period=0 --force
DNS問題
https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution/
kdebug
nslookup google.com
nslookup kubernetes.default
# service
nslookup my-service
← JSON Server Verdaccio →