Networking, Virtualization, vmware

NSX-T and Kubernetes Part 3

The first part of this NSX-T and Kubernetes series of post was about the setup of kubernetes on Ubuntu server using docker.
The second part was about NSX Control plane configuration.
This last part will focus on configure Kubernetes for NSX-T and deploy application with loadbalancer.

Configure Kubernetes for NSX-T

The NSX-T container archive comes with a YAML file which allow the deployment of all NSX-T containers.
For Ubuntu we have the “ncp-ubuntu.yaml” file, we will fill all informations needed like variables and deploy through kubectl command.

Below we we will show all sections that needs to be modified and variables which need to be set in order to deploy successfully.

Secret section

This section set all certificates needed for authentication to the NSX-T manager and for TLS. The NSX manager allow to modify the TLS certificate later.

# Client certificate and key used for NSX authentication
#kind: Secret
#  name: nsx-secret
#  namespace: nsx-system
#apiVersion: v1
#  # Fill in the client cert and key if using cert based auth with NSX
#  tls.crt:
#  tls.key:

In a production environment we should use a dedicated account.
The Key and Certificate must use base64 format in the “tls.crt” and “tls.key” variables.

# Certificate and key used for TLS termination in HTTPS load balancing
kind: Secret
  name: lb-secret
  namespace: nsx-system
apiVersion: v1

This is the certificate and key for load balancer virtual server when using https. use the command: “cat file | base64 -w 0” and paste it.

ConfigMap ncp.ini nsx-ncp-config section

# In a production environment we should use certificate
#nsx_api_cert_file = /etc/nsx-ujo/nsx-cert/tls.crt
#nsx_api_private_key_file = /etc/nsx-ujo/nsx-cert/tls.key
nsx_api_user = admin
nsx_api_password = MyPassword

# Controllers IP addresses
nsx_api_managers =,,

# To bypass self signed certificate of NSX-T controllers
insecure = True

# Each namespace will have a /24 subnet from the container_ip_blocks
subnet_prefix = 24

# NSX-T load balancer configuration
use_native_loadbalancer = True
l4_lb_auto_scaling = True
default_ingress_class_nsx = True
lb_default_cert_path = /etc/nsx-ujo/lb-cert/tls.crt
lb_priv_key_path = /etc/nsx-ujo/lb-cert/tls.key
pool_algorithm = ROUND_ROBIN
service_size = SMALL
l7_persistence = source_ip
l4_persistence = source_ip

# this is where we put all informations retrieve from NSX-T previously 
container_ip_blocks = 0c99b7ea-7d74-4763-8e3e-ba79a0619f3e
external_ip_pools = b49e44b9-6433-4b61-a8a2-c764fe2fd859
top_tier_router = 3d757cf9-1111-4fb8-ac89-d6a4abb73c5c
external_ip_pools_lb = 6c6e6f36-75c6-4493-9791-7f29e1179cf8
overlay_tz = e8bbadc9-cd84-42f3-b28e-07ce585ed0c3
lb_service = 4ba2ccaa-67bf-4ae1-9200-b868a6f8cfe9
top_firewall_section_marker = 81a84999-2114-4cec-bbb8-58d3a9eca1ed
bottom_firewall_section_marker = 84b62ad6-d395-4043-87ce-1d982f88eb03
edge_cluster = d83f08b6-0d13-45f5-8271-f1609831b6ee

dns_servers =

# The name must be the same as the ncp/cluster tag we put on the ports of all kubernetes nodes
cluster = k8s02
node_type = HOSTVM

apiserver_host_ip =
apiserver_host_port = 6443

# This is default configuration, all pods are able to access the apiserver using automatically created token
client_token_file = /var/run/secrets/
ca_file = /var/run/secrets/
http_ingress_port = 80
https_ingress_port = 443

# Pods within the same namespace will be able to communicate with each other
baseline_policy_type = allow_namespace

