in src/AWS.Deploy.Orchestration/Orchestrator.cs [292:374]
private async Task CreateContainerDeploymentBundle(CloudApplication cloudApplication, Recommendation recommendation)
{
if (_interactiveService == null)
throw new InvalidOperationException($"{nameof(_interactiveService)} is null as part of the orchestartor object");
if (_dockerEngine == null)
throw new InvalidOperationException($"{nameof(_dockerEngine)} is null as part of the orchestartor object");
if (_deploymentBundleHandler == null)
throw new InvalidOperationException($"{nameof(_deploymentBundleHandler)} is null as part of the orchestrator object");
if (_optionSettingHandler == null)
throw new InvalidOperationException($"{nameof(_optionSettingHandler)} is null as part of the orchestrator object");
if (_fileManager == null)
throw new InvalidOperationException($"{nameof(_fileManager)} is null as part of the orchestrator object");
if (!DockerUtilities.TryGetDockerfile(recommendation, _fileManager, out _))
{
_interactiveService.LogInfoMessage("Generating Dockerfile...");
try
{
_dockerEngine.GenerateDockerFile(recommendation);
}
catch (DockerEngineExceptionBase ex)
{
var errorMessage = "Failed to generate a docker file due to the following error:" + Environment.NewLine + ex.Message;
throw new FailedToGenerateDockerFileException(DeployToolErrorCode.FailedToGenerateDockerFile, errorMessage, ex);
}
}
_dockerEngine.DetermineDockerExecutionDirectory(recommendation);
// Read this from the OptionSetting instead of recommendation.DeploymentBundle.
// When its value comes from a replacement token, it wouldn't have been set back to the DeploymentBundle
var respositoryName = _optionSettingHandler.GetOptionSettingValue<string>(recommendation, _optionSettingHandler.GetOptionSetting(recommendation, Constants.Docker.ECRRepositoryNameOptionId));
if (respositoryName == null)
throw new InvalidECRRepositoryNameException(DeployToolErrorCode.ECRRepositoryNameIsNull, "The ECR Repository Name is null.");
string imageTag;
try
{
var tagSuffix = _optionSettingHandler.GetOptionSettingValue<string>(recommendation, _optionSettingHandler.GetOptionSetting(recommendation, Constants.Docker.ImageTagOptionId));
imageTag = $"{respositoryName}:{tagSuffix}";
}
catch (OptionSettingItemDoesNotExistException)
{
imageTag = $"{respositoryName}:{DateTime.UtcNow.Ticks}";
}
await _deploymentBundleHandler.BuildDockerImage(cloudApplication, recommendation, imageTag);
// These option settings need to be persisted back as they are not always provided by the user and we have custom logic to determine their values
await _optionSettingHandler.SetOptionSettingValue(recommendation, Constants.Docker.DockerExecutionDirectoryOptionId, recommendation.DeploymentBundle.DockerExecutionDirectory);
await _optionSettingHandler.SetOptionSettingValue(recommendation, Constants.Docker.DockerfileOptionId, recommendation.DeploymentBundle.DockerfilePath);
// Try to inspect the container environment variables to provide better insights on the HTTP port to use for the container.
// If we run into issues doing so, we can proceed without throwing a terminating exception.
try
{
var environmentVariables = await _deploymentBundleHandler.InspectDockerImageEnvironmentVariables(recommendation, imageTag);
if (environmentVariables.ContainsKey(Constants.Docker.DotnetHttpPortEnvironmentVariable))
{
var httpPort = environmentVariables[Constants.Docker.DotnetHttpPortEnvironmentVariable];
// Assuming a single value can be specified
if (int.TryParse(httpPort, out var httpPortInt))
{
if (recommendation.DeploymentBundle.DockerfileHttpPort != httpPortInt)
{
_interactiveService.LogInfoMessage($"The HTTP port you have chosen in your deployment settings is different than the .NET HTTP port exposed in the container. " +
$"The container has the environment variable {Constants.Docker.DotnetHttpPortEnvironmentVariable}={httpPortInt}, " +
$"whereas the port you chose in the deployment settings is {recommendation.DeploymentBundle.DockerfileHttpPort}." +
$"The deployment may fail the health check if these 2 ports are misaligned.");
}
}
}
}
catch (DockerInspectFailedException ex)
{
_interactiveService.LogDebugMessage($"Unable to inspect the docker container to retrieve the HTTP port used by .NET due to the following error: {ex.Message}");
}
_interactiveService.LogSectionStart("Pushing container image to Elastic Container Registry (ECR)", "Using the docker CLI to log on to ECR and push the local image to ECR.");
await _deploymentBundleHandler.PushDockerImageToECR(recommendation, respositoryName, imageTag);
}