Cloud Native 20 min read

Step-by-Step Guide to Installing Kubernetes v1.16.0 on CentOS 7 with Docker and Flannel

This article provides a detailed, step‑by‑step tutorial for installing Kubernetes v1.16.0 on CentOS 7 virtual machines, covering Docker‑CE installation, prerequisite system configuration, master and node setup, flannel network plugin deployment, and includes all necessary command‑line snippets and the full kube‑flannel.yml manifest.

Top Architect
Top Architect
Top Architect
Step-by-Step Guide to Installing Kubernetes v1.16.0 on CentOS 7 with Docker and Flannel

The author encountered repeated errors when trying to install Kubernetes v1.16.2, so they downgraded to v1.16.0 and documented the successful installation process to help others avoid the same pitfalls.

Prerequisites

All machines must run Docker, have at least 2 CPU cores and 2 GB RAM, and be able to ping each other. The author used Windows 10 with VirtualBox, running CentOS 7 (kernel 3.10.0‑957.el7.x86_64). Master IP: 192.168.99.104, Node IP: 192.168.99.105.

1. Install Docker‑CE 18.09.9 on All Machines

# Install Docker prerequisites
yum install -y yum-utils device-mapper-persistent-data lvm2
# Add Alibaba Cloud Docker repo
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Install specific Docker version
yum install -y docker-ce-18.09.9-3.el7
# Enable and start Docker
systemctl enable docker && systemctl start docker

2. Set Kubernetes Environment Preconditions

# Disable firewall
systemctl disable firewalld
systemctl stop firewalld

# Disable SELinux temporarily and permanently
setenforce 0
sed -i 's/SELINUX=permissive/SELINUX=disabled/' /etc/sysconfig/selinux
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

# Turn off swap
swapoff -a
sed -i 's/.*swap.*/#&/' /etc/fstab

# Configure kernel parameters for bridge networking
cat <
/etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

3. Install Kubernetes v1.16.0 Master Node

First ensure Docker is installed and the environment prerequisites are applied.

3.1 Install kubeadm, kubelet, kubectl

# Add Alibaba Cloud Kubernetes repo
cat <
/etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

# Install specific version packages
yum install -y kubeadm-1.16.0-0 kubelet-1.16.0-0 kubectl-1.16.0-0
# Enable and start kubelet
systemctl enable kubelet && systemctl start kubelet

3.2 Initialize the Cluster

The following command pulls required Docker images from the Alibaba Cloud registry and initializes the control plane using the master IP (192.168.99.104). It may pause at a pre‑flight check for about two minutes.

# Initialize with custom image repository and pod network CIDR
kubeadm init \
  --image-repository registry.aliyuncs.com/google_containers \
  --kubernetes-version v1.16.0 \
  --apiserver-advertise-address 192.168.99.104 \
  --pod-network-cidr=10.244.0.0/16 \
  --token-ttl 0

After successful initialization, run the commands below to set up the local kubeconfig:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

3.3 Save the Node Join Command

When kubeadm init finishes, it prints a kubeadm join command. You can also retrieve it later with:

kubeadm token create --print-join-command

4. Install Kubernetes v1.16.0 Worker Node

Repeat Docker installation and environment preparation on each worker node, then install kubeadm and kubelet:

# Add Alibaba Cloud repo (same as master)
cat <
/etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

# Install packages
yum install -y kubeadm-1.16.0-0 kubelet-1.16.0-0
# Enable and start kubelet
systemctl enable kubelet && systemctl start kubelet

Join the cluster using the command obtained from the master, for example:

kubeadm join 192.168.99.104:6443 \
  --token ncfrid.7ap0xiseuf97gikl \
  --discovery-token-ca-cert-hash sha256:47783e9851a1a517647f1986225f104e81dbfd8fb256ae55ef6d68ce9334c6a2

5. Install Flannel Network Plugin on the Master

After the master and nodes are up, the master may still show NotReady . Install flannel to provide pod networking.

5.1 Create Modified kube‑flannel.yml

The original file from the official repository references quay.io , which is blocked in China. The author replaced it with the mirror quay-mirror.qiniu.com and placed the full manifest in the appendix.

5.2 Apply the Manifest

kubectl apply -f kube-flannel.yml

6. Completion

Running kubectl get nodes now shows both master and worker nodes in the Ready state, indicating a successful Kubernetes cluster deployment.

Appendix: Full kube‑flannel.yml Manifest

---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: psp.flannel.unprivileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default
    seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default
    apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
    apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
spec:
  privileged: false
  volumes:
    - configMap
    - secret
    - emptyDir
    - hostPath
  allowedHostPaths:
    - pathPrefix: "/etc/cni/net.d"
    - pathPrefix: "/etc/kube-flannel"
    - pathPrefix: "/run/flannel"
  readOnlyRootFilesystem: false
  runAsUser:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  allowPrivilegeEscalation: false
  defaultAllowPrivilegeEscalation: false
  allowedCapabilities: ['NET_ADMIN']
  defaultAddCapabilities: []
  requiredDropCapabilities: []
  hostPID: false
  hostIPC: false
  hostNetwork: true
  hostPorts:
    - min: 0
      max: 65535
  seLinux:
    rule: 'RunAsAny'
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flannel
rules:
  - apiGroups: ['extensions']
    resources: ['podsecuritypolicies']
    verbs: ['use']
    resourceNames: ['psp.flannel.unprivileged']
  - apiGroups: ['']
    resources: ['pods']
    verbs: ['get']
  - apiGroups: ['']
    resources: ['nodes']
    verbs: ['list', 'watch']
  - apiGroups: ['']
    resources: ['nodes/status']
    verbs: ['patch']
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: flannel
  namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
  labels:
    tier: node
    app: flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {"portMappings": true}
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {"Type": "vxlan"}
    }
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds-amd64
  namespace: kube-system
  labels:
    tier: node
    app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: beta.kubernetes.io/os
                    operator: In
                    values: ["linux"]
                  - key: beta.kubernetes.io/arch
                    operator: In
                    values: ["amd64"]
      hostNetwork: true
      tolerations:
        - operator: Exists
          effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
        - name: install-cni
          image: quay-mirror.qiniu.com/coreos/flannel:v0.11.0-amd64
          command: ["cp"]
          args: ["-f", "/etc/kube-flannel/cni-conf.json", "/etc/cni/net.d/10-flannel.conflist"]
          volumeMounts:
            - name: cni
              mountPath: /etc/cni/net.d
            - name: flannel-cfg
              mountPath: /etc/kube-flannel/
      containers:
        - name: kube-flannel
          image: quay-mirror.qiniu.com/coreos/flannel:v0.11.0-amd64
          command: ["/opt/bin/flanneld"]
          args: ["--ip-masq", "--kube-subnet-mgr"]
          resources:
            requests:
              cpu: "100m"
              memory: "50Mi"
            limits:
              cpu: "100m"
              memory: "50Mi"
          securityContext:
            privileged: false
            capabilities:
              add: ["NET_ADMIN"]
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          volumeMounts:
            - name: run
              mountPath: /run/flannel
            - name: flannel-cfg
              mountPath: /etc/kube-flannel/
      volumes:
        - name: run
          hostPath:
            path: /run/flannel
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg
---
# (Additional DaemonSet definitions for arm64, arm, ppc64le, s390x follow the same pattern with appropriate image tags)
DockerKuberneteskubeletflannelkubectlkubeadmCentOS7
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.