Dockerコンテナ内の処理を定期的に起動

unix/linuxで定期的に処理を動かしたいときはcrontab使う。

たとえばcrontab.txtとか適当なファイルを作っておく。
左から、「分」「時」「日」「月」「曜日」「コマンド」を書く。

#daily rm
00 7 * * *                /bin/find /gvis/ -name ".*DS_Store" -print -exec rm {} ";"
01 7 * * *                /bin/find /gvis/ -name "Thumbs.db"  -print -exec rm {} ";"
02 7 * * *                /bin/find /nari/ -name ".*DS_Store" -print -exec rm {} ";"
03 7 * * *                /bin/find /nari/ -name "Thumbs.db"  -print -exec rm {} ";"

この定義使うと、Thumbs.db(windowsが勝手に作るファイルね)とDS_Store(macが勝手に作るファイルね)を/nariのディレクトリ以下から探し出して抹消してくれる。

毎朝元気に動いてくれてて、不要なデータは定期バックアップ前に抹消できてる。

dockerコンテナには親ホストがいて、親ホストのコントロールで定期的に処理を動かすにはどうしたらいいか。

例えばデータベースの定義を定期的に出力させて、開発してるときは月に1回、普段は四半期に1回とか保管するのに使いたい。

結論

親ホストのrootのcrontabにdocker execを使ってコンテナ内の処理を呼び出す設定を書いてcrondから呼び出させ、永続化領域に出力した結果を親ホストの任意の保管先に持ってくる。

このmariadbにあるデータベース定義を、ubuntu22LTSのrootユーザのcrontab定義使って定期的に901_nariDB_1st_DDLout.shを呼び出すことでテキストファイルに出力させる。

#mariadb output DDL
07 06 * * *    /usr/bin/docker exec docker_sv_mariadb_1 /bin/sh /etc/mysql/conf.d/nari/901_nariDB_1st_DDLout.sh ;  cp -p /gvis/nari/nariDocs/Docker/nariDockerDat/sv_mariadbconf/nari/DDLdefine.txt /gvis/nari/nariDocs/smb/svm/Public/999_その他/  > /dev/null

処理は前半がスクリプト起動で、セミコロンで区切った後半が任意の場所へのファイルのコピー。

この定義のおかげで、毎朝7時すぎにDDLdefine.txtが出力されて、自分が置いときたい場所にコピーしてくれる。

コピーされたファイルは例えばこんな感じ。

----Show DDL ------ 2022-08-03_06:07:02_
---------------------------------------------------------------------
GVIS_keihi      CREATE TABLE `GVIS_keihi` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `workPeriod` datetime DEFAULT NULL COMMENT '業務期間-開始日',
  `workShubetsu` char(4) DEFAULT NULL COMMENT '経費種別',
  `workPriority` int(10) DEFAULT NULL COMMENT '経費No-優先順位',
  `Keihi_date` datetime DEFAULT NULL COMMENT '経費日付',
  `Kamoku` varchar(24) DEFAULT NULL COMMENT '科目',
  `Tehai` varchar(1000) DEFAULT NULL COMMENT '手配方法・名称・機種',
  `Kng` decimal(12,4) DEFAULT 0.0000 COMMENT '金額',
  `Biko` varchar(100) DEFAULT NULL COMMENT '備考',
  `ins_date` datetime DEFAULT NULL COMMENT 'データ作成日',
  `ins_user` varchar(100) DEFAULT NULL COMMENT 'データ作成ユーザ',
  `upd_date` datetime DEFAULT NULL COMMENT 'データ更新日',
  `upd_user` varchar(100) DEFAULT NULL COMMENT 'データ更新ユーザ',
  PRIMARY KEY (`id`),
  KEY `IDX_keihi` (`workPeriod`,`workShubetsu`,`workPriority`,`Keihi_date`,`Kamoku`)
) ENGINE=InnoDB AUTO_INCREMENT=9478 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC
---------------------------------------------------------------------
GVIS_hwcheckResult    CREATE TABLE `GVIS_hwcheckResult` (
  `Computer` varchar(100) NOT NULL COMMENT 'コンピュータ名',
  `ItemOrder` int(11) NOT NULL COMMENT '項番',

    :(省略)

  PRIMARY KEY (`id`),
  KEY `IDX_zaiko` (`SerialShubetsu`,`SerialSeq1`,`SerialSeq2`,`GVIS_No`,`Category1`,`Category2`,`ShokyakuHou`,`alwayson`)
) ENGINE=InnoDB AUTO_INCREMENT=114 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC

