在Kubernetes集群中,是否可以将etcd从外部迁移到内部?

时间:2019-01-24 08:56:47

标签: kubernetes migration external internals etcd

一年前,我用一个外部etcd集群(3个成员)创建了一个Kubernetes集群。

有一次,我不知道可以在内部创建etcd,所以我制作了一个外部集群并将Kubernetes连接到它。

现在我看到一个内部集群是一个东西,它是一个更干净的解决方案,因为当您更新Kubernetes集群时,etcd节点也会更新。

我找不到将外部etcd集群迁移到内部集群的干净解决方案。我希望有一个零停机时间的解决方案。你知道是否可以吗?

感谢您的回复,祝您有愉快的一天!

2 个答案:

答案 0 :(得分:0)

据我所知,从Kubernetes集群的角度来看,您有3个etcd集群成员。预期的结果是使所有三个成员都在Kubernetes主节点上运行。 还有一些未公开的信息,因此我尝试解释几种可能的选择。

首先,有几种合理的方法可以运行etcd进程用作Kubernetes控制平面键值存储:

  • etcd作为静态容器运行,在/etc/kubernetes/manifests/etcd.yaml文件中具有启动配置
  • etcd作为/etc/systemd/system/etcd.service或类似文件中定义的系统服务运行
  • etcd作为使用命令行选项配置的docker容器运行。 (此解决方案并不十分安全,除非您可以让容器在故障或主机重启后重启)

出于实验目的,您还可以运行etcd:

  • 作为Linux用户空间中的简单过程
  • 作为kubernetes集群中的有状态集合
  • 作为由etcd-operator管理的etcd集群。

我的个人建议是有5个成员etcd集群:3个成员在3个主kubernetes节点上作为静态容器运行,另外2个成员在外部(独立于Kubernetes集群)主机上作为静态容器运行。在这种情况下,如果至少有一个主节点正在运行,或者由于任何原因使两个外部节点松动,则仍将达到法定人数。

至少有两种方法可以将etcd集群从外部实例迁移到Kubernetes集群主节点。它也以相反的方式工作。

迁移

迁移集群非常简单。在此过程中,成员被关闭(一次一个),移至另一台主机,然后再次启动。当您在etcd群集中仍然有仲裁时,您的群集应该没有任何问题。我的建议是至少有3个或5个以上节点的etcd群集,以使迁移更安全。对于较大的群集,使用第二个答案中的其他解决方案可能更方便。

official documentation中描述了将etcd成员移动到另一个IP地址的过程:

  

要迁移成员,请执行以下操作:

     
      
  1. 停止成员进程。
  2.   
  3. 将now-idle成员的数据目录复制到新计算机上。
  4.   
  5. 根据运行时重新配置说明更新替换成员的对等URL,以反映新计算机。
  6.   
  7. 使用相同的配置和数据目录的副本在新计算机上启动etcd。
  8.   

现在让我们仔细看看每个步骤:

0.1确保您的etcd集群健康,并且所有成员都状况良好。我还建议您检查所有etcd成员的日志,以防万一。

(要成功运行以下命令,请参阅第3步以获取auth变量和别名)

# last two commands only show you members specified by using --endpoints command line option
# the following commands is suppose to run with root privileges because certificates are not accessible by regular user

e2 cluster-health
e3 endpoint health
e3 endpoint status

0.2检查每个etcd成员配置,并找出etcd数据目录的位置,然后确保在etcd进程终止后仍可访问。在大多数情况下,它位于主机上的/ var / lib / etcd下,可以直接使用,也可以作为卷安装到etcd pod或docker容器中。

每个etcd集群成员的0.3 Create a snapshot ,最好不要使用它,而不要拥有它。

1。停止etcd成员进程。

如果按照建议的here使用kubelet启动etcd,请将etcd.yaml文件移出/etc/kubernetes/manifests/。在那之后,etcd Pod将被kubelet终止:

sudo mv /etc/kubernetes/manifests/etcd.yaml ~/
sudo chmod 644 ~/etcd.yaml 

如果您启动etcd进程as a systemd service,则可以使用以下命令将其停止:

sudo systemctl stop etcd-service-name.service

对于docker容器,您可以使用以下命令将其停止:

docker ps -a 
docker stop <etcd_container_id>
docker rm <etcd_container_id>

如果从命令行运行etcd进程,则可以使用以下命令将其杀死:

kill `pgrep etcd`

