前回、作った、mariadbですが、何かに使いたくなりました。
そこで、以前から、ほしかったスケジューラーを構築することにします。
スケジューラーってのは、cronの凄い版で、曜日や祝日なんかを考慮して、タスク実行してくれるやつです。
基幹業務を作ってる人は、お馴染みのシステムですね。
業務用途で使うことが多いですね。JP1とかSystemWalkerなんかが、日本ではメジャーになるのでしょうか。
オープンソースとなると、JS7 Jobscheduler が有名です。
JS7は、Javaベースのアプリなんで、導入し易いですね。
JS7は、データベースを使うのですが、mysqlをサポートしているので、今回の用途には、ピッタリです。
ということで、今回は、このJS7を、OCIの Kubernetesクラスタ(OKE)で、構築してしまいましょう。
JS7は、Cockpit、Control、Agentと3つのコンポーネントにわかれています。
なので、1つずつ構築していきます。
まず、Cockpitを構築しましょう。
 
では、早速、いってみましょう

JS7は、データベースを使うので、事前にデータベースを構築します。
まー、データベースとユーザーを作って、権限を与えてるだけです。既存ユーザーを使いまわしても良いですよ。
 
rootログイン
mysql -u root
 
DB作成
CREATE DATABASE js7 CHARACTER SET utf8 COLLATE utf8_general_ci;
 
ユーザー作成
CREATE USER 'jobscheduler'@'%' IDENTIFIED BY 'jobscheduler';
CREATE USER 'jobscheduler'@'localhost' IDENTIFIED BY 'jobscheduler';
 
権限設定
GRANT ALL ON js7.* TO 'jobscheduler'@'%';
GRANT CREATE, CREATE VIEW, DROP, ALTER, EXECUTE, SELECT, UPDATE, INSERT, DELETE on js7.* to 'jobscheduler'@'%';
 
GRANT ALL ON js7.* TO 'jobscheduler'@'localhost';
GRANT CREATE, CREATE VIEW, DROP, ALTER, EXECUTE, SELECT, UPDATE, INSERT, DELETE on js7.* to 'jobscheduler'@'localhost';
 

まず、ベースとなる Dockerイメージを構築するのですが、イメージをPullしてくるのは、おもしろくないので、Ubuntuイメージから構築してみます。
では、定番の2つのファイルを作って、起動しましょう。
コンテナは、cockpit としましょう。

mkdir -p js7base/cockpit
cd js7base/cockpit

Dockerfile

FROM ubuntu
RUN bash
 
docker-compose.yml

version: "3"
services:
 main:
  build:
   context: .
  privileged: true
  command: bash
  hostname: main
  tty: true

 

起動してJS7ベース環境を構築していきます。
docker compose up -d
 
Shellに接続します。
docker exec -it cockpit-main-1 bash

では、普通にUbuntuを構築していきます。
apt update
apt upgrade -y
apt install language-pack-ja-base language-pack-ja net-tools iputils-ping traceroute dnsutils vim tzdata sudo curl openjdk-19-jre-headless -y
locale-gen ja_JP.UTF-8
echo "export LANG=ja_JP.UTF-8" >> ~/.bashrc

作業管理用ユーザーを追加します。
useradd scheduler -m -p scheduler
passwd scheduler 
sudo にも登録する
echo 'Defaults:scheduler !requiretty' >> /etc/sudoers.d/scheduler
echo "scheduler ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/scheduler
chmod go-r /etc/sudoers.d/scheduler

作業ユーザーにスイッチします。
su - scheduler

cockpitをインストールします。
curl -O https://download.sos-berlin.com/JobScheduler.2.6/js7_joc_linux.2.6.3.tar.gz
tar -xvf js7_joc_linux.2.6.3.tar.gz
cd joc.2.6.3
joc_install.xml を編集します。
前)
<installpath>[:choose absolute installation path of JOC Cockpit:]</installpath>
後)
<installpath>/opt/sos-berlin.com/js7/joc</installpath>
前)
<entry key="jettyBaseDir" value=""/>
後)
<entry key="jettyBaseDir" value="/home/scheduler/sos-berlin.com/js7/joc"/>
前)
<entry key="launchJetty" value="yes"/>
後)
<entry key="launchJetty" value="no"/>
データベース項目を修正します。ご自分の環境に合わせて下さいね。
databaseHost:[mariadb や mysqlのアドレス]
databasePort:3306
databaseSchema:js7
databaseUser:jobscheduler
databasePassword:jobscheduler

セットアップしましょう
./setup.sh ./joc_install.xml

ルートに戻って、起動スクリプトを作成します。

exit

/root/startjoc.sh

#!/bin/bash

# safty Exit
function exit_script(){
  echo "Caught SIGTERM"
  /opt/sos-berlin.com/js7/joc/jetty/bin/jetty.sh stop
  exit 0
}
trap exit_script SIGTERM

