Browse Source

Pull docker images before running (#275)

* Pull docker images before running
- This step also validates that docker is installed before trying to pull and before running so that logic can be removed from the DockerRunner.
- Let the application exit if it tye run fails to start.

Fixes #222
davidfowl/build-earlier
David Fowler 7 years ago
committed by GitHub
parent
commit
40ecc07dc2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 91
      src/Microsoft.Tye.Hosting/DockerImagePuller.cs
  2. 16
      src/Microsoft.Tye.Hosting/DockerRunner.cs
  3. 27
      src/Microsoft.Tye.Hosting/TyeHost.cs

91
src/Microsoft.Tye.Hosting/DockerImagePuller.cs

@ -0,0 +1,91 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Tye.Hosting.Model;
namespace Microsoft.Tye.Hosting
{
public class DockerImagePuller : IApplicationProcessor
{
private readonly ILogger _logger;
public DockerImagePuller(ILogger logger)
{
_logger = logger;
}
public async Task StartAsync(Application application)
{
var images = new HashSet<string>();
foreach (var s in application.Services)
{
if (s.Value.Description.RunInfo is DockerRunInfo docker)
{
images.Add(docker.Image);
}
}
// No images, no docker skip it.
if (images.Count == 0)
{
return;
}
if (!await DockerDetector.Instance.IsDockerInstalled.Value)
{
_logger.LogError("Unable to detect docker installation. Docker is not installed.");
throw new CommandException("Docker is not installed.");
}
if (!await DockerDetector.Instance.IsDockerConnectedToDaemon.Value)
{
_logger.LogError("Unable to connect to docker daemon. Docker is not running.");
throw new CommandException("Docker is not running.");
}
var tasks = new Task[images.Count];
var index = 0;
foreach (var image in images)
{
tasks[index++] = PullContainerAsync(image);
}
await Task.WhenAll(tasks);
}
private async Task PullContainerAsync(string image)
{
await Task.Yield();
var command = $"pull {image}";
_logger.LogInformation("Running docker command {command}", command);
var result = await ProcessUtil.RunAsync(
"docker",
command,
outputDataReceived: data => _logger.LogInformation("{Image}: " + data, image),
errorDataReceived: data => _logger.LogInformation("{Image}: " + data, image),
throwOnError: false);
if (result.ExitCode != 0)
{
throw new CommandException("Docker pull command failed");
}
}
public Task StopAsync(Application application)
{
return Task.CompletedTask;
}
}
}

16
src/Microsoft.Tye.Hosting/DockerRunner.cs

@ -61,22 +61,6 @@ namespace Microsoft.Tye.Hosting
private async Task StartContainerAsync(Application application, Service service, DockerRunInfo docker) private async Task StartContainerAsync(Application application, Service service, DockerRunInfo docker)
{ {
if (!await DockerDetector.Instance.IsDockerInstalled.Value)
{
_logger.LogError("Unable to start docker container for service {ServiceName}, Docker is not installed.", service.Description.Name);
service.Logs.OnNext($"Unable to start docker container for service {service.Description.Name}, Docker is not installed.");
return;
}
if (!await DockerDetector.Instance.IsDockerConnectedToDaemon.Value)
{
_logger.LogError("Unable to start docker container for service {ServiceName}, Docker is not running.", service.Description.Name);
service.Logs.OnNext($"Unable to start docker container for service {service.Description.Name}, Docker is not running.");
return;
}
var serviceDescription = service.Description; var serviceDescription = service.Description;
var environmentArguments = ""; var environmentArguments = "";
var volumes = ""; var volumes = "";

27
src/Microsoft.Tye.Hosting/TyeHost.cs

@ -60,13 +60,18 @@ namespace Microsoft.Tye.Hosting
public async Task RunAsync() public async Task RunAsync()
{ {
await StartAsync(); try
{
var waitForStop = new TaskCompletionSource<object?>(TaskCreationOptions.RunContinuationsAsynchronously); await StartAsync();
_lifetime?.ApplicationStopping.Register(obj => waitForStop.TrySetResult(null), null);
await waitForStop.Task;
await StopAsync(); var waitForStop = new TaskCompletionSource<object?>(TaskCreationOptions.RunContinuationsAsynchronously);
_lifetime?.ApplicationStopping.Register(obj => waitForStop.TrySetResult(null), null);
await waitForStop.Task;
}
finally
{
await StopAsync();
}
} }
public async Task<WebApplication> StartAsync() public async Task<WebApplication> StartAsync()
@ -91,14 +96,7 @@ namespace Microsoft.Tye.Hosting
_logger.LogInformation("Dashboard running on {Address}", app.Addresses.First()); _logger.LogInformation("Dashboard running on {Address}", app.Addresses.First());
try await _processor.StartAsync(_application);
{
await _processor.StartAsync(_application);
}
catch (Exception ex)
{
_logger.LogError(0, ex, "Failed to launch application");
}
return app; return app;
} }
@ -280,6 +278,7 @@ namespace Microsoft.Tye.Hosting
new PortAssigner(logger), new PortAssigner(logger),
new ProxyService(logger), new ProxyService(logger),
new HttpProxyService(logger), new HttpProxyService(logger),
new DockerImagePuller(logger),
new DockerRunner(logger, replicaRegistry), new DockerRunner(logger, replicaRegistry),
new ProcessRunner(logger, replicaRegistry, ProcessRunnerOptions.FromArgs(args, servicesToDebug)) new ProcessRunner(logger, replicaRegistry, ProcessRunnerOptions.FromArgs(args, servicesToDebug))
}; };

Loading…
Cancel
Save