2。将now-idle成员的数据目录复制到新计算机上。

这里没有太多复杂性。将etcd data-dir压缩到文件中,然后将其复制到目标实例。如果您打算以相同的方式在新实例上运行etcd,我还建议复制etcd清单或systemd服务配置。

tar -C /var/lib -czf etcd-member-name-data.tar.gz etcd
tar -czf etcd-member-name-conf.tar.gz [etcd.yaml] [/etc/systemd/system/etcd.service]  [/etc/kubernetes/manifests/etcd.conf ...]
scp etcd-member-name-data.tar.gz destination_host:~/
scp etcd-member-name-conf.tar.gz destination_host:~/

3。根据运行时重新配置说明,为替换的成员更新对等URL ,以反映新的成员IP地址。

使用etcd API或运行etcdctl实用程序有两种方法。

这就是etcdctl的样子:
(用正确的etcd集群成员ip地址替换etcd端点变量)

# all etcd cluster members should be specified
export ETCDSRV="--endpoints https://etcd.ip.addr.one:2379,https://etcd.ip.addr.two:2379,https://etcd.ip.addr.three:2379"
#authentication parameters for v2 and v3 etcdctl APIs
export ETCDAUTH2="--ca-file /etc/kubernetes/pki/etcd/ca.crt --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file  /etc/kubernetes/pki/etcd/peer.key"
export ETCDAUTH3="--cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key"

# etcdctl API v3 alias
alias e3="ETCDCTL_API=3 etcdctl $ETCDAUTH3 $ETCDSRV"
# etcdctl API v2 alias
alias e2="ETCDCTL_API=2 etcdctl $ETCDAUTH2 $ETCDSRV"

# list all etcd cluster members and their IDs
e2 member list

e2 member update member_id http://new.etcd.member.ip:2380
#or
e3 member update member_id --peer-urls="https://new.etcd.member.ip:2380"

这就是etcd API的样子:

export CURL_ETCD_AUTH="--cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key --cacert /etc/kubernetes/pki/etcd/ca.crt"

curl https://health.etcd.istance.ip:2379/v2/members/member_id -XPUT -H "Content-Type: application/json" -d '{"peerURLs":["http://new.etcd.member.ip:2380"]}' ${CURL_ETCD_AUTH}

4。使用调整后的配置和数据目录的副本在新计算机上启动etcd

在新主机上解压缩etcd数据目录:

tar -xzf etcd-member-name-data.tar.gz -C /var/lib/

根据需要调整etcd启动配置。此时,很容易选择另一种运行etcd的方式。根据您的选择,准备清单或服务定义文件,并将旧的IP地址替换为新的IP地址。例如:

sed -i  's/\/10.128.0.12:/\/10.128.0.99:/g' etcd.yaml

现在是时候通过将etcd.yaml移至/etc/kubernetes/manifests/或运行以下命令(如果您将etcd作为systemd服务运行)来启动etcd

sudo systemctl start etcd-service-name.service

5。检查更新的etcd进程日志和etcd集群运行状况,以确保成员运行状况良好。

为此,您可以使用以下命令:

$ e2 cluster-health

$ kubectl logs etct_pod_name -n kube-system

$ docker logs etcd_container_id 2>&1 | less

$ journalctl -e -u etcd_service_name     

答案 1 :(得分:0)

我在另一个答案中提到的第二个解决方案是

先扩大然后缩小etcd集群

此方法的缺点是etcd仲裁数量会暂时增加,并且在多个节点出现故障的情况下,etcd群集可能会break。为了避免这种情况,您可能需要在添加另一个现有的etcd集群成员之前将其删除。

这是该过程的简要概述:

  1. 使用etcd ca.crtca.key从现有etcd节点文件夹(/etc/kubernetes/pki/etcd/)中为所有其他成员生成证书。
  2. 使用etcdctl命令将新成员添加到集群中
  3. 为新成员创建etcd配置
  4. 使用新键和配置启动新的etcd成员
  5. 检查集群运行状况
  6. 重复步骤2-5 ,直到添加了所有必需的etcd节点
  7. 使用etcdctl命令删除一个大型etcd集群成员
  8. 检查集群运行状况
  9. 重复步骤7-8 ,直到达到所需大小的etcd簇
  10. 为所有etcd集群成员调整所有etcd.yaml文件。
  11. 调整所有kube-apiserver.yaml清单中的etcd端点

