GitLabのCIを使用したサーバーにあるファイルの自動バックアップ

2022/07/18に公開

はじめに

ふつうは逆だと思いますけど、
非エンジニアも更新するWebページなのでGitを使ってデプロイとかできなかったので、苦肉の策でlftpコマンドを使って自動バックアップの仕組みを作りました。
(何かあってもバックアップから戻せるように...)

ちょっとコマンド変えればデプロイできるようになると思います。

Project Access Tokenの作成

Project Access Tokenを使用するのはユーザーに依存せず実行できるようにしたかったから。
ほかにもDeploy KeyやPersonal Access Tokenを使用してGitの認証を行う方法があるが、ユーザーの権限や存在に依存する部分が出てくるので今回は使用していない。

  • 特定のプロジェクト>Settings>Access TokensページでAccess Tokenを作成する。
  • それぞれの設定値
    • Token name:任意
    • Expiration date:任意
    • Select a role:CIを実行するブランチに直pushできる権限(今回はMaintainer)
    • Select scopes:read_repository, write_repository
  • 作成したらAccess Tokenの値はコピーしておく。

CIの環境変数を登録

  • 特定のプロジェクト>Settings>CI/CD>VariablesでExpandを押下して独自環境変数を登録する。
Key Value
HOST lftpで接続するときのホスト名
PASSWORD lftpで接続するときのパスワード
USERNAME lftpで接続するときのユーザー名
PROJECT_ACCESS_TOKEN 作成したProject Access Tokenの値
  • 上記以外のgitlab-ci.ymlで使用している環境変数はもともと定義されている環境変数。

gitlab-ci.yml

  • バックアップを保存したいプロジェクトにgitlab-ci.ymlを作成する。
  • おおまかなながれとしてはCIを実行するプロジェクトをCIを実行中にクローン、lftpコマンドでサーバーに保存されているファイルをダウンロード、差分があればpushする。
gitlab-ci.yml
stages:
  - writeback-gitrepo

.git:push:
  after_script:
    # Go to the new directory
    - cd "${CI_COMMIT_SHA}"

    # Add all generated files to Git
    - git add .

    - |-
      # Check if we have modifications to commit
      ret=$(git status| sed -ne 's|.*\(clean\)|\1|p')

      if [ -z $ret ];then
        # Show the status of files that are about to be created, updated or deleted
        git status

        export TIME=$(date +%Y%m%d)
        echo ${TIME}

        # Commit all changes
        git commit -m "${TIME} Push by GitLab runner"

        # Update the repository and make sure to skip the pipeline create for this commit
        git push origin "${CI_COMMIT_REF_NAME}" -o ci.skip
      fi
  before_script:
    - apt-get update && apt-get install -y git lftp language-pack-ja-base language-pack-ja
    # Set Character code
    - locale-gen ja_JP.UTF-8
    - echo export LANG=ja_JP.UTF-8 >> ~/.profile
    - source ~/.profile

    # Clone the repository via HTTPS inside a new directory
    - git clone "https://gitlab-ci-token:${PROJECT_ACCESS_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "${CI_COMMIT_SHA}"

    # Set the displayed user with the commits that are about to be made
    - git config --global user.email "${GITLAB_USER_EMAIL}"
    - git config --global user.name "${GITLAB_USER_NAME}"
  image: ubuntu
  stage: writeback-gitrepo

writeback-gitrepo:
  extends: .git:push
  script:
    # Download files via lftp
    - lftp -c "set ftp:ssl-allow no; open -u $USERNAME,$PASSWORD $HOST; mirror --verbose / ${CI_COMMIT_SHA}"
  only:
    - schedules

それぞれのポイント

  • language-pack-ja-base language-pack-jaをインストールしているのはCIの中で言語をja_JP.UTF-8にしないと、サーバーに保管されているファイル名が日本語の場合に文字化けしてしまいダウンロード時にエラーになってしまうから。
  • onlyで指定している部分は、GitLabのGUIで設定するスケジュールの時のみ実行するようにするため。
  • ${TIME}は何も指定しないとタイムゾーンがutfになるので、jstにする場合は別途設定が必要。
  • git commit -m "${TIME} Push by GitLab runner"いつpushされたのか分かるようにしたかったので、環境変数でyyyyMMddを表示させるようにしている。コミットメッセージをシングルクォーテーションで囲むと環境変数が表示されないので注意。
  • その他のポイントは参考にあるサイトを参照していただければと思います。(ほとんどコードは参考にさせていただきましたm(__)m)

CIのスケジュールを設定する

  • 任意のプロジェクト>CI/CD>SchedulesページでCIを定期実行できるようにする。
  • それぞれの設定値
    • Description:任意
    • Interval Pattern:任意
    • Cron Timezone:日本の時間にする場合はTokyoまたはOsaka
    • Target branch or tag:任意
    • Variables:特に設定必要なし

参考

Discussion