2013年4月29日月曜日

[dropbox]dotcloudからdropboxAPIを利用してwordpressをバックアップしてみた[dotcloud]

このエントリーをはてなブックマークに追加 はてなブックマーク - [dropbox]dotcloudからdropboxAPIを利用してwordpressをバックアップしてみた[dotcloud]
Bloggerへの移行前のWordpressにて2013-03-31に投稿した記事です。

このBlogというかWordpressはdotcloudで動いているのですが、今までバックアップをとっておらず、それめっちゃ怖いと今更思い、定期的にバックアップをするようにしてみたのでその時のメモ。

概要

バックアップ対象としてはWordpressのDBwp-contentで、バックアップ先はdropboxになります。

バックアップ方法としてはDropboxAPIのPython版をdotcloudで動かせるようにしてcronで定期的にファイル送信するという感じです。

Dropboxへファイルを送信するする方法はdotcloudに特化している訳ではないので、それ以外のPasSや自分で管理しているサーバーでも出来るかも。

なお、dotcloudの場合、dbとWebサーバーが別インスタンスみたいなのでそれぞれに環境及びcronの設定を行いました。(一つの環境でできるやり方を知っている方いましたら教えて下さい。。。)

ちなみにプラグインがうまく動くようであれば、BackWPupとかが良い感じみたいです。(dotcloudだと上記プラグインうまく動きませんでした。。。。)

目次

  1. Dropbox Applicationの登録
  2. Python環境の準備
  3. DropboxAPIの設定、確認
  4. PUT用スクリプトの作成
  5. backup.shの作成
  6. cronの設定

1.Dropbox Applicationの登録

DropboxAPIを利用する為にアプリケーション登録を行います。
この情報は適当にググれば出てくるので省略します。

Access typeについはapp_folderにしました。(本エントリの確認も上記が前提です。)

下記サイトが参考になりました。
DROPBOX API(PYTHON)を使ってみる

2.Python環境の準備

Pythonが利用出来るようにvirtualenvを利用します。
dotcloudではPython自体は既にインストールされていましたが、モジュールをインストールする際に必要なsetuptoolsが無かったのでvirtualenvを利用しています。(virtualenvを利用するとsetuptoolsは一緒にインストール出来る)

dotcloudのwww,dbインスタンスの確認。
$dotcloud conncet <アプリケーション名>
$dotcloud info
=== wordpressapp
flavor:          sandbox
cost to date:    Free
+------+-------+------------+-----------------+
| name | type  | containers | reserved memory |
+------+-------+------------+-----------------+
| db   | mysql | 1          | N/A             |
| www  | php   | 1          | N/A             |
+------+-------+------------+-----------------+
wwwサーバーにログイン。
$dotcloud run www
DBサーバーにログイン。
$dotcloud run www
以降の処理は両サーバーで実行する。

ダウンロード、解凍
$wget https://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.9.1.tar.gz
$tar -zxvf virtualenv-1.9.1.tar.gz
インストール、有効化
$cd virtualenv-1.9.1
$python virtualenv.py --distribute ENV
$source ENV/bin/activate

3.DropboxAPIの設定、確認

DropboxAPIのインストール及び、接続確認を行います。
基本的には公式のドキュメントDropbox Developerに書いてある通りに実行しました。

DropboxAPIのダウンロード、解凍
$wget https://www.dropbox.com/static/developers/dropbox-python-sdk-1.5.1.zip
$unzip dropbox-python-sdk-1.5.1.zip
DropboxAPIのインストール
$cd dropbox-python-sdk-1.5.1
$python setup.py install
Exampleコードを利用して接続確認を行います。
1.Dropbox Applicationの登録で登録したアプリケーションの情報でApp key,App secretが必要なので確認しておいて下さい。(webから確認できます。)

App key,App secretの編集
$cd example
$vi cli_client.py
cli_client.py
# XXX Fill in your consumer key and secret below
# You can find these at http://www.dropbox.com/developers/apps
APP_KEY = ''
APP_SECRET = ''
ACCESS_TYPE = 'app_folder'  # should be 'dropbox' or 'app_folder' as configured for your app
APP_KEY,APP_SECRETを入力して下さい。

また、Dropboxへのアプリ登録時にAccess typeをapp_folderじゃなく設定した場合にはACCESS_TYPEの変更が必要そうですがうまくいくかは未確認です。

適当にDropboxに送信するファイルを作成します。
$touch put.txt
サンプルコードの実行。
CLIでdropboxAPIが利用出来ます。
まずはログイン。
$python cli_client.py
Dropbox>login
url: https://www.dropbox.com/1/oauth/authorize?oauth_token=xxxxxxxxx
Please authorize in the browser. After you're done, press enter.
表示されたURLをブラウザで表示すると認証するかの確認画面になるのでAllowを選択。
その後、コンソールに戻ってenterを押します。
その後はDropboxAPIが使えます。(詳細はhelpを入力)

