Notes for using Kubernetes Ingress Controller

Append the nginx ingress http redirect to https

  • Add extra port to nginx deployment for example: 8080, look like following
 1ports:
 2  - name: http
 3    containerPort: 80
 4    protocol: TCP
 5  - name: https
 6    containerPort: 443
 7    protocol: TCP
 8  - name: webhook
 9    containerPort: 8443
10    protocol: TCP 
11  - name: http-redirect
12    containerPort: 8080 
  • Add section http-snippet to ConfigMap ingress-nginx-controller
 1data:
 2  allow-snippet-annotations: 'true'
 3  compute-full-forwarded-for: 'true'
 4  use-forwarded-headers: 'true'
 5  server-tokens: 'false'
 6  http-snippet: |
 7    server {
 8      listen 8080;
 9      return 308 https://$host$request_uri;
10    }     
  • Modify the ingress service loadbalance configure, let http-80 forward to http-redirect-8080
1- name: http
2  protocol: TCP
3  appProtocol: http
4  port: 80
5  targetPort: http-redirect
6  nodePort: 32009

Using Nginx-Ingress Controller in AWS Eks environment

  • Need manually enable the Proxy protocol V2 in NLB target group just only TCP https 443 listener Rather than TCP http 80 listener
  • Multiple SSL certificate need manually add to NLB
  • The http redirect to https, need to change some paramets
 1	# use http-snippet and open proxy protocol
 2  use-proxy-protocol: 'true'
 3  use-forwarded-headers: 'true'
 4  server-tokens: 'false'
 5  http-snippet: |
 6  server {
 7  listen 8000;
 8  return 308 https://$host$request_uri;
 9  }        
10  proxy-real-ip-cidr: ${join(",", var.internal_cidr)}  
11 # Add special port in controller container
12 set {
13 type = "string"
14 name = "controller.containerPort.special"
15 value = "8000"
16 }
17 # Let https redirect to http port and http port redirect to special port , the special port listener in `http-snippet` section
18 set {
19 type = "string"
20 name = "controller.service.targetPorts.https"
21 value = "http"
22 }
23
24set {
25type = "string"
26name = "controller.service.targetPorts.http"
27value = "special"
28}
  • The complete Terraform configuration is shown below
      1	resource "helm_release" "ingress_nginx_controller" {
      2  name = "nginx-ingress-controller"  
      3  repository = "https://kubernetes.github.io/ingress-nginx"
      4  chart = "ingress-nginx"
      5  version = "3.8.0"
      6  namespace = "kube-system"
      7
      8  values = [
      9    <<-EOF
     10    controller:
     11      config:
     12        use-proxy-protocol: 'true'
     13        use-forwarded-headers: 'true'
     14        server-tokens: 'false'
     15        http-snippet: |
     16          server {
     17            listen 8000;
     18            return 308 https://$host$request_uri;
     19          }                  
     20        proxy-real-ip-cidr: ${join(",", var.internal_cidr)}
     21    EOF
     22  ]
     23
     24  set {
     25    type = "string"
     26    name = "controller.resources.requests.memory"
     27    value = "256Mi"
     28  }
     29
     30  set {
     31    type = "string"
     32    name = "controller.resources.limits.memory"
     33    value = "500Mi"
     34  }
     35
     36  set {
     37    name = "fullnameOverride"
     38    value = "nginx-ingress"
     39  }
     40
     41  set {
     42    type = "string"
     43    name = "controller.service.targetPorts.https"
     44    value = "http"
     45  }
     46
     47  set {
     48    type = "string"
     49    name = "controller.service.targetPorts.http"
     50    value = "special"
     51  }
     52
     53  dynamic "set" {
     54    for_each = concat(var.office_cidr, var.internal_cidr)
     55    content {
     56      name = join("", ["controller.service.loadBalancerSourceRanges[", set.key, "]"])
     57      value = set.value
     58    }
     59  }
     60
     61  set {
     62    type = "string"
     63    name = "controller.containerPort.special"
     64    value = "8000"
     65  }
     66
     67  set {
     68    type = "string"
     69    name = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-ssl-cert"
     70    value = var.alb_certificate
     71  }
     72
     73  set {
     74    type = "string"
     75    name = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-proxy-protocol"
     76    value = "*"
     77  }
     78
     79  set {
     80    type = "string"
     81    name = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"
     82    value = "tcp"
     83  }
     84
     85  set{
     86    type = "string"
     87    name = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-ssl-ports"
     88    value = "https"
     89  }
     90
     91  set {
     92    type = "string"
     93    name = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-connection-idle-timeout"
     94    value = "120"
     95  }
     96
     97  set {
     98    type = "string"
     99    name = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-type"
    100    value = "nlb"
    101  }
    102
    103  set {
    104    type = "string"
    105    name = "controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-cross-zone-load-balancing-enabled"
    106    value = "true"
    107  }
    108}

