Browse Source

Improve nginx-ingress experience (#664)

johluo/lock
Glenn Condron 6 years ago
committed by GitHub
parent
commit
0b0ae57bed
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      samples/dockercompose/ingress.yml
  2. 44
      src/Microsoft.Tye.Core/DeployApplicationKubernetesManifestStep.cs
  3. 16
      src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs
  4. 15
      src/Microsoft.Tye.Core/ValidateIngressStep.cs
  5. 30
      test/E2ETest/testassets/generate/apps-with-ingress.yaml

2
samples/dockercompose/ingress.yml

@ -1,4 +1,4 @@
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-basic

44
src/Microsoft.Tye.Core/DeployApplicationKubernetesManifestStep.cs

@ -2,6 +2,7 @@
// 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.CommandLine.Invocation;
using System.IO;
using System.Text;
@ -15,7 +16,7 @@ namespace Microsoft.Tye
public override async Task ExecuteAsync(OutputContext output, ApplicationBuilder application)
{
using var step = output.BeginStep("");
using var step = output.BeginStep("Applying Kubernetes Manifests...");
if (!await KubectlDetector.IsKubectlInstalledAsync(output))
{
@ -59,6 +60,47 @@ namespace Microsoft.Tye
}
output.WriteInfoLine($"Deployed application '{application.Name}'.");
if (application.Ingress.Count > 0)
{
output.WriteInfoLine($"Waiting for ingress to be deployed. This may take a long time.");
foreach (var ingress in application.Ingress)
{
using var ingressStep = output.BeginStep($"Retrieving details for {ingress.Name}...");
var done = false;
Action<string> complete = line =>
{
done = line != "''";
if (done)
{
output.WriteInfoLine($"IngressIP: {line}");
}
};
var retries = 0;
while (!done && retries < 60)
{
var ingressExitCode = await Process.ExecuteAsync(
"kubectl",
$"get ingress {ingress.Name} -o jsonpath='{{..ip}}'",
Environment.CurrentDirectory,
complete,
capture.StdErr);
if (ingressExitCode != 0)
{
throw new CommandException("'kubectl get ingress' failed");
}
if (!done)
{
await Task.Delay(2000);
retries++;
}
}
}
}
}
}
}

16
src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs

@ -20,7 +20,7 @@ namespace Microsoft.Tye
var root = new YamlMappingNode();
root.Add("kind", "Ingress");
root.Add("apiVersion", "extensions/v1beta1");
root.Add("apiVersion", "networking.k8s.io/v1");
var metadata = new YamlMappingNode();
root.Add("metadata", metadata);
@ -74,7 +74,10 @@ namespace Microsoft.Tye
var backend = new YamlMappingNode();
path.Add("backend", backend);
backend.Add("serviceName", ingressRule.Service);
var backendService = new YamlMappingNode();
backend.Add("service", backendService);
backendService.Add("name", ingressRule.Service);
var service = application.Services.FirstOrDefault(s => s.Name == ingressRule.Service);
if (service is null)
@ -88,7 +91,11 @@ namespace Microsoft.Tye
throw new InvalidOperationException($"Could not resolve an http binding for service '{service.Name}'.");
}
backend.Add("servicePort", (binding.Port ?? 80).ToString(CultureInfo.InvariantCulture));
var backendPort = new YamlMappingNode();
backendService.Add("port", backendPort);
backendPort.Add("number", (binding.Port ?? 80).ToString(CultureInfo.InvariantCulture));
// Tye implements path matching similar to this example:
// https://kubernetes.github.io/ingress-nginx/examples/rewrite/
@ -111,6 +118,9 @@ namespace Microsoft.Tye
path.Add("path", regex);
}
}
// Only support prefix matching for now
path.Add("pathType", "Prefix");
}
}

15
src/Microsoft.Tye.Core/ValidateIngressStep.cs

@ -140,21 +140,20 @@ namespace Microsoft.Tye
else
{
// If we get here then we should deploy the ingress controller.
// For some reason, the first time we apply the ingress controller, an exception is thrown
// saying "ingress-nginx-admission-create" is invalid. Therefore, we are going to blindly assume the
// controller successfully ran.
output.WriteDebugLine($"Running 'kubectl apply'");
output.WriteCommandLine("kubectl", $"apply -f \"https://aka.ms/tye/ingress/deploy\"");
var capture = output.Capture();
var exitCode = await Process.ExecuteAsync(
$"kubectl",
$"apply -f \"https://aka.ms/tye/ingress/deploy\"",
System.Environment.CurrentDirectory,
stdOut: capture.StdOut,
stdErr: capture.StdErr);
System.Environment.CurrentDirectory);
output.WriteDebugLine($"Done running 'kubectl apply' exit code: {exitCode}");
if (exitCode != 0)
{
throw new CommandException("'kubectl apply' failed.");
}
output.WriteInfoLine($"Waiting for ingress-nginx controller to start.");
@ -162,7 +161,7 @@ namespace Microsoft.Tye
// after creating the controller will fail if the webhook isn't ready.
//
// Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io":
// Post https://ingress-nginx-controller-admission.ingress-nginx.svc:443/extensions/v1beta1/ingresses?timeout=30s:
// Post https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking.k8s.io/v1/ingresses?timeout=30s:
// dial tcp 10.0.31.130:443: connect: connection refused
//
// Unfortunately this is the likely case for us.

30
test/E2ETest/testassets/generate/apps-with-ingress.yaml

@ -125,7 +125,7 @@ spec:
...
---
kind: Ingress
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
metadata:
name: ingress
annotations:
@ -138,25 +138,37 @@ spec:
- http:
paths:
- backend:
serviceName: appa
servicePort: 80
service:
name: appa
port:
number: 80
path: /A(/|$)(.*)
pathType: Prefix
- backend:
serviceName: appb
servicePort: 80
service:
name: appb
port:
number: 80
path: /B(/|$)(.*)
pathType: Prefix
- host: a.example.com
http:
paths:
- backend:
serviceName: appa
servicePort: 80
service:
name: appa
port:
number: 80
path: /()(.*)
pathType: Prefix
- host: b.example.com
http:
paths:
- backend:
serviceName: appb
servicePort: 80
service:
name: appb
port:
number: 80
path: /()(.*)
pathType: Prefix
...

Loading…
Cancel
Save