Many organizations use separate development, staging, and production environments to maintain the quality of their websites. When used in your ArcGIS Enterprise organization, those environments are often set up as follows:
- Development—This is a sandbox environment, where you can freely test your applications and services. Typically, the development environment runs on a small machine, disconnected from the production ArcGIS Enterprise environment. Once changes are validated on the development environment, they are applied to the staging environment.
- Staging—This environment is a clone of the production environment. Testing at this level results in a decision to apply the changes on the production environment, or reject the changes and wait for a new iteration from the development environment. The staging site is not used for development, only performance and functional testing. Esri provides staging licenses for ArcGIS Enterprise at a lower cost than production licenses.
- Production—No development or testing occurs on this environment, given that GIS users (and, in some cases, the public) access it. Only changes that have passed testing on the staging site are applied to the production site.
The development, staging, and production environments ideally use different databases and infrastructures. Each organization has its own rules for how changes are tested and approved across the environments.
Moving a change from environment to environment can present logistical challenges. This help topic provides patterns and scripts to guide you through the process, whether your ArcGIS Server site is federated with a portal or stands alone.
This topic discusses considerations for ArcGIS Server in development, staging, and production environments. It does not cover other ArcGIS Enterprise components.
Configuring each environment
In each environment, install ArcGIS Server, create a site, and configure security, server object extensions (SOEs), and other settings. Most of these tasks are faster if performed manually, although they can also be automated with a script.
Get your development site working first and create the staging site, followed by the production site.
The key to deploying services in multiple environments is to register your folders and databases correctly with ArcGIS Server and use service definitions (SDs) for publishing.
Registering folders and databases with ArcGIS Server
When you register a folder or database with ArcGIS Server, you provide the publisher’s path to the data and the server’s path.
- The publisher’s path is the data path on the machine you’ll use to make the SD files. The publisher’s path is always the same when you register an item on the development, staging, and production servers.
- The server’s path is the data path on the server. This path can vary when you register an item on the development, staging, and production servers.
If you have many data folders or databases to register, you may consider using scripts. Example: Register folders and databases listed in a text file uses the ArcPy AddDataStoreItem function to register a list of folders and database connections supplied in a text file. You modify the text file for each environment.
Use SD files when deploying your services in multiple environments. The SD takes the information needed to publish a service and packages it into one convenient file. Although it’s possible to package the GIS data within the SD, it may be more efficient to preload the data in each environment and use replication to keep it in sync.
Create connection-neutral SD files (choose the No available connection option in the Save a Service Definition wizard) so they are flexible enough to be published on any server. When you publish an SD file, ArcGIS Server automatically corrects the paths written in the SD so that your server paths are used. Careful data registration allows you to deploy the same SD file in multiple environments.
Publishing services is a task that is well suited for scripting. You can use the ArcPy function Upload Service Definition to create a script that will publish each SD.
After deploying your services from the SDs, enable any extensions required by the services. You can do this manually or through scripting.
Another task that can be scripted is applying permissions to various services as listed in a text file.
Sometimes you may want to update a service to use new properties or reflect changes in the source document, such as a set of permanent symbology edits in an ArcGIS Pro project. The recommended way to update a service in multiple environments is to save a new SD file, delete the service, and publish the updated SD.
When you take this approach, the same example script used above for publishing can also perform service updates. Modify the input file to include only the services you want to update. If an existing service is found, the script deletes it before uploading the SD.
After you update a service in this way, reenable any SOEs used by the service.
You can alternatively script updates to service properties (but not the map or source document) using ArcGIS REST API.
Keeping data in sync
Ensure your data is kept in sync across your multiple environments. Geodatabase replication can help you with this. Alternatively, you can completely replace the old dataset with a new dataset. For example, you may delete a file geodatabase and replace it with an updated file geodatabase.
If you decide to entirely replace tables or file geodatabases, remember that ArcGIS Server services lock the schemas of the underlying datasets by default. If the schema is locked, stop your service before you can replace the data. With some degree of caution, you can disable schema locking for map services, but you can’t disable it for other service types.
To move an application between the development, staging, and production environments, copy the application files from one site to the other and update any web service URLs in your code so they point to the new site. Use configuration files to define the URLs for your services.
The script below helps you update the URLs in your code. The code recursively looks for files in a folder you provide, searches for a particular string such as http://myDevServer/arcgis, and replaces it with the location of your staging or production site, such as http://myProdServer/arcgis.
Once you’ve replaced the URLs using the script, copy the application files onto the next server in the workflow (staging or production).
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:] 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) + ".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() tbinfo = traceback.format_tb(tb) pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n " + \ str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n" print '\n\n\n' + pymsg