Docker オーケストレーションツールの一つに Kubernetes (k8s) があります。k8s 実行環境の構築方法は複数ありますが、ここでは AWS や GCP 等のクラウドサービスを利用せず、Debian9 がインストールされた複数台の物理マシンがネットワーク内に存在する状況を考えます。これら複数の Debian9 上に k8s クラスタを立ち上げるためには Rancher が利用できます。k8s 以外の用途で利用しないことが分かっている場合は、Debian9 上で Rancher を利用するのではなく専用の RancherOS を利用することもできます。
ホストマシンの用意
ここでは実験のため VirtualBox で二つの Debian9 マシンを起動して、それらを同じ NAT ネットワーク 10.0.2.0/24
に所属させます。
- debian1
10.0.2.4/24
- debian2
10.0.2.5/24
各ホストマシンへの Rancher のインストール
簡単のため Docker イメージとして提供される Rancher を利用します。Docker エンジンをインストールします。
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable"
sudo apt-get update
sudo apt-get install docker-ce
sudo なしで docker コマンドを利用できるように設定できます。
sudo groupadd docker
sudo usermod -aG docker $USER
exit # ログインしなおし
docker ps
以下のコマンドで Rancher を起動します。データを永続化するための -v
、および後に Node 追加のために起動する rancher-agent コンテナへのポート割り当てを考慮した -p
を指定します。
docker run -d --name=rancher --restart=unless-stopped \
-v /host/rancher:/var/lib/rancher \
-p 8080:80 \
-p 8443:443 \
rancher/rancher:stable
ブラウザからアクセスして admin
の初期パスワードを設定してログインします https://127.0.0.1:8080
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cc89ae5eac4a rancher/rancher:stable "entrypoint.sh" 28 minutes ago Up 28 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp rancher
Rancher Server URL にはホスト名など、ネットワーク内の他のマシンおよびローカルからアクセスできるものを指定します。更に必要な場合は nginx 等でリバースプロキシ設定を行います。X-Forwarded-Proto
を指定することで、Rancher 側では http から https へのリダイレクトを行わなくなります。
Rancher で k8s クラスタを立ち上げる
ブラウザから「Add Cluster」→「CUSTOM」→「Cluster Name: mycluster」→「Next」として k8s クラスタの設定を追加します。
k8s クラスタに追加する Node を起動するための docker run コマンドを生成するためのオプションとして「etcd, Control, Worker」すべてにチェックを入れると以下のようなコマンドが表示されます。
sudo docker run -d --privileged --restart=unless-stopped --net=host -v /etc/kubernetes:/etc/kubernetes -v /var/run:/var/run rancher/rancher-agent:v2.1.1 --server https://10.0.2.4:8443 --token 9c5p642z52p7tllfjzc2hgfwkb5xmck6266vdlvs82lfc8crwbbsd6 --ca-checksum a42937938e0c38ba4e56845260c8105017205e886677fa0c6c5d020bf6a9ed93 --etcd --controlplane --worker
これを Rancher を起動したホストで実行すると、同じ Debian マシン上に Rancher サーバコンテナに加えて、Rancher-agent コンテナおよびその他必要なコンテナが起動した状態になります。
$ docker ps | awk '{ print $2 }' | grep rancher | sort | uniq
rancher/coreos-etcd:v3.2.18
rancher/hyperkube:v1.11.3-rancher1
rancher/metrics-server-amd64
rancher/pause-amd64:3.1
rancher/rancher:stable
同様に別の Debian マシンで上記コマンドによって Rancher-agent を起動して Rancher サーバに接続することで、クラスタに Node を追加できます。以下の画像は debian1 10.0.2.4/24
と debian2 10.0.2.5/24
で Node 数が 2 の状態です。Node の追加が正常に完了するまでは Alert が表示された状態になります。
k8s クラスタで Docker コンテナを走らせる
k8s クラスタで Docker コンテナを走らせるためには、Rancher の WebUI および HTTP API に加えて、標準の kubectl コマンドも利用できます。kubectl は Rancher ではなく k8s 標準のコマンドです。クラスタを複数台のマシン間で組む必要がない場合は microk8s や minikube を利用すると、ローカルマシン上に k8s クラスタを比較的簡単に構築でき、kubectl コマンドの動作確認等が行えます。以下では Rancher で起動した k8s クラスタを kubectl から利用するコマンドサンプルを記載します。
kubectl コマンドのインストール
kubectl は k8s クラスタのクライアントコマンドです。OS に応じて apt、yum、brew 等でインストールできます。Debian9 の場合は以下のようになります。
sudo apt-get update && sudo apt-get install -y apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl
補足: バイナリをダウンロードする方法
curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
Web UI から取得したサーバへの接続情報を ~/.kube/config
にコピーして接続確認します。kubectl クライアントと k8s クラスタのバージョンは Minor の一つ違いまで動作することが保証されています。例えば v1.2 クライアントは v1.1, v1.2, v1.3 クラスタに対して利用できます。
$ kubectl cluster-info
Kubernetes master is running at https://192.168.56.11:8443/k8s/clusters/c-zt2l5
KubeDNS is running at https://192.168.56.11:8443/k8s/clusters/c-zt2l5/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.2", GitCommit:"17c77c7898218073f14c8d573582e8d2313dc740", GitTreeState:"clean", BuildDate:"2018-10-24T06:54:59Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.3", GitCommit:"a4529464e4629c21224b3d52edfe0ea91b072862", GitTreeState:"clean", BuildDate:"2018-09-09T17:53:03Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
また、Rancher の WebUI に実装されている簡易シェルからも kubectl コマンドが利用できます。
k8s クラスタについて
k8s クラスタは複数のコンポーネントで構成されます。コンポーネントはクラスタを構成するマシン上で実行されます。これらマシンを Node とよびます。k8s は実行するコンポーネントを etcd、Control Plane、Worker の三つのロールに分けて管理しており、上記の通り Node となる各マシンで rancher/rancher-agent
を docker run するときの --etcd --controlplane --worker
オプションで選択できるようになっています。"Node" という表現が重複しますが、コンポーネントを Master コンポーネントと Node コンポーネントで分けた場合において、etcd は Master コンポーネントに分類されます。
- etcd → クラスタ内の分散 KVS です。
- Control Plane → スケジューラや API サーバの機能を提供します。クラスタの状態はすべて etcd が管理するためステートレスなコンポーネントです。
- Worker → ユーザアプリケーションを実行します。
Worker で実行するユーザアプリケーションは Pod という単位で管理されます。Pod は一つ以上の Docker コンテナおよび必要となるファイル等から成ります。Worker では複数の Pod を同時に実行できます。Worker には Kubelet というプロセスが常駐しており、コンテナの状態等を監視します。
nginx コンテナを起動して HTTP サービスを公開する例
クラスタ内のノードを確認
kubectl get nodes
NAME STATUS ROLES AGE VERSION
debian1 Ready controlplane,etcd,worker 6d v1.11.3
debian2 Ready controlplane,etcd,worker 5d v1.11.3
クラスタ内に Pod のデプロイ設定を登録して Pod を起動 (kubectl run)
設定ファイルを基本とした kubectl create
によるクラスタ操作の方法と、設定ファイルを用いない kubectl run
による方法があります。状況に応じてメリットとデメリットを考慮しながら使い分けます。
kubectl run mydeployment --image=nginx
kubectl get deployments
kubectl describe deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
mydeployment 1 1 1 1 3m
自動的にデプロイ設定に応じた Pod も作成されます。
kubectl get pods
kubectl describe pods
NAME READY STATUS RESTARTS AGE
mydeployment-65b9f8795d-r4hrs 1/1 Running 0 4m
デプロイにサービスポートを設定
kubectl expose deployment/mydeployment --type="NodePort" --port 80
kubectl get services
kubectl describe services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 10d ←k8s作成時から存在
mydeployment NodePort 10.43.89.123 <none> 80:31685/TCP 6s ←今回新規作成
nginx のサービスを利用してみます。
kubectl cluster-info
curl 192.168.56.11:31685
NAT の外部 IP は以下のコマンドで取得できます。
kubectl get services/mydeployment -o go-template='{{(index .spec.ports 0).nodePort}}'
削除
サービス
kubectl delete services mydeployment
デプロイ (Pod も合わせて削除されます)
kubectl delete deployments mydeployment
kubectl get pods
NAME READY STATUS RESTARTS AGE
mydeployment-65b9f8795d-r4hrs 0/1 Terminating 0 12m
コマンドサンプル
Pod 内のログを確認
Pod 名の確認
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
mydeployment-65b9f8795d-8r4pl 1/1 Running 0 16m 10.42.0.8 debian <none>
tailf のように監視できます。
kubectl logs mydeployment-65b9f8795d-8r4pl -f
すべて削除
Pod 削除が完了するまで待つ
kubectl delete services,deployments,jobs,pods,cronjobs --all
Terminate されたことの確認を待たない
kubectl delete services,deployments,jobs,pods,cronjobs --all --grace-period 0 --force
Pod 一覧の取得
echo "kubectl get pods -o go-template --template '[[range .items]][[.metadata.name]][[\"\\n\"]][[end]]'" | tr '[' '{' | tr ']' '}'
mydeployment-65b9f8795d-vb72j
mydeployment2-6dcc9fb68-9gbbs
kubectl get pods -o name
pod/mydeployment-65b9f8795d-vb72j
pod/mydeployment2-6dcc9fb68-9gbbs
起動済みの Pod に対してコマンドを発行
-c
を指定しない場合は Pod 内のコンテナが一つ選択されます。
kubectl exec -it mydeployment-65b9f8795d-dpt96 /bin/bash
kubectl exec mydeployment-65b9f8795d-dpt96 -- ls /
kubectl exec mydeployment-65b9f8795d-dpt96 -- /bin/bash -c "ls && ls"
クラスタ内への HTTP プロキシを一時的に立てる
kubectl proxy --port 8001
curl http://localhost:8001/
Rancher から利用する場合は /k8s/clusters/ を付けます。例えば API OVERVIEW に記載の namespaces
一覧を取得する例は以下のようになります。
curl http://127.0.0.1:8001/k8s/clusters/<CLUSTER_ID>/api/v1/namespaces
kubectl run のオプション
環境変数の設定
kubectl run mydeployment --image=nginx --env="MYENV1=xxx" --env="MYENV2=yyy"
kubectl exec mydeployment-6c6b59798f-2bqp4 -- /bin/bash -c 'echo $MYENV1'
イメージのコマンドを上書き
kubectl run mydeployment --image=nginx --restart=Never -it --command -- /bin/bash -c "ls /"
kubectl run mydeployment --image=nginx --restart=Never -it --command -- /bin/bash
--restart=Never
を付与すると Pod のみ作成されます。デプロイ設定は作成されません。
kubectl run mydeployment --image=nginx --restart=Never
kubectl get pods
kubectl get deployments
Pod のみを create する YAML
Deployment や Job を利用せず直接 Pod だけを create できます。
apiVersion: v1
kind: Pod
metadata:
labels:
run: mypod
name: mypod
spec:
containers:
- image: nginx
name: nginx
restartPolicy: Never
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mypod 1/1 Running 0 15s
cron ジョブ
kubectl run mydeployment --image=nginx --restart=Never --schedule="0/2 * * * *" --command -- /bin/bash -c "date"
kubectl get cronjobs
kubectl delete cronjobs --all
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
mydeployment 0/2 * * * * False 0 <none> 20s
デプロイ設定は作成されません。
$ kubectl get deployments
No resources found.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mydeployment-1542640920-rhphc 0/1 Completed 0 8s
$ kubectl logs mydeployment-1542640920-rhphc
Mon Nov 19 15:22:14 UTC 2018
kubectl create で設定する YAML/JSON を kubectl run で設定
例えば --cap-add ALL --privileged
、--name xxx
、-h yyy
に相当する設定は以下のようになります。--env
で指定した環境変数の値は無視されるため JSON 内に記載します。以下では特権モードにした状態でホストのデバイスファイルをマウントしています。
kubectl run mydeployment --image=nginx --overrides '{
"spec": {
"template": {
"spec": {
"hostname": "yyy",
"containers": [
{
"name": "xxx",
"image": "nginx",
"env": [
{"name":"MYENV", "value":"zzz"}
],
"securityContext": {
"capabilities": {
"add": ["ALL"]
},
"privileged": true
},
"volumeMounts": [
{
"mountPath": "/dev/fuse",
"name": "devfuse"
}
]
}
],
"volumes": [
{
"name": "devfuse",
"hostPath": {
"path": "/dev/fuse"
}
}
]
}
}
}
}'
kubectl exec -it `kubectl get pods -l run=mydeployment -o name | cut -d/ -f2` -- /bin/bash -c 'hostname'
yyy
kubectl exec -it `kubectl get pods -l run=mydeployment -o name | cut -d/ -f2` -- /bin/bash -c 'ls -l /dev/fuse'
crw-rw-rw- 1 root root 10, 229 Sep 7 08:28 /dev/fuse
kubectl exec -it `kubectl get pods -l run=mydeployment -o name | cut -d/ -f2` -- /bin/bash -c 'echo $MYENV'
zzz
kubectl describe pods -l run=mydeployment | grep -A1 Containers:
Containers:
xxx:
docker の ENTRYPOINT は command
で変更できます。CMD は args
で指定できます。
kubectl run mydeployment --image=nginx --overrides '{
"spec": {
"template": {
"spec": {
...
"containers": [
{
...
"command": ["/bin/bash", "-c"],
"args": ["echo 123 && echo 123"]
}
],
既定では imagePullPolicy
が IfNotPresent
になっているため、:latest
タグを指定している場合等を除いて、既に同名のイメージが Node 上に存在する場合は pull されません。Always
を指定することでこれを回避できます。
"image": "nginx",
"imagePullPolicy": "Always",
...
特定のデバイスファイルを隠したい場合
ホスト側のデバイスファイルを利用したい場合があります。docker の --device
オプションに相当する機能が k8s で利用できない場合は --privileged
で全デバイスファイルの利用を許可するしかありません。デバイスファイルのうち一部を隠したい場合は、以下のように設定できます。hostPath で FileOrCreate を指定しています。
kubectl run mydeployment --image=nginx --overrides '{
"spec": {
"template": {
"spec": {
"hostname": "yyy",
"containers": [
{
"name": "xxx",
"image": "nginx",
"env": [
{"name":"MYENV", "value":"zzz"}
],
"securityContext": {
"capabilities": {
"add": ["ALL"]
},
"privileged": true
},
"volumeMounts": [
{
"mountPath": "/dev/fuse",
"name": "devfuse"
},
{
"mountPath": "/dev/port",
"name": "devport"
}
]
}
],
"volumes": [
{
"name": "devfuse",
"hostPath": {
"path": "/dev/fuse"
}
},
{
"name": "devport",
"hostPath": {
"path": "/dev/shm/mydevport_mydeployment",
"type": "FileOrCreate"
}
}
]
}
}
}
}'
ラベルの利用
Pod とサービスを作成します。
kubectl run mydeployment --image=nginx
kubectl expose deployment/mydeployment --type="NodePort" --port 80
-l
で key=value
形式のラベルに合致する Pod およびサービスを選択できます。
kubectl get deployments -l run=mydeployment
kubectl get pods -l run=mydeployment
kubectl get services -l run=mydeployment
追加のラベルを付与するためには以下のようにします。
kubectl label pod mydeployment-65b9f8795d-f67s7 mykey=myvalue
kubectl get pods -l mykey=myvalue
ラベルを指定した削除も行えます。
kubectl delete service -l run=mydeployment
kubectl delete deployments -l run=mydeployment
Pod 内のコンテナへのファイル転送および取得
Pod を作成します。
kubectl run mydeployment --image=nginx
ファイルを転送します。-c
でコンテナを指定できます。
echo 'hello' > /tmp/hello.txt
kubectl cp /tmp/hello.txt mydeployment-65b9f8795d-z7b9d:/tmp/
kubectl exec mydeployment-65b9f8795d-z7b9d -- cat /tmp/hello.txt
ディレクトリも転送できます。
mkdir /tmp/mydir
echo 'hello' > /tmp/mydir/hello1.txt
echo 'hello' > /tmp/mydir/hello2.txt
kubectl cp /tmp/mydir mydeployment-65b9f8795d-z7b9d:/tmp/
kubectl exec mydeployment-65b9f8795d-z7b9d -- ls /tmp/mydir/
取得は以下のようになります。
mkdir /tmp/mydir2
kubectl cp mydeployment-65b9f8795d-z7b9d:/tmp/mydir /tmp/mydir2
一時的なポート転送
Pod を作成します。
kubectl run mydeployment --image=nginx
Pod 内の 80 番を localhost の 8080 で Listen するようにポート転送します。
kubectl port-forward mydeployment-65b9f8795d-d7n66 8080:80
curl localhost:8080
デプロイ設定に対しても実行できます。
kubectl port-forward deployment/mydeployment 8080:80
CPU/メモリ 使用量の調査
Node マシン
kubectl top node
kubectl top node debian1
Pod 毎
kubectl top pod -l run=mydeployment
コンテナ間通信
Pod 内のコンテナはネットワークを共有するため、お互いのサービスに localhost:xxxx でアクセスできます。異なる Pod 内のコンテナとの通信については、Rancher の場合、各 Pod に割り当てられた Rancher managed IP を指定して通信できます。既定では managed
ネットワーク 10.42.0.0/16
から各 Pod に ip が割り当てられます。
kubectl exec -it mydeployment-65b9f8795d-5qwtf -- /bin/bash
apt update
apt install iproute2
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
3: eth0@if181: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 0a:a4:0d:10:28:38 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.42.0.84/32 scope global eth0
valid_lft forever preferred_lft forever
また別の方法として kubectl expose
でサービスを作成し、サービスに ClusterIP
を割り当てることで、背後の Pod にアクセスをプロキシして通信することもできます。Rancher の場合は既定では 10.43.0.0/16
が指定できます。
kubectl expose deployment/mydeployment --cluster-ip 10.43.0.123 --port=8080 --container-port=80
kubectl get services
curl 10.43.0.123:8080
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 24m
mydeployment ClusterIP 10.43.0.123 <none> 8080/TCP 23m
NodePort で利用するポート番号を指定
以下のコマンドでテンプレートを作成できます。
kubectl expose deployment/mydeployment --type="NodePort" --port 80 --cluster-ip 10.43.0.101 --port=22,80,5900 --dry-run -o yaml
出力された YAML を編集して nodePort
の設定を追加できます。
...
spec:
...
ports:
- name: ssh
port: 22
protocol: TCP
targetPort: 22
nodePort: 30022
...
expose
ではなく create
を利用してサービスを作成します。
kubectl create -f /path/to/my.yaml
YAML 設定ファイルに関するコマンド
新規作成
kubectl create -f nginx.yaml
kubectl create -f configs/
再作成
kubectl replace -f nginx.yaml
削除
kubectl delete -f nginx.yaml -f redis.yaml
ネームスペース
一覧取得
kubectl get namespaces
YAML から作成
apiVersion: v1
kind: Namespace
metadata:
name: mynamespace
リソースタイプに関する説明を表示
kubectl explain pods
クラスタ内のイベントを表示
時系列順にクラスタ内でのイベントを表示できます。デバッグ等で役立ちます。
kubectl get events --sort-by=.metadata.creationTimestamp
kubectl サブコマンドの登録
v1.12 以上の kubectl で利用できるプラグイン機能を利用すると、実行ファイルをサブコマンドとして登録できます。パスの通ったディレクトリに kubectl-
で始まるファイルを設置するだけで利用できます。
kubectl-xxx-yyy
#!/bin/bash
echo ok
パスの通ったディレクトリに設置
chmod +x kubectl-xxx-yyy
sudo mv kubectl-xxx-yyy /usr/local/bin/
実行例
$ kubectl xxx yyy
ok
プラグインの確認
$ kubectl plugin list
The following kubectl-compatible plugins are available:
/usr/local/bin/kubectl-xxx-yyy
特定の Node で起動
xxxx
というホスト名の Node で起動させたい場合は kubernetes.io/hostname
を設定します。
apiVersion: v1
kind: Pod
metadata:
labels:
run: mypod
name: mypod
spec:
containers:
- image: nginx
name: nginx
restartPolicy: Never
nodeSelector:
kubernetes.io/hostname: xxxx
コンテナで利用できる CPU/Memory を保証および制限
apiVersion: v1
kind: Pod
metadata:
labels:
run: mypod
name: mypod
spec:
containers:
- image: nginx
name: nginx
resources:
requests:
cpu: 0.0
memory: 1024Mi
limits:
cpu: 1.0
memory: 1024Mi
restartPolicy: Never
正しく設定されていることを確認します。
$ kubectl describe pods | grep Limits -A5
Limits:
cpu: 1
memory: 1Gi
Requests:
cpu: 0
memory: 1Gi
要求したリソースを持つ Node が存在しない場合はスケジューリングに失敗します。
$ kubectl get events --sort-by=.metadata.creationTimestamp
...
Warning FailedScheduling default-scheduler 0/1 nodes are available: 1 Insufficient memory.
Pod IP を引けるように DNS 登録 (headless service)
clusterIP を None に設定した Service を作成して Pod に向けることで、Service 名が Pod の IP に解決されるような DNS レコードを登録できます。このような Service を Headless service とよびます。Headless service の ports には仮のものを設定します。
apiVersion: v1
kind: Pod
metadata:
labels:
run: mypod
name: mypod
spec:
containers:
- image: nginx
name: nginx
restartPolicy: Never
---
apiVersion: v1
kind: Service
metadata:
labels:
run: myheadless
name: myheadless
spec:
clusterIP: None
selector:
run: mypod
ports:
- name: myheadless
port: 1
Headless service 名で Pod の IP が取得できていることが分かります。Headless service 名を Pod 名と同じにすることもできます。
kubectl -it exec mypod /bin/bash
apt update && apt install dnsutils
root@mypod:/# dig +short +search myheadless
10.42.0.70
root@mypod:/# dig +short +search mypod | wc -l
0
root@mypod:/# cat /etc/hosts | grep 10.
10.42.0.70 mypod
設定ファイルをコンテナにマウント
ConfigMap を利用すると、設定ファイルをコンテナ内にマウントできます。
apiVersion: v1
kind: ConfigMap
metadata:
name: myconfig
data:
myconfig.yml: |
xxx: 123
yyy: 123
---
apiVersion: v1
kind: Pod
metadata:
labels:
run: mypod
name: mypod
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: config-volume
mountPath: /mnt/etc/
volumes:
- name: config-volume
configMap:
name: myconfig
restartPolicy: Never
確認
$ kubectl -it exec mypod /bin/bash
root@mypod:/# cat /mnt/etc/myconfig.yml
xxx: 123
yyy: 123
/etc/hosts ファイルに追記
hostAliases
を設定することでコンテナ内の /etc/hosts
にエントリを追加できます。
apiVersion: v1
kind: Pod
metadata:
labels:
run: mypod
name: mypod
spec:
containers:
- image: nginx
name: nginx
restartPolicy: Never
hostAliases:
- ip: 1.2.3.4
hostnames:
- xxx.example.com
- yyy.example.com
設定の確認
$ kubectl -it exec mypod -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.42.0.76 mypod
# Entries added by HostAliases.
1.2.3.4 xxx.example.com
1.2.3.4 yyy.example.com
WebUI の設定
Kubernetes 公式のクラスタ管理用 WebUI が存在します。手動インストールもできますが、Rancher で利用するためにはカタログからインストールすると簡単です。作成したクラスタの kube-system ネームスペースに存在する Catalog Apps タブを開いて kubernetes-dashboard
をインストールします。その際 IMPORTANT: Enable Dashboard Cluster Admin Role*
は True
に設定する必要があります。
$ kubectl -n kube-system get secret | grep dashboard
kubernetes-dashboard Opaque 0 13s
kubernetes-dashboard-key-holder Opaque 2 13h
kubernetes-dashboard-token-bqsh8 kubernetes.io/service-account-token 3 13s
token を確認します。
$ kubectl -n kube-system describe secret kubernetes-dashboard-token-bqsh8 | grep token:
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZC10b2tlbi1icXNoOCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImNjOTAxMjk3LTA3NDUtMTFlOS04Y2E5LTA4MDAyNzA4MTczOSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTprdWJlcm5ldGVzLWRhc2hib2FyZCJ9.tepB_K8BlyPc6gqmlw8xLkBgPlbzq-K5PAsQZ2hq1CCeqffFSoQ1AqVeMMyLqQdJmf2FAUN7eit3WoXenS8q1pJGYerX_rBr_MY2QhkMvlBCpulqjT0Ss5fenfKPk4V5Cxwk9zYGe8skyaWtGFiVlz4rz0qtt-jAm7qBPZuVXYvZIGTHuYOlRm0wnf37V4SnsMeDashcJ-JWfGJynchIiF1k36U7g_Z3VjJJSMIeQZhsw-RF4pr-JAzhQ3VZLwvioP-XNhbVSzqmGju3IHIYw992VBj9zaY9HKOg8VW9Ix7U29U2shnb9q6isvNEheL3p3vSB5LpdSt7ca31YREjuw
エンドポイントを確認します。
ログインすると以下のような画面になります。
Init Containers による初期化処理
アプリケーションコンテナ起動前に別のコンテナを起動して初期化処理を行うことができます。
apiVersion: v1
kind: Pod
metadata:
labels:
run: mypod
name: mypod
spec:
volumes:
- name: shared-volume
hostPath:
path: /tmp/shared
type: DirectoryOrCreate
initContainers:
- name: hello-1
image: debian:stretch
volumeMounts:
- name: shared-volume
mountPath: /shared
command: ['/bin/bash']
args: ['-c', 'echo "aaa" > /shared/hello.txt']
- name: hello-2
image: debian:stretch
volumeMounts:
- name: shared-volume
mountPath: /shared
command: ['/bin/chmod']
args: ['a+rwx', '/shared/hello.txt']
containers:
- image: nginx
name: nginx
volumeMounts:
- name: shared-volume
mountPath: /shared
restartPolicy: Never
初期化処理で作成したファイルがアプリケーションコンテナから参照できる状態にあることが分かります。
$ kubectl exec mypod -- /bin/bash -c 'ls -l /shared'
total 4
-rwxrwxrwx 1 root root 4 Dec 27 16:08 hello.txt
$ kubectl exec mypod -- /bin/bash -c 'cat /shared/hello.txt'
aaa
L7 ロードバランサ (Ingress)
k8s の Ingress リソースを利用すると HTTP リバースプロキシで Service を外部に公開できます。AWS ALB に相当する L7 ロードバランサであるため、HTTP/HTTPS 以外の L4 ロードバランサとしては利用できません。Rancher の実装において Ingress は Nginx です。
kubectl create -f xxx.yml
kubectl describe ingresses
以下のように YAML で定義できます。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: localhost
http:
paths:
- path: /mypath
backend:
serviceName: myservice
servicePort: 80
---
apiVersion: v1
kind: Pod
metadata:
labels:
run: mypod
name: mypod
spec:
containers:
- image: nginx
name: nginx
restartPolicy: Never
---
apiVersion: v1
kind: Service
metadata:
labels:
run: myservice
name: myservice
spec:
clusterIP: None
selector:
run: mypod
ports:
- name: myservice
protocol: TCP
port: 80
targetPort: 80
Ingress は Node マシンの 80 および 443 を利用します。同じマシンでマスターとなる Rancher と Rancher Agent を両方とも起動する場合は、マスターとなる Rancher が利用するポート番号を 80 および 443 から変更する必要があることに注意します。
Prometheus 連携
Prometheus の node-exporter を DaemonSet で各 Node に設置した場合等は Prometheus の設定で kubernetes_sd_configs の記載が必要になります。role: node
を利用するためには namespace 毎に存在する default Service Account では権限が不足するため https://127.0.0.1:8001/apikeys
で Rancher API トークンを発行する必要があります。発行したトークンの利用確認は以下のようなコマンドで行えます。
curl -sS -k -H "Authorization: Bearer token-f6rdl:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" https://127.0.0.1:8001/k8s/clusters/c-xxxxx/api/v1/nodes
こちらのページを参考にしながら Prometheus 設定を行います。Rancher API を経由するため公式ドキュメントに記載の api_server
等を設定する必要があります。また relabel_config を用いて prometheus node exporter のホスト名等を書き換えることができます。Grafanaを Import すると簡単です。
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus
data:
prometheus.yml: |
global:
scrape_interval: '15s'
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'k8s-nodes'
kubernetes_sd_configs:
- role: node
api_server: https://127.0.0.1:8001/k8s/clusters/c-xxxxx
bearer_token: token-f6rdl:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
tls_config:
insecure_skip_verify: true
relabel_configs:
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __address__
replacement: ${1}:9100
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
latest タグのイメージの Deployment Pod を無停止更新
非推奨ですが、latest タグが付与された docker イメージを利用している Deployment の Pod を再作成したいことがあります。
サービスが停止しても良い場合は Pod を削除すると Deployment によって新しい Pod が再作成されます。新しい Pod を作成する際に latest イメージが docker pull されます。
kubectl delete pods xxxxx-yyyyyy
サービスの無停止更新を行いたい場合は以下のように kubectl patch を利用できます。イメージタグの代わりに metadata を現在時刻のタイムスタンプで書き換えています。
kubectl patch deployment xxxxx -p "{\"spec\": {\"template\": {\"metadata\": {\"labels\": {\"date\": \"$(date +'%s')\" }}}}}"
v1.15 以降であれば以下のコマンドが利用できます。
kubectl rollout restart deployment xxxxx
関連記事
- RancherOS で構築した k8s クラスタ用に GlusterFS で簡単な分散ファイルシステムを構築k8s クラスタの各 Node マシンに GlusterFSサーバのコンテナを一つだけ起動して、簡単な分散ファイルシステムを構築します。各 Node へのコンテナ設置のためには DaemonSet が利用できそうですが、ここでは RancherOS の rancher.services を利用します。 1台構成 後に `rancher.ser
- Rancher で構築した kubernetes クラスタのアップグレード手順RancherOS 等、docker が使える何らかの OS で Rancher によって構築した kubernetes クラスタのアップグレードを行うためには、以下のようにします。 v2.1.5 の Rancher で構築した k8s クラスタに存在する脆弱性 CVE-2019-11253 への対応がなされた [v2.3.2](https://github.com
- Docker CLI チートシートDocker に関するコマンド逆引き集です。公式ページの「Reference documentation」情報をもとにしています。 Docker 用語について コンテナ 後述のイメージという型をもとに作られる実体です。例えるならば、オブジェクト指向プログラミングにおけるクラスが Docker イメージで、インスタンスが Docker コンテナです。ある
- Dockerfile ベストプラクティス (仮)Dockerfile を書く際に気になるポイント集です。「Best practices for writing Dockerfiles」および「Dockerfile Reference」をもとにしています。 Dockerfil
- RancherOS による Kubernetes クラスタの構築Kubernetes クラスタを RancherOS で構築する場合の設定例を記載します。 インストール ISO ファイルをダウンロードして起動すると ros コマンドが利用できるコンソールに入ります。インストール可能なバージョン一覧はコンソール上で以下のコマンドによって確認できます。 sud