> For the complete documentation index, see [llms.txt](https://close.gitbook.io/yun-wei-bi-ji/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://close.gitbook.io/yun-wei-bi-ji/kubernetes/k8s/kua-vpc-wang-luo-k8s/kua-vpc-wang-luo-shi-yong-kubeadm-chuang-jian-ji-qun-v1.24.md).

# 跨VPC网络-使用 kubeadm 创建集群（v1.24）

### 使用 kubeadm 创建集群（v1.24）

* 部署单个控制平面的 Kubernetes 集群，使用外部 etcd 集群设置 Kubernetes 集群
* 在集群上安装 Pod 网络，以便你的 Pod 可以相互连通

**前提**

* 1. 跨 VPC 网络搭建 k8s 集群-工具安装
* 2. 跨 VPC 网络二进制部署 etcd 集群

**3.1 初始化控制平面节点**

> 将 etcd 认证文件从任何一个 etcd 节点复制到控制平面节点（master）

```bash
export CONTROL_PLANE="root@112.71.24.110"
scp /etc/etcd/ssl/ca.pem "${CONTROL_PLANE}":
scp /etc/etcd/ssl/etcd.pem "${CONTROL_PLANE}":
scp /etc/etcd/ssl/etcd-key.pem "${CONTROL_PLANE}":
```

**3.2 集群配置参数** 首先生成配置文件

```bash
 # 生成默认的 kubeadm 配置文件
kubeadm config print init-defaults > kubeadm.yaml

# 编辑修改参数
vim kubeadm.yaml
```

调整好的 kubeadm.yaml 如下：

```bash
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 43.129.25.161    # master 的外网 IP,
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
  imagePullPolicy: IfNotPresent
  name: master
  taints: null
---
apiServer:
  certSANs:
  - 43.129.25.161    # 指定证书认证的域名或者 IP 地址
  extraArgs:
    authorization-mode: Node,RBAC
    advertise-address: 43.129.25.161    # 对外访问的 IP
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
controlPlaneEndpoint: 43.129.25.161:6443    # 控制平面的外网 IP,或者LB域名
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
  external:
    endpoints:    # 外部 etcd 集群的 IP 地址
      - https://43.129.25.161:2379
      - https://43.134.80.11:2379
      - https://43.135.160.117:2379
    caFile: /data/etcd/ssl/ca.pem
    certFile: /data/etcd/ssl/etcd.pem
    keyFile: /data/etcd/ssl/etcd-key.pem
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: 1.24.4
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
  podSubnet: 10.244.0.0/16    # Pod 网络子网，这里是 flannel
scheduler: {}
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd    # kubelet 的控制组驱动,  kubelet 的 cgroup 选项设置就在此处。
```

### 初始化命令

```bash
# 初始化命令格式 kubeadm init <args>
# 在控制平面节点（master）上运行：
kubeadm init --config kubeadm.yaml --upload-certs

```

> kubeadm init 首先运行一系列预检查。这些预检查会显示警告并在错误时退出。预检查通过后 kubeadm init 下载并安装集群控制平面组件。这可能需要几分钟。 完成之后你应该看到：

```bash
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of the control-plane node running the following command on each as root:

  kubeadm join 43.129.25.161:6443 --token abcdef.0123456789abcdef \
        --discovery-token-ca-cert-hash sha256:138fe28c94b751d9b46243391b827b36fe7e1a3b6df086a5c87c3d8113b78fbf \
        --control-plane --certificate-key 1801d1376fd21ceccc9dc66b5c9fc782ea5fcb922dfd78e349da4888e55477fc

Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.

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

kubeadm join 43.129.25.161:6443 --token abcdef.0123456789abcdef \
        --discovery-token-ca-cert-hash sha256:138fe28c94b751d9b46243391b827b36fe7e1a3b6df086a5c87c3d8113b78fbf 
```

**在控制平面节点运行以下命令，就能够开始使用 kubectl 操作集群**

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

**加入其它控制平面节点**

在追求高稳定性的生产环境中，集群的冗余是必要的。如果只有一个控制平面节点，当这个节点宕机时，整个集群处于不可用状态。为了降低这类风险，我们需要准备多个控制平面节点。集群数量是1、3、5、7……，奇数。

```bash
kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash> --control-plane --certificate-key <certificate-key>
```

**加入工作节点** 在工作节点机器上运行 kubeadm init 输出的 kubeadm join 命令

```bash
kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>
```

输出如下：

```bash
[preflight] Running pre-flight checks

... (log output of join workflow) ...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
```

回到控制平面节点（master）上运行 kubectl get nodes 命令查看节点加入情况，发现 kubectl 命令报错，无法查看节点信息。

因为 kubeadm join 命令将工作节点的内网 IP 上传给控制平面节点，跨 VPC 情况下，在控制平面节点当然无法通过工作节点的内网 IP 与工作节点通讯。

**解决方案：** 在控制平台节点（master）设置各个工作节点内、外网 IP NAT 转发规则（有 n 个工作节点就设置 n 条转发规则），使 kubectl 能够与所有工作节点通讯。命令格式如下：

```bash
iptables -t nat -A OUTPUT -d <internal IP of worker node> -j DNAT --to-destination <external IP of worker node>
```

此处有 2 个工作节点，故需要在 master 上执行 2 条命令：

```bash
# 在 master 上执行以下命令
iptables -t nat -A OUTPUT -d 172.22.0.10 -j DNAT --to-destination 43.134.80.11
iptables -t nat -A OUTPUT -d 172.26.0.9 -j DNAT --to-destination 43.135.160.117
```

kubectl 此刻可正常查看各个工作节点信息：

```bash
root@VM-200-6-ubuntu:/data# kubectl get nodes
NAME     STATUS     ROLES           AGE   VERSION
node1    NotReady   <none>          70s   v1.24.4
node2    NotReady   <none>          18s   v1.24.4
master   NotReady   control-plane   25m   v1.24.4

root@VM-200-6-ubuntu:/data# kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                             READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
kube-system   coredns-6d4b75cb6d-fvwdw         0/1     Pending   0          26m     <none>         <none>   <none>           <none>
kube-system   coredns-6d4b75cb6d-zswpf         0/1     Pending   0          26m     <none>         <none>   <none>           <none>
kube-system   kube-apiserver-master            1/1     Running   0          8m4s    172.19.200.6   master   <none>           <none>
kube-system   kube-controller-manager-master   1/1     Running   0          8m4s    172.19.200.6   master   <none>           <none>
kube-system   kube-proxy-7c2wz                 1/1     Running   1          26m     172.19.200.6   master   <none>           <none>
kube-system   kube-proxy-jhwcb                 1/1     Running   0          2m54s   172.22.0.10    etcd2    <none>           <none>
kube-system   kube-proxy-pktkf                 1/1     Running   0          2m2s    172.26.0.9     etcd3    <none>           <none>
kube-system   kube-scheduler-master            1/1     Running   1          27m     172.19.200.6   master   <none>           <none>
```

### 安装 Pod 网络插件 flannel

> `kubectl get nodes` 查看全部节点状态，都是 Not Ready；再用 `kubectl get pods --all-namespaces -o wide` 查看所有 pod，CoreDNS 都是 pending 状态。

这是还没安装 Pod 网络插件的状态，k8s 集群还没就绪。

第一种方式是在每个节点上安装二进制包，然后以 systemd 服务运行 flanneld，指定-public-ip 参数，绑定外网ip，详见 <https://github.com/flannel-io/flannel/blob/master/Documentation/running.md> 第二种方式，容器化部署 flannel，一键执行，方便快捷。

**在部署之前，有个关键问题：**

> flannel 默认将网卡 IP 设置为 Public IP，跨 VPC 服务器上的 flannel 实例以该服务器的内网 IP 为 Public IP，然后就出现控制平面节点的 flannel 运行成功，而工作节点的 flannel 不断重启、不断失败的状况……

**解决方案：** 在每个节点（控制平台节点、工作节点）上设置节点注释，命令格式如下：

```bash
kubectl annotate node <node name> flannel.alpha.coreos.com/public-ip-overwrite=<external IP of node>
```

在控制节点执行以下命令：

```bash
# 给 master 执行
kubectl annotate node master flannel.alpha.coreos.com/public-ip-overwrite=43.129.25.161

# 给 node1 上执行
kubectl annotate node node1 flannel.alpha.coreos.com/public-ip-overwrite=43.134.80.11

# 给 node2 上执行
kubectl annotate node node2 flannel.alpha.coreos.com/public-ip-overwrite=43.135.160.117
```

接着回到 master 上，用以下命令部署 flannel

```bash
# flannel 在每个节点启动后，读取该节点的 public-ip-overwrite 值，设为 Public IP。
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
```

```bash
root@VM-200-6-ubuntu:/data# kubectl get no
NAME     STATUS   ROLES           AGE   VERSION
node1    Ready    <none>          11m   v1.24.4
node2    Ready    <none>          10m   v1.24.4
master   Ready    control-plane   36m   v1.24.4
```

每个集群只能安装一个 Pod 网络。

> 安装 Pod 网络后，你可以通过在 kubectl get pods --all-namespaces 输出中检查 CoreDNS Pod 是否 Running 来确认其是否正常运行。 一旦 CoreDNS Pod 和 flannel Pod 启用并运行，集群就完成部署工作。

```bash
root@VM-200-6-ubuntu:/data# kubectl get pods --all-namespaces 
NAMESPACE      NAME                             READY   STATUS    RESTARTS   AGE
kube-flannel   kube-flannel-ds-dknqp            1/1     Running   0          2m50s
kube-flannel   kube-flannel-ds-t2v8z            1/1     Running   0          2m50s
kube-flannel   kube-flannel-ds-vb4n9            1/1     Running   0          2m50s
kube-system    coredns-6d4b75cb6d-fvwdw         1/1     Running   0          37m
kube-system    coredns-6d4b75cb6d-zswpf         1/1     Running   0          37m
kube-system    kube-apiserver-master            1/1     Running   0          18m
kube-system    kube-controller-manager-master   1/1     Running   0          18m
kube-system    kube-proxy-7c2wz                 1/1     Running   1          37m
kube-system    kube-proxy-jhwcb                 1/1     Running   0          13m
kube-system    kube-proxy-pktkf                 1/1     Running   0          12m
kube-system    kube-scheduler-master            1/1     Running   1          37m
```