Using Alb-ingress-controller in AWS Eks

  • Every ingress should create application loadbalance it will cost a lot
  • Alb-ingress controller need aws IAM policy to create ALB
  • The ALB-ingress controller Terraform configurate
  1	resource "kubernetes_cluster_role" "ingress" {
  2  metadata {
  3    name = "alb-ingress-controller"
  4    labels = {
  5      "app.kubernetes.io/name"       = "alb-ingress-controller"
  6      "app.kubernetes.io/managed-by" = "terraform"
  7    }
  8  }
  9
 10  rule {
 11    api_groups = ["", "extensions"]
 12    resources  = ["configmaps", "endpoints", "events", "ingresses", "ingresses/status", "services"]
 13    verbs      = ["create", "get", "list", "update", "watch", "patch"]
 14  }
 15
 16  rule {
 17    api_groups = ["", "extensions"]
 18    resources  = ["nodes", "pods", "secrets", "services", "namespaces"]
 19    verbs      = ["get", "list", "watch"]
 20  }
 21
 22  depends_on = [
 23    aws_eks_cluster.main
 24  ]
 25}
 26
 27resource "kubernetes_cluster_role_binding" "ingress" {
 28  metadata {
 29    name = "alb-ingress-controller"
 30    labels = {
 31      "app.kubernetes.io/name"       = "alb-ingress-controller"
 32      "app.kubernetes.io/managed-by" = "terraform"
 33    }
 34  }
 35  role_ref {
 36    api_group = "rbac.authorization.k8s.io"
 37    kind      = "ClusterRole"
 38    name      = kubernetes_cluster_role.ingress.metadata[0].name
 39  }
 40  subject {
 41    kind      = "ServiceAccount"
 42    name      = kubernetes_service_account.ingress.metadata[0].name
 43    namespace = kubernetes_service_account.ingress.metadata[0].namespace
 44  }
 45
 46  depends_on = [
 47    aws_eks_cluster.main,
 48    kubernetes_cluster_role.ingress
 49  ]
 50}
 51
 52resource "kubernetes_service_account" "ingress" {
 53  automount_service_account_token = true
 54  metadata {
 55    name      = "alb-ingress-controller"
 56    namespace = "kube-system"
 57    labels = {
 58      "app.kubernetes.io/name"       = "alb-ingress-controller"
 59      "app.kubernetes.io/managed-by" = "terraform"
 60    }
 61    annotations = {
 62      "eks.amazonaws.com/role-arn" = aws_iam_role.eks_alb_ingress_controller.arn
 63    }
 64  }
 65
 66  depends_on = [
 67    aws_eks_cluster.main
 68  ]
 69}
 70
 71resource "kubernetes_deployment" "ingress" {
 72  metadata {
 73    name      = "alb-ingress-controller"
 74    namespace = "kube-system"
 75    labels = {
 76      "app.kubernetes.io/name"       = "alb-ingress-controller"
 77      "app.kubernetes.io/version"    = "v1.1.9"
 78      "app.kubernetes.io/managed-by" = "terraform"
 79    }
 80  }
 81
 82  spec {
 83    replicas = 1
 84
 85    selector {
 86      match_labels = {
 87        "app.kubernetes.io/name" = "alb-ingress-controller"
 88      }
 89    }
 90
 91    template {
 92      metadata {
 93        labels = {
 94          "app.kubernetes.io/name"    = "alb-ingress-controller"
 95          "app.kubernetes.io/version" = "v1.1.9"
 96        }
 97      }
 98
 99      spec {
100        dns_policy                       = "ClusterFirst"
101        restart_policy                   = "Always"
102        service_account_name             = kubernetes_service_account.ingress.metadata[0].name
103        termination_grace_period_seconds = 60
104
105        container {
106          name              = "alb-ingress-controller"
107          image             = "docker.io/amazon/aws-alb-ingress-controller:v1.1.9"
108          image_pull_policy = "Always"
109
110          args = [
111            "--ingress-class=alb",
112            "--cluster-name=${aws_eks_cluster.main.id}",
113            "--aws-vpc-id=${var.vpc_id}",
114            "--aws-region=${var.region}",
115            "--aws-max-retries=10",
116          ]
117
118          volume_mount {
119            mount_path = "/var/run/secrets/kubernetes.io/serviceaccount"
120            name       = kubernetes_service_account.ingress.default_secret_name
121            read_only  = true
122          }
123
124          port {
125            name           = "health"
126            container_port = 10254
127            protocol       = "TCP"
128          }
129
130          readiness_probe {
131            http_get {
132              path   = "/healthz"
133              port   = "health"
134              scheme = "HTTP"
135            }
136
137            initial_delay_seconds = 30
138            period_seconds        = 60
139            timeout_seconds       = 3
140          }
141
142          liveness_probe {
143            http_get {
144              path   = "/healthz"
145              port   = "health"
146              scheme = "HTTP"
147            }
148
149            initial_delay_seconds = 60
150            period_seconds        = 60
151          }
152        }
153
154        volume {
155          name = kubernetes_service_account.ingress.default_secret_name
156
157          secret {
158            secret_name = kubernetes_service_account.ingress.default_secret_name
159          }
160        }
161      }
162    }
163  }
164
165  depends_on = [
166    kubernetes_cluster_role_binding.ingress,
167    aws_eks_cluster.main
168  ]
169}
  • The Alb ingress resource should look likes following
 1	resource "kubernetes_ingress" "example_ingress" {
 2  metadata {
 3    name      = "example-ingress"
 4    namespace = "default"
 5    annotations = {
 6      "kubernetes.io/ingress.class"                    = "alb"
 7      "alb.ingress.kubernetes.io/scheme"               = "internet-facing"
 8      "alb.ingress.kubernetes.io/target-type"          = "instance"
 9      "alb.ingress.kubernetes.io/listen-ports"         = "[{\"HTTPS\": 443},{\"HTTP\": 80}]"
10      "alb.ingress.kubernetes.io/actions.ssl-redirect" = "{\"Type\": \"redirect\", \"RedirectConfig\": { \"Protocol\": \"HTTPS\", \"Port\": \"443\", \"StatusCode\": \"HTTP_301\"}}"
11      "alb.ingress.kubernetes.io/security-groups"      = var.alb_security_group_ids
12      "alb.ingress.kubernetes.io/certificate-arn"      = var.alb_certificates
13      "alb.ingress.kubernetes.io/healthcheck-path"     = "/"
14      "alb.ingress.kubernetes.io/success-codes"        = "200,201,302,301"
15      "alb.ingress.kubernetes.io/unhealthy-threshold-count" =  "5"
16    }
17  }
18  spec {
19    rule {
20      host = var.web_dns_name
21      http {
22        path {
23          backend {
24            service_name = "ssl-redirect"
25            service_port = "use-annotation"
26          }
27          path = "/*"
28        }
29        path {
30          backend {
31            service_name = "example-web"
32            service_port = 80
33          }
34          path = "/*"
35        }
36      }
37    }
38  }
39}

