まず、ベースとなる Dockerイメージを構築するのですが、イメージをPullしてくるのは、おもしろくないので、Ubuntuイメージから構築してみます。
では、定番の2つのファイルを作って、起動しましょう。
コンテナは、mariadbcluster2としましょう。
mkdir mariadbcluster2
cd mariadbcluster2
Dockerfile
FROM ubuntu
RUN bash
version: "3"
services:
dbsvr:
build:
context: .
privileged: true
command: bash
hostname: dbsvr
tty: true
起動してMariadb環境を構築していきます。docker compose up -d
Shellに接続します。docker exec -it mariadbcluster2-dbsvr-1 bash
では、普通にUbuntuを構築していきます。apt update
apt upgrade -y
apt install init systemd language-pack-ja-base language-pack-ja net-tools iputils-ping traceroute dnsutils tzdata vim -y
locale-gen ja_JP.UTF-8
echo "export LANG=ja_JP.UTF-8" >> ~/.bashrc
exit
ここで、一旦、コンテナに保存です。docker commit mariadbcluster2-dbsvr-1 mariadbcluster2-dbsvr
で、停止です。docker compose down
次は、Dockerfileとdocker-compose.ymlを修正します。
Dockerfile
FROM mariadbcluster2-dbsvr
ENTRYPOINT [ "/root/start.sh" ]
EXPOSE 3306/tcp
EXPOSE 4444/tcp
EXPOSE 4567/tcp
EXPOSE 4568/tcp
version: "3"
services:
dbsvr:
stop_signal: SIGTERM
build:
context: .
dockerfile: Dockerfile
privileged: true
networks:
- backend
command: /sbin/init
hostname: dbsvr
tty: true
volumes:
- ./mysqldata:/var/lib/mysql
- ./conf:/etc/mysql/conf.d/
networks:
backend:
driver: bridge
docker compose up -d
Shellに接続します。
docker exec -it mariadbcluster2-dbsvr-1 bash
apt install mariadb-server mariadb-client galera-4 galera-arbitrator-4 -y
次に、起動シェルを作成します。
/root/start.sh
#!/bin/bash
CMDNAME=`basename $0`
while getopts adc OPT
do
case $OPT in
"d" ) DELETE="TRUE" ;;
esac
done
# safty Exit
function exit_script(){
echo "Caught SIGTERM"
/etc/init.d/mariadb stop
exit 0
}
trap exit_script SIGTERM
# Initialize Database
if [[ $DELETE = "TRUE" ]]; then
rm -rf /var/lib/mysql/*
fi
# Auto boot strap for kubernetes
if [ ! -e /etc/mysql/conf.d/galera.cnf ]; then
CLUSTER="TRUE"
cp /root/galeratmp.cnf /etc/mysql/conf.d/galera.cnf
else
CLUSTER="FALSE"
fi
# Building Database
if [ ! -d /var/lib/mysql/mysql ]; then
/usr/bin/mysql_install_db --user=mysql
fi
if [[ $CLUSTER = "TRUE" ]]; then
echo 'Start mariadb Cluster'
sed -i 's/safe_to_bootstrap: 0/safe_to_bootstrap: 1/' /var/lib/mysql/grastate.dat
#Hostadd
cp /root/galeratmp.cnf /etc/mysql/conf.d/galera.cnf
/etc/init.d/mariadb start --wsrep-new-cluster
/root/ghostadd.py > /root/galera.cnf
cp /root/galera.cnf /etc/mysql/conf.d/galera.cnf
else
echo 'Start mariadb'
/usr/bin/sleep 30
#Hostadd
/root/ghostadd.py > /root/galera.cnf
cp /root/galera.cnf /etc/mysql/conf.d/galera.cnf
/etc/init.d/mariadbstart
fi
trap break ERR
while [ 1 ]
do
/usr/bin/sleep 5
mysql -e "show status like 'wsrep_%';" | grep wsrep_incoming_addresses
done
後、ghostadd.pyとgaleratmp.cnfを作成します。
ghostadd.py
#!/usr/bin/python3
import os
import re
import socket
# IP Address
host = socket.gethostname()
ip = socket.gethostbyname(host)
#Hostname
hname = os.uname()[1]
#Current
f = open('/etc/mysql/conf.d/galera.cnf', 'r')
data = f.read()
f.close()
for line in data.split("\n"):
result = re.search('gcomm://',line)
if result is not None :
endchr = line[len(line)-1]
if endchr != '/' and endchr != ',':
line = line + ","
print(line + ip)
else:
print( line)
/root/galeratmp.cnf
[galera]
wsrep_cluster_address = gcomm://
起動可能にします。
chmod a+x /root/start.sh
chmod a+x /root/ghostadd.py
初期DBは、いらないので、消去します。
rm -rf /var/lib/mysql/*
次に、mariadbの調整をします。
mv /etc/mysql/conf.d/* /etc/mysql/mariadb.conf.d
#bind-address = 127.0.0.1
/etc/mysql/mariadb.conf.d/60-galera.cnf
[galera]
# Mandatory settings
wsrep_on = ON
wsrep_cluster_name = "MariaDB Galera Cluster"
binlog_format = row
default_storage_engine = InnoDB
innodb_autoinc_lock_mode = 2
# Allow server to accept connections on all interfaces.
bind-address = 0.0.0.0
# Optional settings
wsrep_slave_threads = 2
#innodb_flush_log_at_trx_commit = 0
wsrep_sst_method = rsync
wsrep_provider = '/usr/lib/galera/libgalera_smm.so'
コンテナからexitし、保存です。docker commit mariadbcluster2-dbsvr-1 mariadbcluster2-dbsvr
で、停止です。docker compose down
さー、ここからが本番です
レジストリの作成
パブリック
リボジトリ名を mariadbcluster2で構築します。
次にリポジトリアクセス用の認証トークンを作成します。
自分のプロファイルから認証トークンを選択して作成します。
すると、謎の文字列を生成してくれるので、記録して下さい。
さっ、Dockerに戻ります。
リポジトリにログインします。 サンプルは、大阪リージョン(kix.ocir.io
)ですよ。
サーバーアドレスは、ここに載ってます。
docker login kix.ocir.io
認証するんですが、ユーザー名の前にネームスペースを付けないとダメなんですね。
ネームスペースって何っと思うでしょ。テナンシに割りついている謎の文字列のことです。
テナンシ詳細画面から、オブジェクト・ストレージ・ネームスペースってとこに書かれているので、記録して下さい。
ということで、認証は、以下です。
User:ネームスペース/ユーザー名
Pass:認証トークン
無事認証すると、イメージを構築しリポジトリにプッシュします。
docker image build -t kix.ocir.io/ネームスペース/mariadbcluster2:1.0 .
docker push kix.ocir.io/ネームスペース/mariadbcluster2:1.0
いよいよ、Kubernetesクラスタ(OKE)の出番となります。
とにもかくにも、環境作りです。
kubernetesのクライアント環境を構築します。
apt install apt-transport-https gnupg2 curl sudo
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list
apt update
apt install kubectl kubelet kubeadm
apt-mark hold kubelet kubeadm kubectl
次に、OCI CLI環境を構築します。
apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget libbz2-dev
apt install python3 python3-pip python3-venv
bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"
oci setup config
OCI CLIのセットアップは、公式サイトを参考に構築して下さい。 <- 書くのが疲れました。
では、やっと本作業です
VNCとサブネット、ルート表とかってのは、先に構築しておいて下さいね。
サブネットですが、OCIでは、以下のルールがあるので、ご注意を 当然ですが、各サブネットが疎通可能な状態として下さいね。
Kubernetes APIエンドポイントサブネット
コントロールブレーンが配置されるとこなんで、Privateが良さそうだ
ワーカーノードサブネット
ノード(仮想PC)を配置するところ。PrivateでもPublicでも良さそうだ
このサブネットは、ロードバランサーと同じサブネットに配置出来ないので、注意
ロードバランサーサブネット
LoadBalancerタイプのServiceとして作成されるOCIロードバランサーを配置するサブネット
ここは、外部通信を受け入れることになるので、基本Publicだろう。用途によっては、Privateでも問題無しだ
Pod通信のサブネットは、ロードバランサーと同じサブネットに配置出来ないので、注意
OCI コンソールで、Kubernetes クラスタ(OKE)を構築します。
シェイプは、構築したコンテナイメージとアーキテクチャを合わせて下さいね。
ノードタイプに管理対象を選択した場合、基本的なクラスタの確認 チェックを選択することが可能です。
ここでチェックしないと、ランニングコストがかかってしまうので、お財布と相談して下さいませ。
構築には、まーまーの時間が掛かるので、ゆっくりお茶でも飲んで待ちましょう。
クラスターが完成したら、以下のコマンドで、接続環境を構築しましょう。
クラスタのOCIIDとリージョンを指定してくださいね。
CLUSTERID=ocid1.cluster.oc1.ap-osaka-1.....
oci ce cluster create-kubeconfig --cluster-id ${CLUSTERID} --file $HOME/.kube/config --region ap-osaka-1 --token-version 2.0.0 --kube-endpoint PRIVATE_ENDPOINT
Nodeを確認してみましょう。
kubectl get node -o wide
kubernetesで、OCIのコンテナレジストリにアクセス出きるように、認証情報を登録します。
kubectl create secret docker-registry myrepo --docker-server=kix.ocir.io --docker-username=hogehoge/ユーザー名 --docker-password='パスワード' --docker-email=適当なメールアドレス
いよいよ、超高可用なMariadbサーバーの要である、kubernetesのyamlファイルを作成します。
mariadb-sfull.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: mariadbconf-storage
provisioner: fss.csi.oraclecloud.com
parameters:
availabilityDomain: NtKM:AP-OSAKA-1-AD-1
mountTargetSubnetOcid: ocid1.subnet.oc1.ap-osaka-1...........
compartmentOcid: ocid1.compartment.oc1...........
exportPath: /mariadbconf
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mariadbconfclaim
spec:
accessModes:
- ReadWriteMany
storageClassName: "mariadbconf-storage"
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
labels:
app: mariadb-service
name: mariadb-svc
annotations:
oci.oraclecloud.com/load-balancer-type: "nlb"
oci-network-load-balancer.oraclecloud.com/backend-policy: "FIVE_TUPLE"
oci-network-load-balancer.oraclecloud.com/internal: "true"
spec:
selector:
app: mariadb-dep
type: LoadBalancer
ports:
- port: 3306
protocol: TCP
targetPort: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: mariadb-pod
name: mariadb-dep
spec:
replicas: 3
selector:
matchLabels:
app: mariadb-dep
template:
metadata:
labels:
app: mariadb-dep
spec:
terminationGracePeriodSeconds: 10
containers:
- image: kix.ocir.io/hogehoge/mariadbcluster2:1.0
imagePullPolicy: Always
name: mariadb
command: [ "/root/start.sh" ]
ports:
- name: mysql
containerPort: 3306
- name: cluster1
containerPort: 4444
- name: cluster2
containerPort: 4567
- name: cluster3
containerPort: 4568
volumeMounts:
- name: data
mountPath: /var/lib/mysql
- name: conf
mountPath: /etc/mysql/conf.d
imagePullSecrets:
- name: myrepo
volumes:
- name: data
persistentVolumeClaim:
claimName: mariadbclaim
- name: conf
persistentVolumeClaim:
claimName: mariadbconfclaim
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "oci-bv"
resources:
requests:
storage: 50Gi
- image: kix.ocir.io/hogehoge/mariadbcluster2:1.0
availabilityDomain: NtKM:AP-OSAKA-1-AD-1
mountTargetSubnetOcid: ocid1.subnet.oc1.ap-osaka-1...........
compartmentOcid: ocid1.compartment.oc1...........
storage: 50Gi
replicas: 3
何度も確かめて下さいね
良ければ、Goです。
kubectl apply -f ./mariadb-sfull.yaml
すぐには、構築出来ないので、ゆっくり待ちましょう。
確認は、以下で行えます。
kubectl get pod -o wide
kubectl get pvc
kubectl get svc -o wide
適当なpodが完成すると、中にログインして mariadb環境を構築していきましょう。
kubectl exec -it mariadb-dep-0 -- bash
クラスタ状態を確認してみましょう
mysql -u root -e "show status like 'wsrep_%';" | grep wsrep_incoming_addresses
ここからは、mysqlやmariadbの世界なんで、適当にぐぐってもらって、DBの環境構築して下さい。
Network Load Balancerが構築されているので、これに対して接続することで、超高可用データベースの完成となります。
NLBのアドレス確認
kubectl get svc
NLBへの接続
mysql -u [ユーザー名] -h [NLBのアドレス] -p
あっ、これを破棄したい時は、以下で破壊することが出来ます。
kubectl delete -f ./mariadb-sfull.yaml
しかしながら、今回は、Statefulset で構築したので、BlockStorageは、破壊しません。
だから、もう一回、構築すると、データベースが復活するんですね。
まー便利
でも、本当にいらなくなったら、PVCを全部破棄して下さい。
kubectl delete pvc data-mariadb-dep-0 kubectl delete pvc data-mariadb-dep-1 kubectl delete pvc data-mariadb-dep-3
今回は、実験レベルなんですが、十分実用出来そうですね。
本当に可用性を求めるから、nodeとpodの数を考慮する必要がありそうです。
それと、nodeを増やしたりするとpodの再配置を行わないといけません。そういったことは、よくわからんので、chatgptにでも尋ねて下さいな
一度作ってしまえば、clusterを変えて、どんどん作れそうなんで、お試しあれ