Deployment Section

          - name: config-volume
            # NCP expects ncp.ini is present in /etc/nsx-ujo
            mountPath: /etc/nsx-ujo/ncp.ini
            subPath: ncp.ini
            readOnly: true
          # To use cert based auth, uncomment the volumeMount
          # Update ncp.ini with the mounted cert and key file paths
          #- name: nsx-cert
          #  mountPath: /etc/nsx-ujo/nsx-cert
          #  readOnly: true
          # To add default LB cert, uncomment the volumeMount
          # Update ncp.ini with the mounted cert and key file paths
          - name: lb-cert
            mountPath: /etc/nsx-ujo/lb-cert
            readOnly: true
        - name: config-volume
          # ConfigMap nsx-ncp-config is expected to supply ncp.ini
            name: nsx-ncp-config
        # To use cert based auth, uncomment and update the secretName
        #- name: nsx-cert
        #  secret:
        #    secretName: nsx-secret
        # To add default LB cert, uncomment and update the secretName
        - name: lb-cert
            secretName: lb-secret

As we have provided a default Load Balancer certificate for https trafic, we must mount the volume “/etc/nsx-ujo/lb-cert”.
This volume will host the “tls.crt” and “tls.key” files.
In a Production environment we should do the same for “nsx-cert”

ConfigMap ncp.ini nsx-node-agent-config section

apiserver_host_ip =
apiserver_host_port = 6443

client_token_file = /var/run/secrets/
ca_file = /var/run/secrets/

http_ingress_port = 80
https_ingress_port = 443

baseline_policy_type = allow_namespace


cluster = k8s02
node_type = HOSTVM

ovs_bridge = br-int
# ens192 is the interface we defined as manual and will be used for pods trafic.
ovs_uplink_port = ens192

Ensure that the container_ip_blocks is correctly routed and will be able to join the apiserver IP address. See Configure NSX-T Routing.
Don’t forget to redistribute NAT IP on Tier-0 router so all pods will be able to join apiserver IP address.

We are now ready to apply the configuration to the kubernetes master.
Issue the “kubectl apply -f ncp-ubuntu.yaml” command on the master node.

loasys@kube-master01:~$ kubectl apply -f ncp-ubuntu.yaml created created
namespace/nsx-system created
serviceaccount/ncp-svc-account created created created created created
serviceaccount/nsx-node-agent-svc-account created created created
secret/lb-secret created
configmap/nsx-ncp-config created
deployment.extensions/nsx-ncp created
configmap/nsx-node-agent-config created
daemonset.extensions/nsx-ncp-bootstrap created
daemonset.extensions/nsx-node-agent created

Use the watch command to see what is going on. After a few minutes, you should see:

loasys@kube-master01:~$ kubectl get pods --all-namespaces                                                                                                            
NAMESPACE     NAME                                    READY   STATUS    RESTARTS   AGE
kube-system   coredns-6dcc67dcbc-rftwj                1/1     Running   4          2d6h
kube-system   coredns-6dcc67dcbc-vbftr                1/1     Running   4          2d6h
kube-system   etcd-kube-master01                      1/1     Running   0          2d6h
kube-system   kube-apiserver-kube-master01            1/1     Running   0          2d6h
kube-system   kube-controller-manager-kube-master01   1/1     Running   0          2d6h
kube-system   kube-proxy-jbxcd                        1/1     Running   0          2d6h
kube-system   kube-proxy-kxdtk                        1/1     Running   0          2d6h
kube-system   kube-proxy-q4qcs                        1/1     Running   0          2d6h
kube-system   kube-scheduler-kube-master01            1/1     Running   0          2d6h
nsx-system    nsx-ncp-bc857f4b9-x29kt                 1/1     Running   0          14m
nsx-system    nsx-ncp-bootstrap-r6blg                 1/1     Running   0          14m
nsx-system    nsx-ncp-bootstrap-tj2pz                 1/1     Running   0          14m
nsx-system    nsx-ncp-bootstrap-zwthn                 1/1     Running   0          14m
nsx-system    nsx-node-agent-g5nkg                    3/3     Running   0          14m
nsx-system    nsx-node-agent-nj8jl                    3/3     Running   0          14m
nsx-system    nsx-node-agent-vh2ln                    3/3     Running   0          14m

