post Image
Datastoreのバックアップを取得する

GAEを利用してDatastoreのバックアップを取得する

単にバックアップを取得するのであれば特にプログラムを書く必要はなく、こちら(https://cloud.google.com/appengine/articles/scheduled_backups) の記事にあるように cron.yaml に以下のような記述をすれば定時のバックアップができる。

cron.yaml
cron:
- description: My Daily Backup
  url: /_ah/datastore_admin/backup.create?name=BackupToCloud&kind=LogTitle&kind=EventLog&filesystem=gs&gs_bucket_name=whitsend
  schedule: every 12 hours
  target: ah-builtin-python-bundle

ただ、 cron.yaml にbucket名まで記述することになるため、1つのコードの記述で 本番環境 ステージング環境 とbucketを切り替えることができない。
そのため、goのコードからDatastoreのバックアップを取得を試みた。

早速実装

処理に必要なファイルと実装は以下。

goのアプリケーションをデプロイするための記述と、出力先バケット名とバックアップの出力のprefixを記述している。
あと、バックアップ対象から除外したいKind名はカンマ区切りで入力できるように。

app.yaml
application: hogehoge-backup-test
version: 1
runtime: go
api_version: go1

handlers:
- url: /.*
  script: _go_app
  login: admin

env_variables:
  TARGET_BUCKET_NAME: "hogehoge-backup-bucket"
  BACKUP_PREFIX: "backup-prefix"
#  IGNORE_KINDS: "b,c" # backupから除外したいkind名をカンマ区切りで

cron(定時実行の設定)を記述。

cron.yaml
cron:
- description: Daily Backup
  url: /backup
  schedule: every day 02:00
  timezone: Asia/Tokyo
  target: default

queue設定。このqueueのtargetが重要

queue.yaml
queue:
- name: backupQueue
  rate: 1/s
  target: ah-builtin-python-bundle

メインのプログラム。

backup.go
import (
    "fmt"
    "golang.org/x/net/context"
    "google.golang.org/appengine"
    "google.golang.org/appengine/datastore"
    "google.golang.org/appengine/taskqueue"
    "net/http"
    u "net/url"
    "os"
    "strings"
)

func init() {
    http.HandleFunc("/backup", handler)
}

const (
    BackupQueueName = "backupQueue"
    BackupPath      = "/_ah/datastore_admin/backup.create"
)

func handler(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    bucketName := os.Getenv("TARGET_BUCKET_NAME")
    backupPrefix := os.Getenv("BACKUP_PREFIX")
    ignoreKindsString := os.Getenv("IGNORE_KINDS")

    kinds, err := getKinds(c)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        fmt.Fprint(w, http.StatusText(http.StatusInternalServerError))
        return
    }

    q := u.Values{
        "name":           {fmt.Sprintf("%s-", backupPrefix)},
        "filesystem":     {"gs"},
        "gs_bucket_name": {bucketName},
    }

    ignoreMap := map[string]bool{}
    if ignoreKindsString != "" {
        ignoreKinds := strings.Split(ignoreKindsString, ",")
        for _, kind := range ignoreKinds {
            ignoreMap[kind] = true
        }
    }

    for _, kind := range kinds {
        if _, ok := ignoreMap[kind]; !ok {
            q.Add("kind", kind)
        }
    }

    backupTask := taskqueue.NewPOSTTask(BackupPath, q)

    if _, err := taskqueue.Add(c, backupTask, BackupQueueName); err != nil {
        // fail
        w.WriteHeader(http.StatusInternalServerError)
        fmt.Fprint(w, http.StatusText(http.StatusInternalServerError))
    } else {
        // success
        w.WriteHeader(http.StatusOK)
        fmt.Fprint(w, http.StatusText(http.StatusOK))
    }
}

func getKinds(c context.Context) ([]string, error) {
    t := datastore.NewQuery("__kind__").KeysOnly().Run(c)
    var kinds []string
    for {
        key, err := t.Next(nil)
        if err == datastore.Done {
            break
        }
        if err != nil {
            return nil, err
        }
        if strings.HasPrefix(key.StringID(), "_") {
            continue
        }
        kinds = append(kinds, key.StringID())
    }
    return kinds, nil
}

だいたいこんな感じ。
ディレクトリに上記のファイルを配置して goapp deploy ./ と実行するだけで(app.yamlの内容は各自環境に合わせる必要はありますが) appengine環境にデプロイして動作します。

上のコードでは最初に言っていたBucket名をプロジェクトごとに切り替えることができていないが、Bucket名にプロジェクト名を含めるなどとし、 appengine.AppID(context) でappengineのプロジェクト名を取得してBucket名の切り替えなどを行うことで対応できます。

上記のコードでできていること

  • Datastore内の _ prefix のついていないKind一覧を取ってバックアップ(prefixがついているものは各種メタ的な情報(?)なので)
  • 全部取られたくない場合のため、無視させたいKindの一覧をわたせるようにした。

一般的なバックアップしたいという要求はみたせるのではないかと。

ソースコード

githubに置きました。

https://github.com/chidakiyo/datastore-backup

謝辞

@sinmetal さん、 @soundTricker さん、Datastoreのバックアップに関する情報ありがとうございました。
@vvakame さん一般的なHandlerに書き直してみました。ありがとうございます。
m(_ _)m


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。