--Update on Docker container --
-rw-r--r-- 1 1002 1003 14720 Aug  3 06:07 /etc/mysql/conf.d/nari/DDLdefine.txt

項目定義を増やしたり、削ったり、変更したりしたとき、その履歴を残して経緯を確認したり元に戻したくなったときに参考にする。

最も新しい更新見ると、djangoでこのデータベースにあるテーブルを使わせたくなったとき、AUTO_INCREMENTって型でidって列を先頭につけた。

利用構成について

構成はこんな感じ。

+------------------------------------------------------------+
|ubuntu22LTS(docker20)                                       |
|  +---------------------------+                             |
|  | dockerコンテナ(https)     |                             |
|  +---------------------------+                             |
|  +---------------------------+  +----------------------+   |
|  | dockerコンテナ(django4)   |->|永続化領域(sv_django) |   |
|  +---------------------------+  +----------------------+   |
|  +---------------------------+  +----------------------+   |
|  | dockerコンテナ(mariadb10) |->|永続化領域(sv_mariadb)|   |
|  +---------------------------+  +----------------------+   |
|               ↑                            ↓             |
|  +---------------------------+  +----------------------+   |
|  | crond                     |  |任意の保管場所        |   |
|  +---------------------------+  +----------------------+   |
|                                                            |
+------------------------------------------------------------+

djangoで作ったwebアプリをssl経由で使ってて、mariadb使ってる。

元々mariadbはmysqlとしてdjangoよりもっと前から稼働させてて、sun microsystems(oracle)社がmysqlを買収した頃にmariadbに切り替えた。その後数年後にdockerでのコンテナ稼働に切り替えた。

去年にphpからdjangoアプリへの移行に着手するとき、djangoの管理テーブルも内包させた。

前はmariadbの中でデータベース領域を複数使って、定期的に本番からテスト環境へコピーする処理みたいなことやってたけど、コンテナ運用するようになってからはgoogle cloud環境とローカルPCでそれぞれ1つずつデータベース領域使うようになった。

今はgoogle cloudを本番環境に見立てて、クラウドの永続化領域をローカルにコピーすることで、ローカルPCでテスト環境を使ってる。

ファイルのアクセス権について

永続化領域の実態はコンテナに親ホストの領域を起動時にマウントさせること。

docker-compose使ってるので、そのマウント箇所を見るとこうしてる。

volumes:
  - ./nariDockerDat/sv_mariadb:/var/lib/mysql
  - ./nariDockerDat/sv_mariadbconf:/etc/mysql/conf.d

データ領域は/var/lib/mysqlでデータが入ってる。

設定領域はwindowsホストから編集したいこともあるので、同じように切り出してマウントさせてる。ここにcrontabで呼び出すスクリプトも置いてる。

mariadbに限らず、コンテナ内では特定のユーザアカウントで動くこともあるし、rootユーザで稼働してることもある。

mariadbの永続化領域をコンテナに入って見てみるとibdataやデータベースの入ったフォルダはmysqlってユーザがオーナになってる。

nari@nafslinux-ubu22:~$ docker exec -it docker-sv_mariadb-1 bash
root@svmariadb:/# cd /var/lib/mysql
root@svmariadb:/var/lib/mysql# ll
total 1192856
drwxr-xr-x 7 mysql  1000       4096 Aug  4 04:51 ./
drwxr-xr-x 8 root  root          80 Nov  5  2020 ../
-rw-r----- 1 mysql  1000      65536 Aug  3 11:59 aria_log.00000001
-rw-r----- 1 mysql  1000         52 Aug  3 11:59 aria_log_control
-rw-rw---- 1 mysql mysql     841351 Aug  3 11:59 ib_buffer_pool
-rw-rw---- 1 mysql mysql  134217728 Aug  4 04:51 ib_logfile0
-rw-r----- 1 mysql  1000 1073741824 Aug  3 11:59 ibdata1
-rw-rw---- 1 mysql mysql   12582912 Aug  4 04:51 ibtmp1
-rw-r----- 1 mysql  1000          0 Oct 27  2019 multi-master.info
drwx------ 2 mysql  1000       4096 Oct 27  2019 mysql/
drwx------ 2 mysql  1000       4096 Feb 24 06:47 nariDB_1st/
drwx------ 2 mysql  1000       4096 Dec  4  2021 nariDB_1st_daily/
drwx------ 2 mysql mysql       4096 Aug  3 05:27 nariDB_Django/
drwx------ 2 mysql  1000       4096 Oct 27  2019 performance_schema/
root@svmariadb:/var/lib/mysql#