另一个可能的顺序:

  1. 使用etcd ca.crtca.key从现有etcd节点文件夹(/etc/kubernetes/pki/etcd/)中为所有其他成员生成证书。
  2. 使用etcdctl命令删除一个etcd集群成员
  3. 使用etcdctl命令将新成员添加到集群中
  4. 为新成员创建etcd配置
  5. 使用新键和配置启动新的etcd成员
  6. 检查集群运行状况
  7. 重复步骤2-6 ,直到完成所需的etcd配置
  8. 调整所有etcd集群成员的所有etcd.yaml文件。
  9. 调整所有kube-apiserver.yaml清单中的etcd端点

如何生成证书:

注意:如果您拥有etcd集群,则可能在某处拥有etcd-CA证书。考虑将其与etcd-CA密钥一起使用,以为所有其他etcd成员生成证书。

注意::如果您选择手动生成证书,则通常的Kubernetes证书的参数为:

  • 签名算法:sha256WithRSAEncryption
  • 公钥算法:rsaEncryption
  • RSA公钥:(2048位)
  • CA认证年龄:10岁
  • 其他证书年龄:1岁

您可以使用以下命令检查证书的内容:

find /etc/kubernetes/pki/ -name *.crt | xargs -l  bash -c 'echo $0 ; openssl x509 -in $0 -text -noout'

如何从etcd集群中remove a member

(有关变量和别名的定义,请参阅我的第一个答案,第3步)

e3 member list

b67816d38b8e9d2, started, kube-ha-m3, https://10.128.0.12:2380, https://10.128.0.12:2379
3de72bd56f654b1c, started, kube-ha-m1, https://10.128.0.10:2380, https://10.128.0.10:2379
ac98ece88e3519b5, started, kube-etcd2, https://10.128.0.14:2380, https://10.128.0.14:2379
cfb0839e8cad4c8f, started, kube-ha-m2, https://10.128.0.11:2380, https://10.128.0.11:2379
eb9b83c725146b96, started, kube-etcd1, https://10.128.0.13:2380, https://10.128.0.13:2379
401a166c949e9584, started, kube-etcd3, https://10.128.0.15:2380, https://10.128.0.15:2379  # Let's remove this one

e2 member remove 401a166c949e9584

该成员将立即关闭。为了防止进一步尝试加入集群,请从/ etc / kubernetes / manifests /中移动/删除etcd.yaml或在etcd成员节点上关闭etcd服务


如何add a member到etcd集群

e3 member add kube-etcd3 --peer-urls="https://10.128.0.16:2380"

输出显示启动新的etcd集群成员所需的参数,例如:

ETCD_NAME="kube-etcd3"
ETCD_INITIAL_CLUSTER="kube-ha-m3=https://10.128.0.15:2380,kube-ha-m1=https://10.128.0.10:2380,kube-etcd2=https://10.128.0.14:2380,kube-ha-m2=https://10.128.0.11:2380,kube-etcd1=https://10.128.0.13:2380,kube-etcd3=https://10.128.0.16:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://10.128.0.16:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"

注意: ETCD_INITIAL_CLUSTER变量包含所有现有的etcd集群成员以及新节点。如果需要添加多个节点,则应一次添加一个节点。

注意All ETCD_INITIAL_*变量和相应的命令行参数仅在第一个etcd Pod启动时才需要。将节点成功添加到etcd集群后,这些参数将被忽略,并可从启动配置中删除。所有必需的信息都存储在etcd数据库文件的/var/lib/etcd文件夹中。

可以使用以下kubeadm命令生成默认的etcd.yaml清单:

kubeadm init phase etcd local

最好将etcd.yaml的文件从/etc/kubernetes/manifests/移到某处进行调整。

还删除/var/lib/etcd文件夹的内容。它包含新的etcd集群的数据,因此不能用于将成员添加到现有集群。

然后应根据成员添加命令输出对其进行调整。 (--advertise-client-urls, -initial-advertise-peer-urls, --initial-cluster, --initial-cluster-state, --listen-client-urls, --listen-peer-urls)例如:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    component: etcd
    tier: control-plane
  name: etcd
  namespace: kube-system