試しにファイルをputします。put後の名前はabc.txtとします。
Dropbox> ls
2013-03-31_04:00:01_UTC.data.tar.gz
2013-03-31_04:00:01_UTC.sql.gz

Dropbox> put put.txt abc.txt

Dropbox> ls
2013-03-31_04:00:01_UTC.data.tar.gz
2013-03-31_04:00:01_UTC.sql.gz
abc.txt
これでサーバーからファイルが送信出来る事が確認できました。

4.PUT用スクリプトの作成

下記参考にさせていただき、コードを少しだけ変えてシェルスクリプトから実行出来るようにします。
DROPBOX API(PYTHON)を使ってみる2
$cd dropbox-python-sdk-1.5.1/example/
$vi backup-wordpress.py
backup-wordpress.py
#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import cmd
import locale
import os
import pprint
import shlex
import time

from dropbox import client, rest, session

# XXX Fill in your consumer key and secret below
# You can find these at http://www.dropbox.com/developers/apps
APP_KEY = ''
APP_SECRET = ''
ACCESS_TYPE = 'app_folder'  # should be 'dropbox' or 'app_folder' as configured for your app

def command(login_required=True):
    """a decorator for handling authentication and exceptions"""
    def decorate(f):
        def wrapper(self, *args):
            if login_required and not self.sess.is_linked():
                self.stdout.write("Please 'login' to execute this command\n")
                return

            try:
                return f(self, *args)
            except TypeError, e:
                #self.stdout.write(str(e) + '\n')
                print str(e)
            except rest.ErrorResponse, e:
                msg = e.user_error_msg or str(e)
                #self.stdout.write('Error: %s\n' % msg)
                print ('Error: %s' % msg)

        wrapper.__doc__ = f.__doc__
        return wrapper
    return decorate

class DropboxTerm():
    def __init__(self, app_key, app_secret):
        self.sess = StoredSession(app_key, app_secret, access_type=ACCESS_TYPE)
        self.api_client = client.DropboxClient(self.sess)
        self.current_path = ''

        self.sess.load_creds()

    def do_ls(self):
        """list files in current remote directory"""
        resp = self.api_client.metadata(self.current_path)

        if 'contents' in resp:
            for f in resp['contents']:
                name = os.path.basename(f['path'])
                encoding = locale.getdefaultlocale()[1]
                #self.stdout.write(('%s\n' % name).encode(encoding))
                print ('Filename=%s' % name).encode(encoding)
                #print ('FullFilename=%s' % f['path']).encode(encoding)

    @command()
    def do_cd(self, path):
        """change current working directory"""
        if path == "..":
            self.current_path = "/".join(self.current_path.split("/")[0:-1])
        else:
            self.current_path += "/" + path

    @command()
    def do_put(self, from_path, to_path):
        """
        Copy local file to Dropbox

        Examples:
        Dropbox> put ~/test.txt dropbox-copy-test.txt
        """
        from_file = open(os.path.expanduser(from_path), "rb")
        #from_file = open(from_path, "rb")

        self.api_client.put_file(self.current_path + "/" + to_path, from_file)

    @command()
    def do_rm(self, path):
        """delete a file or directory"""
        self.api_client.file_delete(self.current_path + "/" + path)

class StoredSession(session.DropboxSession):
    """a wrapper around DropboxSession that stores a token to a file on disk"""
    TOKEN_FILE = "token_store.txt"

    def load_creds(self):
        try:
            stored_creds = open(self.TOKEN_FILE).read()
            self.set_token(*stored_creds.split('|'))
            print "[loaded access token]"
        except IOError:
            pass # don't worry if it's not there

    def write_creds(self, token):
        f = open(self.TOKEN_FILE, 'w')
        f.write("|".join([token.key, token.secret]))
        f.close()

    def delete_creds(self):
        os.unlink(self.TOKEN_FILE)

    def link(self):
        request_token = self.obtain_request_token()
        url = self.build_authorize_url(request_token)
        print "url:", url
        print "Please authorize in the browser. After you're done, press enter."
        raw_input()

        self.obtain_access_token(request_token)
        self.write_creds(self.token)

    def unlink(self):
        self.delete_creds()
        session.DropboxSession.unlink(self)

def main(s):
    if APP_KEY == '' or APP_SECRET == '':
        exit("You need to set your APP_KEY and APP_SECRET!")
    term = DropboxTerm(APP_KEY, APP_SECRET)

    print(s);
    #term.do_rm(s[1])
    term.do_put(s[0],s[1])

