この記事について
Kubernetes(k8sと呼びます)に関するコマンドを集めたチートシートです。
実際に簡単な構成のk8sクラスタをいじりながら、k8sの基本コマンドである kubectl
の使い方を中心にまとめていきます。
環境
k8sを動かす環境としては、
- ローカルではminikube
- AWS EKS
などがありますが、簡単のためにminikubeを用いたローカル環境を使うことにします。
EKSクラスタでも権限さえ調整すれば基本的には同じ使い方ができます。
準備
minikubeを以下のURLを参考にしながらインストールします。
(https://kubernetes.io/docs/tasks/tools/install-minikube/)
まずは、minikubeを起動し、クラスタのIPを確認してみましょう。
$ minikube start
...
$ minikube ip
192.168.99.101
設定の確認
K8sの基本コマンドである kubectl
を使って、情報をみてみましょう。
設定全体をみる
minikubeやEKSだと、これらの設定は自動で作られますが、中身を理解しておくとうまくいかない時に対処がしやすいと思うので説明していきます。
設定ファイルは ~/.kube/config
にありますが、 kubectl config view
で見ることもできます。
kubectl config view
の結果から、minikubeに関する情報を抜き出しました。
- cluster:
certificate-authority: /Users/zawawahoge/.minikube/ca.crt
server: https://192.168.99.101:8443
name: minikube
contexts:
- context:
cluster: minikube
user: minikube
name: minikube
current-context: minikube
構造としては、minikube
という名前のcluster
があり、それを参照しているminikube
という名前のcontext
があるというものになっています。
まず、cluster
にクラスタIPと認証キーを登録しておき、それをcontext
が参照しています。
先ほどのクラスタIPと同じIPが設定ファイルにも書き込まれています。
続いて、kubectlが接続する先のクラスタ情報を記述したコンテクストについて kubectl
を使って確認しましょう。
コンテクストとは、k8sは、複数のクラスタとの接続を簡単にするために用意された、クラスタやプロジェクトの接続先の情報のことです。
詳細には、
- name(コンテクストそのものの名前)
- cluster(どのクラスタ設定を使うか)
- user(どういうユーザとしてクラスタに接続するか)
- authinfo
- namespace(名前空間)
から構成されています。
現在設定されているコンテクストの一覧をみる
kubectl config get-contexts
が使えます。
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* minikube minikube minikube
minikubeのデフォルト値が少し味気ないですが、EKSクラスタなどの場合はもっと複雑な名前になります。
デフォルトのコンテクスト名を確認
$ kubectl config current-context
minikube
コンテクストは、kubectlでクラスタに接続しようとしているクライアント側にある情報ですので、書き換えてもリモートには反映されません。
異なるクラスタor名前空間に接続したい場合は、新しくコンテクストを作るか、既存のコンテクストを編集する必要があります。
新しくコンテクストを作る
$ kubectl config set-context my-context
Context "my-context" created.
$ kubectl config get-contexts my-context
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
my-context
まっさらなコンテクストが作られました。
コンテクストを編集する
$ kubectl config set-context my-context --namespace new-namespace --cluster minikube
Context "my-context" modified.
$ kubectl config get-contexts my-context
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
my-context minikube new-namespace
デフォルトのコンテクストを変更する
$ kubectl config use-context my-context
Switched to context "my-context".
デフォルトのコンテクストの名前空間を変更する
実用上、接続しているクラスタは同じだが、名前空間を変えたい場合があるかもしれません。
その時は、カレントコンテクストの名前空間を書き換えればいけます。
# 変更前のコンテクストの詳細
$ kubectl config get-contexts $(kubectl config current-context)
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* my-context minikube new-namespace
$ kubectl config set-context --current --namespace new-new-namespace
Context "my-context" modified.
# 変更後のコンテクストの詳細
$ kubectl config get-contexts $(kubectl config current-context)
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* my-context minikube new-new-namespace
コンテクストの設定詳細
$ kubectl config view
# デフォルトのコンテクストの設定詳細
$ kubectl config view --minify
実際にクラスタを動かしてみる
前座が長くなってしまいましたが、実際にminikubeのクラスタを動かしてみましょう。
nginx
のイメージから作られたコンテナが3つあるような、かなり単純なクラスタをデプロイします。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
デフォルトコンテクストをminikubeに戻してクラスタにアクセスできるように準備します。
kubectl config use-context minikube
Switched to context "minikube".
クラスタをデプロイする
$ kubectl apply -f nginx-deploy.yaml
クラスタに関する情報の一覧をみる
k8sでは、
- Deployment
- ReplicaSet
- Pod
- Service
の4つを組み合わせてクラスタを作っていくことになります。
kubectl get
を使うと、クラスタの情報を取得できます。all
とすると、上の4つ全てについて出力されます。
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/nginx-56db997f77-6rvxq 1/1 Running 0 8m27s
pod/nginx-56db997f77-9w55k 1/1 Running 0 8m27s
pod/nginx-56db997f77-ptw9c 1/1 Running 0 8m27s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 3/3 3 3 8m27s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-56db997f77 3 3 3 8m27s
例えば、Deploymentだけをみたい時は、all
の代わりにdeploy
を渡します。
-o wide
のオプションをつけると出力される情報が増えます。
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 3/3 3 3 11m
$ kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx 3/3 3 3 11m nginx nginx app=nginx
詳細な設定を見る
-o yaml
や -o json
とすると、さらに詳細な情報がみられます。先ほどapplyしたyamlファイルはかなり省略して書いていましたが、省略されたデフォルトの値がコマンドで確認できます。
kubectl get deploy -o yaml
の結果が以下のようになります。
apiVersion: v1
items:
- apiVersion: extensions/v1beta1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"nginx","namespace":"default"},"spec":{"replicas":3,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"image":"nginx","name":"nginx","ports":[{"containerPort":80}]}]}}}}
creationTimestamp: "2019-05-11T17:51:32Z"
generation: 1
name: nginx
namespace: default
resourceVersion: "211356"
selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/nginx
uid: 693dc4b4-7415-11e9-9b1f-0800273e0575
spec:
progressDeadlineSeconds: 600
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
availableReplicas: 3
conditions:
- lastTransitionTime: "2019-05-11T17:54:24Z"
lastUpdateTime: "2019-05-11T17:54:24Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: "2019-05-11T17:51:32Z"
lastUpdateTime: "2019-05-11T17:54:24Z"
message: ReplicaSet "nginx-56db997f77" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
observedGeneration: 1
readyReplicas: 3
replicas: 3
updatedReplicas: 3
kind: List
metadata:
resourceVersion: ""
selfLink: ""
かなり詳細な情報が得られました。
Pod一覧をみる
-o wide
をオプションとしてつけると、表示される情報が増えます。
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-56db997f77-6rvxq 1/1 Running 0 22m 172.17.0.10 minikube <none> <none>
nginx-56db997f77-9w55k 1/1 Running 0 22m 172.17.0.9 minikube <none> <none>
nginx-56db997f77-ptw9c 1/1 Running 0 22m 172.17.0.8 minikube <none> <none>
Pod名のリストを求める
awkを使うと、Pod名のリストを簡単に抜き出せます。2行目以降について一列目を表示します。
# Pod名のリストを表示
$ kubectl get pods | awk 'NR>1{print $1}'
nginx-56db997f77-6rvxq
nginx-56db997f77-9w55k
nginx-56db997f77-ptw9c
# PodのIPのリストを表示
$ kubectl get pods -o wide | awk 'NR>1{print $6}'
172.17.0.9
172.17.0.8
172.17.0.4
特定のラベルを持つPodのリストを求める
-l
オプションでラベルを指定すると、特定のラベルを持つPODのみを抜き出せます。
$ kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-56db997f77-6rvxq 1/1 Running 2 36h
nginx-56db997f77-9w55k 1/1 Running 2 36h
nginx-56db997f77-ptw9c 1/1 Running 2 36h
クラスタ内のコンテナにアクセスする
3つのPodはそれぞれクラスタにおけるプライベートIPを持ちます。
k8sの特徴として、同一クラスタ内のPodはこのプライベートIPを用いて互いに通信できる、というものがあります。
実際に確かめてみましょう。
クラスタ内にアクセスするための一時的なPodを立てる
busyboxでwgetするためだけのPodを立てて、172.17.0.10
のPodにリクエストを送信すると、無事index.html
が返ってきました。
$ kubectl run -i -t busybox --image=busybox --restart=Never
/ # wget 172.17.0.10:80
Connecting to 172.17.0.10:80 (172.17.0.10:80)
index.html 100% |****************************************************************************************| 612 0:00:00 ETA
/ # ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 scope link src 172.17.0.11
# このPodのプライベートIPは172.17.0.11
コンテナに入ってみる
docker execと同じ使い方ができる kubectl exec
を使うことで、Podのなかのコンテナにアクセスすることができます。
$ kubectl exec -it nginx-56db997f77-6rvxq bash
root@nginx-56db997f77-6rvxq:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@nginx-56db997f77-6rvxq:/#
ただ、nginxのログは標準出力に出されていたようなので、kubectl logs
で確認します。
Pod内のコンテナが出力したログを確認する
$ kubectl logs nginx-56db997f77-6rvxq
172.17.0.11 - - [11/May/2019:18:28:39 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
先ほどhttpリクエストを送った送信元のbusyboxコンテナのIPが172.17.0.11
でしたので、ログがちゃんと保存されていることがわかります。
Service
LoadBalancerで外部からの通信をPodにルーティングする
3つのnginxのPodが正常に動いていることは確認できましたが、このままではクラスタの外からは通信ができません。
外部からの通信を、指定した方法でPodにルーティングしてくれるLoad balancerというTypeのServiceがあります。
apiVersion: v1
kind: Service
metadata:
name: nginx-lb
spec:
selector:
app: nginx
ports:
- port: 80
type: LoadBalancer
apply -f
すると、新しくServiceが作られます。
このServiceをDeploymentと別々に追加してちゃんとLoadBalancerとDeploymentが組み合わさるのか心配になると思います。
実は、selector
がDeploymentのものと一致しているおかげで、ServiceがDeploymentを見つけられるようになってます。
$ kubectl apply -f nginx-service.yaml
service/nginx-lb created
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13d
nginx-lb LoadBalancer 10.99.193.167 <pending> 80:32328/TCP 10s
minikubeだとこのServiceがPending状態で進まないので、アクセスができません。
Version 0.31.0からminikubeにminikube tunnel
という機能が追加され、これを使うとアクセスできるようになりました。
参考資料:https://qiita.com/inajob/items/4025a1d1aa83721c453d
$ minikube tunnel
Status:
machine: minikube
pid: 45884
route: 10.96.0.0/12 -> 192.168.99.101
minikube: Running
services: [nginx-lb]
errors:
minikube: no errors
router: no errors
loadbalancer emulator: no errors
再び、get
してみると、EXTERNAL-IP
がちゃんと表示されています。
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13d
nginx-lb LoadBalancer 10.109.96.98 10.109.96.98 80:32425/TCP 10m
$ curl 10.109.96.98
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
...(略)
外部からアクセスできました。
実際のAWSでの運用では、EKSサービスで利用可能なLoadBalancerを使わなければなりませんので、ご注意ください。