spec:
  containers:
  - command:
    - etcd
    - --advertise-client-urls=https://10.128.0.16:2379
    - --cert-file=/etc/kubernetes/pki/etcd/server.crt
    - --client-cert-auth=true
    - --data-dir=/var/lib/etcd
    - --initial-advertise-peer-urls=https://10.128.0.16:2380
    - --initial-cluster=kube-ha-m3=https://10.128.0.15:2380,kube-ha-m1=https://10.128.0.10:2380,kube-etcd2=https://10.128.0.14:2380,kube-ha-m2=https://10.128.0.11:2380,kube-etcd1=https://10.128.0.13:2380,kube-etcd3=https://10.128.0.16:2380
    - --initial-cluster-state=existing
    - --key-file=/etc/kubernetes/pki/etcd/server.key
    - --listen-client-urls=https://10.128.0.16:2379
    - --listen-metrics-urls=http://127.0.0.1:2381
    - --listen-peer-urls=https://10.128.0.16:2380
    - --name=kube-etcd3
    - --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    image: k8s.gcr.io/etcd:3.3.10
    imagePullPolicy: IfNotPresent
    livenessProbe:
      failureThreshold: 8
      httpGet:
        host: 127.0.0.1
        path: /health
        port: 2381
        scheme: HTTP
      initialDelaySeconds: 15
      timeoutSeconds: 15
    name: etcd
    resources: {}
    volumeMounts:
    - mountPath: /var/lib/etcd
      name: etcd-data
    - mountPath: /etc/kubernetes/pki/etcd
      name: etcd-certs
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /etc/kubernetes/pki/etcd
      type: DirectoryOrCreate
    name: etcd-certs
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data

保存文件后,kubelet将重新启动etcd pod。检查etcd容器日志以确保它已加入集群。


如何检查群集运行状况

$ e2 cluster-health
member b67816d38b8e9d2 is healthy: got healthy result from https://10.128.0.15:2379
member 3de72bd56f654b1c is healthy: got healthy result from https://10.128.0.10:2379
member ac98ece88e3519b5 is healthy: got healthy result from https://10.128.0.14:2379
member cfb0839e8cad4c8f is healthy: got healthy result from https://10.128.0.11:2379
member eb9b83c725146b96 is healthy: got healthy result from https://10.128.0.13:2379
cluster is healthy

$ e2 member list
b67816d38b8e9d2: name=kube-ha-m3 peerURLs=https://10.128.0.15:2380 clientURLs=https://10.128.0.15:2379 isLeader=true
3de72bd56f654b1c: name=kube-ha-m1 peerURLs=https://10.128.0.10:2380 clientURLs=https://10.128.0.10:2379 isLeader=false
ac98ece88e3519b5: name=kube-etcd2 peerURLs=https://10.128.0.14:2380 clientURLs=https://10.128.0.14:2379 isLeader=false
cfb0839e8cad4c8f: name=kube-ha-m2 peerURLs=https://10.128.0.11:2380 clientURLs=https://10.128.0.11:2379 isLeader=false
eb9b83c725146b96: name=kube-etcd1 peerURLs=https://10.128.0.13:2380 clientURLs=https://10.128.0.13:2379 isLeader=false

$ e3 endpoint health
# the output includes only etcd members that are specified  in --endpoints cli option or corresponded environment variable. I've included only three out of five members
https://10.128.0.13:2379 is healthy: successfully committed proposal: took = 2.310436ms
https://10.128.0.15:2379 is healthy: successfully committed proposal: took = 1.795723ms
https://10.128.0.14:2379 is healthy: successfully committed proposal: took = 2.41462ms

$ e3 endpoint status
# the output includes only etcd members that are specified  in --endpoints cli option or corresponded environment variable. I've included only three out of five members
https://10.128.0.13:2379 is healthy: successfully committed proposal: took = 2.531676ms
https://10.128.0.15:2379 is healthy: successfully committed proposal: took = 1.285312ms
https://10.128.0.14:2379 is healthy: successfully committed proposal: took = 2.266932ms

如何在不使用kubectl的情况下检查etcl Pod日志?

如果仅使用kubelet运行etcd成员,则可以使用以下命令检查其日志:

docker logs `docker ps -a | grep etcd | grep -v pause | awk '{print $1}' | head -n1` 2>&1 | less

注意:通常,只能在同一节点上同时运行一个etcd Pod,因为它使用主机目录/var/lib/etcd/中的数据库,并且不能在两个目录之间共享豆荚。另外etcd Pod使用节点网络接口与etcd群集进行通信。
当然,您可以将etcd Pod配置为使用不同的主机目录并使用不同的主机端口作为一种解决方法,但是以上命令假定节点上仅存在一个etcd Pod。