/opt/sos-berlin.com/js7/joc/jetty/bin/jetty.sh run

trap break ERR

while [ 1 ]
do
  /usr/bin/sleep 10
  PIDSTR=`/opt/sos-berlin.com/js7/joc/jetty/bin/jetty.sh check | grep 'Jetty running pid'`
  if [ ! -n "$PIDSTR" ]; then
    break
  fi
done

起動権限を与えます。

chmod a+x /root/startjoc.sh

exit

 

ここで、コンテナに保存です。

docker stop cockpit-main-1

docker commit cockpit-main-1 js7-cockpit

で、停止です。
docker compose down

最後に、仕上げのDockerfileとdocker-compose.ymlを修正します。

Dockerfile

FROM js7-cockpit
ENTRYPOINT [ "/root/startjoc.sh" ]
EXPOSE 4446/tcp
 
docker-compose.yml
version: "3"
services:
 cockpit:
  image : js7-cockpit
  build: 
   context: .
  ports:
    - "0.0.0.0:4446:4446"
  command: /root/startjoc.sh
  hostname: js7cockpit
  tty: true

次、Controlを構築しましょう。

mkdir -p js7base/control
cd js7base/control

Dockerfile

FROM ubuntu
RUN bash
 
docker-compose.yml

version: "3"
services:
 main:
  build:
   context: .
  command: bash
  hostname: main
  tty: true

 

起動してJS7ベース環境を構築していきます。
docker compose up -d
 
Shellに接続します。
docker exec -it control-main-1 bash

では、普通にUbuntuを構築していきます。
apt update
apt upgrade -y
apt install net-tools iputils-ping traceroute dnsutils vim tzdata curl openjdk-19-jre-headless -y

controlをインストールします。
cd
tar -xvf js7_controller_unix.2.6.3.tar.gz
cd controller/bin
cp -p controller_instance.sh-example controller_instance.sh
起動スクリプトを作成します。

/root/startcnt.sh

#!/bin/bash
 
# safty Exit
function exit_script(){
  echo "Caught SIGTERM"
  /root/controller/bin/controller_instance.sh stop
  exit 0
}
trap exit_script SIGTERM
 
/root/controller/bin/controller_instance.sh start-container

起動権限を与えます。

chmod a+x /root/startcnt.sh

exit

ここで、コンテナに保存です。

docker stop control-main-1

docker commit control-main-1 js7-control

で、停止です。
docker compose down

最後に、仕上げのDockerfileとdocker-compose.ymlを修正します。

Dockerfile

FROM js7-control
ENTRYPOINT [ "/root/startcnt.sh" ]
EXPOSE 4444/tcp
 
docker-compose.yml
version: "3"
services:
 control:
  image : js7-control
  build: 
   context: .
  ports:
    - "0.0.0.0:4444:4444"
  command: /root/startcnt.sh
  hostname: js7control
  tty: true

次、Agentを構築しましょう。

作業前に、NFSのポイントを作成しておいて下さい。

Agentは、揮発ボリュームにインストールすると不整合が起きて、再起動時に正常動作しなくなるようです。

なので、OCIのファイルストレージを作成して、そこにインストールすることにします。

docker-compose.ymlの赤字の部分が、ファイルストレージになるので、ここを確保しておいて下さい。

 

mkdir -p js7base/agent
cd js7base/agent

Dockerfile

FROM ubuntu
RUN bash
 
docker-compose.yml
version: "3"
services:
 main:
  build: 
   context: .
  command: bash
  hostname: main
  tty: true
  volumes:
   - agentvol:/root/agent
 
volumes:
  agentvol:
    driver_opts:
      type: nfs
      o: "addr=k8mount.private.vcn6.oraclevcn.com,soft"
      device: ":/js7agent"

 

起動してJS7ベース環境を構築していきます。
docker compose up -d
 
Shellに接続します。
docker exec -it agent-main-1 bash

では、普通にUbuntuを構築していきます。
apt update
apt upgrade -y
apt install language-pack-ja-base language-pack-ja net-tools iputils-ping traceroute dnsutils vim tzdata curl openjdk-19-jre-headless -y
locale-gen ja_JP.UTF-8
echo "export LANG=ja_JP.UTF-8" >> ~/.bashrc

agentをインストールします。

cd
tar -xvf js7_agent_unix.2.6.3.tar.gz
 
cd agent/bin/
cp agent_instance.sh-example agent_4445.sh
起動スクリプトを作成します。

/root/startagent.sh

#!/bin/bash

# safty Exit
function exit_script(){
  echo "Caught SIGTERM"
  /root/agent/bin/agent_4445.sh stop 
  exit 0
}
trap exit_script SIGTERM

