k8s v1.10 をvagrantの仮想環境上で動作させて、iSCSIディスクを共有ディスクとして、ノード障害時のテイクオーバーの動作を検証したメモです。
vagrantの仮想サーバーで、k8s v1.10のクラスタを動作させて検証した4回目の記事で、これまでの記事を列挙しておきます。
- Kubenetes v1.10 クラスタをVagrantで構築したメモ
- K8s Node障害時の振る舞いについての検証記録
- K8s v1.10 on Vagrantのダッシュボードのセットアップ
- K8s on Vagrant の NFS 永続ボリュームの利用メモ
システム構成
iSCSIターゲット(サーバー)をk8sクラスタ外部に構成して、k8sクラスタ内のポッドからiSCSIの永続ディスクを利用します。 NFSの様にネットワーク上で複数のクライアントのファイル共有を目的として開発されたソフトウェアと異なり、iSCSIは、コンピュータと周辺機器を接続するために開発されたSCSIをTCP/IPネットワーク上で利用するためのソフトウェアです。 そのため、次の図の様に、同時に一つのポッドのみ接続を行う必要があります。
例えば、iSCSIターゲットが提供するボリュームは、複数のイニシエータ(クライアント)からの同時書き込みに用いることができません。
しかし、RDBなどのデータベースのソフトウェアは、SCSIを用いたディスクアクセス環境上で、トランザクションの一貫性を維持しながら、パフォーマンスを確保するための機構を備えたソフトウェアです。 ハイエンドUNIXサーバーなどでは、ファイバーチャネルのストレージ・エリアネットワークを用いることがありますが、このファイバーチャネルも SCSIの規格で定められたプロトコルを通す仕組みとなっており、iSCSIと同じ制約を持っています。
RDBMSのコンテナ化されたソフトウェアとiSCSIを組み合わせることで、ファイバーチャンネルを利用するのに近いパフォーマンスで、k8s上でアクティブ・スタンバイの高可用性の構成を作ることができます。例えば、次の図で表すイメージになります。
今回は、MySQLとiSCSIのボリュームで、k8sのデプロイメントの機能で、アクティブ・スタンバイの構成を作り、アプリケーションがアクセスするVIPに相当する固定のIPアドレスを k8s のサービス Cluster IPを利用して構築してみます。
iSCSIサーバーの構築用Vagrantfile
iSCSIのターゲットとイニシエータの機能を作るために、下記のVagrantfileを作成しました。 このスクリプトによって、ボリュームを提供するiSCSIサーバー(ターゲット)と、クライアントのサンプルとしてのiSCSIイニシエータの二つの仮想サーバーを起動します。 目的の構成では、イニシエーターは、MySQLが稼働するポッドになりますが、テスト用として仮想サーバー上にイニシエータを同時に作成します。
# coding: utf-8
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
hosts = Array["target", "initiator"]
ip_x = 0
hosts.each do |host|
config.vm.define vm_name = "#{host}" do |config|
config.vm.hostname = host
public_ip = "192.168.1.#{ip_x+70}"
ip_x = ip_x + 1
config.vm.network :public_network, ip: public_ip, bridge: "en0: Ethernet"
#
config.vm.provider "virtualbox" do |vb|
vb.gui = false
vb.memory = "512"
end
# iscsiイニシエータ (クライアント)
if host == "initiator" then
target_ip = "#{public_ip}"
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y open-iscsi
sed 's/^InitiatorName=/InitiatorName=iqn.2016-04.world.srv:target00/' -i /etc/iscsi/initiatorname.iscsi
sed 's/^#node.session.auth.authmethod = CHAP/node.session.auth.authmethod = CHAP/' -i /etc/iscsi/iscsid.conf
sed 's/^#node.session.auth.username = username/node.session.auth.username = username/' -i /etc/iscsi/iscsid.conf
sed 's/^#node.session.auth.password = password/node.session.auth.password = password/' -i /etc/iscsi/iscsid.conf
systemctl restart iscsid open-iscsi
iscsiadm -m discovery -t sendtargets -p 192.168.1.70
iscsiadm -m node --login -p 192.168.1.70
SHELL
end
# iscsiターゲット (サーバー)
if host == "target" then
config.vm.provider :virtualbox do |p|
vdisk = "vdisk.vdi"
# iscsi device 4Gi
if not File.exist?(vdisk) then
p.customize [
'createmedium', 'disk',
'--filename', vdisk,
'--format', 'VDI',
'--size', 4096]
end
p.customize [
'storageattach', :id,
'--storagectl', 'SCSI',
'--port', 2,
'--device', 0,
'--type', 'hdd',
'--medium', vdisk]
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y iscsitarget iscsitarget-dkms
sed 's/^ISCSITARGET_ENABLE=false/ISCSITARGET_ENABLE=true/' -i /etc/default/iscsitarget
cat >> /etc/iet/ietd.conf <<EOF
Target iqn.2016-04.world.srv:target00
Lun 0 Path=/dev/sdc,Type=fileio
incominguser username password
EOF
mkfs.ext4 -q /dev/sdc
systemctl restart iscsitarget
SHELL
end
end
end
end
Vagrantfileの実行内容の要約
iSCSIの設定は、今回の目的では無いので、詳しい説明は省略しますが、実行する内容を以下に箇条書きにします。
- 192.168.1.70 の IPアドレスで、iSCSIターゲットとなる仮想サーバーを起動する
- ターゲットの仮想サーバーには、iSCSIとして提供するボリュームを vdisk.vdi として4GBの容量を確保する
- 192.168.1.71 の IPアドレスで、イニシエータと持つ仮想サーバーを作成する
- イニシエータの仮想サーバーは、ターゲットのボリュームを接続して、マウントできる状態で起動する
iSCSIサーバーの起動
上記のVagrantfileを置いた場所で、vagrant status
を実行して、Vagrantfileが認識されることを確認します。
imac:k8s-pv-iscsi maho$ vagrant status
Current machine states:
target not created (virtualbox)
initiator not created (virtualbox)
This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.
次に、vagrant up
を実行することで、iSCSIターゲット(サーバー) と iSCSIイニシエータ(クライアント)が起動します。
imac:k8s-pv-iscsi maho$ vagrant up
Bringing machine 'target' up with 'virtualbox' provider...
Bringing machine 'initiator' up with 'virtualbox' provider...
==> target: Importing base box 'ubuntu/xenial64'...
省略
initiator: Logging in to [iface: default, target: iqn.2016-04.world.srv:target00, portal: 192.168.1.70,3260] (multiple)
initiator: Login to [iface: default, target: iqn.2016-04.world.srv:target00, portal: 192.168.1.70,3260] successful.
iSCSIサーバーの稼働確認
vagrant status
を実行することで、下記の様に起動を確認することができます。
imac:k8s-pv-iscsi maho$ vagrant status
Current machine states:
target running (virtualbox)
initiator running (virtualbox)
省略
一つのVagrantfileから、二つの仮想サーバーが起動しています。 次の様にvagrant ssh サーバー名
でログインしたいサーバー名を指定することで、目的の仮想サーバーにログインします。 ここでは、iSCSIのボリュームをアタッチするクライアント側のサーバーにログインします。
root権限で、fdisk -l
を実行することで、iSCSIで接続されたボリュームと内臓ボリュームを一度にリストすることができます。
mount -t ext4 /dev/sdc /mnt
によって、ファイルシステムのマウントできる事を確認しておきます。
imac:k8s-pv-iscsi maho$ vagrant ssh initiator
Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.4.0-119-generic x86_64)
省略
vagrant@initiator:~$
vagrant@initiator:~$ sudo fdisk -l
Disk /dev/sda: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x334a7b8f
Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 20971486 20969439 10G 83 Linux
Disk /dev/sdb: 10 MiB, 10485760 bytes, 20480 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/sdc: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
vagrant@initiator:~$ sudo mount -t ext4 /dev/sdc /mnt
vagrant@initiator:~$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 238M 0 238M 0% /dev
tmpfs 49M 1.9M 47M 4% /run
/dev/sda1 9.7G 1.1G 8.7G 11% /
tmpfs 245M 0 245M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 245M 0 245M 0% /sys/fs/cgroup
tmpfs 49M 0 49M 0% /run/user/1000
vagrant 931G 506G 425G 55% /vagrant
/dev/sdc 3.9G 8.0M 3.6G 1% /mnt
vagrant@initiator:~$ ls -al /mnt
total 24
drwxr-xr-x 3 root root 4096 Apr 22 12:29 .
drwxr-xr-x 24 root root 4096 Apr 22 12:30 ..
drwx------ 2 root root 16384 Apr 22 12:29 lost+found
マウントした状態で、iSCSIのボリュームに cd
で移動して、MySQLが、テーブルスペースとして利用するディレクトリを `mkdir /mnt/mysql-data' として作成して、モードを変更して、MySQLのコンテナがアクセスできる様にしておきます。
vagrant@initiator:~$ sudo mkdir /mnt/mysql-data
vagrant@initiator:~$ sudo chmod 0777 /mnt/mysql-data
vagrant@initiator:~$ ls -al /mnt
total 28
drwxr-xr-x 4 root root 4096 Apr 22 12:40 .
drwxr-xr-x 24 root root 4096 Apr 22 12:30 ..
drwx------ 2 root root 16384 Apr 22 12:29 lost+found
drwxrwxrwx 2 root root 4096 Apr 22 12:40 mysql-data
umount /mnt
でアンマウントしてから、iscsiadm -m node --logout
でiSCSIもログアウトして、接続を解除します。
vagrant@initiator:~$ sudo umount /mnt
vagrant@initiator:~$ sudo iscsiadm -m node --logout
Logging out of session [sid: 1, target: iqn.2016-04.world.srv:target00, portal: 192.168.1.70,3260]
Logout of [sid: 1, target: iqn.2016-04.world.srv:target00, portal: 192.168.1.70,3260] successful.
以上で、iSCSIのターゲットとマウントするべきボリュームの準備が完了しました。
Secretの作成
ここから、k8sに必要な設定を実施していきます。 MySQLのコンテナが動作するポッドは、iSCSIターゲットに、ユーザーIDとパスワードで認証を通過して、ログインする必要があります。 一方で、k8sには、ユーザーIDやパスワードなどのセンシティブな情報を日常的に操作するオペレータや開発者から見えない様する secretという機能があります。
そこで、iSCSIのユーザーIDとパスワードをシークレットに保存します。 ポッドが利用する場合には、metadata.name
の値フィールドの chap-secret
を指定することで、利用できる様になります。
apiVersion: v1
kind: Secret
metadata:
name: chap-secret
type: "kubernetes.io/iscsi-chap"
data:
node.session.auth.username: dXNlcm5hbWUK
node.session.auth.password: cGFzc3dvcmQK
ユーザー名とパスワードのbase64エンコード
ここで注意点が、ユーザIDとパスワードの文字列は、base64でエンコードしておく必要があります。 次の例では、MacOSのコマンドで、ユーザーIDの'username'とpassword
をbase64でエンコードする例です。 usernameとpasswordは、実際のシステムに適用する場合には、推定されない値を利用してくださいね。 変換された文字列をコピペで、chap-secret.yamlに貼り付けて、編集を終えます。
imac:k8s-pv-iscsi maho$ echo username |base64
dXNlcm5hbWUK
imac:k8s-pv-iscsi maho$ echo password |base64
cGFzc3dvcmQK
secretの作成
次に、上記で作成したYAMLファイルをkubectl apply -f YAMLファイル名
で、k8sクラスタへ保存します。 そして、kubectl get secrets
で保存された事を確認することできます。
vagrant@k8s1:/vagrant/yaml$ kubectl apply -f chap-secret.yaml
secret "chap-secret" created
vagrant@k8s1:/vagrant/yaml$ kubectl get secrets
NAME TYPE DATA AGE
chap-secret kubernetes.io/iscsi-chap 2 2s
ポッドからiSCSIディスクのマウント
MySQLのコンテナをデプロイする前に、iSCSIで接続するだけの、ポッドを作成して、接続できる事を確認します。
このYAMLファイルで実現する事を以下に箇条書きで列挙しておきます。
- ubuntuコンテナを利用
- iscsiボリュームを/mntにマウントする。 subPathを指定して mysql-data を /mnt へマウント
- sleep 3600を実行して、コンテナが即時終了しない様に、1時間ほど待機させる
- Volumes 以下の設置で、iSCSIへ接続する。 (PVやPVCを利用せず、ポッドから直接接続する点に注目)
- secretRedで、ユーザーIDとパスワードを参照させる
apiVersion: v1
kind: Pod
metadata:
name: ubuntu-initiator
spec:
containers:
- name: mysql
image: ubuntu:latest
volumeMounts:
- mountPath: /mnt
name: iscsivol
subPath: mysql-data
command: ["sleep","3600"]
volumes:
- name: iscsivol
iscsi:
targetPortal: 192.168.1.70
iqn: iqn.2016-04.world.srv:target00
lun: 0
fsType: ext4
readOnly: true
chapAuthDiscovery: true
chapAuthSession: true
secretRef:
name: chap-secret
ここで作成したYAMLファイルを適用して、ポッドを作成します。
vagrant@k8s1:/vagrant/yaml$ kubectl apply -f ubuntu-pod-iscsi.yaml
pod "ubuntu-initiator" created
実行を確認するために、kubelet get pods
で確認します。
vagrant@k8s1:/vagrant/yaml$ kubectl get pods
NAME READY STATUS RESTARTS AGE
ubuntu-initiator 1/1 Running 0 1m
このポッドで、対話型でシェルを動作させて、ログインした様にします。そして、/mntにiSCSIのボリュームがマウントされている事を確認します。
vagrant@k8s1:/vagrant/yaml$ kubectl exec -it ubuntu-initiator bash
root@ubuntu-initiator:/# df -h
Filesystem Size Used Avail Use% Mounted on
none 9.7G 2.6G 7.2G 27% /
tmpfs 1001M 0 1001M 0% /dev
tmpfs 1001M 0 1001M 0% /sys/fs/cgroup
/dev/sdc 3.9G 8.0M 3.6G 1% /mnt
/dev/sda1 9.7G 2.6G 7.2G 27% /etc/hosts
shm 64M 0 64M 0% /dev/shm
tmpfs 1001M 12K 1001M 1% /run/secrets/kubernetes.io/serviceaccount
tmpfs 1001M 0 1001M 0% /sys/firmware
root@ubuntu-initiator:/# ls -al /mnt
total 8
drwsrwxrwx 2 root root 4096 Apr 22 12:40 .
drwxr-xr-x 35 root root 4096 Apr 22 13:03 ..
もし、ここでPODが実行できない場合、k8sクラスタのノードの仮想サーバーに、open-iscsi のパッケージが、インストールされている事を確認してください。 コンテナは、ホストになっているカーネルを利用して、名前空間の異なるプロセスとして実行しているために、ホスト側のカーネルにiSCSIの機能拡張が無い場合、コンテナがiSCSIを利用できないためです。
# apt-get update
# apt-get install -y open-iscsi
これで、確認用のポッドが動作したら、MySQLを実行します。
その前に、クリーンナップとして、以下を実行して、ポッドを停止しておきます。
vagrant@k8s1:/vagrant/yaml$ kubectl delete -f ubuntu-pod-iscsi.yaml
MySQLサーバーの起動
これから、MySQLサーバーを起動するためのYAMLファイルを準備します。 MySQLの公式コンテナには、環境変数によるAPIが準備されており、パスワードやデータベースを設定する事ができます。 前回同様にYAMLファイルで実現するポイントを箇条書きにします。
-
kind
でDeployment
を指定します。 このデプロイメント・コントローラの機能によって、k8sクラスタ上で常にreplicasの数だけ、ポッドが起動する様になります。 これによって、MySQLコンテナが稼働するワーカーノードが、停止した際に、他の健全なワーカーノードにMySQLを起動してくれます。 - マウントポイントは、/var/lin/mysqlとして、公式MySQLコンテナのAPI仕様に従って指定します。
- MySQLサーバーのポート番号として、3306を公開します。
- iSCSIのボリュームの設定部分は、前述の接続テスト用の設定と同字ですが、一箇所、
readOnly:
のフィールドをfalseに変更します。もし、この変更を忘れると、MySQLがボリュームを初期化できずに、ポッドが再起動を繰り返す事になるので注意です。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mysql-server
spec:
replicas: 1
template:
metadata:
labels:
app: mysql-server
spec:
containers:
- name: mysql
image: mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_DATABASE
value: test
- name: MYSQL_ROOT_PASSWORD
value: root
- name: MYSQL_USER
value: dev
- name: MYSQL_PASSWORD
value: dev
volumeMounts:
- mountPath: /var/lib/mysql
name: iscsivol
subPath: mysql-data
volumes:
- name: iscsivol
iscsi:
targetPortal: 192.168.1.70
iqn: iqn.2016-04.world.srv:target00
lun: 0
fsType: ext4
readOnly: false
chapAuthDiscovery: true
chapAuthSession: true
secretRef:
name: chap-secret
ISCSIダーゲットのIPアドレスを直書きしていますので、kube-dnsを利用してIPアドレスを解決する方法は、後日、補足したいと思います。
上記で作成したYAMLファイルを適応して、デプロイします。
vagrant@k8s1:/vagrant/yaml$ kubectl apply -f mysql-deploy-iscsi.yaml
deployment.extensions "mysql-server" created
次のコマンドで、確認することができます。 IPはポッドのIPアドレス、NODEはデプロイされたワーカーノードになります。
vagrant@k8s1:/vagrant/yaml$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
mysql-server-68b5dfdf4d-2wb67 1/1 Running 0 54s 10.244.1.88 k8s2
kubectl exec -it mysql-server-68b5dfdf4d-2wb67 bash
でポッド名を指定して、MySQLのコンテナと対話的にコマンド実行することができます。 iSCSIデバイスの/dev/sdc
が /var/lib/mysql
にマウントされている事が確認できます。
vagrant@k8s1:/vagrant/yaml$ kubectl exec -it mysql-server-68b5dfdf4d-2wb67 bash
root@mysql-server-68b5dfdf4d-2wb67:/# df
Filesystem 1K-blocks Used Available Use% Mounted on
none 10098468 2657036 7425048 27% /
tmpfs 1024024 0 1024024 0% /dev
tmpfs 1024024 0 1024024 0% /sys/fs/cgroup
/dev/sda1 10098468 2657036 7425048 27% /etc/hosts
shm 65536 0 65536 0% /dev/shm
/dev/sdc 3997376 223192 3548088 6% /var/lib/mysql
tmpfs 1024024 12 1024012 1% /run/secrets/kubernetes.io/serviceaccount
tmpfs 1024024 0 1024024 0% /sys/firmware
MySQLの公式コンテナでは、空のテーブルスペース領域が与えられると、初期化処理を実行します。 /var/lib/mysql
をリストすると、次の様に初期化が完了していることが解ります。
root@mysql-server-68b5dfdf4d-2wb67:/# ls -al /var/lib/mysql
total 188488
drwsrwxrwx 6 mysql mysql 4096 Apr 22 13:15 .
drwxr-xr-x 19 root root 4096 Apr 20 08:47 ..
-rw-r----- 1 mysql mysql 56 Apr 22 13:14 auto.cnf
-rw------- 1 mysql mysql 1675 Apr 22 13:14 ca-key.pem
-rw-r--r-- 1 mysql mysql 1107 Apr 22 13:14 ca.pem
-rw-r--r-- 1 mysql mysql 1107 Apr 22 13:14 client-cert.pem
-rw------- 1 mysql mysql 1679 Apr 22 13:14 client-key.pem
-rw-r----- 1 mysql mysql 1341 Apr 22 13:14 ib_buffer_pool
-rw-r----- 1 mysql mysql 50331648 Apr 22 13:15 ib_logfile0
-rw-r----- 1 mysql mysql 50331648 Apr 22 13:14 ib_logfile1
-rw-r----- 1 mysql mysql 79691776 Apr 22 13:15 ibdata1
-rw-r----- 1 mysql mysql 12582912 Apr 22 13:15 ibtmp1
drwxr-x--- 2 mysql mysql 4096 Apr 22 13:14 mysql
drwxr-x--- 2 mysql mysql 4096 Apr 22 13:14 performance_schema
-rw------- 1 mysql mysql 1679 Apr 22 13:14 private_key.pem
-rw-r--r-- 1 mysql mysql 451 Apr 22 13:14 public_key.pem
-rw-r--r-- 1 mysql mysql 1107 Apr 22 13:14 server-cert.pem
-rw------- 1 mysql mysql 1679 Apr 22 13:14 server-key.pem
drwxr-x--- 2 mysql mysql 12288 Apr 22 13:14 sys
drwxr-x--- 2 mysql mysql 4096 Apr 22 13:14 test
root@mysql-server-68b5dfdf4d-2wb67:/#
サービスの作成
k8sクラスタ内のアプリケーションに対して、コンテナをホストするノードが変わっても一定のIPアドレスでアクセスできる様に、サービスを設定して、クラスタIPを取得します。それと同時に、ノードのIPアドレス上のポート番号を通じてk8sクラスタの外部からアクセスできる様にNodePortを利用します。 NodePortは、ノードにポートを開くと同時に、クラスタIPを獲得することができます。
mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
type: NodePort
selector:
app: mysql-server
ports:
- protocol: TCP
port: 3306
nodePort: 32306
上記のYAMLファイルを適応して、サービスを作成後、確認します。 以下の確認結果では、k8sクラスタ内にサービスIPアドレスは、ポッドネットワーク上の10.244.120.7 であること、そして、ノードポート 32306 で、MySQLサーバーのアクセスを受け付けることがわかります。
vagrant@k8s1:/vagrant/yaml$ kubectl apply -f mysql-service.yaml
service "mysql" created
vagrant@k8s1:/vagrant/yaml$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
省略
mysql NodePort 10.244.120.7 <none> 3306:32306/TCP 7s
MySQLサーバーへのアクセス
MySQLサーバーにアクセスして、動作確認を進めていきます。
k8sクラスタ内からのアクセス
k8sクラスタ内に対話でシェルやコマンドが使えるデプロイメントを起動します。
vagrant@k8s1:/vagrant/yaml$ kubectl run ubuntu --image=ubuntu:latest -- tail -f /dev/null
deployment.apps "ubuntu" created
デプロイメントのポッド名を確認して、対話シェルを起動します。 そして、mysql-clientをインストールします。
vagrant@k8s1:/vagrant/yaml$ kubectl get pods
NAME READY STATUS RESTARTS AGE
ubuntu-fcdb8ff7-4dkvb 1/1 Running 0 11s
vagrant@k8s1:/vagrant/yaml$ kubectl exec -it ubuntu-fcdb8ff7-4dkvb bash
root@ubuntu-fcdb8ff7-4dkvb:/# apt-get update
Get:1 http://archive.ubuntu.com/ubuntu xenial InRelease [247 kB]
省略
root@ubuntu-fcdb8ff7-4dkvb:/# apt-get install mysql-client -y
サービス名は、kube-dnsに登録されていますから、mysql -h mysql -u root -proot
で、DNS名でアクセスすることができます。
root@ubuntu-fcdb8ff7-4dkvb:/# mysql -h mysql -u root -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.22 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
mysql>
k8sクラスタのポッドから、mysqlのVIP相当のIPアドレスにアクセスすることができました。
クラスタ外からのアクセス
次に、ノードのポート番号に対して、アクセスを確認します。 マスターノードにも kube-proxyが動作していますから、マスターノードのIPアドレスとNodePortで指定したポート番号に、MySQLクライアントで接続できる事を確認します。
imac:yaml maho$ mysql -u root -proot -h 192.168.1.91 -P 32306
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.22 MySQL Community Server (GPL)
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
ノード障害時の計画的な退避
ポッドをホストするノードに何らかの障害が発生してケースを想定して、現在ポッドが動作しているノードから、他のノードへポッドを退避させる動作を見てみます。 まず、現在のノードを調べます。
vagrant@k8s1:/vagrant/yaml$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
mysql-server-68b5dfdf4d-jd2fn 1/1 Running 0 7m 10.244.1.98 k8s2
省略
ワーカノード k8s2上のポッドを他のポッドに退避させるために、kubectl drain k8s2 --ignore-daemonsets
を実行します。
以下の結果から、48秒で退避(テイクオーバー)が完了したことが判ります。
vagrant@k8s1:/vagrant/yaml$ date
Sun Apr 22 13:43:59 UTC 2018
vagrant@k8s1:/vagrant/yaml$ kubectl drain k8s2 --ignore-daemonsets
node "k8s2" cordoned
WARNING: Ignoring DaemonSet-managed pods: kube-flannel-ds-5lsd4, kube-proxy-n82vs
省略
pod "mysql-server-68b5dfdf4d-jd2fn" evicted
省略
node "k8s2" drained
vagrant@k8s1:/vagrant/yaml$ date
Sun Apr 22 13:44:47 UTC 2018
退避先のノードを確認しておきます。
vagrant@k8s1:/vagrant/yaml$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
省略
mysql-server-68b5dfdf4d-jlgj2 1/1 Running 0 1m 10.244.2.88 k8s3
省略
k8s2に、ポッドにスケジュールされる様に、状態を変更しておきます。
vagrant@k8s1:/vagrant/yaml$ kubectl uncordon k8s2
node "k8s2" uncordoned
突然のノード停止時の動作
次に、ハードウェア障害などで、突然停止したケースを想定したテストを実施します。 $ vagrant halt k8s3
を実行して、直後に、次のdate
コマンドを実行しました。 この状態ではk8sは障害を検知していません。
vagrant@k8s1:/vagrant/yaml$ date
Sun Apr 22 13:48:29 UTC 2018
vagrant@k8s1:/vagrant/yaml$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
mysql-server-68b5dfdf4d-jlgj2 1/1 Running 0 4m 10.244.2.88 k8s3
省略
vagrant@k8s1:/vagrant/yaml$ kubectl get deploy -o wide
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
mysql-server 1 1 1 1 34m mysql mysql:5.7 app=mysql-server
省略
約30秒後に、AVAILABLE = 0となり、停止を検知しています。
vagrant@k8s1:/vagrant/yaml$ date
Sun Apr 22 13:49:08 UTC 2018
vagrant@k8s1:/vagrant/yaml$ kubectl get deploy -o wide
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
mysql-server 1 1 1 0 34m mysql mysql:5.7 app=mysql-server
省略
それから、約5分後に、ワーカーノードk8s2で mysqlサーバーのポッドが立ち上がり、フェイルオーバーが完了したことが判ります。
vagrant@k8s1:/vagrant/yaml$ date
Sun Apr 22 13:53:54 UTC 2018
vagrant@k8s1:/vagrant/yaml$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
mysql-server-68b5dfdf4d-7j642 1/1 Running 0 27s 10.244.1.108 k8s2
mysql-server-68b5dfdf4d-jlgj2 1/1 Unknown 0 9m 10.244.2.88 k8s3
まとめ
k8sクラスタのポッドから、iSCSIターゲットのボリュームを利用できること、iSCSIはポッドとボリュームが一対一接続のために、PVやPVCを利用することなく、ポッドに設定してボリュームをアクセスできることが確認できました。 さらに、サービスを利用することで、ノード障害時にも、アプリケーションはVIP相当のクラスタIPのDNS名でアクセスを続けられることが確認できました。
ポッドが健全なノードで起動するまでには、約5分間の猶予時間が設定されていて、テスト中は長いと感じます。 しかし、敏感に反応してしまうと、例えば重い処理が実行されているケースに、意図しないフェールオーバーが起動して、障害となるケースを考慮すると、5分程度の適度な猶予時間を持つことは、適切な動きと思います。