AzureのBlobに定期バックアップファイルを投げ込む

Azure上にあるVMのデータはAzureのblobに投げたらいいかなと思ってやってみた小ネタ。
[azコマンド入れる](https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli?view=azure-cli-latest)ところはマケプレのimageから起動したVMだと要らないようでしたがオレオレイメージだと必要だと思われます。
（ローカルから使えるようにしたいということでなければポータルの`>_`というマークをクリックするとCloudShellというコンソールっぽいのが画面下の方に上がってきてazコマンド使えたりterraform使えたりします。GCPも似たのがあったような。）

####スクリプト
以下はjenkinsHOMEのバックアップをローカルで取りAzureのストレージに転送するjenkinsジョブ（シェルの実行）です。
（1世代だけ。ストレージアカウントは要るのですがazコマンド用のログインは要らないようでした。）

```
#/bin/bash -e
TMPDIR=/tmp
TARFILE='jenkins-bkup.tar.gz'
EXCLUDE='exclude.txt'

test -e ${TMPDIR}/${EXCLUDE} || cat  <<_EOD_ > ${TMPDIR}/${EXCLUDE}
workspace
workspace/[0-9a-zA-Z\/\.-]*
backup
_EOD_

cd $JENKINS_HOME
test -e ${TMPDIR}/${TARFILE} && mv -f ${TMPDIR}/${TARFILE} ${TMPDIR}/${TARFILE}.1
tar czf ${TMPDIR}/${TARFILE} --exclude-from=${TMPDIR}/${EXCLUDE} .

export AZURE_STORAGE_ACCOUNT=${myaccount}
export AZURE_STORAGE_ACCESS_KEY=${AZURE_STORAGE_ACCESS_KEY}

export container_name=backup
export blob_name=${TARFILE}
export file_to_upload=${TMPDIR}/${TARFILE}

AZ_CMD=/usr/bin/az
ContainerExists=`${AZ_CMD} storage container exists --account-name ${AZURE_STORAGE_ACCOUNT} \
--account-key ${AZURE_STORAGE_ACCESS_KEY} --name $container_name --output tsv`
if [ "${ContainerExists}" = "False" ];then
  echo "Creating the container..."
  ${AZ_CMD} storage container create --name $container_name \
  --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}
fi

echo "Uploading the file..."
${AZ_CMD} storage blob upload --container-name $container_name --file $file_to_upload --name $blob_name \
  --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}

echo "Listing the blobs..."
${AZ_CMD} storage blob list --container-name $container_name --output table \
  --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}

echo "Done"
```
シェル内で定義されてない変数はmask-passwords-pluginというジョブ毎に設定できる別のプラグインで別途設定してます。
実行ログは切り回し実装しなくてよく標準出力にだしとけばjenkinsが拾って記録してくれます。
サーバにログインせずブラウザから実行ログを後から追いやすく地味に便利です。

名前を統一できない複数ファイルを扱い古いものを消す運用するスクリプト例↓
（めんどくさかったのでrsyncの--deleteオプションみたいなことができてほしい気持ちでいっぱいです）

