# 集群联邦

本文将介绍如何安装`federation-v2`。注意：本文要参考`https://github.com/kubernetes-sigs/kubefed/blob/v0.0.10/docs/userguide.md`，不要参考`https://github.com/kubernetes-sigs/kubefed/blob/master/docs/userguide.md`

## 前置条件

准备三个kubernetes集群，它们的用处分别为

* `f-cluster`：用来部署kubefed的组件, 192.168.2.103
* `a-cluster`：联邦下的一个集群 192.168.2.101
* `b-cluster`：联邦下的一个集群 192.168.2.102

版本信息如下：

* k8s版本：`federation-v2`要求kubernetes的版本在`v1.11`或以上，本教程使`v1.14.0`版本。
* 集群安装方法：kubeadm安装
* helm：f-cluster集群中已安装好tiller，本教程使用的helm的版本为`v2.13.1`

在`f-cluster`主机上配置好`KUBECONFIG`，使`kubectl`、`kubefed2`能连接到其他两个集群，内容如下：

在`f-cluster`主机上执行命令`kubectl config get-clusters`查看集群信息

```
$ kubectl config get-clusters
NAME
b-cluster
f-cluster
a-cluster
```

执行`kubectl config get-contexts`查看上下文信息

```
$ kubectl config get-contexts
CURRENT   NAME        CLUSTER     AUTHINFO   NAMESPACE
          a-context   a-cluster   a-admin    
          b-context   b-cluster   b-admin    
*         f-context   f-cluster   f-admin
```

## 安装kubefed-v2的控制平面

这里我们使用helm来安装。下载chart，链接为`https://github.com/kubernetes-sigs/federation-v2/releases`，这里我们选择最新的`v0.0.10`版本（这就是为什么文章一开始说要参考`v0.0.10`版本的文档而不要参考最新的文档，因为有很多不一样），下载后文件名为`federation-v2-0.0.10.tgz`。然后执行以下的命令安装：

```
$ helm install federation-v2-0.0.10.tgz --name federation --namespace federation-system
```

安装好之后，`f-cluster`中会有如下两个Pod在运行：

```
$ kubectl get pod -n federation-system -o wide
NAME                                             READY   STATUS    RESTARTS   AGE
federation-controller-manager-7b4d48c9f5-cljsc   1/1     Running   0          11s
federation-controller-manager-7b4d48c9f5-xtbx7   1/1     Running   0          11s
```

同时，里面会有一系列的`CRD`资源生成：

```
$ kubectl get crd | grep federation.k8s.io
clusterpropagatedversions.core.federation.k8s.io            2019-05-16T03:29:28Z
dnsendpoints.multiclusterdns.federation.k8s.io              2019-05-16T03:29:28Z
domains.multiclusterdns.federation.k8s.io                   2019-05-16T03:29:28Z
federatedclusterroles.types.federation.k8s.io               2019-05-16T03:29:28Z
federatedclusters.core.federation.k8s.io                    2019-05-16T03:29:28Z
federatedconfigmaps.types.federation.k8s.io                 2019-05-16T03:29:28Z
federateddeployments.types.federation.k8s.io                2019-05-16T03:29:28Z
federatedingresses.types.federation.k8s.io                  2019-05-16T03:29:28Z
federatedjobs.types.federation.k8s.io                       2019-05-16T03:29:28Z
federatednamespaces.types.federation.k8s.io                 2019-05-16T03:29:29Z
federatedreplicasets.types.federation.k8s.io                2019-05-16T03:29:29Z
federatedsecrets.types.federation.k8s.io                    2019-05-16T03:29:29Z
federatedserviceaccounts.types.federation.k8s.io            2019-05-16T03:29:29Z
federatedservices.types.federation.k8s.io                   2019-05-16T03:29:29Z
federatedservicestatuses.core.federation.k8s.io             2019-05-16T03:29:29Z
federatedtypeconfigs.core.federation.k8s.io                 2019-05-16T03:29:29Z
federationconfigs.core.federation.k8s.io                    2019-05-16T03:29:29Z
ingressdnsrecords.multiclusterdns.federation.k8s.io         2019-05-16T03:29:29Z
propagatedversions.core.federation.k8s.io                   2019-05-16T03:29:29Z
replicaschedulingpreferences.scheduling.federation.k8s.io   2019-05-16T03:29:29Z
servicednsrecords.multiclusterdns.federation.k8s.io         2019-05-16T03:29:29Z
```

以及`FederatedTypeConfig`

```
$ kubectl get FederatedTypeConfig -n federation-system
NAME                                     AGE
clusterroles.rbac.authorization.k8s.io   101s
configmaps                               101s
deployments.apps                         101s
ingresses.extensions                     101s
jobs.batch                               101s
namespaces                               101s
replicasets.apps                         101s
secrets                                  101s
serviceaccounts                          101s
services                                 101s
```

### 卸载

如果要卸载控制平面，首先删除`FederatedTypeConfig`

```
$ kubectl delete FederatedTypeConfig --all -n kube-federation-system
```

然后删除所有关于联邦的CRD

