Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add KubernetesIngressAddOn for enhanced Ingress Management #989

Merged
merged 41 commits into from
Jun 28, 2024

Conversation

Pjv93
Copy link
Contributor

@Pjv93 Pjv93 commented Apr 23, 2024

Issue #, if available:

*Description of changes: This PR introduces the Kubernetes Ingress Add-On class that supports additional configuration options like SSL redirection, cross-zone load balancing, and external DNS integration. The aim is to provide an extensible and configurable Ingress solution within the EKS blueprints framework.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@shapirov103
Copy link
Collaborator

@Pjv93 do you mind adding a blueprint that we can use to validate that the addon works?

@Pjv93
Copy link
Contributor Author

Pjv93 commented Apr 23, 2024

@shapirov103 OFC! Here is a sample blueprint that:

  • Sets up a Kubernetes ingress controller with specified configurations for handling ingress traffic, including load balancing settings, SSL/TLS termination, and routing.

  • Automates DNS record management based on services and ingresses within the cluster, simplifying the process of connecting domain names to dynamically provisioned resources like load balancers.

import * as cdk from 'aws-cdk-lib';
import * as blueprints from '@aws-quickstart/eks-blueprints';
import { KubernetesIngressAddOn } from '../lib/addons/kubernetes-nginx';

const app = new cdk.App();
const account = '1234567890';
const region = 'us-east-2';
const version = 'auto';
const myDomainName = "test.example.com";





// Configure the Kubernetes Ingress AddOn
const kubernetesIngressAddOn = new KubernetesIngressAddOn({
    crossZoneEnabled: true,
    internetFacing: true,
    targetType: 'ip',
    externalDnsHostname: 'example.com',
    certificateResourceName: 'arn:aws:acm:us-east-2:123456789:certificate/xxxxxxxxx',
});

const addOns: Array<blueprints.ClusterAddOn> = [
    new blueprints.addons.CalicoOperatorAddOn(),
    new blueprints.addons.AwsLoadBalancerControllerAddOn(),
    new blueprints.addons.VpcCniAddOn(),
    new blueprints.addons.CoreDnsAddOn(),
    new blueprints.addons.CertManagerAddOn(),
    new blueprints.addons.ExternalsSecretsAddOn(),
    kubernetesIngressAddOn,
    new blueprints.addons.ExternalDnsAddOn({
        hostedZoneResources: ["MyHostedZone1"]
    })
    
];

const stack = blueprints.EksBlueprint.builder()
    .account(account)
    .region(region)
    .version(version)
    .resourceProvider("MyHostedZone1", new blueprints.LookupHostedZoneProvider(myDomainName))
    .addOns(...addOns)
    .build(app, 'eks-blueprint');

Here are the annotations applied to the Ingress Controller

helm get values k8s-ingress -n kube-system
USER-SUPPLIED VALUES:
controller:
  electionID: ingress-controller-leader
  ingressClassResource:
    controllerValue: k8s.io/ingress-nginx
    default: false
    enabled: true
    name: nginx
  service:
    annotations:
      external-dns.alpha.kubernetes.io/hostname: pjv.people.aws.dev
      nginx.ingress.kubernetes.io/force-ssl-redirect: true
      service.beta.kubernetes.io/aws-load-balancer-attributes: load_balancing.cross_zone.enabled=true
      service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
      service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "3600"
      service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
      service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-2:0123456789:certificate/xxxxxx
      service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
      service.beta.kubernetes.io/aws-load-balancer-type: external
    targetPorts:
      http: http
      https: http
Screenshot 2024-04-23 at 4 50 01 PM

Simple Ingress using test.pjv.people.aws.dev/
Screenshot 2024-04-23 at 4 52 12 PM

Copy link
Collaborator

@elamaran11 elamaran11 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Pjv93 Awesome work, Thankyou for working on this change. Following are some high level feedback.

  1. Fix all GH action errors, i dont think the addon will compile with these errors. make build and make lint
  2. Add documentation to the addon similar to other Ingress One
  3. Make sure to update mkdocs and doc index for the new addon
  4. Recommend to add a test script for the new addon
  5. Add the addon to example blueprint so this can be tested with e2e.
  6. Also share screenshots of working addon with ALB creation etc.

@@ -60,6 +60,7 @@ export * from './apache-airflow';
export * from './neuron';
export * from './eks-pod-identity-agent';
export * from './neuron';
export * from './kubernetes-nginx'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semi colon

@@ -0,0 +1,112 @@
// Import necessary AWS CDK and utility modules
import { ICertificate, Certificate } from "aws-cdk-lib/aws-certificatemanager";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove ICertificate.

