diff --git a/docs/redis.md b/docs/redis.md
index 5bb73b29..3c506a7c 100644
--- a/docs/redis.md
+++ b/docs/redis.md
@@ -95,7 +95,7 @@ We just showed how `tye` makes it easier to communicate between 2 applications r
- port: 6379
- name: redis-cli
image: redis
- args: "redis-cli -h host.docker.internal MONITOR"
+ args: "redis-cli -h redis MONITOR"
```
We've added 2 services to the `tye.yaml` file. The `redis` service itself and a `redis-cli` service that we will use to watch the data being sent to and retrieved from redis.
diff --git a/samples/mongo-sample/tye.yaml b/samples/mongo-sample/tye.yaml
new file mode 100644
index 00000000..33c0435e
--- /dev/null
+++ b/samples/mongo-sample/tye.yaml
@@ -0,0 +1,21 @@
+services:
+- name: mongo
+ image: mongo
+ env:
+ - name: ME_CONFIG_MONGODB_ADMINUSERNAME
+ value: root
+ - name: ME_CONFIG_MONGODB_ADMINPASSWORD
+ value: example
+ bindings:
+ - port: 27017
+- name: mongo-express
+ image: mongo-express
+ bindings:
+ - port: 8081
+ containerPort: 8081
+ protocol: http
+ env:
+ - name: ME_CONFIG_MONGODB_ADMINUSERNAME
+ value: root
+ - name: ME_CONFIG_MONGODB_ADMINPASSWORD
+ value: example
\ No newline at end of file
diff --git a/samples/redis/tye.yaml b/samples/redis/tye.yaml
new file mode 100644
index 00000000..e914dc93
--- /dev/null
+++ b/samples/redis/tye.yaml
@@ -0,0 +1,8 @@
+services:
+ - name: redis
+ image: redis
+ bindings:
+ - port: 6379
+ - name: redis-cli
+ image: redis
+ args: "redis-cli -h redis MONITOR"
\ No newline at end of file
diff --git a/src/Microsoft.Tye.Hosting/Dashboard/Pages/Index.razor b/src/Microsoft.Tye.Hosting/Dashboard/Pages/Index.razor
index 3b218af8..53a9bd47 100644
--- a/src/Microsoft.Tye.Hosting/Dashboard/Pages/Index.razor
+++ b/src/Microsoft.Tye.Hosting/Dashboard/Pages/Index.razor
@@ -42,7 +42,7 @@
{
if (b.Port != null)
{
- if (b.Protocol == null || b.Protocol == "http" || b.Protocol == "https")
+ if (b.Protocol == "http" || b.Protocol == "https")
{
var url = GetUrl(b);
@url
@@ -79,7 +79,7 @@
string GetUrl(ServiceBinding b)
{
- return $"{(b.Protocol ?? "http")}://{b.Host ?? "localhost"}:{b.Port}";
+ return $"{(b.Protocol ?? "tcp")}://{b.Host ?? "localhost"}:{b.Port}";
}
protected override void OnInitialized()
diff --git a/src/Microsoft.Tye.Hosting/DockerRunner.cs b/src/Microsoft.Tye.Hosting/DockerRunner.cs
index a07d4041..452bbc13 100644
--- a/src/Microsoft.Tye.Hosting/DockerRunner.cs
+++ b/src/Microsoft.Tye.Hosting/DockerRunner.cs
@@ -34,17 +34,53 @@ namespace Microsoft.Tye.Hosting
{
await PurgeFromPreviousRun();
- var tasks = new Task[application.Services.Count];
- var index = 0;
+ var containers = new List();
+
foreach (var s in application.Services)
{
- tasks[index++] = s.Value.Description.RunInfo is DockerRunInfo docker ? StartContainerAsync(application, s.Value, docker) : Task.CompletedTask;
+ if (s.Value.Description.RunInfo is DockerRunInfo)
+ {
+ containers.Add(s.Value);
+ }
+ }
+
+ if (containers.Count == 0)
+ {
+ return;
+ }
+
+ string? dockerNetwork = null;
+
+ // We're going to be making containers, only make a network if we have more than one (we assume they'll need to talk)
+ if (containers.Count > 1)
+ {
+ dockerNetwork = "tye_network_" + Guid.NewGuid().ToString().Substring(0, 10);
+
+ application.Items["dockerNetwork"] = dockerNetwork;
+
+ _logger.LogInformation("Creating docker network {Network}", dockerNetwork);
+
+ var command = $"network create --driver bridge {dockerNetwork}";
+
+ _logger.LogInformation("Running docker command {Command}", command);
+
+ await ProcessUtil.RunAsync("docker", command);
+ }
+
+ var tasks = new Task[containers.Count];
+ var index = 0;
+
+ foreach (var s in containers)
+ {
+ var docker = (DockerRunInfo)s.Description.RunInfo!;
+
+ tasks[index++] = StartContainerAsync(application, s, docker, dockerNetwork);
}
await Task.WhenAll(tasks);
}
- public Task StopAsync(Application application)
+ public async Task StopAsync(Application application)
{
var services = application.Services;
@@ -56,10 +92,22 @@ namespace Microsoft.Tye.Hosting
tasks[index++] = StopContainerAsync(state);
}
- return Task.WhenAll(tasks);
+ await Task.WhenAll(tasks);
+
+ if (application.Items.TryGetValue("dockerNetwork", out var dockerNetwork))
+ {
+ _logger.LogInformation("Removing docker network {Network}", dockerNetwork);
+
+ var command = $"network rm {dockerNetwork}";
+
+ _logger.LogInformation("Running docker command {Command}", command);
+
+ // Clean up the network we created
+ await ProcessUtil.RunAsync("docker", command, throwOnError: false);
+ }
}
- private async Task StartContainerAsync(Application application, Service service, DockerRunInfo docker)
+ private async Task StartContainerAsync(Application application, Service service, DockerRunInfo docker, string? dockerNetwork)
{
var serviceDescription = service.Description;
var environmentArguments = "";
@@ -167,9 +215,10 @@ namespace Microsoft.Tye.Hosting
var command = $"run -d {workingDirectory} {volumes} {environmentArguments} {portString} --name {replica} --restart=unless-stopped {docker.Image} {docker.Args ?? ""}";
_logger.LogInformation("Running docker command {Command}", command);
- service.Logs.OnNext($"[{replica}]: {command}");
+ service.Logs.OnNext($"[{replica}]: docker {command}");
status.DockerCommand = command;
+ status.DockerNetwork = dockerNetwork;
WriteReplicaToStore(replica);
var result = await ProcessUtil.RunAsync(
@@ -208,6 +257,24 @@ namespace Microsoft.Tye.Hosting
_logger.LogInformation("Running container {ContainerName} with ID {ContainerId}", replica, shortContainerId);
+ if (!string.IsNullOrEmpty(dockerNetwork))
+ {
+ // If this is the only replica then the network alias is the service name
+ var alias = serviceDescription.Replicas == 1 ? serviceDescription.Name : replica;
+
+ status.DockerNetworkAlias = alias;
+
+ var networkCommand = $"network connect {dockerNetwork} {replica} --alias {alias}";
+
+ service.Logs.OnNext($"[{replica}]: docker {networkCommand}");
+
+ _logger.LogInformation("Running docker command {Command}", networkCommand);
+
+ result = await ProcessUtil.RunAsync("docker", networkCommand);
+
+ PrintStdOutAndErr(service, replica, result);
+ }
+
service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Started, status));
_logger.LogInformation("Collecting docker logs for {ContainerName}.", replica);
diff --git a/src/Microsoft.Tye.Hosting/HttpProxyService.cs b/src/Microsoft.Tye.Hosting/HttpProxyService.cs
index 6834f9d2..8148ae73 100644
--- a/src/Microsoft.Tye.Hosting/HttpProxyService.cs
+++ b/src/Microsoft.Tye.Hosting/HttpProxyService.cs
@@ -154,12 +154,14 @@ namespace Microsoft.Tye.Hosting
conventions.WithDisplayName(rule.Service);
}
- }
- }
- foreach (var app in _webApplications)
- {
- await app.StartAsync();
+ await webApp.StartAsync();
+
+ foreach (var replica in service.Replicas)
+ {
+ service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Started, replica.Value));
+ }
+ }
}
}
diff --git a/src/Microsoft.Tye.Hosting/Model/Application.cs b/src/Microsoft.Tye.Hosting/Model/Application.cs
index 668427aa..0811f0f7 100644
--- a/src/Microsoft.Tye.Hosting/Model/Application.cs
+++ b/src/Microsoft.Tye.Hosting/Model/Application.cs
@@ -24,6 +24,8 @@ namespace Microsoft.Tye.Hosting.Model
public Dictionary Services { get; }
+ public Dictionary