さー、今回は、mysql いや、mariadb を構築してみたいと思います。
しかも、Dockerで、さらに、覚えたての Kubernetesで、落ちないサーバーに仕上げます。
ちなみに、OCIだと、mysqlが saasで提供されているので、普通の人は、そっちを使って下さい。
 
mariadb には、マルチマスタークラスターなる、凄い高可用性重視の機能があるようです。
これを構築出来れば、DBは、これだけで良いんじゃないかと思うぐらいです。
せっかく、こんな機能があるなら、OCI の Kubernetes を使えば、落ちないサーバーが作れるかと思い作ってみました。
 
では、早速、いってみましょう

 


まず、ベースとなる Dockerイメージを構築するのですが、イメージをPullしてくるのは、おもしろくないので、Ubuntuイメージから構築してみます。

では、定番の2つのファイルを作って、起動しましょう。

コンテナは、mariadbcluster2としましょう。

mkdir mariadbcluster2
cd mariadbcluster2

Dockerfile

FROM ubuntu
RUN bash
 
docker-compose.yml

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
 
docker-compose.yml
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
 
 
MariaDBのインストール

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

 

/etc/mysql/mariadb.conf.d/50-server.cnf の bind-address をコメントします

#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

 

これで、とりあえず、Mariadbサーバーの完成です。

 

OCIのコンテナとして、イメージをPushします。

さー、ここからが本番です
まず、OCI のコンテナレジストリに登録します。

レジストリの作成

パブリック

リボジトリ名を 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
 
このファイルは、OCIのファイルストレージを構築するようになっています。
  availabilityDomain: NtKM:AP-OSAKA-1-AD-1
  mountTargetSubnetOcid: ocid1.subnet.oc1.ap-osaka-1...........
  compartmentOcid: ocid1.compartment.oc1...........
この部分なんですが、ファイルストレージを作成するサブネットを指定しています。自分の環境で、各Pod達がアクセス可能なサブネットを指定してあげて下さいね。
 
データベースの容量ですが、以下で決定しています。でかいのがほしい方は、ここを増やして下さいませ。
 storage: 50Gi
 
可用性ですが、以下で、Podの数を指定しています。各Podは、個別のストレージを持つことになるので、ここを大きくすると、それだけBlockStorageを構築することになるので、お財布と相談して下さい。
   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を変えて、どんどん作れそうなんで、お試しあれ

 

Joomla templates by a4joomla