```
#/bin/bash -e
#
## set localhost's variables.
BK_DIR=/var/opt/gitlab/backups
LOG=/opt/log/bk.log

# log redirect.
exec >> ${LOG}  
exec 2>&1

## daily backup.
echo "$(/bin/date +%Y%m%d.%H%M%S) daily backup start."
/opt/gitlab/bin/gitlab-rake gitlab:backup:create
echo "$(/bin/date +%Y%m%d.%H%M%S) daily backup end."

## remove old backups.
find ${BK_DIR} -name "*.tar.gz" -ctime +1 -type f -exec rm -f {} \;

## set azure variables.
export AZURE_STORAGE_ACCOUNT={{ azure_storage_account }}
AZURE_STORAGE_ACCESS_KEY='{{ azure_storage_access_key }}'
export AZURE_STORAGE_ACCESS_KEY=${AZURE_STORAGE_ACCESS_KEY}
export container_name={{ azure_container_name }}
AZ_CMD=/usr/bin/az

## if not exist container, create it.
ContainerExists=`${AZ_CMD} storage container exists --account-name ${AZURE_STORAGE_ACCOUNT} \
--account-key ${AZURE_STORAGE_ACCESS_KEY} --name ${container_name} --output tsv`
if [ "${ContainerExists}" = "False" ];then
  echo "Creating the container..."
  ${AZ_CMD} storage container create --name ${container_name} \
  --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}
fi

## commpressed and upload backup files to azure blob.
### commpressed
cd ${BK_DIR}
test -f ${BK_DIR}/*.tar
result=$(echo $?)
if [ ${result} == 1 ];then
  echo "un commpressed backup files is not exists."
  exit 0
fi
### rename
placetag='lan'
find ${BK_DIR} -name "*_gitlab_*" | sed "p;s/_gitlab_/_gitlab-${placetag}_/g" | xargs -n2 mv
### upload to azure blob
bkupfiles=$(ls -1 ${BK_DIR}/*.tar)
for bkupfile in ${bkupfiles}
do
  gzip ${bkupfile}
  export blob_name=$(basename ${bkupfile}.gz)
  export file_to_upload=${bkupfile}.gz
  echo "Uploading the file...${bkupfile}.gz."
  ${AZ_CMD} storage blob upload --container-name ${container_name} \
   --file ${file_to_upload} --name ${blob_name} \
   --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}
done

## get list of uploaded backup files.
echo "Listing the blobs..."
uploaded_list=$(
${AZ_CMD} storage blob list --container-name ${container_name} --output tsv \
  --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY} \
  --query '[].{Name: name, Lastmodified: properties.lastModified}'|grep gitlab| \
  sed -e 's/[",]//g' -e 's/\t/,/g'
)

## limit check and delete old backup files.
numofgeneration="3"
days_ago=$(/bin/date -d "${numofgeneration} days ago" +%Y-%m-%d'T'%H:%M'Z')
days_ago_unixtime=$(/bin/date -d "${numofgeneration} days ago" +%s)
today_unixtime=$(/bin/date +%s)
retention_limit=$(echo ${today_unixtime} - ${days_ago_unixtime}|bc)
for filedata in ${uploaded_list}
do
  uploadedfile=$(echo ${filedata} |awk -F , '{print $1}')
  lastmodified=$(echo ${filedata} |awk -F , '{print $2}')
  lastmodified_conv=$(echo ${lastmodified}|sed -e 's/T/ /g' -e 's/+00:00//g' -e 's/$/ UTC/g')
  lastmodified_unixtime=$(/bin/date -d "${lastmodified_conv}" +%s)
  diff_seconds=$(echo ${today_unixtime} - ${lastmodified_unixtime}|bc)
  if [ ${retention_limit} -gt ${diff_seconds} ];then
    echo "${uploadedfile} is still newer than expiration date."
    continue
  fi
  echo "Delete old backup files. ${filedata}"
  ${AZ_CMD} storage blob delete --container-name ${container_name} --output table \
  --name ${uploadedfile} --if-unmodified-since ${days_ago} \
  --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}
done

echo "$(/bin/date +%Y%m%d.%H%M%S) Done."

## rotate logs.
find /opt/log -name bk.log -size +5M -exec mv bk.log{,.$(/bin/date +%Y%m%d)} \;
find /opt/log -name "bk.log.*" -atime +365 -delete

exit 0
```
とりあえず三日(numofgenerationで指定)より前のファイルを消す仕様です。
（unixtimeに変換して引き算してif分岐で判定して旧くなければループの次に移るのでazによる古くねーよエラーはでない）

####Ansibleタスク

azコマンドも入れるansibleのタスクファイルを一応書いた。
（Debian向けはマニュアルに丁寧に書いてあったので一応書いただけでテストしてないけどsyntaxエラーは出てない）

```
---
# tasks file for azure
#
- block:
  - name: check azure-cli yum repo
    shell: yum repolist azure-cli|grep repolist|awk '{print $2}'
    register: res_exist_azclirepo_yum
  - name: install az yum repository gpg key.
    command: rpm --import https://packages.microsoft.com/keys/microsoft.asc
  - name: copy yum repository file
    copy:
      src: azure-cli.repo
      dest: /etc/yum.repos.d/azure-cli.repo
  - name: yum install azure-cli
    yum:
      name: azure-cli
      state: present
  when:
    - res_exist_azclirepo_yum == '0'
    - ansible_os_family == 'RedHat'
- block:
  - name: check azure-cli apt repo
    command: ls /etc/apt/sources.list.d/azure-cli.list
    register: res_exist_azclirepo_apt
    ignore_errors: ture
  - name: copy apt source list
    copy:
      src: azure-cli.list
      dest: /etc/apt/sources.list.d/azure-cli.list
  - name: install azure-cli apt-key
    apt_key:
      id: 417A0893
      keyserver: packages.microsoft.com
      state: present
  - name: apt install azure-cli
    apt:
      name: "{{ item }}" 
      state: present
    with_items:
      - apt-transport-https
      - azure-cli
  when:
    - res_exist_azclirepo_apt != ''
    - ansible_os_family == 'Debian'
- block:
  - name: copy backup script for azureblob
    template:
      src: backup.sh-gitlab-azureblob 
      dest: /opt/bin/backup.sh
    no_log: True
  - name: set cron job for backup to azureblob
    cron:
      name: "gitlab backup(send to remote storage)"
      user: 'root'
      job: '/opt/bin/backup.sh'
      minute: '0'
      hour: '3'
      weekday: '0'
  when: use_azureblob_bkup_script == 'yes'
```
上記はローカルにcron登録する感じのタスクでweekday 0になってるので日曜しか作動しないですがローカル用は別にとっててシステムの重要度に応じてクラウドストレージに向けてはまあ通信料もあるし毎日じゃなくてもいいかな、という思想によります。

####参考
[Using the Azure CLI 2.0 with Azure Storage | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/storage/common/storage-azure-cli)
[Amazon S3, Google Cloud Storageなど各種オブジェクトストレージの料金比較まとめ (2017/04/30) - Qiita](https://qiita.com/Yuhsak/items/04a9d99bfe76d01f7916#%E6%B5%B7%E5%A4%96%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
az blob delete --help
az blob list --help
[JMESPath Tutorial — JMESPath](http://jmespath.org/tutorial.html)
[Azure CLI 2.0 のインストール | Microsoft Docs](https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli?view=azure-cli-latest)
[Azure Storage アカウント キーの漏洩対策 - Qiita](https://qiita.com/Aida1971/items/37051e63ba7702f28481)