```
$ kubectl get crd | grep federation.k8s.io | awk '{print $1}' | xargs kubectl delete crd
```

然后删除release

```
$ helm delete --purge federation
```

## 下载kubefedctl二进制文件

下载`kubefedctl`客户端工具，链接为`https://github.com/kubernetes-sigs/federation-v2/releases`，由于上面federation的控制平台我们安装的是`0.0.10`，所以我们也下载这个版本的客户端。下载下来后是一个`kubefedctl.tgz`，解压并核实版本信息：

```
$ tar xzvf kubefedctl.tgz
$ ./kubefedctl version
kubefedctl version: version.Info{Version:"v0.0.10-dirty", GitCommit:"71d233ede685707df554ef653e06bf7f0229415c", GitTreeState:"dirty", BuildDate:"2019-05-06T22:30:31Z", GoVersion:"go1.11.2", Compiler:"gc", Platform:"linux/amd64"}
```

## 添加集群到联邦

在添加集群前，要先在`f-cluster`中创建命名空间`kube-multicluster-public`

```
$ kubectl create namespace kube-multicluster-public
```

然后在`f-cluster`上执行如下命令添加`a-cluster`至联邦中

```
$ ./kubefedctl join a-cluster --cluster-context a-context --host-cluster-context f-context --add-to-registry --v=2
```

然后查看`a-cluster`的状态，应该是Ready，如果不是请查看两个Pod`federation-controller-manager-xxxxxxxxxx-yyyy`的日志（见FAQ）

```
$ kubectl get federatedcluster -n federation-system
NAME        READY   AGE
a-cluster   True    40s
```

添加成功后会有`a-cluster`中自动创建一个命名空间`federation-system`。

接着我们继续添加b集群

```
$ ./kubefedctl join b-cluster --cluster-context b-context --host-cluster-context f-context --add-to-registry --v=2
```

确定两个集群都添加成功

```
$ kubectl get federatedcluster -n federation-system
NAME        READY   AGE
a-cluster   True    79s
b-cluster   True    18s
```

### 删除集群

如果有需要，可以使用以下的命令来删掉一个集群

```
$ ./kubefedctl unjoin b-cluster --cluster-context b-context --host-cluster-context f-context --remove-from-registry --v=2
```

## 发布一个资源

接下来我们发布一个`FederatedDeployment`。首先创建好该资源所属的命名空间`test-namespace`:

```
$ kubectl create namespace test-namespace
```

然后创建`FederatedNamespace`，让`federation-controller-manager`在`a-cluster`与`b-cluster`中也创建命名空间`test-namespace`

```
$ kubectl apply -f federatednamespace.yaml
```

`federatednamespace.yaml`文件内容如下：

验证在三个集群中都已存在`test-namespace`这个命名空间。

然后，我们创建一个`FederatedDeployment`

```
$ kubectl apply -f federateddeployment.yaml
```

`federateddeployment.yaml`的内容如下，它的意思是：在a-cluster与b-cluster中发布一个Deployment，每个集群的副本数都为1

接下来，我们查看a集群与b集群上命名空间`test-namespace`下的`Deployment`，发现与期望的一致

```
$ kubectl get deploy -n test-namespace --context a-context
NAME              READY   UP-TO-DATE   AVAILABLE   AGE
test-deployment   1/1     1            1           93s

$ kubectl get deploy -n test-namespace --context b-context
NAME              READY   UP-TO-DATE   AVAILABLE   AGE
test-deployment   1/1     1            1           109s
```

## FAQ

**Q：执行命令`kubectl get federatedcluster -n federation-system`发现`a-cluster`不是Ready状态？**

A：查看Pod`federation-controller-manager-7779795856-wvbfq`的日志如下，说连不上`a-cluster`的apiserver

```
E0429 07:51:39.060715       1 clusterclient.go:122] Failed to list nodes while getting zone names: Get https://192.168.1.101:6443/api/v1/nodes: dial tcp 192.168.1.101:6443: i/o timeout
W0429 07:51:39.060788       1 controller.go:216] Failed to get zones and region for cluster a-cluster: Get https://192.168.1.101:6443/api/v1/nodes: dial tcp 192.168.1.101:6443: i/o timeout
```

进入到该Pod中去ping `192.168.1.101`发现也不通，于是开始解决网络问题。由于`federation-controller-manager-7779795856-wvbfq`的IP是`172.26.0.18`，当它去访问`192.168.1.101`时并没有做SNAT，所以导致包去了回不来，我们在`192.168.1.101`上有抓包为证：

```
$ tcpdump -i ens33 icmp
...
04:27:47.244546 IP 172.26.0.18 > peng01: ICMP echo request, id 8192, seq 0, length 64
```

这个与calico的配置有关，这里我们先在`f-cluster`上执行如下的命令暂时解决这个问题

```
$ iptables -t nat -I POSTROUTING -s 172.26.0.0/16 ! -d 172.26.0.0/16 -j MASQUERADE
```

## Reference

* <https://github.com/kubernetes-sigs/kubefed/blob/v0.0.10/docs/userguide.md>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pshizhsysu.gitbook.io/kubernetes/ji-qun-lian-bang.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
