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 kind: Ingress
metadata: metadata:
name: ingress-basic 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. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System;
using System.CommandLine.Invocation; using System.CommandLine.Invocation;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -15,7 +16,7 @@ namespace Microsoft.Tye
public override async Task ExecuteAsync(OutputContext output, ApplicationBuilder application) 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)) if (!await KubectlDetector.IsKubectlInstalledAsync(output))
{ {
@ -59,6 +60,47 @@ namespace Microsoft.Tye
} }
output.WriteInfoLine($"Deployed application '{application.Name}'."); 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(); var root = new YamlMappingNode();
root.Add("kind", "Ingress"); root.Add("kind", "Ingress");
root.Add("apiVersion", "extensions/v1beta1"); root.Add("apiVersion", "networking.k8s.io/v1");
var metadata = new YamlMappingNode(); var metadata = new YamlMappingNode();
root.Add("metadata", metadata); root.Add("metadata", metadata);
@ -74,7 +74,10 @@ namespace Microsoft.Tye
var backend = new YamlMappingNode(); var backend = new YamlMappingNode();
path.Add("backend", backend); 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); var service = application.Services.FirstOrDefault(s => s.Name == ingressRule.Service);
if (service is null) if (service is null)
@ -88,7 +91,11 @@ namespace Microsoft.Tye
throw new InvalidOperationException($"Could not resolve an http binding for service '{service.Name}'."); 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: // Tye implements path matching similar to this example:
// https://kubernetes.github.io/ingress-nginx/examples/rewrite/ // https://kubernetes.github.io/ingress-nginx/examples/rewrite/
@ -111,6 +118,9 @@ namespace Microsoft.Tye
path.Add("path", regex); 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 else
{ {
// If we get here then we should deploy the ingress controller. // 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.WriteDebugLine($"Running 'kubectl apply'");
output.WriteCommandLine("kubectl", $"apply -f \"https://aka.ms/tye/ingress/deploy\""); output.WriteCommandLine("kubectl", $"apply -f \"https://aka.ms/tye/ingress/deploy\"");
var capture = output.Capture(); var capture = output.Capture();
var exitCode = await Process.ExecuteAsync( var exitCode = await Process.ExecuteAsync(
$"kubectl", $"kubectl",
$"apply -f \"https://aka.ms/tye/ingress/deploy\"", $"apply -f \"https://aka.ms/tye/ingress/deploy\"",
System.Environment.CurrentDirectory, System.Environment.CurrentDirectory);
stdOut: capture.StdOut,
stdErr: capture.StdErr);
output.WriteDebugLine($"Done running 'kubectl apply' exit code: {exitCode}"); 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."); 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. // after creating the controller will fail if the webhook isn't ready.
// //
// Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io": // 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 // dial tcp 10.0.31.130:443: connect: connection refused
// //
// Unfortunately this is the likely case for us. // Unfortunately this is the likely case for us.

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

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

Loading…
Cancel
Save