同じ領域を親ホストから見てみる。

nari@nafslinux-ubu22:/docker/nariDockerDat/sv_mariadb$ pwd
/docker/nariDockerDat/sv_mariadb
nari@nafslinux-ubu22:/docker/nariDockerDat/sv_mariadb$ ll
合計 1.2G
drwxr-xr-x  7  999 nari   4.0K 2022-08-04 04:51:49 ./
drwxrwxrwx 17 nari nari   4.0K 2022-08-03 05:25:32 ../
-rw-r-----  1  999 nari    64K 2022-08-03 11:59:02 aria_log.00000001
-rw-r-----  1  999 nari     52 2022-08-03 11:59:02 aria_log_control
-rw-rw----  1  999 docker 822K 2022-08-03 11:59:01 ib_buffer_pool
-rw-rw----  1  999 docker 128M 2022-08-04 04:51:49 ib_logfile0
-rw-r-----  1  999 nari   1.0G 2022-08-03 11:59:01 ibdata1
-rw-rw----  1  999 docker  12M 2022-08-04 04:51:51 ibtmp1
-rw-r-----  1  999 nari      0 2019-10-27 08:34:00 multi-master.info
drwx------  2  999 nari   4.0K 2019-10-27 08:34:29 mysql/
drwx------  2  999 nari   4.0K 2022-02-24 06:47:14 nariDB_1st/
drwx------  2  999 nari   4.0K 2021-12-04 06:44:38 nariDB_1st_daily/
drwx------  2  999 docker 4.0K 2022-08-03 05:27:59 nariDB_Django/
drwx------  2  999 nari   4.0K 2019-10-27 08:33:58 performance_schema/
nari@nafslinux-ubu22:/docker/nariDockerDat/sv_mariadb$

さっきのmysqlっていうユーザは999って見えるし、1000ってグループ番号は親ホストで使ってる普段使いのユーザnariって見えてる。

親ホストにあるdockerってグループは番号が999で、コンテナのmysqlのグループの番号と被ってる。ぐっちゃぐちゃやなぁ。

こんな感じだと親ホストから永続化領域へのファイル操作は、一般ユーザでは失敗してしまうので、処理は常にrootユーザを使って呼び出す。

永続化領域を所有権を含んでバックアップ維持しているので、本番データをローカルのコンテナにマウントしてテストに使える。

スクリプトでやってること

mariadbの設定ファイル置いてる永続化領域にスクリプト置いてる。
コンテナ化してなかったときに作った処理なので、コピー先をコンテナから見た永続化領域に書き換えてある。

#!/bin/sh
## -------------------------------------------------------------------------
## Script Name  : 901_nariDB_1st_DDLout.sh
##  Created by  : T.Naritomi
##          on  : 2014.04.12
##  Updated by  : 2014.11.09
##          on  :
##  Parameters  :
##  Return Code : 0=Normal End
##     Comments :
## -------------------------------------------------------------------------
LANG=ja_JP.UTF-8

TMP1_FILE=/tmp/$$_1.txt
TMP2_FILE=/tmp/$$_1.txt
RES_FILE=$0.res.txt
###CP_DEST=/nari/nariDocs/smb/svm/Public/999_その他/DDLdefine.txt
CP_DEST=/etc/mysql/conf.d/nari/DDLdefine.txt
DBPASS=xxxxxxxxxxxxxxxxxxxxx

rm -f ${RES_FILE}

## ----detail --------------------------------------------------------------

## ----Show DDL on MySQL ---------------------

echo '----Show DDL ------' `date +%F_%T_` >> ${TMP1_FILE}

/usr/bin/mysql -u root -p${DBPASS}  >> ${TMP1_FILE} << EOF
  use nariDB_1st ;
  set character_set_results='utf8';

     show create table GVIS_hwcheckResult                       ;
     show create table GVIS_keihi                               ;
     show create table GVIS_log                                 ;
     show create table GVIS_logon                               ;
     show create table GVIS_mst_customer                        ;
     show create table GVIS_mst_kamoku                          ;
     show create table GVIS_mst_keihishubetsu                   ;
     show create table GVIS_mst_kshisanShokyaku                 ;
     show create table GVIS_mst_kshisanShokyakuRit              ;
     show create table GVIS_mst_nohin                           ;
     show create table GVIS_transaction                         ;
     show create table GVIS_work                                ;
     show create table GVIS_zaiko                               ;

     exit

EOF