/root/agent/bin/agent_4445.sh start

while [ 1 ]
do
  /usr/bin/sleep 10
  STATUSSTR=`/root/agent/bin/agent_4445.sh status | grep version`
  if [ ! -n "$STATUSSTR" ]; then
    break
  fi
done

起動権限を与えます。

chmod a+x /root/startagent.sh

exit

ここで、コンテナに保存です。

docker stop agent-main-1

docker commit agent-main-1 js7-agent

で、停止です。
docker compose down

最後に、仕上げのDockerfileとdocker-compose.ymlを修正します。

Dockerfile

FROM js7-agent
ENTRYPOINT [ "/root/startagent.sh" ]
EXPOSE 4445/tcp
 
docker-compose.yml
 
version: "3"
services:
 agent:
  image: js7-agent
  build: 
   context: .
  ports:
    - "0.0.0.0:4445:4445"
  command: /root/startagent.sh
  hostname: js7agent
  tty: true
  volumes:
   - agentvol:/root/agent
 
volumes:
  agentvol:
    driver_opts:
      type: nfs
      o: "addr=k8mount.private.vcn6.oraclevcn.com,soft"
      device: ":/js7agent"
 

以上で、JS7のコンテナ化は、完了です。
Agentは、コンテナにしなくても、操作したい端末にインストールするのが良いでしょうね。
sshでも入れといてリモート操作でも良いですよ。
 
さっ、今回もOCI で、kubernetes にする予定となっているので、OCIのコンテナとして、イメージをPushします。

OCI のコンテナレジストリに登録します。

レジストリの作成

パブリックかプライベート

※プライベートの場合、kubectl create secret docker-registry で、シークレットを登録し、yaml定義に、imagePullSecrets: を指定する必要があります。

リボジトリ名を js7-cockpitとjs7-controlとjs7-agentで構築します。

 

次にリポジトリアクセス用の認証トークンを作成します。

自分のプロファイルから認証トークンを選択して作成します。

すると、謎の文字列を生成してくれるので、記録して下さい。

 

さっ、Dockerに戻ります。

リポジトリにログインします。 サンプルは、大阪リージョン(kix.ocir.io)ですよ。

サーバーアドレスは、ここに載ってます。

docker login kix.ocir.io

認証するんですが、ユーザー名の前にネームスペースを付けないとダメなんですね。

ネームスペースって何っと思うでしょ。テナンシに割りついている謎の文字列のことです。

テナンシ詳細画面から、オブジェクト・ストレージ・ネームスペースってとこに書かれているので、記録して下さい。

ということで、認証は、以下です。

User:ネームスペース/ユーザー名

Pass:認証トークン

 

無事認証すると、イメージを構築しリポジトリにプッシュします。

 

cd js7base/cockpit
docker image build -t kix.ocir.io/ネームスペース/js7-cockpit:1.0 .
docker push kix.ocir.io/ネームスペース/js7-cockpit:1.0
 
cd js7base/control
docker image build -t kix.ocir.io/ネームスペース/js7-control:1.0 .
docker push kix.ocir.io/ネームスペース/js7-control:1.0
 
cd js7base/agent
docker image build -t kix.ocir.io/ネームスペース/js7-agent:1.0 .
docker push kix.ocir.io/ネームスペース/js7-agent:1.0

いよいよ、kubernetesの出番となります。

これは、OCI で、MariaDB Cluster を構築 そして、Kubernetes で、落ちないサーバーにする で、記載しているので、構築しておいて下さいね。

やっと本作業です

OCIにて、OKE クラスターが完成し、接続環境を準備しましょう。

 

さーて、JS7の環境を構築しましょう。

kubernetesのyamlファイルを作成します。

これは、cockpitとcontrollerになります。agentは、わけておいた方が良いでしょうね。

js7-dep.yaml

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: js7log-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: /js7log
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: js7logclaim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "js7log-storage"
  resources:
    requests:
      storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: js7-service
  name: js7-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: js7-cockpit
  type: LoadBalancer
  ports:
  - port: 4446
    protocol: TCP
    targetPort: 4446
---    
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: js7-cockpit
  name: js7-cockpit
spec:
  replicas: 1
  selector:
    matchLabels:
      app: js7-cockpit
  template:
    metadata:
      labels:
        app: js7-cockpit
    spec:
      containers:
      - image: kix.ocir.io/hogehoge/js7-cockpit:1.0
        imagePullPolicy: Always
        name: js7cockpit
        command: [ "/root/startjoc.sh" ]
        ports:
        - name: js7entry
          containerPort: 4446
        volumeMounts:
          - name: log
            mountPath: /var/log/sos-berlin.com/js7/joc
      volumes:
        - name: log
          persistentVolumeClaim:
            claimName: js7logclaim
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: js7-control
  name: js7-cnt
  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: js7-control
  type: LoadBalancer
  ports:
  - port: 4444
    protocol: TCP
    targetPort: 4444