if __name__ == '__main__':
    import sys
    args = sys.argv
    if len(args) > 1:
           s = args[1:]
    main(s)
引数を利用してファイルをputするようにしました。(といってもmain文をほんの少し変えただけですが。。。) ファイルをputする処理を実行する場合、以下のようにします。
$python backup-wordpress.py put.txt abc.txt

5.backup.shの作成

次に上記スクリプトを実行するシェルを作成します。
といってもdotcloudではバックアップ用のシェルスクリプトが用意されており、それを少しだけ変更すればOKです。

下記を参考にさせて頂きました。
DotCloudをDropboxへバックアップ 2

まずはdotcloudの公式サイトからバックアップ用のシェルをダウンロードしてきます。
$wget http://docs.dotcloud.com/_downloads/backup.sh
次に上記を変更します。
#!/bin/bash
# Syntax: 
# backup.sh <what> <how> <where> [whereexactly]
# <what> indicates what you want to backup: mysql, pgsql, riak, data.
# <how> indicates the backup method: ssh, ftp, s3.
# <where> is a <user[:password]@host>.
# [whereexactly] is an optional path on the <where> target, when applicable.
set -e
TAG="$HOSTNAME_$(TZ=UTC date +%Y-%m-%d_%H:%M:%S_UTC)"
source ~/virtualenv-1.9.1/ENV/bin/activate

: <<'#__COMMENT_OUT__'
[ "$3" ] || {
	echo "Please specify what to backup, how, and where."
	exit 1
}
#__COMMENT_OUT__


case "$1" in
	mysql)
		FILENAME="$TAG.sql.gz"
		FILEPATH="/tmp/$FILENAME"
		mysqldump --all-databases | gzip > "$FILEPATH"
		;;
	pgsql)
		FILENAME="$TAG.sql.gz"
		FILEPATH="/tmp/$FILENAME"
		pg_dumpall | gzip > "$FILEPATH"
		;;
	riak)
		FILENAME="$TAG.bitcask.tar.gz"
		FILEPATH="/tmp/$FILENAME"
		tar -czf "$FILEPATH" /var/lib/riak
		;;
	data)
		FILENAME="$TAG.data.tar.gz"
		FILEPATH="/tmp/$FILENAME"
		tar -C "$HOME" -czf "$FILEPATH" "data"
		;;
	*)
		echo "Sorry, I don't know how to backup $1."
		exit 1
		;;
esac

: <<'#__COMMENT_OUT__'
if [ "$4" ]
then
	DEST="$4/$FILENAME"
else
	DEST="$FILENAME"
fi
#__COMMENT_OUT__

case "$2" in
	ssh)
		scp -q -o BatchMode=yes "$FILEPATH" "$3:$DEST"
		;;
	ftp)
		curl -sST "$FILEPATH" "ftp://$3/$DEST"
		;;
	s3)
		s3cmd put "$FILEPATH" "s3://$3/$DEST"
		;;
	s3multi)
		split --numeric-suffixes --bytes=4G "$FILEPATH" "$FILEPATH".
		s3cmd put "$FILEPATH".?? "s3://$3/$DEST/"
		;;
	dropbox)
		cd ~/dropbox-python-sdk-1.5.1/example/
	        python backup-wordpress.py "$FILEPATH" "$FILENAME"
		;;
	*)
		echo "Sorry, transfer method $2 is not supported."
		exit 1
esac

SIZE="$(stat --printf %s "$FILEPATH")"
echo "Backup $TAG completed. Its (compressed) size is $SIZE bytes."
rm -f "$FILEPATH"
変更点は以下の通りです。
  • shをbashにした
  • source ~/virtualenv-1.9.1/ENV/bin/activateを利用してvirtualenvを使う。
  • 引数$3,$4は使わないのでコメントアウト(必須ではない)
  • 第2引数にdropboxと指定した場合、dropboxAPIを利用する用に設定
実行権限設定。
$chmod +x backup.sh
下記に利用方法について記載します。

1.MySQLのバックアップをdropboxへ送信する場合。
$./backup.sh mysql dropbox
2.wp-conentのバックアップをdropboxへ送信する場合。
$./backup.sh data dropbox

6.cronの設定

最後にcronの設定をします。といっても特別な事はしません。
必要に応じて時間は適当に変更して下さい。

DBインスタンス側。
$crontab -e
00 4 * * * ~/backup.sh mysql dropbox >> result.txt
wwwインスタンス側。
$crontab -e
00 4 * * * ~/backup.sh data dropbox >> result.txt

0 件のコメント:

コメントを投稿