【问题标题】:In a Kubernetes cluster, is there a way to migrate etcd from external to internal?在 Kubernetes 集群中,有没有办法将 etcd 从外部迁移到内部?
【发布时间】:2019-06-17 22:56:43
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: kubernetes migration external internals etcd


    【解决方案1】:

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

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

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

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

    • 作为 linux 用户空间中的一个简单进程
    • 作为 Kubernetes 集群中的状态集
    • 作为由 etcd-operator 管理的 etcd 集群。

    我个人的建议是拥有 5 个成员的 etcd 集群:3 个成员作为静态 Pod 在 3 个主 Kubernetes 节点上运行,另外两个成员作为静态 Pod 在外部(独立于 Kubernetes 集群)主机上运行。在这种情况下,如果您至少有一个主节点正在运行,或者您因任何原因失去了两个外部节点,那么您仍然会有一个仲裁。

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

    迁移

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

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

    迁移成员:

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

    现在让我们仔细看看每一步:

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

    (要成功运行以下命令,请参阅步骤 3 了解身份验证变量和别名)

    # 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 data-dir所在位置,确保etcd进程终止后仍可访问。在大多数情况下,它位于主机上的 /var/lib/etcd 下,并直接使用或作为卷安装到 etcd pod 或 docker 容器。

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

    1.停止 etcd 成员进程。

    如果您使用kubelet 启动etcd,按照here 的建议,将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 数据目录压缩到文件并将其复制到目标实例。如果您打算以相同的方式在新实例上运行 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 端点变量替换为正确的 etcd 集群成员 ip 地址)

    # 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 data-dir:

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

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

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

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

    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     
    

    【讨论】:

      【解决方案2】:

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

      增加然后收缩 etcd 集群

      这种方法的缺点是etcd quorum size是临时增加的,如果多个节点故障,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 文件夹中。

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

      kubeadm init phase etcd local
      

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

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

      然后根据member add命令输出进行调整。 (--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/ 中的数据库,不能在两个 Pod 之间共享。此外,etcd Pod 使用节点网络接口与 etcd 集群通信。
      当然,您可以将 etcd Pod 配置为使用不同的主机目录并使用不同的主机端口作为解决方法,但上述命令假设节点上只有一个 etcd Pod。

      【讨论】:

        猜你喜欢
        • 2019-12-15
        • 2019-06-04
        • 2019-11-16
        • 1970-01-01
        • 1970-01-01
        • 2020-06-10
        • 2020-08-15
        • 2018-12-28
        • 1970-01-01
        相关资源
        最近更新 更多