@ -204,21 +204,6 @@ namespace Microsoft.Tye.Hosting
var hostname = "host.docker.internal" ;
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 )
{
_l ogger . LogInformation ( "Running docker command with exception info {ExceptionStdOut} {ExceptionStdErr}" , dockerBuildResult . StandardOutput , dockerBuildResult . StandardError ) ;
throw new CommandException ( "'docker build' failed." ) ;
}
}
if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) )
{
// See: https://github.com/docker/for-linux/issues/264
@ -229,9 +214,7 @@ namespace Microsoft.Tye.Hosting
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 )
async Task RunDockerContainer ( IEnumerable < ( int ExternalPort , int Port , int? ContainerPort , string? Protocol ) > ports , CancellationToken cancellationToken )
{
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
// 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 [ "CONTAINER_HOST" ] = hostname ;
environment [ "CONTAINER_HOST" ] = hostname ! ;
status . Environment = environment ;
@ -321,7 +304,7 @@ namespace Microsoft.Tye.Hosting
"docker" ,
command ,
throwOnError : false ,
cancellationToken : do ckerInfo . S topp ingT oke nSource . Token ,
cancellationToken : cancella tionToken ,
outputDataReceived : 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 ) )
{
status . DockerNetworkAlias = docker . NetworkAlias ? ? serviceDescription . Name ;
status . DockerNetworkAlias = docker . NetworkAlias ? ? serviceDescription ! . Name ;
var networkCommand = $"network connect {dockerNetwork} {replica} --alias {status.DockerNetworkAlias}" ;
@ -370,7 +353,7 @@ namespace Microsoft.Tye.Hosting
var sentStartedEvent = false ;
while ( ! do ckerInfo . S topp ingT oke nSource . Token . IsCancellationRequested )
while ( ! cancella tionToken . IsCancellationRequested )
{
if ( sentStartedEvent )
{
@ -396,7 +379,7 @@ namespace Microsoft.Tye.Hosting
service . ReplicaEvents . OnNext ( new ReplicaEvent ( ReplicaState . Started , status ) ) ;
sentStartedEvent = true ;
await using var _ = do ckerInfo . S topp ingT oke nSource . Token . Register ( ( ) = > status . StoppingTokenSource . Cancel ( ) ) ;
await using var _ = cancella tionToken . Register ( ( ) = > status . StoppingTokenSource . Cancel ( ) ) ;
_l ogger . LogInformation ( "Collecting docker logs for {ContainerName}." , replica ) ;
@ -473,34 +456,79 @@ namespace Microsoft.Tye.Hosting
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
// port
for ( var i = 0 ; i < serviceDescription . Replicas ; i + + )
if ( docker . DockerFile ! = null )
{
var ports = new List < ( int , int , int? , string? ) > ( ) ;
foreach ( var binding in serviceDescription . Bindings )
{
if ( binding . Port = = null )
{
continue ;
}
_l ogger . LogInformation ( "Building docker image {Image} from docker file" , dockerImage ) ;
ports . Add ( ( binding . Port . Value , binding . ReplicaPorts [ i ] , binding . ContainerPort , binding . Protocol ) ) ;
void Log ( string data )
{
_l ogger . 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 ;
}
@ -511,7 +539,7 @@ namespace Microsoft.Tye.Hosting
{
var container = replica [ "container" ] ;
await ProcessUtil . RunAsync ( "docker" , $"rm -f {container}" , throwOnError : false ) ;
_l ogger . LogInformation ( "removed contaie nr {container} from previous run" , container ) ;
_l ogger . LogInformation ( "removed containe r {container} from previous run" , container ) ;
}
_ replicaRegistry . DeleteStore ( DockerReplicaStore ) ;
@ -547,7 +575,7 @@ namespace Microsoft.Tye.Hosting
{
di . StoppingTokenSource . Cancel ( ) ;
return Task . WhenAll ( di . Tasks ) ;
return di . Task ;
}
return Task . CompletedTask ;
@ -555,12 +583,7 @@ namespace Microsoft.Tye.Hosting
private class DockerInformation
{
public DockerInformation ( Task [ ] tasks )
{
Tasks = tasks ;
}
public Task [ ] Tasks { get ; }
public Task Task { get ; set ; } = default ! ;
public CancellationTokenSource StoppingTokenSource { get ; } = new CancellationTokenSource ( ) ;
}