---    
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: js7-control
  name: js7-control
spec:
  replicas: 1
  selector:
    matchLabels:
      app: js7-control
  template:
    metadata:
      labels:
        app: js7-control
    spec:
      containers:
      - image: kix.ocir.io/hogehoge/js7-control:1.0
        imagePullPolicy: Always
        name: js7control
        command: [ "/root/startcnt.sh" ]
        ports:
        - name: js7control
          containerPort: 4444
 
コンテナレジストリを指定して下さいね。
     - image: kix.ocir.io/hogehoge/js7-cockpit:1.0
      - image: kix.ocir.io/hogehoge/js7-control:1.0
 
このファイルは、OCIのファイルストレージを構築するようになっています。
  availabilityDomain: NtKM:AP-OSAKA-1-AD-1
  mountTargetSubnetOcid: ocid1.subnet.oc1.ap-osaka-1...........
  compartmentOcid: ocid1.compartment.oc1...........
この部分なんですが、ファイルストレージを作成するサブネットを指定しています。自分の環境で、Podがアクセス可能なサブネットを指定してあげて下さいね。
 
何度も確かめて下さいね

良ければ、Goです。

kubectl apply -f ./js7-dep.yaml

 

すぐには、構築出来ないので、ゆっくり待ちましょう。

確認は、以下で行えます。

kubectl get pod -o wide

kubectl get pvc

kubectl get svc -o wide

Network Load Balancer(svc)が構築されているので、これに対して接続することで、cockpitとcontrollerに接続することが出来ます。

NLBのアドレス確認

kubectl get svc

破棄したい時は、以下で破壊することが出来ます。

kubectl delete -f ./js7-dep.yaml

 

agent用の構築ファイルです。

構築した時のファイルストレージをマウントするようにしておきます。

IPアドレス直書きしていますが、ここをFQDNにするとマウント出来ませんでした。なんででしょうね。

js7-agent.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: js7agent-storage
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: fss.csi.oraclecloud.com
    volumeHandle: ocid1.filesystem.oc1.ap_osaka_1.abcdefghifzt3dsnnuxqllqojxwiotboaww643bnnqs2mqprfsc2mia:15.9.2.12:/js7agent
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: js7agentclaim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: ""
  resources:
    requests:
      storage: 10Gi
  volumeName: js7agent-storage
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: js7-agent
  name: js7-agent-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: js7-agent
  type: LoadBalancer
  ports:
  - port: 4445
    protocol: TCP
    targetPort: 4445
---    
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: js7-agent
  name: js7-agent
spec:
  replicas: 1
  selector:
    matchLabels:
      app: js7-agent
  template:
    metadata:
      labels:
        app: js7-agent
    spec:
      containers:
      - image: kix.ocir.io/hogehoge/js7-agent:1.0
        imagePullPolicy: Always
        name: js7agent
        command: [ "/root/startagent.sh" ]
        ports:
        - name: js7agent
          containerPort: 4445
        volumeMounts:
          - name: agent
            mountPath: /root/agent
      imagePullSecrets:
        - name: danrepo
      volumes:
        - name: agent
          persistentVolumeClaim:
            claimName: js7agentclaim

 

agentも Network Load Balancer(svc)が構築されているので、これに対して接続することで、agentに接続することが出来ます。


JS7の具体的な使い方は、googleさんや、chatgptにでも尋ねれば良いかと思います。

コックピットへの接続は、Network Load Balancer(svc) のリスナーアドレスに接続します。

http://[コックピットのNLB]:4446/

コントローラーの追加とエージェントの追加は、kubernetesのDNSを設定します。

コントローラー

http://js7-cnt.default.svc.cluster.local:4444

エージェント

http://js7-agent-svc.default.svc.cluster.local:4445


ということで、完成したのですが、あんまり個人で、こんなスケジューラー使うことって無いんですよね。

cronでこと足りるのですわ。

でも、せっかく構築したので、REST API とか使って、何かしてみましょう。

 

おまけネタです

セレクタからpodのipアドレスを取得するワザです。

kubectl get pods --selector=app=セレクタ名 -o wide -o=jsonpath='{.items[*].status.podIP}'`

そして、それを OCIのDNSゾーンに更新するワザです。

PODIP=IPアドレス

ZONEID=ゾーンのOCID

FQDN=対象ドメイン名

oci dns record rrset update --domain $FQDN --zone-name-or-id ${ZONEID} --rtype A --force --items '[{"domain":"'$FQDN'","isProtected": false,"rdata":"'$PODIP'" ,"rtype":"A","ttl":"3600"}]'

 

Joomla templates by a4joomla