The Merge ingress it will only work if you create ingress in the same namespace

  • The merge ingress helm chart need download to self github repo merge ingress
1resource "helm_release" "merge_ingress_controller" {
2   name = "merge-ingress"
3   chart = "${path.module}/../../../../charts/ingress-merge"
4    namespace  = "kube-system"
5 }
  • Should create merged_ingress configmap in every namespace if has ingress
 1resource "kubernetes_config_map" "merged_ingress" {
 2   metadata {
 3     name = "merged-ingress"
 4     namespace = "default"
 5   }
 6
 7   data = {
 8     annotations =<<DOC
 9       "kubernetes.io/ingress.class": "alb"
10       "alb.ingress.kubernetes.io/scheme": "internet-facing"
11       "alb.ingress.kubernetes.io/target-type": "instance"
12       "alb.ingress.kubernetes.io/listen-ports": "[{\"HTTPS\": 443},{\"HTTP\": 80}]"
13       "alb.ingress.kubernetes.io/actions.ssl-redirect": "{\"Type\": \"redirect\", \"RedirectConfig\": { \"Protocol\": \"HTTPS\", \"Port\": \"443\", \"StatusCode\": \"HTTP_301\"}}"
14       "alb.ingress.kubernetes.io/security-groups": ${var.alb_security_group_ids}
15       "alb.ingress.kubernetes.io/certificate-arn": ${var.alb_certificates}
16       "alb.ingress.kubernetes.io/healthcheck-path": "/"
17       "alb.ingress.kubernetes.io/success-codes": "200,201,302,301"
18       "alb.ingress.kubernetes.io/unhealthy-threshold-count":  "5"
19 DOC
20   }
21 }
  • The ingress resource should be create in default namespace