---
url: /diary/k8s/02/index.md
description: Kubernetes 学习笔记第二篇，在 CentOS 7 裸机上搭建生产级 K8S 集群，包括 master 和 worker 节点配置。
---
## 前言

### 主节点组件

* docker（或其他容器）
* kubectl
* kubeadm

### 工作节点组件

* docker
* kubectl

## 生产环境搭建

本次使用3台虚拟机模拟节点，以`centOs7`系统做演示

1. 初始(所有节点)，操作为三台机器共同操作，将3台虚拟机分别命名为
   * master `192.168.171.130`
   * node1   `192.168.171.131`
   * node2   `192.168.171.132`

2. 修改3台机器的hosts
   ```shell
   vim /etc/hosts
   #加入以下内容
   192.168.171.130 master
   192.168.171.131 node1
   192.168.171.132 node2
   ```

3. 设置SELinux
   ```shell
   #将 SELinux 设置为 permissive 模式（相当于将其禁用）
   sudo setenforce 0
   sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

   #或者直接禁用
   setenforce 0
   sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux
   ```

4. 关闭swap

   需关闭swap，否则 kubelet 无法正常工作

   ```shell
   swapoff -a
   yes | cp /etc/fstab /etc/fstab_bak
   cat /etc/fstab_bak |grep -v swap > /etc/fstab
   ```

5. 添加k8s安装源

   ```shell
   # 添加 k8s 安装源
   cat <<EOF > 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
   mv kubernetes.repo /etc/yum.repos.d/
   ```

6. 添加docker安装源

   ```shell
   # 添加 Docker 安装源
   yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
   ```

7. 安装所需组件

   ```shell
   yum install -y kubelet kubeadm kubectl docker-ce

   #设置开机启动
   systemctl enable kubelet
   systemctl start kubelet
   systemctl enable docker
   systemctl start docker
   ```

8. 修改docker配置

   > \[!warning]
   > 必须修改`docker`配置，否则`kubelet` 无法正常工作

   ```shell
   # kubernetes 官方推荐 docker 等使用 systemd 作为 cgroupdriver，否则 kubelet 启动不了
   cat <<EOF > daemon.json
   {
     "exec-opts": ["native.cgroupdriver=systemd"],
     "registry-mirrors": ["https://ud6340vz.mirror.aliyuncs.com"]
   }
   EOF
   mv daemon.json /etc/docker/
   ```

### 初始化集群（master）

#### 初始化

```shell
kubeadm init --image-repository=registry.aliyuncs.com/google_containers --pod-network-cidr 10.244.0.0/16
```

* 成功后提示类似如下，其中`kubeadm join xxx` 需保存起来

  ```shell
  Then you can join any number of worker nodes by running the following on each as       root:

  kubeadm join 192.168.171.130:6443 --token eez76b.z8xu5q1510sps4vv \
          --discovery-token-ca-cert-hash sha256:038b319037ec6ec9a1daf1a81f9e7fd762      a5427a63aedadd71ac7aee49b6eb7a
  ```

  * 如果`kubeadm join xxx` 丢失，可以重新获取：

    ```shell
    kubeadm token create --print-join-command
    ```
  * 如果初始化失败，则可以进行重置，然后再初始化：

    ```shell
    kubeadm reset
    kubeadm init --image-repository=registry.aliyuncs.com/google_containers --pod-network-cidr 10.244.0.0/16
    ```

#### 复制授权文件

```shell
# 复制授权文件，以便 kubectl 可以有权限访问集群
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
```

#### 安装网络插件

> \[!warning]
> 必须安装网络插件，否则node的`STATUS`是 `NotReady`

> \[!warning]
> 在安装网络之前，集群 DNS (CoreDNS) 将不会启动。

> \[!warning]
> 注意你的 Pod 网络最好不与任何主机网络重叠

网络插件可以[参考](https://kubernetes.io/zh/docs/concepts/cluster-administration/networking/#how-to-implement-the-kubernetes-networking-model)

```shell
#Flannel
## Flannel 是一个非常简单的能够满足 Kubernetes 所需要的覆盖网络。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
```

* 如果下载失败，可以使用以下文件直接安装

  ```yml :collapsed-lines
  ---
  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
    # Users and groups
    runAsUser:
      rule: RunAsAny
    supplementalGroups:
      rule: RunAsAny
    fsGroup:
      rule: RunAsAny
    # Privilege Escalation
    allowPrivilegeEscalation: false
    defaultAllowPrivilegeEscalation: false
    # Capabilities
    allowedCapabilities: ['NET_ADMIN', 'NET_RAW']
    defaultAddCapabilities: []
    requiredDropCapabilities: []
    # Host namespaces
    hostPID: false
    hostIPC: false
    hostNetwork: true
    hostPorts:
    - min: 0
      max: 65535
    # SELinux
    seLinux:
      # SELinux is unused in CaaSP
      rule: 'RunAsAny'
  ---
  kind: ClusterRole
  apiVersion: rbac.authorization.k8s.io/v1
  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/v1
  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
    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: kubernetes.io/os
                  operator: In
                  values:
                  - linux
        hostNetwork: true
        priorityClassName: system-node-critical
        tolerations:
        - operator: Exists
          effect: NoSchedule
        serviceAccountName: flannel
        initContainers:
        - name: install-cni-plugin
          image: rancher/mirrored-flannelcni-flannel-cni-plugin:v1.0.0
          command:
          - cp
          args:
          - -f
          - /flannel
          - /opt/cni/bin/flannel
          volumeMounts:
          - name: cni-plugin
            mountPath: /opt/cni/bin
        - name: install-cni
          image: quay.io/coreos/flannel:v0.15.1
          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.io/coreos/flannel:v0.15.1
          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", "NET_RAW"]
          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-plugin
          hostPath:
            path: /opt/cni/bin
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg
  ```

  保存为`kube-flannel.yml` 文件，并运行以下命令：

  ```shell
  [root@master .kube]# kubectl apply -f kube-flannel.yml
  Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable i      n v1.25+
  podsecuritypolicy.policy/psp.flannel.unprivileged created
  clusterrole.rbac.authorization.k8s.io/flannel created
  clusterrolebinding.rbac.authorization.k8s.io/flannel created
  serviceaccount/flannel created
  configmap/kube-flannel-cfg created
  daemonset.apps/kube-flannel-ds created
  ```

### 加入集群（node）

分别在`node1` 和 `node2` 上加入集群

#### 加入命令

```shell
kubeadm join 192.168.171.130:6443 --token eez76b.z8xu5q1510sps4vv \
        --discovery-token-ca-cert-hash sha256:038b319037ec6ec9a1daf1a81f9e7fd762      a5427a63aedadd71ac7aee49b6eb7a
```

### 查看集群（master）

```shell
[root@master .kube]# kubectl get nodes
NAME     STATUS   ROLES                  AGE   VERSION
master   Ready    control-plane,master   56m   v1.23.1
node1    Ready    <none>                 52m   v1.23.1
node2    Ready    <none>                 50m   v1.23.1
```
