Kubernetes (K8s) is an open-source system for automating deployment, scaling, and management of containerized applications. K8s use network plugin to provide the required networking functions like routing, switching, firewall and load balancing. VMware NSX-T provides a network plugin called NCP for K8s as well. If you want to know more about VMware NSX-T, please go to docs.vmware.com.
In this blog, I will show you how to integrate VMWare NSX-T with Kubernetes.
Here, we will build a three nodes single master K8s cluster. All 3 nodes are RHEL 7.5 virtual machine.
- master node:
- Hostname: master.k8s
- Mgmt IP: 10.1.73.233
- worker node1:
- Hostname: node1.k8s
- Mgmt IP: 10.1.73.234
- worker node2:
- Hostname: node2.k8s
- Mgmt IP: 10.1.73.235
On each node, there are 2 vNICs attached. The first vNIC is ens192 which is for management and the second vNIC is ens224, which is for K8s transport and connected to an overlay logical switch.
NSX-T version: 2.3.0.0.0.10085405;
NSX-T NCP version: 2.3.1.10693410
Docker version: 18.03.1-ce;
K8s version: 1.11.4
1. Prepare K8s Cluster Setup
1.1 Get Offline Packages and Docker Images
As there is no Internet access in my environment, I have to prepare my K8s cluster offline. To do that, I need to get the following packages:
- Docker offline installation packages
- Kubeadm offline installation packages which will be used to set up the K8s cluster;
- Docker offline images;
1.1.1 Docker Offline Installation Packages
Regarding how to get Docker offline installation packages, please refer to my other blog: Install Docker Offline on Centos7.
1.1.2 Kubeadm Offline Installation Packages
Getting Kubeadm offline installation packages is quite straightforward as well. You can use Yum with downloadonly option.
yum install --downloadonly --downloaddir=/root/ kubelet-1.11.0
yum install --downloadonly --downloaddir=/root/ kubeadm-1.11.0
yum install --downloadonly --downloaddir=/root/ kubectl-1.11.0
1.1.3 Docker Offline Images
Below are the required Docker images for K8s cluster.
- k8s.gcr.io/kube-proxy-amd64 v1.11.4
- k8s.gcr.io/kube-apiserver-amd64 v1.11.4
- k8s.gcr.io/kube-controller-manager-amd64 v1.11.4
- k8s.gcr.io/kube-scheduler-amd64 v1.11.4
- k8s.gcr.io/coredns 1.1.3
- k8s.gcr.io/etcd-amd64 3.2.18
- k8s.gcr.io/pause-amd64 3.1
- k8s.gcr.io/pause 3.1
You possibly notice that the above includes two
identical pause images although these two have different repository names. There is a story around this. Initially, I only got the first image
“k8s.gcr.io/pause-amd64” loaded. The setup passed through “kubeadm init” pre-flight but failed at the real cluster setup stage. When I checked the log, I found out that the cluster set up process kept requesting the second image. I guess it is a bug with kubeadm v1.11.0 which I am using.
I put an example here to show how to use “docker pull” CLI to download a docker image in case you don’t know how to do it.
docker pull k8s.gcr.io/kube-proxy-amd64:v1.11.4
Once you have all Docker images, you need to export these Docker images as offline images via “docker save”.
docker save k8s.gcr.io/pause-amd64:3.1 -o /pause-amd64:3.1.docker
Now it is time to upload all your installation packages and offline images to all your K8s 3 nodes including master node.
1.2 Disable SELinux and Firewalld
# disable SELinux
setenforce 0
# Change SELINUX to permissive for /etc/selinux/config
vi /etc/selinux/config
SELINUX=permissive
# Stop and disable firewalld
systemctl disable firewalld && systemctl stop firewalld
1.3 Config DNS Resolution
# Update the /etc/hosts file as below on all three K8s nodes
10.1.73.233 master.k8s
10.1.73.234 node1.k8s
10.1.73.235 node2.k8s
1.4 Install Docker and Kubeadm
To install Docker and Kubeadm, first you put all required packages for Docker or kubeadm into a different directory. For example, all required packages for kubeadm are put into a directory called kubeadm. Then use rpm to install kubeadm as below:
[root@master kubeadm]# rpm -ivh --replacefiles --replacepkgs *.rpm
warning: 53edc739a0e51a4c17794de26b13ee5df939bd3161b37f503fe2af8980b41a89-cri-tools-1.12.0-0.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 3e1ba8d5: NOKEY
warning: socat-1.7.3.2-2.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY
Preparing... ########################## [100%]
Updating / installing...
1:socat-1.7.3.2-2.el7 ########################## [ 17%]
2:kubernetes-cni-0.6.0-0 ########################## [ 33%]
3:kubelet-1.11.0-0 ########################## [ 50%]
4:kubectl-1.11.0-0 ########################## [ 67%]
5:cri-tools-1.12.0-0 ########################## [ 83%]
6:kubeadm-1.11.0-0 #########################3 [100%]
After Docker and Kubeadm are installed, you can go to enable and start docker and kubelet service:
systemctl enable docker && systemctl start docker
systemctl enable kubelet && systemctl start kubelet
In addition, you need to perform some OS level setup so that your K8s environment can run properly.
# ENABLING THE NET.BRIDGE.BRIDGE-NF-CALL-IPTABLES KERNEL OPTION
sysctl -w net.bridge.bridge-nf-call-iptables=1
echo "net.bridge.bridge-nf-call-iptables=1" > /etc/sysctl.d/k8s.conf
# Disable Swap
swapoff -a && sed -i '/ swap / s/^/#/' /etc/fstab
1.5 Load Docker Offline Images
Now let us load all offline docker images into your local Docker repo on all K8s node via CLI “docker load”.
docker load -i kube-apiserver-amd64:v1.11.4.docker
docker load -i coredns:1.1.3.docker
docker load -i etcd-amd64:3.2.18.docker
docker load -i kube-apiserver-amd64:v1.11.4.docker
docker load -i kube-controller-manager-amd64:v1.11.4.docker
docker load -i kube-proxy-amd64:v1.11.4.docker
docker load -i kube-scheduler-amd64:v1.11.4.docker
docker load -i pause-amd64:3.1.docker
docker load -i pause:3.1.docker
1.6 NSX NCP Plugin
Now you can upload your NSX NCP plugin to all 3 nodes and load the NCP images into local Docker repo.
1.6.1 Load NSX Container Image
docker load -i nsx-ncp-rhel-2.3.1.10693410.tar
Now the docker image list on your K8s nodes will be similar to below:
[root@master ~]# docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.local/2.3.1.10693410/nsx-ncp-rhel latest 97d54d5c80db 5 months ago 701MB
k8s.gcr.io/kube-proxy-amd64 v1.11.4 5071d096cfcd 5 months ago 98.2MB
k8s.gcr.io/kube-apiserver-amd64 v1.11.4 de6de495c1f4 5 months ago 187MB
k8s.gcr.io/kube-controller-manager-amd64 v1.11.4 dc1d57df5ac0 5 months ago 155MB
k8s.gcr.io/kube-scheduler-amd64 v1.11.4 569cb58b9c03 5 months ago 56.8MB
k8s.gcr.io/coredns 1.1.3 b3b94275d97c 11 months ago 45.6MB
k8s.gcr.io/etcd-amd64 3.2.18 b8df3b177be2 12 months ago 219MB
k8s.gcr.io/pause-amd64 3.1 da86e6ba6ca1 16 months ago 742kB
k8s.gcr.io/pause 3.1 da86e6ba6ca1 16 months ago 742kB
1.6.2 Install NSX CNI
rpm -ivh --replacefiles nsx-cni-2.3.1.10693410-1.x86_64.rpm
Please note replacefiles option is required as a known bug with NSX-T 2.3. If you don’t include the replacefiles option, you will see an error like below:
[root@master rhel_x86_64]# rpm -i nsx-cni-2.3.1.10693410-1.x86_64.rpm
file /opt/cni/bin/loopback from install of nsx-cni-2.3.1.10693410-1.x86_64 conflicts with file from package kubernetes-cni-0.6.0-0.x86_64
1.6.3 Install and Config OVS
# Go to OpenvSwitch directory
rpm -ivh openvswitch-2.9.1.9968033.rhel75-1.x86_64.rpm
systemctl start openvswitch.service && systemctl enable openvswitch.service
ovs-vsctl add-br br-int
ovs-vsctl add-port br-int ens224 -- set Interface ens224 ofport_request=1
ip link set br-int up
ip link set ens224 up
2. Setup K8s Cluster
Now you are ready to set up your K8s cluster. I will use kubeadm config file to define my K8s cluster when I initiate the K8s cluster setup. Below is the content of my kubeadm config file.
apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
kubernetesVersion: v1.11.4
api:
advertiseAddress: 10.1.73.233
bindPort: 6443
From the above, you can see that Kubernetes version v1.11.4 will be used and the API server IP is 10.1.73.233, which is the master node IP. Run the following CLI from K8s master node to create the K8s cluster.
kubeadm init --config kubeadm.yml
After the K8s cluster is set up, you can join the resting two worker nodes into the cluster via CLI below:
kubeadm join 10.1.73.233:6443 --token up1nz9.iatqv50bkrqf0rcj --discovery-token-ca-cert-hash sha256:3f9e96e70a59f1979429435caa35d12270d60a7ca9f0a8436dff455e4b8ac1da
Note: You can get the required token and discovery-token-ca-cert-hash from the output of “kubeadm init”.
3. NSX-T and K8s Integration
3.1 Prepare NSX Resource
Before the integration, you have to make sure that you have NSX-T resources configured in NSX manager. The required resource includes:
- Overlay Transport Zone: overlay_tz
- Tier 0 router: tier0_router
- K8s Transport Logical Switch
- IP Blocks for Kubernetes Pods: container_ip_blocks
- IP Pool for SNAT: external_ip_pools
- Firewall Marker Sections: top_firewall_section_marker and bottom_firewall_section_marker
Please refer the NSX Container Plug-in for Kubernetes and Cloud Foundry – Installation and Administration Guide to further check how to create the NSX-T resource. The following are the UUID for all created resources:
- tier0_router = c86a625e-54e0-4510-9185-e9e1b7e26eb9
- overlay_tz = f6d90300-c56e-4d26-8684-8eff64cdf5a0
- container_ip_blocks = f9e411f5-654e-4f0d-99e8-2e5a9812f295
- external_ip_pools = 84ffd635-640f-41c6-be85-71337e112e69
- top_firewall_section_marker = ab07e559-79aa-4bc9-a6f0-126ea59278c2
- bottom_firewall_section_marker = 35aaa6c5-0870-4ac4-bf47-114780863956
In addition, make sure that you tagged switching ports which three k8s nodes are attached to in the following ways:
{'ncp/node_name': '<node_name>'}
{'ncp/cluster': '<cluster_name>'}
node_name is the FQDN hostname of the K8s node and the cluster_name is what you call this cluster in NSX not in K8s cluster context. I show you here my K8s nodes’ tags.



