Browse Source

Small tweak to docker build (#498)

* Small tweak to docker build
- Log the output to both the main window and the service logs when building.

Fixes #491
jkotalik/porter
David Fowler 6 years ago
committed by GitHub
parent
commit
3de1aff106
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 119
      src/Microsoft.Tye.Hosting/DockerRunner.cs
  2. 2
      test/Test.Infrastructure/TestHelpers.cs

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

@ -204,21 +204,6 @@ namespace Microsoft.Tye.Hosting
var hostname = "host.docker.internal"; var hostname = "host.docker.internal";
var dockerImage = docker.Image ?? service.Description.Name; var dockerImage = docker.Image ?? service.Description.Name;
if (docker.DockerFile != null)
{
var dockerBuildResult = await ProcessUtil.RunAsync(
$"docker",
$"build \"{docker.DockerFileContext?.FullName}\" -t {dockerImage} -f \"{docker.DockerFile}\"",
docker.WorkingDirectory,
throwOnError: false);
if (dockerBuildResult.ExitCode != 0)
{
_logger.LogInformation("Running docker command with exception info {ExceptionStdOut} {ExceptionStdErr}", dockerBuildResult.StandardOutput, dockerBuildResult.StandardError);
throw new CommandException("'docker build' failed.");
}
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{ {
// See: https://github.com/docker/for-linux/issues/264 // See: https://github.com/docker/for-linux/issues/264
@ -229,9 +214,7 @@ namespace Microsoft.Tye.Hosting
hostname = addresses[0].ToString(); hostname = addresses[0].ToString();
} }
var dockerInfo = new DockerInformation(new Task[service.Description.Replicas]); async Task RunDockerContainer(IEnumerable<(int ExternalPort, int Port, int? ContainerPort, string? Protocol)> ports, CancellationToken cancellationToken)
async Task RunDockerContainer(IEnumerable<(int ExternalPort, int Port, int? ContainerPort, string? Protocol)> ports)
{ {
var hasPorts = ports.Any(); var hasPorts = ports.Any();
@ -282,10 +265,10 @@ namespace Microsoft.Tye.Hosting
// //
// The way we do proxying here doesn't really work for multi-container scenarios on linux // The way we do proxying here doesn't really work for multi-container scenarios on linux
// without some more setup. // without some more setup.
application.PopulateEnvironment(service, (key, value) => environment[key] = value, hostname); application.PopulateEnvironment(service, (key, value) => environment[key] = value, hostname!);
environment["APP_INSTANCE"] = replica; environment["APP_INSTANCE"] = replica;
environment["CONTAINER_HOST"] = hostname; environment["CONTAINER_HOST"] = hostname!;
status.Environment = environment; status.Environment = environment;
@ -321,7 +304,7 @@ namespace Microsoft.Tye.Hosting
"docker", "docker",
command, command,
throwOnError: false, throwOnError: false,
cancellationToken: dockerInfo.StoppingTokenSource.Token, cancellationToken: cancellationToken,
outputDataReceived: data => service.Logs.OnNext($"[{replica}]: {data}"), outputDataReceived: data => service.Logs.OnNext($"[{replica}]: {data}"),
errorDataReceived: data => service.Logs.OnNext($"[{replica}]: {data}")); errorDataReceived: data => service.Logs.OnNext($"[{replica}]: {data}"));
@ -355,7 +338,7 @@ namespace Microsoft.Tye.Hosting
if (!string.IsNullOrEmpty(dockerNetwork)) if (!string.IsNullOrEmpty(dockerNetwork))
{ {
status.DockerNetworkAlias = docker.NetworkAlias ?? serviceDescription.Name; status.DockerNetworkAlias = docker.NetworkAlias ?? serviceDescription!.Name;
var networkCommand = $"network connect {dockerNetwork} {replica} --alias {status.DockerNetworkAlias}"; var networkCommand = $"network connect {dockerNetwork} {replica} --alias {status.DockerNetworkAlias}";
@ -370,7 +353,7 @@ namespace Microsoft.Tye.Hosting
var sentStartedEvent = false; var sentStartedEvent = false;
while (!dockerInfo.StoppingTokenSource.Token.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
if (sentStartedEvent) if (sentStartedEvent)
{ {
@ -396,7 +379,7 @@ namespace Microsoft.Tye.Hosting
service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Started, status)); service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Started, status));
sentStartedEvent = true; sentStartedEvent = true;
await using var _ = dockerInfo.StoppingTokenSource.Token.Register(() => status.StoppingTokenSource.Cancel()); await using var _ = cancellationToken.Register(() => status.StoppingTokenSource.Cancel());
_logger.LogInformation("Collecting docker logs for {ContainerName}.", replica); _logger.LogInformation("Collecting docker logs for {ContainerName}.", replica);
@ -473,34 +456,79 @@ namespace Microsoft.Tye.Hosting
service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Removed, status)); service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Removed, status));
}; };
if (serviceDescription.Bindings.Count > 0) async Task DockerBuildAsync(CancellationToken cancellationToken)
{ {
// Each replica is assigned a list of internal ports, one mapped to each external if (docker.DockerFile != null)
// port
for (var i = 0; i < serviceDescription.Replicas; i++)
{ {
var ports = new List<(int, int, int?, string?)>(); _logger.LogInformation("Building docker image {Image} from docker file", dockerImage);
foreach (var binding in serviceDescription.Bindings)
{
if (binding.Port == null)
{
continue;
}
ports.Add((binding.Port.Value, binding.ReplicaPorts[i], binding.ContainerPort, binding.Protocol)); void Log(string data)
{
_logger.LogInformation("[" + serviceDescription!.Name + "]:" + data);
service.Logs.OnNext(data);
} }
dockerInfo.Tasks[i] = RunDockerContainer(ports); var dockerBuildResult = await ProcessUtil.RunAsync(
$"docker",
$"build \"{docker.DockerFileContext?.FullName}\" -t {dockerImage} -f \"{docker.DockerFile}\"",
outputDataReceived: Log,
errorDataReceived: Log,
workingDirectory: docker.WorkingDirectory,
cancellationToken: cancellationToken,
throwOnError: false);
if (dockerBuildResult.ExitCode != 0)
{
throw new CommandException("'docker build' failed.");
}
} }
} }
else
Task DockerRunAsync(CancellationToken cancellationToken)
{ {
for (var i = 0; i < service.Description.Replicas; i++) var tasks = new Task[serviceDescription!.Replicas];
if (serviceDescription.Bindings.Count > 0)
{
// Each replica is assigned a list of internal ports, one mapped to each external
// port
for (var i = 0; i < serviceDescription.Replicas; i++)
{
var ports = new List<(int, int, int?, string?)>();
foreach (var binding in serviceDescription.Bindings)
{
if (binding.Port == null)
{
continue;
}
ports.Add((binding.Port.Value, binding.ReplicaPorts[i], binding.ContainerPort, binding.Protocol));
}
tasks[i] = RunDockerContainer(ports, cancellationToken);
}
}
else
{ {
dockerInfo.Tasks[i] = RunDockerContainer(Enumerable.Empty<(int, int, int?, string?)>()); for (var i = 0; i < service.Description.Replicas; i++)
{
tasks[i] = RunDockerContainer(Enumerable.Empty<(int, int, int?, string?)>(), cancellationToken);
}
} }
return Task.WhenAll(tasks);
}
async Task BuildAndRunAsync(CancellationToken cancellationToken)
{
await DockerBuildAsync(cancellationToken);
await DockerRunAsync(cancellationToken);
} }
var dockerInfo = new DockerInformation();
dockerInfo.Task = BuildAndRunAsync(dockerInfo.StoppingTokenSource.Token);
service.Items[typeof(DockerInformation)] = dockerInfo; service.Items[typeof(DockerInformation)] = dockerInfo;
} }
@ -511,7 +539,7 @@ namespace Microsoft.Tye.Hosting
{ {
var container = replica["container"]; var container = replica["container"];
await ProcessUtil.RunAsync("docker", $"rm -f {container}", throwOnError: false); await ProcessUtil.RunAsync("docker", $"rm -f {container}", throwOnError: false);
_logger.LogInformation("removed contaienr {container} from previous run", container); _logger.LogInformation("removed container {container} from previous run", container);
} }
_replicaRegistry.DeleteStore(DockerReplicaStore); _replicaRegistry.DeleteStore(DockerReplicaStore);
@ -547,7 +575,7 @@ namespace Microsoft.Tye.Hosting
{ {
di.StoppingTokenSource.Cancel(); di.StoppingTokenSource.Cancel();
return Task.WhenAll(di.Tasks); return di.Task;
} }
return Task.CompletedTask; return Task.CompletedTask;
@ -555,12 +583,7 @@ namespace Microsoft.Tye.Hosting
private class DockerInformation private class DockerInformation
{ {
public DockerInformation(Task[] tasks) public Task Task { get; set; } = default!;
{
Tasks = tasks;
}
public Task[] Tasks { get; }
public CancellationTokenSource StoppingTokenSource { get; } = new CancellationTokenSource(); public CancellationTokenSource StoppingTokenSource { get; } = new CancellationTokenSource();
} }

2
test/Test.Infrastructure/TestHelpers.cs

@ -19,7 +19,7 @@ namespace Test.Infrastructure
{ {
public static class TestHelpers public static class TestHelpers
{ {
private static readonly TimeSpan WaitForServicesTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(20); private static readonly TimeSpan WaitForServicesTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromMinutes(1);
// https://github.com/dotnet/aspnetcore/blob/5a0526dfd991419d5bce0d8ea525b50df2e37b04/src/Testing/src/TestPathUtilities.cs // https://github.com/dotnet/aspnetcore/blob/5a0526dfd991419d5bce0d8ea525b50df2e37b04/src/Testing/src/TestPathUtilities.cs
// This can get into a bad pattern for having crazy paths in places. Eventually, especially if we use helix, // This can get into a bad pattern for having crazy paths in places. Eventually, especially if we use helix,

Loading…
Cancel
Save