I recently needed to add a Windows Service to a web app solution to handle some long-processing operations asynchronously. The web app is being deployed to Elastic Beanstalk (EB). You can log into the EC2 instance that EB creates and install the service manually, but this won’t last. EB can delete your instance at any time and create another one, and redeploy the app from it’s own git repository. So in order for the service to persist, it also has to be installed during the deployment. Fortunately for us, Amazon already supports this and there is a introductory article explaining how to do it and some sparse documentation.
Basically, you are adding a new directory called .ebextensions to your .Net project. In that directory you place YAML files with a .config extension. The YAML files contain the commands you can execute, as described in the docs. You can have more than one file, they execute in alphabetical order. The series of commands you create allow you to install the Windows Service when deploying a web application to EB.
Unfortunately, the procedure in the article only works on the initial install. If you need to push incremental updates, the script just doesn’t work because you can’t copy files over the versions currently in use by the Windows Service. Stopping the service wasn’t working for me because the account performing the deployment didn’t seem to have enough permissions to stop the service. But it did have enough permissions to uninstall and install the service.
The solution ended up being similar to the article, but with some variation. The correct steps for me turned out to be:
- Fetch the zipped files from S3, unzipping to a temp location
- Create the destination directory, ignoring errors (it already exists for updates)
- Uninstall the existing Windows Service, also ignoring errors (the service doesn’t exist on the first install)
- Copy the unzipped files in the temp directory to the destination directory
- Install the Windows Service
- Start the Windows Service
This translates to the following YAML file:
sources:
“c:/service/temp”: https://s3.amazonaws.com/bucket/service/service-archive.zip
commands:
a-create-directory:
command: mkdir c:\\service\\serviceName\\Release
cwd: “c:/service/temp/”
waitAfterCompletion: 0
ignoreErrors: true
b-remove-service
command: C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\installutil NameOfService.exe /u > “Remove.txt”
cwd: “c:/service/serviceNamer/Release”
waitAfterCompletion: 11
ignoreErrors: true
c-copy-service
command: copy c:\\service\\temp\\Release c:\\service\\vserviceName\\Release
cwd: “c:/service/temp/”
waitAfterCompletion: 0
d-install-service
command: C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\installutil NameOfService.exe > “Install.txt”
cwd: “c:/service/serviceName/Release”
waitAfterCompletion: 0
services:
windows:
NameOfService:
enabled: true
ensureRunning: true
commands: d-install-service
The service uninstall/install commands are piping out their results to text files, so that if there is an error during execution I can RDP to the server and take a look at the specific error message. Also of note for troubleshooting, there is a directory created by the EB install process at c:\cfn. It contains a log directory, and in there is cfn-init.txt. If your install process fails, the errors can be found there.