開発、ステージング、および本番環境の ArcGIS Server

多くの組織は独立した開発、ステージング、および本番環境を使用して、Web サイトの品質を維持しています。ここでは、ArcGIS Server を使用する場合の各環境について説明します。

開発、ステージング、および本番の各環境では、異なるデータベースとインフラストラクチャを使用することが理想的です。サイト間で変更をテストして承認する方法については、組織によってそのルールが異なります。

サイト間で変更を移動する際には、ロジスティクスに関する問題が生じる場合があります。このヘルプ トピックでは、パターンとスクリプトを使用してプロセス全体を紹介します。

各環境の構成

各環境では、ArcGIS Server のインストール、サイトの作成、セキュリティの構成、SOE(サーバ オブジェクト エクステンション)の構成、およびその他の設定の構成が必要です。「例: 2 つのテキスト ファイルからのユーザとロールの作成」で説明するようなスクリプトも使用できますが、これらのタスクのほとんどは手動で実行するほうが簡単です。

まず、開発サイトを稼働できるようにします。続いてステージング サイトを作成し、最後に本番サイトを作成します。

サービスの配置

サービスを複数の環境に配置する際に重要となるのは、フォルダとデータベースを ArcGIS Server に正しく登録し、SD(サービス定義)を使用して公開を行うことです。

ArcGIS Server へのフォルダとデータベースの登録

フォルダまたはデータベースを ArcGIS Server に登録する際に、データに対する公開者のパスとサーバのパスの両方を指定します。

  • 公開者のパスは、SD ファイルの作成に使用するコンピュータ上でのデータの パスです。アイテムを開発サーバ、ステージング サーバ、および本番サーバのいずれに登録する場合でも、公開者のパスは常に同じです。
  • サーバのパスは、サーバ上でのデータ パスです。このパスは、アイテムの登録先(開発サーバ、ステージング サーバ、および本番サーバ)によって異なる場合があります。

登録するデータ フォルダまたはデータベースが多数ある場合は、スクリプトを使用することもできます。「例: テキスト ファイルにリストされたフォルダとデータベースの登録」では、ArcPy の AddDataStoreItem 関数を使用して、テキスト ファイルに指定したフォルダおよびデータベース接続のリストを登録しています。テキスト ファイルは各環境に合わせて変更します。

サービスの公開

サービスを複数の環境に配置する場合は、SD ファイルを使用します。SD はサービスの公開に必要な情報を取得して、これらを 1 つのファイルにパッケージ化します。SD 内に GIS データをパッケージ化することもできますが、各環境にあらかじめデータを読み込み、レプリケーションを使用して同期するほうが簡単です。

いずれのサーバでの公開にも使用できるように、接続に依存しない SD ファイルを作成します([サービス定義を保存] ウィザードで [使用可能な接続がありません] オプションを選択します)。SD ファイルを公開するときに、ArcGIS Server は指定されたサーバ パスを使用するように、SD に記述されているパスを自動的に修正します。したがって、慎重にデータ登録を行うことで、同じ SD ファイルを複数の環境に配置できます。

サービスの公開は、スクリプトの利用に適したタスクです。「例: テキスト ファイルにリストしたサービス定義の公開」のスクリプトは、テキスト ファイルを読み取り、ファイルにリストされているすべての SD を公開します。スクリプトは、ArcPy のサービス定義のアップロード関数を使用して各 SD を公開しています。

スクリプトを使用して各環境に配置される SD ファイル

SD からサービスを配置した後、サービスで必要な SOE を有効にする必要があります。これは手動か、またはスクリプトを使用して実行することができます。

権限の付与も、別のタスクとしてスクリプトで実行できます。「例: テキスト ファイルからのサービスのアクセス権の適用」では、ArcGIS REST API を使用して、テキスト ファイルにリストされている各サービスのアクセス権を適用しています。

サービスの更新

新しいプロパティを使用したり、ソース ドキュメントの変更を反映したりするために、サービスの更新が必要となる場合があります(たとえば、ArcMap ドキュメント(MXD)で永続的なシンボル セットを編集した場合)。このような場合は、複数の環境でサービスを更新する方法として、新しい SD ファイルを保存した後にサービスを削除して、更新した SD を公開することをお勧めします。

この方法を使用する場合は、公開の際と同じスクリプト例を使用してサービスの更新も実行できます。更新するサービスのみを含むように入力ファイルを変更するだけで、サービスを更新できます。既存のサービスが見つかった場合、スクリプトは SD をアップロードする前にそのサービスを削除します。

この方法でサービスを更新した後、サービスが使用する SOE を再有効化する必要があります。