import * as dot from 'dot-object';
import { dependable, supportsALL } from "../../utils";
import { setPath } from "../../utils/object-utils";
import { AwsLoadBalancerControllerAddOn, ClusterInfo, Values, HelmAddOn, HelmAddOnProps, HelmAddOnUserProps, GlobalResources } from "@aws-quickstart/eks-blueprints";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove GlobalResources if not used

lib/addons/kubernetes-nginx/index.ts Outdated Show resolved Hide resolved
@Pjv93
Copy link
Contributor Author

Pjv93 commented Apr 23, 2024

Sounds good! I know it needs a lot of work but wanted to at least have some visibility on it. I will work on your comments. Thanks!

@elamaran11
Copy link
Collaborator

Sounds good! I know it needs a lot of work but wanted to at least have some visibility on it. I will work on your comments. Thanks!

Honestly this is great work, addon work is almost there, you just need to complete to cover all grounds.

@elamaran11 elamaran11 linked an issue Apr 23, 2024 that may be closed by this pull request
1 task
@Pjv93
Copy link
Contributor Author

Pjv93 commented Jun 3, 2024

Hi @elamaran11 & @shapirov103, here is an updated blueprint to test the addon below. I have since fixed the errors from the GH Actions, Add documentation to the addon in the docs folder, and updated mkdocs and doc index for the addon.

import * as cdk from 'aws-cdk-lib';
import * as blueprints from '../lib';

const app = new cdk.App();
const account = 'xxxxxxxxxxx';
const region = 'us-east-1';
const myDomainName = "YourDomainName.com";

// Create the stack
const stack = new cdk.Stack(app, 'EksBlueprintStack', {
    env: {
        account: account,
        region: region,
    }
});

// Lookup the hosted zone by domain name
const hostedZone = cdk.aws_route53.HostedZone.fromLookup(stack, 'HostedZoneLookup', {
    domainName: myDomainName,
});

const addOns: Array<blueprints.ClusterAddOn> = [
    new blueprints.addons.AwsLoadBalancerControllerAddOn(),
    new blueprints.addons.ExternalDnsAddOn({
        hostedZoneResources: [blueprints.GlobalResources.HostedZone]
    }),
    new blueprints.addons.KubernetesIngressAddOn({
        crossZoneEnabled: true,
        internetFacing: true,
        targetType: 'ip',
        externalDnsHostname: myDomainName,
        certificateResourceName: blueprints.GlobalResources.Certificate
    }),
    new blueprints.addons.CalicoOperatorAddOn(),
    new blueprints.addons.VpcCniAddOn(),
    new blueprints.addons.CoreDnsAddOn(),
    new blueprints.addons.KubeProxyAddOn(),
    new blueprints.addons.CertManagerAddOn(),
    new blueprints.addons.ExternalsSecretsAddOn()
];

blueprints.EksBlueprint.builder()
    .resourceProvider(blueprints.GlobalResources.HostedZone, new blueprints.ImportHostedZoneProvider(hostedZone.hostedZoneId))
    .resourceProvider(blueprints.GlobalResources.Certificate, new blueprints.CreateCertificateProvider('DomainWildcardCert', `*.${myDomainName}`, blueprints.GlobalResources.HostedZone)) // referencing hosted zone for automatic DNS validation
    .account(account)
    .region(region)
    .version("auto")
    .addOns(...addOns)
    .build(stack, 'EksBlueprintStack');

Copy link
Contributor Author

@Pjv93 Pjv93 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GH action errors have been resolved.

Copy link
Collaborator

@elamaran11 elamaran11 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Pjv93 Nice work some minor feedback. Did you test different scenerios like different LBs, using DNS etc? Btw the addon also needs to be added to blueprints e2e stack.

@shapirov103 Overall approach looks great, please check and provide your feedback.

@@ -0,0 +1,259 @@
# Kubernetes NGINX Add-on
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add this md file entry in to docs/addons/index.md so it gets in to list of addons.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@@ -8,4 +8,4 @@ const account = process.env.CDK_DEFAULT_ACCOUNT;
const region = process.env.CDK_DEFAULT_REGION;
const props = { env: { account, region } };

new BlueprintConstruct(app, props);
new BlueprintConstruct(app, props);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this file checked in.

Copy link
Contributor Author

@Pjv93 Pjv93 Jun 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might have been a mistake as I was testing my own main.ts file and reverted it to the original file. Theres no difference. I think the blank line in line 12 was removed in the process.