k8s node2 swicthing port tags
3.2 Install NSX NCP Plugin
3.2.1 Create Name Space
kubectl create ns nsx-system
3.2.2 Create Service Account for NCP
kubectl apply -f rbac-ncp.yml -n nsx-system
3.2.3 Create NCP ReplicationController
kubectl apply -f ncp-rc.yml -n nsx-system
3.2.4 Create NCP nsx-node-agent and nsx-kube-proxy DaemonSet
kubectl create -f nsx-node-agent-ds.yml -n nsx-system
You can find the above 3 yaml files in Github
https://github.com/insidepacket/nsxt-k8s-integration-yaml
Now you have completed the NSX-T and K8s integration. If you check the pods running on your K8s cluster, you will see the similar as below:
[root@master ~]# k get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-78fcdf6894-pg4dz 1/1 Running 0 9d
kube-system coredns-78fcdf6894-q727q 1/1 Running 128 9d
kube-system etcd-master.k8s 1/1 Running 3 14d
kube-system kube-apiserver-master.k8s 1/1 Running 2 14d
kube-system kube-controller-manager-master.k8s 1/1 Running 3 14d
kube-system kube-proxy-5p482 1/1 Running 2 14d
kube-system kube-proxy-9mnwk 1/1 Running 0 12d
kube-system kube-proxy-wj8qw 1/1 Running 3 14d
kube-system kube-scheduler-master.k8s 1/1 Running 3 14d
ns-test1000 http-echo-deployment-b5bbfbb86-j4dxq 1/1 Running 0 2d
nsx-system nsx-ncp-rr989 1/1 Running 0 11d
nsx-system nsx-node-agent-kbsld 2/2 Running 0 9d
nsx-system nsx-node-agent-pwhlp 2/2 Running 0 9d
nsx-system nsx-node-agent-vnd7m 2/2 Running 0 9d
nszhang busybox-756b4db447-2b9kx 1/1 Running 0 5d
nszhang busybox-deployment-5c74f6dd48-n7tp2 1/1 Running 0 9d
nszhang http-echo-deployment-b5bbfbb86-xnjz6 1/1 Running 0 2d
nszhang jenkins-deployment-8546d898cd-zdzs2 1/1 Running 0 11d
nszhang whoami-deployment-85b65d8757-6m7kt 1/1 Running 0 6d
nszhang whoami-deployment-85b65d8757-b4m99 1/1 Running 0 6d
nszhang whoami-deployment-85b65d8757-pwwt9 1/1 Running 0 6d
In NSX-T manager GUI, you will see the following resources are created for K8s cluster.



Tips:
I have met a few issues during my journey. The following CLIs are used a lot when I troubleshoot. I shared these CLI here and hope can help you a bit as well.
- How to check kubelet service’s log
journalctl -xeu kubelet
- How to check log for a specific pod
kubectl logs nsx-ncp-rr989 -n nsx-system
“nsx-ncp-rr989” is the name of pod and “nsx-system” is the namespace which we created for NCP.
- How to check log for a specific container when there are more than 1 container in the pod
kubectl logs nsx-node-agent-n7n7g -c nsx-node-agent -n nsx-system
“nsx-node-agent-n7n7g” is the pod name and “nsx-node-agent” is the container name.
- Show details of a specific pod
kubectl describe pod nsx-ncp-rr989 -n nsx-system
Nice post!
Is there a sample guidance on configuring NSX-T Ingress or NSX-T L4 LB + Nginx-Ingress? I tried both scenarios but all failed, I cannot see anything created after ingress config were applied in NSX-T VirtualServer’s Pool Members.
LikeLike