ArcGIS REST API のサービスの編集操作を使用して、スクリプトで(マップまたはソース ドキュメントではなく)サービス プロパティを更新することもできます。

データの同期

複数の環境の間で、データが同期されていることを確認する必要があります。これには、ジオデータベース レプリケーションが役立ちます。また、古いデータセットを新しいデータセットで完全に置き換えることもできます。たとえば、ファイル ジオデータベースを削除して、更新されたファイル ジオデータベースで置換できます。

テーブルまたはファイル ジオデータベースを完全に置換する場合は、ArcGIS Server サービスが基になるデータセットのスキーマをデフォルトでロックすることに注意してください。スキーマがロックされている場合は、データを置換する前にサービスを停止する必要があります。マップ サービスの場合は、いくつかの点に注意してスキーマのロックを無効化することができますが、その他のサービス タイプではロックを無効化することはできません。

アプリケーションの更新

開発、ステージング、および本番環境の間でアプリケーションを移動するには、アプリケーションのファイルをサイト間でコピーした後、コードに記述されている Web サービスの URL を新しいサイトに合わせて更新します。サービスの URL を定義するには、構成ファイルを使用します。

コード内の URL を更新する際に、次のスクリプトを使用できます。コードは指定したフォルダ内のファイルを再帰的に検索し、「http://myDevServer/arcgis」などの特定の文字列を検索して、ステージング サイトまたは本番サイトの場所(「http://myProdServer/arcgis」など)で置換します。

このスクリプトを実行する前に、元のアプリケーション ファイルのバックアップ コピーを作成してください。また、スクリプトには処理するテキスト ファイルの拡張子を指定できます。たとえば、ArcGIS Viewer for Flex の構成ファイルの場合は「.xml」、ArcGIS API for JavaScript ファイルの場合は「.js」および「.html」を指定できます。

スクリプトを使用して URL を置換したら、アプリケーション ファイルをワークフローの次のサーバ(ステージングまたは本番)にコピーできます。

import os
import sys
import shutil
import traceback

def dirEntries(dir_name, subdir, *args):
    '''Return a list of file names found in directory 'dir_name'
    If 'subdir' is True, recursively access subdirectories under 'dir_name'.
    Additional arguments, if any, are file extensions to match filenames. Matched
        file names are added to the list.
    If there are no additional arguments, all files found in the directory are
        added to the list.
    Example usage: fileList = dirEntries(r'H:\TEMP', False, 'txt', 'py')
        Only files with 'txt' and 'py' extensions will be added to the list.
    Example usage: fileList = dirEntries(r'H:\TEMP', True)
        All files and all the files in subdirectories under H:\TEMP will be added
        to the list.
    '''
    fileList = []
    for file in os.listdir(dir_name):
        dirfile = os.path.join(dir_name, file)
        if os.path.isfile(dirfile):
            if not args:
                fileList.append(dirfile)
            else:
                if os.path.splitext(dirfile)[1][1:] in args:
                    fileList.append(dirfile)
        # recursively access file names in subdirectories
        elif os.path.isdir(dirfile) and subdir:
            print "Accessing directory:", dirfile
            fileList.extend(dirEntries(dirfile, subdir, *args))
    return fileList

def updateString(infileName, srchString,rplString):
    bakFileName = os.path.splitext(infileName)[0] + ".bak"
    if not os.path.exists(bakFileName):
        # copy the original file
        shutil.copy(infileName, bakFileName)

    # Open the backup (= original) file to read
    inFileHndl = open(bakFileName,"r")
    outFileHndl = open(infileName,"w")  

    for line in inFileHndl:
        if line.find(searchString) > 0:
            line = line.replace(searchString, replaceString)
        outFileHndl.write(line)
        
    outFileHndl.close()
    inFileHndl.close()
    # remove the backup (=original content file)
    os.remove(bakFileName)

if __name__ == '__main__':

    try:
        inFolder = r"C:\inetpub\wwwroot\viewer"  # path to search
        searchString = "http://mydevserver"      # string to find
        replaceString = "http://mystgserver"     # string - replace searchString with replaceString
        
        fList = dirEntries(inFolder, True, 'xml')
        for f in fList:
            updateString(f, searchString, replaceString)
            
        print '\n\n\n' + 'Process Complete'

    except:
        # Return any python specific errors as well as any errors from the geoprocessor
        #
        tb = sys.exc_info()[2]
        tbinfo = traceback.format_tb(tb)[0]
        pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n    " + \
                str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"
        print '\n\n\n' + pymsg
5/20/2014