cat ${TMP1_FILE} | awk {'gsub(/\\n/,"\n") ; print '} | awk {'gsub(/Table    Create Table/,"---------------------------------------------------------------------") ; print '} > ${RES_FILE}

cp -p ${RES_FILE} ${CP_DEST}
ls -ld ${CP_DEST} | awk 'BEGIN{print ""; print "--Update on Docker container --" ; }{print $0}' >> ${CP_DEST}


## ----Finish --------------------------------------------------------------

rm -f ${TMP1_FILE}

exit

データベース接続してset character_set_results='utf8'ってやることで、テーブルのコメントに全角文字入れてるのが化けなくて済む。

後ろのほうでawk使ってるのは、出力結果の加工。
前はawkに色々書いてたけど、今は最終行にdockerコンテナからの出力でっせー、って書き足してるだけ。

昔やってたデータベース間のコピー処理

ついでに思い出したのでメモ。

開発でデータベースを複数維持してたときのスクリプト。
もう動かしてないけど、処理作るとき最初は苦労したなぁ。

nariDB_1stからnariDB_1st_dailyへまるごとコピーする処理。
自分のデータは10GB程度やけど、コンテナ化する前も後も5分以内で処理完了してたと思う。

#!/bin/sh
## -------------------------------------------------------------------------
## Script Name  : 020_copy_nariDB_daily.sh
##  Created by  : T.Naritomi
##          on  : 2013.04.12
##  Updated by  :
##          on  :
##  Parameters  :
##  Return Code : 0=Normal End
##     Comments :
## -------------------------------------------------------------------------
LANG=ja_JP.UTF-8

TMP_FILE=/tmp/$$_1.txt
RES_FILE=$0.res.txt
DBPASS=xxxxxxxxxxxxxxxxxxxxx

rm -f ${RES_FILE}

## ----detail --------------------------------------------------------------

## ----Copy nariDB_1st to nariDB_1st_daily on MySQL ---------------------

echo '----drop&create database ------' `date +%F_%T_` >> ${TMP_FILE}

/usr/bin/mysql -u root -p${DBPASS}  >> ${TMP_FILE} << EOF
        drop database nariDB_1st_daily ;
        create database nariDB_1st_daily ;
        show databases ;
        exit

EOF


echo '----copy Start  ------' `date +%F_%T_` >> ${TMP_FILE}


/usr/bin/mysqldump -u root -p${DBPASS} -n nariDB_1st | /usr/bin/mysql -u root -p${DBPASS} nariDB_1st_daily

echo '----show tables ------' `date +%F_%T_` >> ${TMP_FILE}

/usr/bin/mysql -u root -p${DBPASS}  >> ${TMP_FILE} << EOF
        use nariDB_1st_daily
        show tables ;
        exit

EOF


echo '----copy Finished-----' `date +%F_%T_` >> ${TMP_FILE}


## ----For MySQL -----------------------------------------------------------


cat ${TMP_FILE} >  ${RES_FILE}

## ----Finish --------------------------------------------------------------

rm -f ${TMP_FILE}

exit

rootでなくてもええんやけど・・・

crontabはユーザごとに定義できる。
rootじゃなくて、自分の普段使いユーザで昔は定義してた。

そのうち用途ごとのユーザを使うようになって、OS切り替えしたときにcrontab定義の引っ越しを忘れたことがあって、けっこうツラかった。

それに、一般ユーザで実行してる処理とrootで実行してる処理で時間帯が被ってることに気づかず、処理結果が変なことになっても答えを見つけづらい。

一元化しといたほうが、引っ越しするときに漏れないし全体を見渡せる。

そういうわけで、crontabはrootユーザで全部定義し、ユーザ単位で動かしたい処理はsudoして動かすようにしてる。

コンテナ使うと、永続化領域の所有権ぐちゃぐちゃになりやすいから、バックアップ取るときのためにもrootで動かすほうが楽。

OSを変えた時に点検するのは、フォルダ位置がずれたり、コンテナ名が変わったりしてないかってこと。

最近あったのはコンテナ全削除して作り直したとき、コンテナ名が微妙に変わってたことがあった。

ubuntu20から22に引っ越してdockerもdocker-composeもバージョン上げたら、データベース定義の出力結果が出てないなって気づいた。

アンダースコアがハイフンに変わってたから、docker runするときの名前を変えなきゃいけないことに気づいた。

windowsのタスクスケジューラはときどき起動してくれないことあって腹立つけど、crontabは起動できずに腹立ったことないなぁ。

古い仕組みかもしれんけど、cron/crontab定義はずっと使うと思う。

タイトルとURLをコピーしました