Remember on Part1 our nodes were in “Not Ready” state.
Issue the “kubectl get nodes” command.

loasys@kube-master01:~$ kubectl get nodes
kube-master01   Ready    master   2d6h   v1.14.8
kube-worker01   Ready    <none>   2d6h   v1.14.8
kube-worker02   Ready    <none>   2d6h   v1.14.8

Namespace and Tier-1 router

In this configuration we choose to have a Tier-1 router per namespace but NSX-T 2.5 also allow a topology with a single shared Tier-1 router for all namespace. (In the shared Tier-1 router mode, each created namespace will have a new segment on the shared Tier-1).

Issue the “kubectl create namespace loasys” to create a new namespace.

loasys@kube-master01:~$ kubectl create namespace loasys
namespace/loasys created

Let’s go to NSX Manager to see what happened. Beware that all object created by the kubernetes NSX control plane are located in the old fashioned UI.
Go to “Advanced Networking & Security”, click “Routers” under “Networking”. You should see a “k8s02-loasys” Tier-1 router

If we go to “Configuration” dropdown list and click “Router Ports”, we should see a “Downlink” containing an IP address in a /24 subnet of the container_ip_blocks.

Deploy App with load balancer

We are going to deploy a WordPress APP with a load balancer and see it automatically configured on NSX-T.

Donwload the YAML file for wordpress available on
I have remove the persistent volume and volume claim as this is not needed for this test.
I have also added an ingress on the wordpress deployment which will have http and https with the load balancer as backend.

apiVersion: extensions/v1beta1
kind: Ingress
  name: wordpress-ingress
  - hosts:
    - wordpress.loasys.lan
    serviceName: wordpress
    servicePort: 80

Issue the “kubectl create -k ./ -n loasys” command to create the deployment in the loasys namespace.

loasys@kube-master01:~/wordpress$ kubectl create -k ./ -n loasys
secret/mysql-pass-b727294t7t created
service/wordpress-mysql created
service/wordpress created
deployment.apps/wordpress-mysql created
deployment.apps/wordpress created
ingress.extensions/wordpress-ingress created

Let’s check out in kubernetes what was created and which ip addresses were used.

loasys@kube-master01:~/wordpress$ kubectl get all -n loasys
NAME                                  READY   STATUS    RESTARTS   AGE
pod/wordpress-57dcdd76c5-mmq84        1/1     Running   0          93s
pod/wordpress-mysql-86c56c7fc-r5gv7   1/1     Running   0          93s

NAME                      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/wordpress         LoadBalancer    80:30844/TCP   93s
service/wordpress-mysql   ClusterIP      None             <none>        3306/TCP       93s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/wordpress         1/1     1            1           93s
deployment.apps/wordpress-mysql   1/1     1            1           93s

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/wordpress-57dcdd76c5        1         1         1       93s
replicaset.apps/wordpress-mysql-86c56c7fc   1         1         1       93s

loasys@kube-master01:~/wordpress$ kubectl get ingress -n loasys
NAME                HOSTS   ADDRESS      PORTS     AGE
wordpress-ingress   *   80, 443   3m24s

We can see that the load balancer took the IP address as external IP address so did the ingress. This is great as it’s an IP address from the K8S02-LB_IPPOOL we defined earlier.

Let’s check out what was created in NSX.
Go to “Advanced Networking & Security”, click “Load Balancers” under “networking” and go to the “Virtual servers” tab.

It’s all good, everything is working and we have access to the wordpress page. There is a lot to test like frontend scale which will automatically add members to the server pool, have fun!

That’s it !, i hope you found this series useful.

Leave a Reply

Your email address will not be published. Required fields are marked *