package.json Outdated
@@ -19,7 +19,7 @@
},
"devDependencies": {
"@types/dot-object": "^2.1.6",
"@types/jest": "^29.5.11",
"@types/jest": "^29.5.12",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a dependency for this addon to work?

package.json Outdated
@@ -31,7 +31,7 @@
"jest": "^29.7.0",
"json-schema-to-typescript": "^13.1.1",
"lint": "^1.1.2",
"ts-jest": "^29.1.1",
"ts-jest": "^29.1.2",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a dependency for this addon to work?

package.json Outdated
"aws-cdk-lib": "2.133.0",
"aws-cdk": "2.133.0"
"aws-cdk": "2.133.0",
"aws-cdk-lib": "2.133.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like I just changed the placement of the aws-cdk above aws-cdk-lib. No real change and actually not necessary.

Pjv93 added 2 commits June 3, 2024 12:09
added kubernetes-nginx to the list of addons
Copy link
Collaborator

@shapirov103 shapirov103 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Pjv93 great work and much needed functionality. Please see my comments, some are less significant than others. Happy to meet and discuss. If you could demo it, that would be even better.

mkdocs.yml Outdated
@@ -68,6 +68,7 @@ nav:
- Kubecost: 'addons/kubecost.md'
- Kubeflow: 'addons/kubeflow.md'
- KubeRay Operator: 'addons/kuberay-operator.md'
- Kubernetes Ingress: 'addons/kubernetes-ingress.md'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kubernetes ingress is a very broad definition. We have to be specific that it is nginx as there are many kubernetes ingress controllers. AWS ALB ingress controller is one of the kubernetes ingress controllers.

I see you made changes to abbreviate. I suggest the following naming to make it clear to the customers (using standard nomenclature):

https://github.com/kubernetes/ingress-nginx - is the repo and project name.

Let's rename to ingress-nginx throughout. The addon name will be ingress-nginx and the entries in the doc will be the same. We will specify that the difference between ingress-nginx and nginx addon are that the former is upstream kubernetes nginx and the latter is F5.

if (props.certificateResourceARN) {
presetAnnotations['service.beta.kubernetes.io/aws-load-balancer-ssl-ports'] = 'https';
presetAnnotations['service.beta.kubernetes.io/aws-load-balancer-ssl-cert'] = props.certificateResourceARN;
presetAnnotations['nginx.ingress.kubernetes.io/force-ssl-redirect'] = true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be hardcoded?



// Setup service annotations based on the properties provided
const presetAnnotations: any = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tested with network load balancer and these annotations set and external DNS?

internetFacing: true,
targetType: 'ip',
externalDnsHostname: 'your-domain.com',
certificateResourceName: 'your-certificate-resource-name'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How will our test work if this is set to placeholder? Please note that this blueprint is actually executed when we run do-e2e-tests. Also I am unclear how it will co-exist with the nginx addon that is from F5.

Can you create a separate blueprint with this addon for testing in examples/examples.ts? We will need something executable before releasing.

};

// Configure SSL-related annotations if certificate resource name is provided
if (props.certificateResourceName) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style: the code block on line 188-196 is almost identical to the code block in lines 196-200.

How about you use this logic:

let certificateResourceARN = props.certificateResourceARN;

if(!certificateResourceARN && props.certificateResourceName) {
   certificateResourceARN = <populate from the resource provider>;
}

if(certificateResourceARN) {
   // set annotations
}

@shapirov103
Copy link
Collaborator

/do-e2e-tests

@shapirov103
Copy link
Collaborator

/do-e2e-tests

Copy link

@aws-ia-ci aws-ia-ci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end to end tests failed. A maintainer can provide more details.

Copy link

@aws-ia-ci aws-ia-ci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end to end tests failed. A maintainer can provide more details.

@shapirov103
Copy link
Collaborator

/do-e2e-tests

Copy link

@aws-ia-ci aws-ia-ci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end to end tests failed. A maintainer can provide more details.

Copy link
Collaborator

@elamaran11 elamaran11 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@shapirov103
Copy link
Collaborator

e2e failure due to hanging LB provisioned through the ingress-nginx addon (needs more investigation, looks like LB controller was dropped before it had a chance to clean up).

@shapirov103
Copy link
Collaborator

/do-e2e-tests

Copy link

@aws-ia-ci aws-ia-ci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end to end tests failed. A maintainer can provide more details.

@shapirov103 shapirov103 dismissed aws-ia-ci’s stale review June 28, 2024 20:10

Test succeeded, CFN was hanging longer than usual, but removed all the resources

Copy link
Collaborator

@shapirov103 shapirov103 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@shapirov103 shapirov103 merged commit ba65e69 into aws-quickstart:main Jun 28, 2024
@Pjv93
Copy link
Contributor Author

Pjv93 commented Jun 28, 2024

@elamaran11 & @shapirov103 Thank you both for your patience and allowing me to contribute to the eks blueprint addons!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New Kubernetes Nginx Addon to Blueprints
4 participants